Commit f537ec1c584dba651a5c3c0d8515f9fb19085deb

Authored by Christian Herdtweck
1 parent 14e68768

tests: Check behaviour of olevba for rtf, text, empty

Showing 1 changed file with 95 additions and 0 deletions
tests/olevba/test_basic.py
... ... @@ -10,14 +10,109 @@ else:
10 10 from oletools import olevba3 as olevba
11 11 import os
12 12 from os.path import join
  13 +from contextlib import contextmanager
  14 +try:
  15 + from cStringIO import StringIO
  16 +except ImportError: # py3:
  17 + from io import StringIO
13 18  
14 19 # Directory with test data, independent of current working directory
15 20 from tests.test_utils import DATA_BASE_DIR
16 21  
17 22  
  23 +@contextmanager
  24 +def capture_output():
  25 + """
  26 + Temporarily replace stdout/stderr with buffers to capture output.
  27 +
  28 + Once we only support python>=3.4: this is already built into python as
  29 + :py:func:`contextlib.redirect_stdout`.
  30 +
  31 + Not quite sure why, but seems to only work once per test function ...
  32 + """
  33 + orig_stdout = sys.stdout
  34 + orig_stderr = sys.stderr
  35 +
  36 + try:
  37 + sys.stdout = StringIO()
  38 + sys.stderr = StringIO()
  39 + yield sys.stdout, sys.stderr
  40 +
  41 + finally:
  42 + sys.stdout = orig_stdout
  43 + sys.stderr = orig_stderr
  44 +
  45 +
18 46 class TestOlevbaBasic(unittest.TestCase):
19 47 """Tests olevba basic functionality"""
20 48  
  49 + def test_text_behaviour(self):
  50 + """Test behaviour of olevba when presented with pure text file."""
  51 + self.do_test_behaviour('text')
  52 +
  53 + def test_empty_behaviour(self):
  54 + """Test behaviour of olevba when presented with pure text file."""
  55 + self.do_test_behaviour('empty')
  56 +
  57 + def do_test_behaviour(self, filename):
  58 + input_file = join(DATA_BASE_DIR, 'basic', filename)
  59 + ret_code = -1
  60 +
  61 + # run olevba, capturing its output and return code
  62 + with capture_output() as (stdout, stderr):
  63 + with self.assertRaises(SystemExit) as raise_context:
  64 + olevba.main([input_file, ])
  65 + ret_code = raise_context.exception.code
  66 +
  67 + # check that return code is 0
  68 + self.assertEqual(ret_code, 0)
  69 +
  70 + # check there are only warnings in stderr
  71 + stderr = stderr.getvalue()
  72 + skip_line = False
  73 + for line in stderr.splitlines():
  74 + if skip_line:
  75 + skip_line = False
  76 + continue
  77 + self.assertTrue(line.startswith('WARNING ') or
  78 + 'ResourceWarning' in line,
  79 + msg='Line "{}" in stderr is unexpected for {}'
  80 + .format(line.rstrip(), filename))
  81 + if 'ResourceWarning' in line:
  82 + skip_line = True
  83 + self.assertIn('not encrypted', stderr)
  84 +
  85 + # check stdout
  86 + stdout = stdout.getvalue().lower()
  87 + self.assertIn(input_file.lower(), stdout)
  88 + self.assertIn('type: text', stdout)
  89 + self.assertIn('no suspicious', stdout)
  90 + self.assertNotIn('error', stdout)
  91 + self.assertNotIn('warn', stdout)
  92 +
  93 + def test_rtf_behaviour(self):
  94 + """Test behaviour of olevba when presented with an rtf file."""
  95 + input_file = join(DATA_BASE_DIR, 'msodde', 'RTF-Spec-1.7.rtf')
  96 + ret_code = -1
  97 +
  98 + # run olevba, capturing its output and return code
  99 + with capture_output() as (stdout, stderr):
  100 + with self.assertRaises(SystemExit) as raise_context:
  101 + olevba.main([input_file, ])
  102 + ret_code = raise_context.exception.code
  103 +
  104 + # check that return code is olevba.RETURN_OPEN_ERROR
  105 + self.assertEqual(ret_code, 5)
  106 + stdout = stdout.getvalue().lower()
  107 + self.assertNotIn('error', stdout)
  108 + self.assertNotIn('warn', stdout)
  109 +
  110 + stderr = stderr.getvalue().lower()
  111 + self.assertIn('fileopenerror', stderr)
  112 + self.assertIn('is rtf', stderr)
  113 + self.assertIn('rtfobj.py', stderr)
  114 + self.assertIn('not encrypted', stderr)
  115 +
21 116 def test_crypt_return(self):
22 117 """
23 118 Tests that encrypted files give a certain return code.
... ...