Commit e9d29e09f2742aa37f083d4169a19384fa91e062
1 parent
5bccb6aa
tests: test common.uopen
Showing
1 changed file
with
151 additions
and
23 deletions
tests/common/test_encoding_handler.py
| 1 | """Test common.ensure_stdout_handles_unicode""" | 1 | """Test common.ensure_stdout_handles_unicode""" |
| 2 | 2 | ||
| 3 | +from __future__ import print_function | ||
| 4 | + | ||
| 3 | import unittest | 5 | import unittest |
| 4 | import sys | 6 | import sys |
| 5 | -from subprocess import check_call | 7 | +from subprocess import check_call, CalledProcessError |
| 6 | from tempfile import mkstemp | 8 | from tempfile import mkstemp |
| 7 | import os | 9 | import os |
| 8 | from os.path import isfile | 10 | from os.path import isfile |
| 11 | +from contextlib import contextmanager | ||
| 12 | + | ||
| 13 | +FILE_TEXT = u'The unicode check mark is \u2713.\n' | ||
| 14 | + | ||
| 15 | +@contextmanager | ||
| 16 | +def temp_file(just_name=True): | ||
| 17 | + """Context manager that creates temp file and deletes it in the end""" | ||
| 18 | + tmp_descriptor = None | ||
| 19 | + tmp_name = None | ||
| 20 | + tmp_handle = None | ||
| 21 | + try: | ||
| 22 | + tmp_descriptor, tmp_name = mkstemp() | ||
| 23 | + | ||
| 24 | + # we create our own file handle since we want to be able to close the | ||
| 25 | + # file and open it again for reading. | ||
| 26 | + # We keep the os-level descriptor open so file name is still reserved | ||
| 27 | + # for us | ||
| 28 | + if just_name: | ||
| 29 | + yield tmp_name | ||
| 30 | + else: | ||
| 31 | + tmp_handle = open(tmp_name, 'wb') | ||
| 32 | + yield tmp_handle, tmp_name | ||
| 33 | + except Exception: | ||
| 34 | + raise | ||
| 35 | + finally: | ||
| 36 | + if tmp_descriptor is not None: | ||
| 37 | + os.close(tmp_descriptor) | ||
| 38 | + if tmp_handle is not None: | ||
| 39 | + tmp_handle.close() | ||
| 40 | + if tmp_name is not None and isfile(tmp_name): | ||
| 41 | + os.unlink(tmp_name) | ||
| 9 | 42 | ||
| 10 | 43 | ||
| 11 | class TestEncodingHandler(unittest.TestCase): | 44 | class TestEncodingHandler(unittest.TestCase): |
| 12 | """Tests replacing stdout encoding in various scenarios""" | 45 | """Tests replacing stdout encoding in various scenarios""" |
| 13 | 46 | ||
| 14 | - def test_base(self): | 47 | + def test_print(self): |
| 15 | """Test regular unicode output not raise error""" | 48 | """Test regular unicode output not raise error""" |
| 16 | check_call('{python} {this_file} print'.format(python=sys.executable, | 49 | check_call('{python} {this_file} print'.format(python=sys.executable, |
| 17 | this_file=__file__), | 50 | this_file=__file__), |
| 18 | shell=True) | 51 | shell=True) |
| 19 | 52 | ||
| 20 | - def test_redirect(self): | 53 | + def test_print_redirect(self): |
| 21 | """ | 54 | """ |
| 22 | Test redirection of unicode output to files does not raise error | 55 | Test redirection of unicode output to files does not raise error |
| 23 | 56 | ||
| 24 | TODO: test this on non-linux OSs | 57 | TODO: test this on non-linux OSs |
| 25 | """ | 58 | """ |
| 26 | - tmp_handle = None | ||
| 27 | - tmp_name = None | ||
| 28 | - try: | ||
| 29 | - tmp_handle, tmp_name = mkstemp() | 59 | + with temp_file() as tmp_file: |
| 30 | check_call('{python} {this_file} print > {tmp_file}' | 60 | check_call('{python} {this_file} print > {tmp_file}' |
| 31 | .format(python=sys.executable, this_file=__file__, | 61 | .format(python=sys.executable, this_file=__file__, |
| 32 | tmp_file=tmp_file), | 62 | tmp_file=tmp_file), |
| 33 | shell=True) | 63 | shell=True) |
| 34 | - except Exception: | ||
| 35 | - raise | ||
| 36 | - finally: | ||
| 37 | - if tmp_handle is not None: | ||
| 38 | - os.close(tmp_handle) | ||
| 39 | - if tmp_name is not None and isfile(tmp_name): | ||
| 40 | - os.unlink(tmp_name) | ||
| 41 | 64 | ||
| 42 | @unittest.skipIf(not sys.platform.startswith('linux'), | 65 | @unittest.skipIf(not sys.platform.startswith('linux'), |
| 43 | 'Only tested on linux sofar') | 66 | 'Only tested on linux sofar') |
| 44 | - def test_no_lang(self): | 67 | + def test_print_no_lang(self): |
| 45 | """ | 68 | """ |
| 46 | Test redirection of unicode output to files does not raise error | 69 | Test redirection of unicode output to files does not raise error |
| 47 | 70 | ||
| @@ -51,28 +74,133 @@ class TestEncodingHandler(unittest.TestCase): | @@ -51,28 +74,133 @@ class TestEncodingHandler(unittest.TestCase): | ||
| 51 | .format(python=sys.executable, this_file=__file__), | 74 | .format(python=sys.executable, this_file=__file__), |
| 52 | shell=True) | 75 | shell=True) |
| 53 | 76 | ||
| 77 | + def test_uopen(self): | ||
| 78 | + """Test that uopen in a nice environment is ok""" | ||
| 79 | + with temp_file(False) as (tmp_handle, tmp_file): | ||
| 80 | + tmp_handle.write(FILE_TEXT.encode('utf8')) | ||
| 81 | + tmp_handle.close() | ||
| 82 | + | ||
| 83 | + try: | ||
| 84 | + check_call('{python} {this_file} read {tmp_file}' | ||
| 85 | + .format(python=sys.executable, this_file=__file__, | ||
| 86 | + tmp_file=tmp_file), | ||
| 87 | + shell=True) | ||
| 88 | + except CalledProcessError as cpe: | ||
| 89 | + self.fail(cpe.output) | ||
| 90 | + | ||
| 91 | + def test_uopen_redirect(self): | ||
| 92 | + """ | ||
| 93 | + Test redirection of unicode output to files does not raise error | ||
| 94 | + | ||
| 95 | + TODO: test this on non-linux OSs | ||
| 96 | + """ | ||
| 97 | + with temp_file(False) as (tmp_handle, tmp_file): | ||
| 98 | + tmp_handle.write(FILE_TEXT.encode('utf8')) | ||
| 99 | + tmp_handle.close() | ||
| 100 | + | ||
| 101 | + with temp_file() as redirect_file: | ||
| 102 | + try: | ||
| 103 | + check_call( | ||
| 104 | + '{python} {this_file} read {tmp_file} >{redirect_file}' | ||
| 105 | + .format(python=sys.executable, this_file=__file__, | ||
| 106 | + tmp_file=tmp_file, redirect_file=redirect_file), | ||
| 107 | + shell=True) | ||
| 108 | + except CalledProcessError as cpe: | ||
| 109 | + self.fail(cpe.output) | ||
| 110 | + | ||
| 111 | + @unittest.skipIf(not sys.platform.startswith('linux'), | ||
| 112 | + 'Only tested on linux sofar') | ||
| 113 | + def test_uopen_no_lang(self): | ||
| 114 | + """ | ||
| 115 | + Test that uopen in a C-LANG environment is ok | ||
| 116 | + | ||
| 117 | + TODO: Adapt this for other OSs; for win create batch script | ||
| 118 | + """ | ||
| 119 | + with temp_file(False) as (tmp_handle, tmp_file): | ||
| 120 | + tmp_handle.write(FILE_TEXT.encode('utf8')) | ||
| 121 | + tmp_handle.close() | ||
| 122 | + | ||
| 123 | + try: | ||
| 124 | + check_call('LANG=C {python} {this_file} read {tmp_file}' | ||
| 125 | + .format(python=sys.executable, this_file=__file__, | ||
| 126 | + tmp_file=tmp_file), | ||
| 127 | + shell=True) | ||
| 128 | + except CalledProcessError as cpe: | ||
| 129 | + self.fail(cpe.output) | ||
| 130 | + | ||
| 131 | + | ||
| 132 | +def run_read(filename): | ||
| 133 | + """This is called from test_uopen* tests as script. Reads text, compares""" | ||
| 134 | + from oletools.common import uopen | ||
| 135 | + # open file | ||
| 136 | + with uopen(filename, 'rt') as reader: | ||
| 137 | + # a few tests | ||
| 138 | + if reader.closed: | ||
| 139 | + raise ValueError('handle is closed!') | ||
| 140 | + if reader.name != filename: | ||
| 141 | + raise ValueError('Wrong filename {}'.format(reader.name)) | ||
| 142 | + if reader.isatty(): | ||
| 143 | + raise ValueError('Reader is a tty!') | ||
| 144 | + if reader.tell() != 0: | ||
| 145 | + raise ValueError('Reader.tell is not 0 at beginning') | ||
| 146 | + | ||
| 147 | + # read text | ||
| 148 | + text = reader.read() | ||
| 149 | + | ||
| 150 | + # a few more tests | ||
| 151 | + if not reader.closed: | ||
| 152 | + raise ValueError('Reader is not closed outside context') | ||
| 153 | + if reader.name != filename: | ||
| 154 | + raise ValueError('Wrong filename {} after context'.format(reader.name)) | ||
| 155 | + if reader.isatty(): | ||
| 156 | + raise ValueError('Reader has become a tty!') | ||
| 157 | + | ||
| 158 | + # compare text | ||
| 159 | + if sys.version_info.major <= 2: # in python2 get encoded byte string | ||
| 160 | + expect = FILE_TEXT.encode('utf8') | ||
| 161 | + else: # python3: should get real unicode | ||
| 162 | + expect = FILE_TEXT | ||
| 163 | + if text != expect: | ||
| 164 | + raise ValueError('Wrong contents: {!r} != {!r}' | ||
| 165 | + .format(text, expect)) | ||
| 166 | + return 0 | ||
| 167 | + | ||
| 168 | + | ||
| 54 | def run_print(): | 169 | def run_print(): |
| 55 | """This is called from test_read* tests as script. Prints & logs unicode""" | 170 | """This is called from test_read* tests as script. Prints & logs unicode""" |
| 56 | - # hack required to import common from parent dir, not system-wide one | ||
| 57 | - # (usually unittest seems to do that for us) | ||
| 58 | - from os.path import abspath, dirname, join | ||
| 59 | - ole_base = dirname(dirname(dirname(abspath(__file__)))) | ||
| 60 | - sys.path.insert(0, ole_base) | 171 | + from oletools.common import ensure_stdout_handles_unicode |
| 172 | + from oletools.common.log_helper import log_helper | ||
| 173 | + ensure_stdout_handles_unicode() | ||
| 174 | + print(u'Check: \u2713') # print check mark | ||
| 61 | 175 | ||
| 62 | - from oletools import common | ||
| 63 | - common.ensure_stdout_handles_unicode() | ||
| 64 | - print(u'\u2713') # print check mark | 176 | + # check logging as well |
| 177 | + logger = log_helper.get_or_create_silent_logger('test_encoding_handler') | ||
| 178 | + log_helper.enable_logging(False, 'debug', stream=sys.stdout) | ||
| 179 | + logger.info(u'Check: \u2713') | ||
| 180 | + return 0 | ||
| 65 | 181 | ||
| 66 | 182 | ||
| 67 | # tests call this file as script | 183 | # tests call this file as script |
| 68 | if __name__ == '__main__': | 184 | if __name__ == '__main__': |
| 69 | if len(sys.argv) < 2: | 185 | if len(sys.argv) < 2: |
| 70 | sys.exit(unittest.main()) | 186 | sys.exit(unittest.main()) |
| 187 | + | ||
| 188 | + # hack required to import common from parent dir, not system-wide one | ||
| 189 | + # (usually unittest seems to do that for us) | ||
| 190 | + from os.path import abspath, dirname, join | ||
| 191 | + ole_base = dirname(dirname(dirname(abspath(__file__)))) | ||
| 192 | + sys.path.insert(0, ole_base) | ||
| 193 | + | ||
| 71 | if sys.argv[1] == 'print': | 194 | if sys.argv[1] == 'print': |
| 72 | if len(sys.argv) > 2: | 195 | if len(sys.argv) > 2: |
| 73 | print('Expect no arg for "print"', file=sys.stderr) | 196 | print('Expect no arg for "print"', file=sys.stderr) |
| 74 | sys.exit(2) | 197 | sys.exit(2) |
| 75 | sys.exit(run_print()) | 198 | sys.exit(run_print()) |
| 199 | + elif sys.argv[1] == 'read': | ||
| 200 | + if len(sys.argv) != 3: | ||
| 201 | + print('Expect single arg for "read"', file=sys.stderr) | ||
| 202 | + sys.exit(2) | ||
| 203 | + sys.exit(run_read(sys.argv[2])) | ||
| 76 | else: | 204 | else: |
| 77 | print('Unexpected argument: {}'.format(sys.argv[1]), file=sys.stderr) | 205 | print('Unexpected argument: {}'.format(sys.argv[1]), file=sys.stderr) |
| 78 | sys.exit(2) | 206 | sys.exit(2) |