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 | 1 | """Test common.ensure_stdout_handles_unicode""" |
| 2 | 2 | |
| 3 | +from __future__ import print_function | |
| 4 | + | |
| 3 | 5 | import unittest |
| 4 | 6 | import sys |
| 5 | -from subprocess import check_call | |
| 7 | +from subprocess import check_call, CalledProcessError | |
| 6 | 8 | from tempfile import mkstemp |
| 7 | 9 | import os |
| 8 | 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 | 44 | class TestEncodingHandler(unittest.TestCase): |
| 12 | 45 | """Tests replacing stdout encoding in various scenarios""" |
| 13 | 46 | |
| 14 | - def test_base(self): | |
| 47 | + def test_print(self): | |
| 15 | 48 | """Test regular unicode output not raise error""" |
| 16 | 49 | check_call('{python} {this_file} print'.format(python=sys.executable, |
| 17 | 50 | this_file=__file__), |
| 18 | 51 | shell=True) |
| 19 | 52 | |
| 20 | - def test_redirect(self): | |
| 53 | + def test_print_redirect(self): | |
| 21 | 54 | """ |
| 22 | 55 | Test redirection of unicode output to files does not raise error |
| 23 | 56 | |
| 24 | 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 | 60 | check_call('{python} {this_file} print > {tmp_file}' |
| 31 | 61 | .format(python=sys.executable, this_file=__file__, |
| 32 | 62 | tmp_file=tmp_file), |
| 33 | 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 | 65 | @unittest.skipIf(not sys.platform.startswith('linux'), |
| 43 | 66 | 'Only tested on linux sofar') |
| 44 | - def test_no_lang(self): | |
| 67 | + def test_print_no_lang(self): | |
| 45 | 68 | """ |
| 46 | 69 | Test redirection of unicode output to files does not raise error |
| 47 | 70 | |
| ... | ... | @@ -51,28 +74,133 @@ class TestEncodingHandler(unittest.TestCase): |
| 51 | 74 | .format(python=sys.executable, this_file=__file__), |
| 52 | 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 | 169 | def run_print(): |
| 55 | 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 | 183 | # tests call this file as script |
| 68 | 184 | if __name__ == '__main__': |
| 69 | 185 | if len(sys.argv) < 2: |
| 70 | 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 | 194 | if sys.argv[1] == 'print': |
| 72 | 195 | if len(sys.argv) > 2: |
| 73 | 196 | print('Expect no arg for "print"', file=sys.stderr) |
| 74 | 197 | sys.exit(2) |
| 75 | 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 | 204 | else: |
| 77 | 205 | print('Unexpected argument: {}'.format(sys.argv[1]), file=sys.stderr) |
| 78 | 206 | sys.exit(2) | ... | ... |