Commit f2d2fe46fc282fa28b5ab1ebd4c30e7dafa1c932
1 parent
0c8e06d9
unittest: Create unittests for json output validity in msodde
Showing
2 changed files
with
96 additions
and
0 deletions
tests/json/__init__.py
0 → 100644
tests/json/test_output.py
0 → 100644
| 1 | +""" Test validity of json output | |
| 2 | + | |
| 3 | +Some scripts have a json output flag. Verify that at default log levels output | |
| 4 | +can be captured as-is and parsed by a json parser -- at least if the scripts | |
| 5 | +return 0 | |
| 6 | +""" | |
| 7 | + | |
| 8 | +import unittest | |
| 9 | +import sys | |
| 10 | +import json | |
| 11 | +import os | |
| 12 | +from os.path import join, dirname, normpath | |
| 13 | +from oletools import msodde | |
| 14 | +from tests.test_utils import OutputCapture | |
| 15 | + | |
| 16 | +if sys.version_info[0] <= 2: | |
| 17 | + from oletools import olevba | |
| 18 | +else: | |
| 19 | + from oletools import olevba3 as olevba | |
| 20 | + | |
| 21 | + | |
| 22 | +# Directory with test data, independent of current working directory | |
| 23 | +DATA_DIR = normpath(join(dirname(__file__), '..', 'test-data')) | |
| 24 | + | |
| 25 | + | |
| 26 | +class TestValidJson(unittest.TestCase): | |
| 27 | + """ Ensure that script output is valid json (if return code is 0) """ | |
| 28 | + | |
| 29 | + def iter_test_files(self): | |
| 30 | + """ Iterate over all test files in DATA_DIR """ | |
| 31 | + for dirpath, _, filenames in os.walk(DATA_DIR): | |
| 32 | + for filename in filenames: | |
| 33 | + yield join(dirpath, filename) | |
| 34 | + | |
| 35 | + def run_and_parse(self, program, args, print_output=False): | |
| 36 | + """ run single program with single file and parse output """ | |
| 37 | + return_code = None | |
| 38 | + with OutputCapture() as capturer: # capture stdout | |
| 39 | + try: | |
| 40 | + return_code = program(args) | |
| 41 | + except Exception: | |
| 42 | + return_code = 1 # would result in non-zero exit | |
| 43 | + except SystemExit as se: | |
| 44 | + return_code = se.code or 0 # se.code can be None | |
| 45 | + if return_code is not 0: | |
| 46 | + if print_output: | |
| 47 | + print('Command failed ({0}) -- not parsing output' | |
| 48 | + .format(return_code)) | |
| 49 | + return # no need to test | |
| 50 | + | |
| 51 | + self.assertNotEqual(return_code, None, | |
| 52 | + msg='self-test fail: return_code not set') | |
| 53 | + | |
| 54 | + # now test output | |
| 55 | + if print_output: | |
| 56 | + print(capturer.buffer.getvalue()) | |
| 57 | + capturer.buffer.seek(0) # re-set position in file-like stream | |
| 58 | + try: | |
| 59 | + json_data = json.load(capturer.buffer) | |
| 60 | + except ValueError: | |
| 61 | + self.fail('Invalid json:\n' + capturer.buffer.getvalue()) | |
| 62 | + self.assertNotEqual(len(json_data), 0, msg='Output was empty') | |
| 63 | + | |
| 64 | + def run_all_files(self, program, args_without_filename, print_output=False): | |
| 65 | + """ run test for a single program over all test files """ | |
| 66 | + n_files = 0 | |
| 67 | + for testfile in self.iter_test_files(): # loop over all input | |
| 68 | + args = args_without_filename + [testfile, ] | |
| 69 | + self.run_and_parse(program, args, print_output) | |
| 70 | + n_files += 1 | |
| 71 | + self.assertNotEqual(n_files, 0, | |
| 72 | + msg='self-test fail: No test files found') | |
| 73 | + | |
| 74 | + def test_msodde(self): | |
| 75 | + """ Test msodde.py """ | |
| 76 | + self.run_all_files(msodde.main, ['-j', ]) | |
| 77 | + | |
| 78 | + @unittest.skip('olevba needs patching to accept custom cmd line args') | |
| 79 | + def test_olevba(self): | |
| 80 | + """ Test olevba.py with default args """ | |
| 81 | + self.run_all_files(olevba.main, ['-j', ]) | |
| 82 | + | |
| 83 | + @unittest.skip('olevba needs patching to accept custom cmd line args') | |
| 84 | + def test_olevba_analysis(self): | |
| 85 | + """ Test olevba.py with default args """ | |
| 86 | + self.run_all_files(olevba.main, ['-j', '-a', ]) | |
| 87 | + | |
| 88 | + @unittest.skip('olevba needs patching to accept custom cmd line args') | |
| 89 | + def test_olevba_recurse(self): | |
| 90 | + """ Test olevba.py with default args """ | |
| 91 | + self.run_and_parse(olevba.main, ['-j', '-r', DATA_DIR], True) | |
| 92 | + | |
| 93 | + | |
| 94 | +# just in case somebody calls this file as a script | |
| 95 | +if __name__ == '__main__': | |
| 96 | + unittest.main() | ... | ... |