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__ | 8 import __builtin__ |
9 import os | 9 import os |
10 import random | 10 import random |
(...skipping 10 matching lines...) Expand all Loading... |
21 def __init__(self, keys): | 21 def __init__(self, keys): |
22 self._keys = keys | 22 self._keys = keys |
23 | 23 |
24 def equals(self, rhs): | 24 def equals(self, rhs): |
25 return rhs in self._keys | 25 return rhs in self._keys |
26 | 26 |
27 def __repr__(self): | 27 def __repr__(self): |
28 return '<sequence or map containing \'%s\'>' % str(self._keys) | 28 return '<sequence or map containing \'%s\'>' % str(self._keys) |
29 | 29 |
30 | 30 |
31 class SuperMoxBaseTestBase(mox.MoxTestBase): | 31 class TestCaseUtils(object): |
32 """Base class with some additional functionalities. People will usually want | 32 """Base class with some additional functionalities. People will usually want |
33 to use SuperMoxTestBase instead.""" | 33 to use SuperMoxTestBase instead.""" |
34 # Backup the separator in case it gets mocked | 34 # Backup the separator in case it gets mocked |
35 _OS_SEP = os.sep | 35 _OS_SEP = os.sep |
36 _RANDOM_CHOICE = random.choice | 36 _RANDOM_CHOICE = random.choice |
37 _RANDOM_RANDINT = random.randint | 37 _RANDOM_RANDINT = random.randint |
38 _STRING_LETTERS = string.letters | 38 _STRING_LETTERS = string.letters |
39 | 39 |
40 ## Some utilities for generating arbitrary arguments. | 40 ## Some utilities for generating arbitrary arguments. |
41 def String(self, max_length): | 41 def String(self, max_length): |
42 return ''.join([self._RANDOM_CHOICE(self._STRING_LETTERS) | 42 return ''.join([self._RANDOM_CHOICE(self._STRING_LETTERS) |
43 for x in xrange(self._RANDOM_RANDINT(1, max_length))]) | 43 for x in xrange(self._RANDOM_RANDINT(1, max_length))]) |
44 | 44 |
45 def Strings(self, max_arg_count, max_arg_length): | 45 def Strings(self, max_arg_count, max_arg_length): |
46 return [self.String(max_arg_length) for x in xrange(max_arg_count)] | 46 return [self.String(max_arg_length) for x in xrange(max_arg_count)] |
47 | 47 |
48 def Args(self, max_arg_count=8, max_arg_length=16): | 48 def Args(self, max_arg_count=8, max_arg_length=16): |
49 return self.Strings(max_arg_count, | 49 return self.Strings(max_arg_count, |
50 self._RANDOM_RANDINT(1, max_arg_length)) | 50 self._RANDOM_RANDINT(1, max_arg_length)) |
51 | 51 |
52 def _DirElts(self, max_elt_count=4, max_elt_length=8): | 52 def _DirElts(self, max_elt_count=4, max_elt_length=8): |
53 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)) |
54 | 54 |
55 def Dir(self, max_elt_count=4, max_elt_length=8): | 55 def Dir(self, max_elt_count=4, max_elt_length=8): |
56 return (self._RANDOM_CHOICE((self._OS_SEP, '')) + | 56 return (self._RANDOM_CHOICE((self._OS_SEP, '')) + |
57 self._DirElts(max_elt_count, max_elt_length)) | 57 self._DirElts(max_elt_count, max_elt_length)) |
58 | 58 |
59 def Url(self, max_elt_count=4, max_elt_length=8): | 59 def SvnUrl(self, max_elt_count=4, max_elt_length=8): |
60 return ('svn://random_host:port/a' + | 60 return ('svn://random_host:port/a' + |
61 self._DirElts(max_elt_count, max_elt_length | 61 self._DirElts(max_elt_count, max_elt_length |
62 ).replace(self._OS_SEP, '/')) | 62 ).replace(self._OS_SEP, '/')) |
63 | 63 |
64 def RootDir(self, max_elt_count=4, max_elt_length=8): | 64 def RootDir(self, max_elt_count=4, max_elt_length=8): |
65 return self._OS_SEP + self._DirElts(max_elt_count, max_elt_length) | 65 return self._OS_SEP + self._DirElts(max_elt_count, max_elt_length) |
66 | 66 |
67 def compareMembers(self, object, members): | 67 def compareMembers(self, obj, members): |
68 """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!""" |
69 # 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 |
70 # be for public use. | 70 # be for public use. |
71 actual_members = [x for x in sorted(dir(object)) | 71 actual_members = [x for x in sorted(dir(obj)) |
72 if not x.startswith('_')] | 72 if not x.startswith('_')] |
73 expected_members = sorted(members) | 73 expected_members = sorted(members) |
74 if actual_members != expected_members: | 74 if actual_members != expected_members: |
75 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] + |
76 [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]) |
77 print>>sys.stderr, diff | 77 print>>sys.stderr, diff |
78 self.assertEqual(actual_members, expected_members) | 78 self.assertEqual(actual_members, expected_members) |
79 | 79 |
80 def UnMock(self, object, name): | 80 def setUp(self): |
81 """Restore an object inside a test.""" | 81 self.root_dir = self.Dir() |
82 for (parent, old_child, child_name) in self.mox.stubs.cache: | 82 self.args = self.Args() |
83 if parent == object and child_name == name: | 83 self.relpath = self.String(200) |
84 setattr(parent, child_name, old_child) | 84 |
85 break | 85 def tearDown(self): |
| 86 pass |
86 | 87 |
87 | 88 |
88 class SuperMoxTestBase(SuperMoxBaseTestBase): | 89 class SuperMoxTestBase(TestCaseUtils, mox.MoxTestBase): |
89 def setUp(self): | 90 def setUp(self): |
90 """Patch a few functions with know side-effects.""" | 91 """Patch a few functions with know side-effects.""" |
91 SuperMoxBaseTestBase.setUp(self) | 92 TestCaseUtils.setUp(self) |
| 93 mox.MoxTestBase.setUp(self) |
92 #self.mox.StubOutWithMock(__builtin__, 'open') | 94 #self.mox.StubOutWithMock(__builtin__, 'open') |
93 os_to_mock = ('chdir', 'chown', 'close', 'closerange', 'dup', 'dup2', | 95 os_to_mock = ('chdir', 'chown', 'close', 'closerange', 'dup', 'dup2', |
94 'fchdir', 'fchmod', 'fchown', 'fdopen', 'getcwd', 'getpid', 'lseek', | 96 'fchdir', 'fchmod', 'fchown', 'fdopen', 'getcwd', 'getpid', 'lseek', |
95 'makedirs', 'mkdir', 'open', 'popen', 'popen2', 'popen3', 'popen4', | 97 'makedirs', 'mkdir', 'open', 'popen', 'popen2', 'popen3', 'popen4', |
96 'read', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'symlink', | 98 'read', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'symlink', |
97 'system', 'tmpfile', 'walk', 'write') | 99 'system', 'tmpfile', 'walk', 'write') |
98 self.MockList(os, os_to_mock) | 100 self.MockList(os, os_to_mock) |
99 os_path_to_mock = ('abspath', 'exists', 'getsize', 'isdir', 'isfile', | 101 os_path_to_mock = ('abspath', 'exists', 'getsize', 'isdir', 'isfile', |
100 'islink', 'ismount', 'lexists', 'realpath', 'samefile', 'walk') | 102 'islink', 'ismount', 'lexists', 'realpath', 'samefile', 'walk') |
101 self.MockList(os.path, os_path_to_mock) | 103 self.MockList(os.path, os_path_to_mock) |
102 self.MockList(shutil, ('rmtree')) | 104 self.MockList(shutil, ('rmtree')) |
103 self.MockList(subprocess, ('call', 'Popen')) | 105 self.MockList(subprocess, ('call', 'Popen')) |
104 # Don't mock stderr since it confuses unittests. | 106 # Don't mock stderr since it confuses unittests. |
105 self.MockList(sys, ('stdin', 'stdout')) | 107 self.MockList(sys, ('stdin', 'stdout')) |
106 | 108 |
| 109 def tearDown(self): |
| 110 TestCaseUtils.tearDown(self) |
| 111 mox.MoxTestBase.tearDown(self) |
| 112 |
107 def MockList(self, parent, items_to_mock): | 113 def MockList(self, parent, items_to_mock): |
108 for item in items_to_mock: | 114 for item in items_to_mock: |
109 # Skip over items not present because of OS-specific implementation, | 115 # Skip over items not present because of OS-specific implementation, |
110 # implemented only in later python version, etc. | 116 # implemented only in later python version, etc. |
111 if hasattr(parent, item): | 117 if hasattr(parent, item): |
112 try: | 118 try: |
113 self.mox.StubOutWithMock(parent, item) | 119 self.mox.StubOutWithMock(parent, item) |
114 except TypeError: | 120 except TypeError: |
115 raise TypeError('Couldn\'t mock %s in %s' % (item, parent.__name__)) | 121 raise TypeError('Couldn\'t mock %s in %s' % (item, parent.__name__)) |
| 122 |
| 123 def UnMock(self, object, name): |
| 124 """Restore an object inside a test.""" |
| 125 for (parent, old_child, child_name) in self.mox.stubs.cache: |
| 126 if parent == object and child_name == name: |
| 127 setattr(parent, child_name, old_child) |
| 128 break |
OLD | NEW |