OLD | NEW |
| (Empty) |
1 # Copyright (c) 2001-2007 Twisted Matrix Laboratories. | |
2 # See LICENSE for details. | |
3 | |
4 | |
5 import sys, os | |
6 import new | |
7 | |
8 from twisted.trial import unittest | |
9 from twisted.python import rebuild | |
10 | |
11 import crash_test_dummy | |
12 f = crash_test_dummy.foo | |
13 | |
14 class Foo: pass | |
15 class Bar(Foo): pass | |
16 class Baz(object): pass | |
17 class Buz(Bar, Baz): pass | |
18 | |
19 class RebuildTestCase(unittest.TestCase): | |
20 """ | |
21 Simple testcase for rebuilding, to at least exercise the code. | |
22 """ | |
23 def setUp(self): | |
24 self.libPath = self.mktemp() | |
25 os.mkdir(self.libPath) | |
26 self.fakelibPath = os.path.join(self.libPath, 'twisted_rebuild_fakelib') | |
27 os.mkdir(self.fakelibPath) | |
28 file(os.path.join(self.fakelibPath, '__init__.py'), 'w').close() | |
29 sys.path.insert(0, self.libPath) | |
30 | |
31 def tearDown(self): | |
32 sys.path.remove(self.libPath) | |
33 | |
34 def testFileRebuild(self): | |
35 from twisted.python.util import sibpath | |
36 import shutil, time | |
37 shutil.copyfile(sibpath(__file__, "myrebuilder1.py"), | |
38 os.path.join(self.fakelibPath, "myrebuilder.py")) | |
39 from twisted_rebuild_fakelib import myrebuilder | |
40 a = myrebuilder.A() | |
41 try: | |
42 object | |
43 except NameError: | |
44 pass | |
45 else: | |
46 from twisted.test import test_rebuild | |
47 b = myrebuilder.B() | |
48 class C(myrebuilder.B): | |
49 pass | |
50 test_rebuild.C = C | |
51 c = C() | |
52 i = myrebuilder.Inherit() | |
53 self.assertEquals(a.a(), 'a') | |
54 # necessary because the file has not "changed" if a second has not gone | |
55 # by in unix. This sucks, but it's not often that you'll be doing more | |
56 # than one reload per second. | |
57 time.sleep(1.1) | |
58 shutil.copyfile(sibpath(__file__, "myrebuilder2.py"), | |
59 os.path.join(self.fakelibPath, "myrebuilder.py")) | |
60 rebuild.rebuild(myrebuilder) | |
61 try: | |
62 object | |
63 except NameError: | |
64 pass | |
65 else: | |
66 b2 = myrebuilder.B() | |
67 self.assertEquals(b2.b(), 'c') | |
68 self.assertEquals(b.b(), 'c') | |
69 self.assertEquals(i.a(), 'd') | |
70 self.assertEquals(a.a(), 'b') | |
71 # more work to be done on new-style classes | |
72 # self.assertEquals(c.b(), 'c') | |
73 | |
74 def testRebuild(self): | |
75 """ | |
76 Rebuilding an unchanged module. | |
77 """ | |
78 # This test would actually pass if rebuild was a no-op, but it | |
79 # ensures rebuild doesn't break stuff while being a less | |
80 # complex test than testFileRebuild. | |
81 | |
82 x = crash_test_dummy.X('a') | |
83 | |
84 rebuild.rebuild(crash_test_dummy, doLog=False) | |
85 # Instance rebuilding is triggered by attribute access. | |
86 x.do() | |
87 self.failUnlessIdentical(x.__class__, crash_test_dummy.X) | |
88 | |
89 self.failUnlessIdentical(f, crash_test_dummy.foo) | |
90 | |
91 def testComponentInteraction(self): | |
92 x = crash_test_dummy.XComponent() | |
93 x.setAdapter(crash_test_dummy.IX, crash_test_dummy.XA) | |
94 oldComponent = x.getComponent(crash_test_dummy.IX) | |
95 rebuild.rebuild(crash_test_dummy, 0) | |
96 newComponent = x.getComponent(crash_test_dummy.IX) | |
97 | |
98 newComponent.method() | |
99 | |
100 self.assertEquals(newComponent.__class__, crash_test_dummy.XA) | |
101 | |
102 # Test that a duplicate registerAdapter is not allowed | |
103 from twisted.python import components | |
104 self.failUnlessRaises(ValueError, components.registerAdapter, | |
105 crash_test_dummy.XA, crash_test_dummy.X, | |
106 crash_test_dummy.IX) | |
107 | |
108 def testUpdateInstance(self): | |
109 global Foo, Buz | |
110 | |
111 b = Buz() | |
112 | |
113 class Foo: | |
114 def foo(self): | |
115 pass | |
116 class Buz(Bar, Baz): | |
117 x = 10 | |
118 | |
119 rebuild.updateInstance(b) | |
120 assert hasattr(b, 'foo'), "Missing method on rebuilt instance" | |
121 assert hasattr(b, 'x'), "Missing class attribute on rebuilt instance" | |
122 | |
123 def testBananaInteraction(self): | |
124 from twisted.python import rebuild | |
125 from twisted.spread import banana | |
126 rebuild.latestClass(banana.Banana) | |
127 | |
128 | |
129 | |
130 class NewStyleTestCase(unittest.TestCase): | |
131 """ | |
132 Tests for rebuilding new-style classes of various sorts. | |
133 """ | |
134 def setUp(self): | |
135 self.m = new.module('whipping') | |
136 sys.modules['whipping'] = self.m | |
137 | |
138 | |
139 def tearDown(self): | |
140 del sys.modules['whipping'] | |
141 del self.m | |
142 | |
143 | |
144 def test_slots(self): | |
145 """ | |
146 Try to rebuild a new style class with slots defined. | |
147 """ | |
148 classDefinition = ( | |
149 "class SlottedClass(object):\n" | |
150 " __slots__ = ['a']\n") | |
151 | |
152 exec classDefinition in self.m.__dict__ | |
153 inst = self.m.SlottedClass() | |
154 inst.a = 7 | |
155 exec classDefinition in self.m.__dict__ | |
156 rebuild.updateInstance(inst) | |
157 self.assertEqual(inst.a, 7) | |
158 self.assertIdentical(type(inst), self.m.SlottedClass) | |
159 | |
160 if sys.version_info < (2, 6): | |
161 test_slots.skip = "__class__ assignment for class with slots is only ava
ilable starting Python 2.6" | |
162 | |
163 | |
164 def test_errorSlots(self): | |
165 """ | |
166 Try to rebuild a new style class with slots defined: this should fail. | |
167 """ | |
168 classDefinition = ( | |
169 "class SlottedClass(object):\n" | |
170 " __slots__ = ['a']\n") | |
171 | |
172 exec classDefinition in self.m.__dict__ | |
173 inst = self.m.SlottedClass() | |
174 inst.a = 7 | |
175 exec classDefinition in self.m.__dict__ | |
176 self.assertRaises(rebuild.RebuildError, rebuild.updateInstance, inst) | |
177 | |
178 if sys.version_info >= (2, 6): | |
179 test_errorSlots.skip = "__class__ assignment for class with slots should
work starting Python 2.6" | |
180 | |
181 | |
182 def test_typeSubclass(self): | |
183 """ | |
184 Try to rebuild a base type subclass. | |
185 """ | |
186 classDefinition = ( | |
187 "class ListSubclass(list):\n" | |
188 " pass\n") | |
189 | |
190 exec classDefinition in self.m.__dict__ | |
191 inst = self.m.ListSubclass() | |
192 inst.append(2) | |
193 exec classDefinition in self.m.__dict__ | |
194 rebuild.updateInstance(inst) | |
195 self.assertEqual(inst[0], 2) | |
196 self.assertIdentical(type(inst), self.m.ListSubclass) | |
197 | |
198 | |
199 def test_instanceSlots(self): | |
200 """ | |
201 Test that when rebuilding an instance with a __slots__ attribute, it | |
202 fails accurately instead of giving a L{rebuild.RebuildError}. | |
203 """ | |
204 classDefinition = ( | |
205 "class NotSlottedClass(object):\n" | |
206 " pass\n") | |
207 | |
208 exec classDefinition in self.m.__dict__ | |
209 inst = self.m.NotSlottedClass() | |
210 inst.__slots__ = ['a'] | |
211 classDefinition = ( | |
212 "class NotSlottedClass:\n" | |
213 " pass\n") | |
214 exec classDefinition in self.m.__dict__ | |
215 # Moving from new-style class to old-style should fail. | |
216 self.assertRaises(TypeError, rebuild.updateInstance, inst) | |
217 | |
OLD | NEW |