Skip to content

Commit

Permalink
Added unit test for #254 and isolate() and isolation() decorators and…
Browse files Browse the repository at this point in the history
… context managers.
  • Loading branch information
Bryan Worrell committed Jun 7, 2015
1 parent e7b7a72 commit b5673a5
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 1 deletion.
85 changes: 85 additions & 0 deletions cybox/test/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Copyright (c) 2015, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.

import sys
import json
import logging
import unittest
import functools
import contextlib

from mixbox.binding_utils import ExternalEncoding
from mixbox.vendor import six
Expand All @@ -14,6 +17,88 @@
logger = logging.getLogger(__name__)


@contextlib.contextmanager
def isolation():
"""Context manager that attempts to reset the sys.modules and globals()
to its initial state.
This helps eliminate issues where tests pass because of residuals caused
by previous imports.
Any code which leverages this context manager will need to re-import all
dependencies within.
"""
def del_sys_modules(to_del):
for mod in to_del:
del sys.modules[mod]

def del_globals(to_del):
for g in globals_to_del:
del globals()[g]

mods_snapshot = sys.modules.copy()
globals_snapshot = globals().copy()

required_mods = ('unittest', 'logging', 'contextlib', 'json', 'six',
'inspect', 'functools', 'sys')

required_globals = ('__builtins__', '__name__', '__doc__', '__package__',
'__loader__', '__spec__')

# Removing parent test packages will raise a warning when importing within
# the context manager.
test_mods = tuple(m for m in sys.modules if m.startswith('cybox.test'))

# Modules we want to keep in the sys.modules
mods_to_keep = sys.builtin_module_names + test_mods + required_mods

# Globals we want to keep in globals()
globals_to_keep = mods_to_keep + required_globals

# Globals and modules we want to remove.
mods_to_del = (m for m in mods_snapshot if not m in mods_to_keep)
globals_to_del = (g for g in globals_snapshot if g not in globals_to_keep)

try:
# Remove sys.modules and globals entries that are not required for
# the unit test.
del_sys_modules(mods_to_del)
del_globals(globals_to_del)

# Return to caller
yield

finally:
# Reset everything to the way it was.
mods_to_del = [m for m in sys.modules if m not in mods_snapshot]
globals_to_del = [g for g in globals() if g not in globals_snapshot]

# Remove any imports that may have occurred inside the context manager.
del_sys_modules(mods_to_del)
del_globals(globals_to_del)

# Reset everything to the way it was..sorta
sys.modules.update(mods_snapshot)
globals().update(globals_snapshot)


def isolate(func):
"""Decorator which leverages the ``isolation`` contextmanager to make the
decorated function unaware of outside imports or globals.
The globals() and sys.modules are returned to their previous state once
the decorated function exits.
This helps test units that should fail but pass due to residuals from
previous imports.
"""
@functools.wraps(func)
def inner(*args, **kwargs):
with isolation():
return func(*args, **kwargs)
return inner


def assert_equal_ignore(item1, item2, ignore_keys=None):
"""Recursively compare two dictionaries, ignoring differences in some keys.
"""
Expand Down
10 changes: 9 additions & 1 deletion cybox/test/common/object_properties_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from cybox.common import ObjectProperties, Property
from cybox.objects.address_object import Address
from cybox.test import EntityTestCase
from cybox.test import EntityTestCase, isolate


class TestProperty(EntityTestCase, unittest.TestCase):
Expand Down Expand Up @@ -48,5 +48,13 @@ def test_detect_address(self):
self.assertTrue(isinstance(obj, Address))


@isolate
def test_parent(self):
"""Test that the ``parent`` property of an ObjectProperties object
does not raise an AttributeError.
"""
from cybox.objects.address_object import Address
self.assertTrue(bool(Address().parent.id_))

if __name__ == "__main__":
unittest.main()

0 comments on commit b5673a5

Please sign in to comment.