| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Simplify unit tests based on pymox.""" | 6 """Simplify unit tests based on pymox.""" |
| 7 | 7 |
| 8 import __builtin__ | |
| 9 import os | 8 import os |
| 10 import random | 9 import random |
| 11 import shutil | 10 import shutil |
| 12 import string | 11 import string |
| 13 import StringIO | 12 import StringIO |
| 14 import subprocess | 13 import subprocess |
| 15 import sys | 14 import sys |
| 16 | 15 |
| 17 sys.path.append(os.path.dirname(os.path.dirname(__file__))) | 16 sys.path.append(os.path.dirname(os.path.dirname(__file__))) |
| 18 from third_party.pymox import mox | 17 from third_party.pymox import mox |
| (...skipping 15 matching lines...) Expand all Loading... |
| 34 to use SuperMoxTestBase instead.""" | 33 to use SuperMoxTestBase instead.""" |
| 35 # Backup the separator in case it gets mocked | 34 # Backup the separator in case it gets mocked |
| 36 _OS_SEP = os.sep | 35 _OS_SEP = os.sep |
| 37 _RANDOM_CHOICE = random.choice | 36 _RANDOM_CHOICE = random.choice |
| 38 _RANDOM_RANDINT = random.randint | 37 _RANDOM_RANDINT = random.randint |
| 39 _STRING_LETTERS = string.letters | 38 _STRING_LETTERS = string.letters |
| 40 | 39 |
| 41 ## Some utilities for generating arbitrary arguments. | 40 ## Some utilities for generating arbitrary arguments. |
| 42 def String(self, max_length): | 41 def String(self, max_length): |
| 43 return ''.join([self._RANDOM_CHOICE(self._STRING_LETTERS) | 42 return ''.join([self._RANDOM_CHOICE(self._STRING_LETTERS) |
| 44 for x in xrange(self._RANDOM_RANDINT(1, max_length))]) | 43 for _ in xrange(self._RANDOM_RANDINT(1, max_length))]) |
| 45 | 44 |
| 46 def Strings(self, max_arg_count, max_arg_length): | 45 def Strings(self, max_arg_count, max_arg_length): |
| 47 return [self.String(max_arg_length) for x in xrange(max_arg_count)] | 46 return [self.String(max_arg_length) for _ in xrange(max_arg_count)] |
| 48 | 47 |
| 49 def Args(self, max_arg_count=8, max_arg_length=16): | 48 def Args(self, max_arg_count=8, max_arg_length=16): |
| 50 return self.Strings(max_arg_count, | 49 return self.Strings(max_arg_count, |
| 51 self._RANDOM_RANDINT(1, max_arg_length)) | 50 self._RANDOM_RANDINT(1, max_arg_length)) |
| 52 | 51 |
| 53 def _DirElts(self, max_elt_count=4, max_elt_length=8): | 52 def _DirElts(self, max_elt_count=4, max_elt_length=8): |
| 54 return self._OS_SEP.join(self.Strings(max_elt_count, max_elt_length)) | 53 return self._OS_SEP.join(self.Strings(max_elt_count, max_elt_length)) |
| 55 | 54 |
| 56 def Dir(self, max_elt_count=4, max_elt_length=8): | 55 def Dir(self, max_elt_count=4, max_elt_length=8): |
| 57 return (self._RANDOM_CHOICE((self._OS_SEP, '')) + | 56 return (self._RANDOM_CHOICE((self._OS_SEP, '')) + |
| (...skipping 10 matching lines...) Expand all Loading... |
| 68 def compareMembers(self, obj, members): | 67 def compareMembers(self, obj, members): |
| 69 """If you add a member, be sure to add the relevant test!""" | 68 """If you add a member, be sure to add the relevant test!""" |
| 70 # Skip over members starting with '_' since they are usually not meant to | 69 # Skip over members starting with '_' since they are usually not meant to |
| 71 # be for public use. | 70 # be for public use. |
| 72 actual_members = [x for x in sorted(dir(obj)) | 71 actual_members = [x for x in sorted(dir(obj)) |
| 73 if not x.startswith('_')] | 72 if not x.startswith('_')] |
| 74 expected_members = sorted(members) | 73 expected_members = sorted(members) |
| 75 if actual_members != expected_members: | 74 if actual_members != expected_members: |
| 76 diff = ([i for i in actual_members if i not in expected_members] + | 75 diff = ([i for i in actual_members if i not in expected_members] + |
| 77 [i for i in expected_members if i not in actual_members]) | 76 [i for i in expected_members if i not in actual_members]) |
| 78 print>>sys.stderr, diff | 77 print >> sys.stderr, diff |
| 78 # pylint: disable=E1101 |
| 79 self.assertEqual(actual_members, expected_members) | 79 self.assertEqual(actual_members, expected_members) |
| 80 | 80 |
| 81 def setUp(self): | 81 def setUp(self): |
| 82 self.root_dir = self.Dir() | 82 self.root_dir = self.Dir() |
| 83 self.args = self.Args() | 83 self.args = self.Args() |
| 84 self.relpath = self.String(200) | 84 self.relpath = self.String(200) |
| 85 | 85 |
| 86 def tearDown(self): | 86 def tearDown(self): |
| 87 pass | 87 pass |
| 88 | 88 |
| 89 | 89 |
| 90 class StdoutCheck(object): | 90 class StdoutCheck(object): |
| 91 def setUp(self): | 91 def setUp(self): |
| 92 # Override the mock with a StringIO, it's much less painful to test. | 92 # Override the mock with a StringIO, it's much less painful to test. |
| 93 self._old_stdout = sys.stdout | 93 self._old_stdout = sys.stdout |
| 94 sys.stdout = StringIO.StringIO() | 94 sys.stdout = StringIO.StringIO() |
| 95 sys.stdout.flush = lambda: None | 95 sys.stdout.flush = lambda: None |
| 96 | 96 |
| 97 def tearDown(self): | 97 def tearDown(self): |
| 98 try: | 98 try: |
| 99 # If sys.stdout was used, self.checkstdout() must be called. | 99 # If sys.stdout was used, self.checkstdout() must be called. |
| 100 # pylint: disable=E1101 |
| 100 self.assertEquals('', sys.stdout.getvalue()) | 101 self.assertEquals('', sys.stdout.getvalue()) |
| 101 except AttributeError: | 102 except AttributeError: |
| 102 pass | 103 pass |
| 103 sys.stdout = self._old_stdout | 104 sys.stdout = self._old_stdout |
| 104 | 105 |
| 105 def checkstdout(self, expected): | 106 def checkstdout(self, expected): |
| 106 value = sys.stdout.getvalue() | 107 value = sys.stdout.getvalue() |
| 107 sys.stdout.close() | 108 sys.stdout.close() |
| 109 # pylint: disable=E1101 |
| 108 self.assertEquals(expected, value) | 110 self.assertEquals(expected, value) |
| 109 | 111 |
| 110 | 112 |
| 111 class SuperMoxTestBase(TestCaseUtils, StdoutCheck, mox.MoxTestBase): | 113 class SuperMoxTestBase(TestCaseUtils, StdoutCheck, mox.MoxTestBase): |
| 112 def setUp(self): | 114 def setUp(self): |
| 113 """Patch a few functions with know side-effects.""" | 115 """Patch a few functions with know side-effects.""" |
| 114 TestCaseUtils.setUp(self) | 116 TestCaseUtils.setUp(self) |
| 115 mox.MoxTestBase.setUp(self) | 117 mox.MoxTestBase.setUp(self) |
| 116 #self.mox.StubOutWithMock(__builtin__, 'open') | |
| 117 os_to_mock = ('chdir', 'chown', 'close', 'closerange', 'dup', 'dup2', | 118 os_to_mock = ('chdir', 'chown', 'close', 'closerange', 'dup', 'dup2', |
| 118 'fchdir', 'fchmod', 'fchown', 'fdopen', 'getcwd', 'getpid', 'lseek', | 119 'fchdir', 'fchmod', 'fchown', 'fdopen', 'getcwd', 'getpid', 'lseek', |
| 119 'makedirs', 'mkdir', 'open', 'popen', 'popen2', 'popen3', 'popen4', | 120 'makedirs', 'mkdir', 'open', 'popen', 'popen2', 'popen3', 'popen4', |
| 120 'read', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'symlink', | 121 'read', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'symlink', |
| 121 'system', 'tmpfile', 'walk', 'write') | 122 'system', 'tmpfile', 'walk', 'write') |
| 122 self.MockList(os, os_to_mock) | 123 self.MockList(os, os_to_mock) |
| 123 os_path_to_mock = ('abspath', 'exists', 'getsize', 'isdir', 'isfile', | 124 os_path_to_mock = ('abspath', 'exists', 'getsize', 'isdir', 'isfile', |
| 124 'islink', 'ismount', 'lexists', 'realpath', 'samefile', 'walk') | 125 'islink', 'ismount', 'lexists', 'realpath', 'samefile', 'walk') |
| 125 self.MockList(os.path, os_path_to_mock) | 126 self.MockList(os.path, os_path_to_mock) |
| 126 self.MockList(shutil, ('rmtree')) | 127 self.MockList(shutil, ('rmtree')) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 137 def MockList(self, parent, items_to_mock): | 138 def MockList(self, parent, items_to_mock): |
| 138 for item in items_to_mock: | 139 for item in items_to_mock: |
| 139 # Skip over items not present because of OS-specific implementation, | 140 # Skip over items not present because of OS-specific implementation, |
| 140 # implemented only in later python version, etc. | 141 # implemented only in later python version, etc. |
| 141 if hasattr(parent, item): | 142 if hasattr(parent, item): |
| 142 try: | 143 try: |
| 143 self.mox.StubOutWithMock(parent, item) | 144 self.mox.StubOutWithMock(parent, item) |
| 144 except TypeError: | 145 except TypeError: |
| 145 raise TypeError('Couldn\'t mock %s in %s' % (item, parent.__name__)) | 146 raise TypeError('Couldn\'t mock %s in %s' % (item, parent.__name__)) |
| 146 | 147 |
| 147 def UnMock(self, object, name): | 148 def UnMock(self, obj, name): |
| 148 """Restore an object inside a test.""" | 149 """Restore an object inside a test.""" |
| 149 for (parent, old_child, child_name) in self.mox.stubs.cache: | 150 for (parent, old_child, child_name) in self.mox.stubs.cache: |
| 150 if parent == object and child_name == name: | 151 if parent == obj and child_name == name: |
| 151 setattr(parent, child_name, old_child) | 152 setattr(parent, child_name, old_child) |
| 152 break | 153 break |
| OLD | NEW |