| OLD | NEW |
| (Empty) | |
| 1 import os |
| 2 import shutil |
| 3 import subprocess |
| 4 import tempfile |
| 5 import unittest |
| 6 |
| 7 |
| 8 class SetupStack(object): |
| 9 |
| 10 def __init__(self): |
| 11 self._on_teardown = [] |
| 12 |
| 13 def add_teardown(self, teardown): |
| 14 self._on_teardown.append(teardown) |
| 15 |
| 16 def tear_down(self): |
| 17 for func in reversed(self._on_teardown): |
| 18 func() |
| 19 |
| 20 |
| 21 class TearDownConvenience(object): |
| 22 |
| 23 def __init__(self, setup_stack=None): |
| 24 self._own_setup_stack = setup_stack is None |
| 25 if setup_stack is None: |
| 26 setup_stack = SetupStack() |
| 27 self._setup_stack = setup_stack |
| 28 |
| 29 # only call this convenience method if no setup_stack was supplied to c'tor |
| 30 def tear_down(self): |
| 31 assert self._own_setup_stack |
| 32 self._setup_stack.tear_down() |
| 33 |
| 34 |
| 35 class TempDirMaker(TearDownConvenience): |
| 36 |
| 37 def make_temp_dir(self, dir_=None): |
| 38 temp_dir = tempfile.mkdtemp(prefix="tmp-%s-" % self.__class__.__name__, |
| 39 dir=dir_) |
| 40 def tear_down(): |
| 41 shutil.rmtree(temp_dir) |
| 42 self._setup_stack.add_teardown(tear_down) |
| 43 return temp_dir |
| 44 |
| 45 |
| 46 class MonkeyPatcher(TearDownConvenience): |
| 47 |
| 48 Unset = object() |
| 49 |
| 50 def monkey_patch(self, obj, name, value): |
| 51 orig_value = getattr(obj, name) |
| 52 setattr(obj, name, value) |
| 53 def reverse_patch(): |
| 54 setattr(obj, name, orig_value) |
| 55 self._setup_stack.add_teardown(reverse_patch) |
| 56 |
| 57 def _set_environ(self, env, name, value): |
| 58 if value is self.Unset: |
| 59 try: |
| 60 del env[name] |
| 61 except KeyError: |
| 62 pass |
| 63 else: |
| 64 env[name] = value |
| 65 |
| 66 def monkey_patch_environ(self, name, value, env=os.environ): |
| 67 orig_value = env.get(name, self.Unset) |
| 68 self._set_environ(env, name, value) |
| 69 def reverse_patch(): |
| 70 self._set_environ(env, name, orig_value) |
| 71 self._setup_stack.add_teardown(reverse_patch) |
| 72 |
| 73 |
| 74 class FixtureFactory(object): |
| 75 |
| 76 def __init__(self): |
| 77 self._setup_stack = SetupStack() |
| 78 self._context_managers = {} |
| 79 self._fixtures = {} |
| 80 |
| 81 def register_context_manager(self, name, context_manager): |
| 82 self._context_managers[name] = context_manager |
| 83 |
| 84 def get_fixture(self, name, add_teardown): |
| 85 context_manager = self._context_managers[name] |
| 86 fixture = context_manager.__enter__() |
| 87 add_teardown(lambda: context_manager.__exit__(None, None, None)) |
| 88 return fixture |
| 89 |
| 90 def get_cached_fixture(self, name): |
| 91 fixture = self._fixtures.get(name) |
| 92 if fixture is None: |
| 93 fixture = self.get_fixture(name, self._setup_stack.add_teardown) |
| 94 self._fixtures[name] = fixture |
| 95 return fixture |
| 96 |
| 97 def tear_down(self): |
| 98 self._setup_stack.tear_down() |
| 99 |
| 100 |
| 101 class TestCase(unittest.TestCase): |
| 102 |
| 103 def setUp(self): |
| 104 self._setup_stack = SetupStack() |
| 105 self._monkey_patcher = MonkeyPatcher(self._setup_stack) |
| 106 |
| 107 def tearDown(self): |
| 108 self._setup_stack.tear_down() |
| 109 |
| 110 def register_context_manager(self, name, context_manager): |
| 111 return self.fixture_factory.register_context_manager( |
| 112 name, context_manager) |
| 113 |
| 114 def get_fixture(self, name): |
| 115 return self.fixture_factory.get_fixture(name, self.add_teardown) |
| 116 |
| 117 def get_cached_fixture(self, name): |
| 118 return self.fixture_factory.get_cached_fixture(name) |
| 119 |
| 120 def add_teardown(self, *args, **kwds): |
| 121 self._setup_stack.add_teardown(*args, **kwds) |
| 122 |
| 123 def make_temp_dir(self, *args, **kwds): |
| 124 return TempDirMaker(self._setup_stack).make_temp_dir(*args, **kwds) |
| 125 |
| 126 def monkey_patch(self, *args, **kwds): |
| 127 return self._monkey_patcher.monkey_patch(*args, **kwds) |
| 128 |
| 129 def monkey_patch_environ(self, *args, **kwds): |
| 130 return self._monkey_patcher.monkey_patch_environ(*args, **kwds) |
| 131 |
| 132 def assert_contains(self, container, containee): |
| 133 self.assertTrue(containee in container, "%r not in %r" % |
| 134 (containee, container)) |
| 135 |
| 136 def assert_less_than(self, got, expected): |
| 137 self.assertTrue(got < expected, "%r >= %r" % |
| 138 (got, expected)) |
| 139 |
| 140 |
| 141 # http://lackingrhoticity.blogspot.com/2009/01/testing-using-golden-files-in-py
thon.html |
| 142 |
| 143 class GoldenTestCase(TestCase): |
| 144 |
| 145 run_meld = False |
| 146 |
| 147 def assert_golden(self, dir_got, dir_expect): |
| 148 assert os.path.exists(dir_expect), dir_expect |
| 149 proc = subprocess.Popen(["diff", "--recursive", "-u", "-N", |
| 150 "--exclude=.*", dir_expect, dir_got], |
| 151 stdout=subprocess.PIPE) |
| 152 stdout, stderr = proc.communicate() |
| 153 if len(stdout) > 0: |
| 154 if self.run_meld: |
| 155 # Put expected output on the right because that is the |
| 156 # side we usually edit. |
| 157 subprocess.call(["meld", dir_got, dir_expect]) |
| 158 raise AssertionError( |
| 159 "Differences from golden files found.\n" |
| 160 "Try running with --meld to update golden files.\n" |
| 161 "%s" % stdout) |
| 162 self.assertEquals(proc.wait(), 0) |
| OLD | NEW |