Commit f2d2fe46fc282fa28b5ab1ebd4c30e7dafa1c932

Authored by Christian Herdtweck
1 parent 0c8e06d9

unittest: Create unittests for json output validity in msodde

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()
... ...