OLD | NEW |
| (Empty) |
1 | |
2 import md5 | |
3 import os | |
4 import shutil | |
5 | |
6 from twisted.python import util | |
7 from twisted.trial.test import packages | |
8 from twisted.trial import runner, reporter, unittest | |
9 from twisted.trial.itrial import ITestCase | |
10 | |
11 from twisted.python.modules import getModule | |
12 | |
13 | |
14 | |
15 def testNames(tests): | |
16 """ | |
17 Return the id of each test within the given test suite or case. | |
18 """ | |
19 names = [] | |
20 for test in unittest._iterateTests(tests): | |
21 names.append(test.id()) | |
22 return names | |
23 | |
24 | |
25 | |
26 class FinderTest(packages.PackageTest): | |
27 def setUp(self): | |
28 packages.PackageTest.setUp(self) | |
29 self.loader = runner.TestLoader() | |
30 | |
31 def tearDown(self): | |
32 packages.PackageTest.tearDown(self) | |
33 | |
34 def test_findPackage(self): | |
35 sample1 = self.loader.findByName('twisted') | |
36 import twisted as sample2 | |
37 self.failUnlessEqual(sample1, sample2) | |
38 | |
39 def test_findModule(self): | |
40 sample1 = self.loader.findByName('twisted.trial.test.sample') | |
41 import sample as sample2 | |
42 self.failUnlessEqual(sample1, sample2) | |
43 | |
44 def test_findFile(self): | |
45 path = util.sibpath(__file__, 'sample.py') | |
46 sample1 = self.loader.findByName(path) | |
47 import sample as sample2 | |
48 self.failUnlessEqual(sample1, sample2) | |
49 | |
50 def test_findObject(self): | |
51 sample1 = self.loader.findByName('twisted.trial.test.sample.FooTest') | |
52 import sample | |
53 self.failUnlessEqual(sample.FooTest, sample1) | |
54 | |
55 def test_findNonModule(self): | |
56 self.failUnlessRaises(AttributeError, | |
57 self.loader.findByName, | |
58 'twisted.trial.test.nonexistent') | |
59 | |
60 def test_findNonPackage(self): | |
61 self.failUnlessRaises(ValueError, | |
62 self.loader.findByName, | |
63 'nonextant') | |
64 | |
65 def test_findNonFile(self): | |
66 path = util.sibpath(__file__, 'nonexistent.py') | |
67 self.failUnlessRaises(ValueError, self.loader.findByName, path) | |
68 | |
69 | |
70 | |
71 class FileTest(packages.SysPathManglingTest): | |
72 def test_notFile(self): | |
73 self.failUnlessRaises(ValueError, | |
74 runner.filenameToModule, 'doesntexist') | |
75 | |
76 def test_moduleInPath(self): | |
77 sample1 = runner.filenameToModule(util.sibpath(__file__, 'sample.py')) | |
78 import sample as sample2 | |
79 self.failUnlessEqual(sample2, sample1) | |
80 | |
81 def test_moduleNotInPath(self): | |
82 self.mangleSysPath(self.oldPath) | |
83 sample1 = runner.filenameToModule(os.path.join(self.parent, | |
84 'goodpackage', | |
85 'test_sample.py')) | |
86 self.mangleSysPath(self.newPath) | |
87 from goodpackage import test_sample as sample2 | |
88 self.failUnlessEqual(os.path.splitext(sample2.__file__)[0], | |
89 os.path.splitext(sample1.__file__)[0]) | |
90 | |
91 def test_packageInPath(self): | |
92 package1 = runner.filenameToModule(os.path.join(self.parent, | |
93 'goodpackage')) | |
94 import goodpackage | |
95 self.failUnlessEqual(goodpackage, package1) | |
96 | |
97 def test_packageNotInPath(self): | |
98 self.mangleSysPath(self.oldPath) | |
99 package1 = runner.filenameToModule(os.path.join(self.parent, | |
100 'goodpackage')) | |
101 self.mangleSysPath(self.newPath) | |
102 import goodpackage | |
103 self.failUnlessEqual(os.path.splitext(goodpackage.__file__)[0], | |
104 os.path.splitext(package1.__file__)[0]) | |
105 | |
106 def test_directoryNotPackage(self): | |
107 self.failUnlessRaises(ValueError, runner.filenameToModule, | |
108 util.sibpath(__file__, 'directory')) | |
109 | |
110 def test_filenameNotPython(self): | |
111 self.failUnlessRaises(ValueError, runner.filenameToModule, | |
112 util.sibpath(__file__, 'notpython.py')) | |
113 | |
114 def test_filenameMatchesPackage(self): | |
115 filename = os.path.join(self.parent, 'goodpackage.py') | |
116 fd = open(filename, 'w') | |
117 fd.write(packages.testModule) | |
118 fd.close() | |
119 try: | |
120 module = runner.filenameToModule(filename) | |
121 self.failUnlessEqual(filename, module.__file__) | |
122 finally: | |
123 os.remove(filename) | |
124 | |
125 def test_directory(self): | |
126 """ | |
127 Test loader against a filesystem directory. It should handle | |
128 'path' and 'path/' the same way. | |
129 """ | |
130 path = util.sibpath(__file__, 'goodDirectory') | |
131 os.mkdir(path) | |
132 f = file(os.path.join(path, '__init__.py'), "w") | |
133 f.close() | |
134 try: | |
135 module = runner.filenameToModule(path) | |
136 self.assert_(module.__name__.endswith('goodDirectory')) | |
137 module = runner.filenameToModule(path + os.path.sep) | |
138 self.assert_(module.__name__.endswith('goodDirectory')) | |
139 finally: | |
140 shutil.rmtree(path) | |
141 | |
142 | |
143 | |
144 class LoaderTest(packages.SysPathManglingTest): | |
145 | |
146 def setUp(self): | |
147 self.loader = runner.TestLoader() | |
148 packages.SysPathManglingTest.setUp(self) | |
149 | |
150 def test_sortCases(self): | |
151 import sample | |
152 suite = self.loader.loadClass(sample.AlphabetTest) | |
153 self.failUnlessEqual(['test_a', 'test_b', 'test_c'], | |
154 [test._testMethodName for test in suite._tests]) | |
155 newOrder = ['test_b', 'test_c', 'test_a'] | |
156 sortDict = dict(zip(newOrder, range(3))) | |
157 self.loader.sorter = lambda x : sortDict.get(x.shortDescription(), -1) | |
158 suite = self.loader.loadClass(sample.AlphabetTest) | |
159 self.failUnlessEqual(newOrder, | |
160 [test._testMethodName for test in suite._tests]) | |
161 | |
162 def test_loadMethod(self): | |
163 import sample | |
164 suite = self.loader.loadMethod(sample.FooTest.test_foo) | |
165 self.failUnlessEqual(1, suite.countTestCases()) | |
166 self.failUnlessEqual('test_foo', suite._testMethodName) | |
167 | |
168 def test_loadFailingMethod(self): | |
169 # test added for issue1353 | |
170 import erroneous | |
171 suite = self.loader.loadMethod(erroneous.TestRegularFail.test_fail) | |
172 result = reporter.TestResult() | |
173 suite.run(result) | |
174 self.failUnlessEqual(result.testsRun, 1) | |
175 self.failUnlessEqual(len(result.failures), 1) | |
176 | |
177 def test_loadNonMethod(self): | |
178 import sample | |
179 self.failUnlessRaises(TypeError, self.loader.loadMethod, sample) | |
180 self.failUnlessRaises(TypeError, | |
181 self.loader.loadMethod, sample.FooTest) | |
182 self.failUnlessRaises(TypeError, self.loader.loadMethod, "string") | |
183 self.failUnlessRaises(TypeError, | |
184 self.loader.loadMethod, ('foo', 'bar')) | |
185 | |
186 def test_loadClass(self): | |
187 import sample | |
188 suite = self.loader.loadClass(sample.FooTest) | |
189 self.failUnlessEqual(2, suite.countTestCases()) | |
190 self.failUnlessEqual(['test_bar', 'test_foo'], | |
191 [test._testMethodName for test in suite._tests]) | |
192 | |
193 | |
194 def test_loadNonClass(self): | |
195 import sample | |
196 self.failUnlessRaises(TypeError, self.loader.loadClass, sample) | |
197 self.failUnlessRaises(TypeError, | |
198 self.loader.loadClass, sample.FooTest.test_foo) | |
199 self.failUnlessRaises(TypeError, self.loader.loadClass, "string") | |
200 self.failUnlessRaises(TypeError, | |
201 self.loader.loadClass, ('foo', 'bar')) | |
202 | |
203 def test_loadNonTestCase(self): | |
204 import sample | |
205 self.failUnlessRaises(ValueError, self.loader.loadClass, | |
206 sample.NotATest) | |
207 | |
208 def test_loadModule(self): | |
209 import sample | |
210 suite = self.loader.loadModule(sample) | |
211 self.failUnlessEqual(7, suite.countTestCases()) | |
212 | |
213 def test_loadNonModule(self): | |
214 import sample | |
215 self.failUnlessRaises(TypeError, | |
216 self.loader.loadModule, sample.FooTest) | |
217 self.failUnlessRaises(TypeError, | |
218 self.loader.loadModule, sample.FooTest.test_foo) | |
219 self.failUnlessRaises(TypeError, self.loader.loadModule, "string") | |
220 self.failUnlessRaises(TypeError, | |
221 self.loader.loadModule, ('foo', 'bar')) | |
222 | |
223 def test_loadPackage(self): | |
224 import goodpackage | |
225 suite = self.loader.loadPackage(goodpackage) | |
226 self.failUnlessEqual(7, suite.countTestCases()) | |
227 | |
228 def test_loadNonPackage(self): | |
229 import sample | |
230 self.failUnlessRaises(TypeError, | |
231 self.loader.loadPackage, sample.FooTest) | |
232 self.failUnlessRaises(TypeError, | |
233 self.loader.loadPackage, sample.FooTest.test_foo) | |
234 self.failUnlessRaises(TypeError, self.loader.loadPackage, "string") | |
235 self.failUnlessRaises(TypeError, | |
236 self.loader.loadPackage, ('foo', 'bar')) | |
237 | |
238 def test_loadModuleAsPackage(self): | |
239 import sample | |
240 ## XXX -- should this instead raise a ValueError? -- jml | |
241 self.failUnlessRaises(TypeError, self.loader.loadPackage, sample) | |
242 | |
243 def test_loadPackageRecursive(self): | |
244 import goodpackage | |
245 suite = self.loader.loadPackage(goodpackage, recurse=True) | |
246 self.failUnlessEqual(14, suite.countTestCases()) | |
247 | |
248 def test_loadAnythingOnModule(self): | |
249 import sample | |
250 suite = self.loader.loadAnything(sample) | |
251 self.failUnlessEqual(sample.__name__, | |
252 suite._tests[0]._tests[0].__class__.__module__) | |
253 | |
254 def test_loadAnythingOnClass(self): | |
255 import sample | |
256 suite = self.loader.loadAnything(sample.FooTest) | |
257 self.failUnlessEqual(2, suite.countTestCases()) | |
258 | |
259 def test_loadAnythingOnMethod(self): | |
260 import sample | |
261 suite = self.loader.loadAnything(sample.FooTest.test_foo) | |
262 self.failUnlessEqual(1, suite.countTestCases()) | |
263 | |
264 def test_loadAnythingOnPackage(self): | |
265 import goodpackage | |
266 suite = self.loader.loadAnything(goodpackage) | |
267 self.failUnless(isinstance(suite, self.loader.suiteFactory)) | |
268 self.failUnlessEqual(7, suite.countTestCases()) | |
269 | |
270 def test_loadAnythingOnPackageRecursive(self): | |
271 import goodpackage | |
272 suite = self.loader.loadAnything(goodpackage, recurse=True) | |
273 self.failUnless(isinstance(suite, self.loader.suiteFactory)) | |
274 self.failUnlessEqual(14, suite.countTestCases()) | |
275 | |
276 def test_loadAnythingOnString(self): | |
277 # the important thing about this test is not the string-iness | |
278 # but the non-handledness. | |
279 self.failUnlessRaises(TypeError, | |
280 self.loader.loadAnything, "goodpackage") | |
281 | |
282 def test_importErrors(self): | |
283 import package | |
284 suite = self.loader.loadPackage(package, recurse=True) | |
285 result = reporter.Reporter() | |
286 suite.run(result) | |
287 self.failUnlessEqual(False, result.wasSuccessful()) | |
288 self.failUnlessEqual(2, len(result.errors)) | |
289 errors = [test.id() for test, error in result.errors] | |
290 errors.sort() | |
291 self.failUnlessEqual(errors, ['package.test_bad_module', | |
292 'package.test_import_module']) | |
293 | |
294 | |
295 def test_loadModuleWith_test_suite(self): | |
296 """ | |
297 Check that C{test_suite} is used when present and other L{TestCase}s are | |
298 not included. | |
299 """ | |
300 from twisted.trial.test import mockcustomsuite | |
301 suite = self.loader.loadModule(mockcustomsuite) | |
302 self.failUnlessEqual(0, suite.countTestCases()) | |
303 self.failUnlessEqual("MyCustomSuite", getattr(suite, 'name', None)) | |
304 | |
305 | |
306 def test_loadModuleWith_testSuite(self): | |
307 """ | |
308 Check that C{testSuite} is used when present and other L{TestCase}s are | |
309 not included. | |
310 """ | |
311 from twisted.trial.test import mockcustomsuite2 | |
312 suite = self.loader.loadModule(mockcustomsuite2) | |
313 self.assertEqual(0, suite.countTestCases()) | |
314 self.assertEqual("MyCustomSuite", getattr(suite, 'name', None)) | |
315 | |
316 | |
317 def test_loadModuleWithBothCustom(self): | |
318 """ | |
319 Check that if C{testSuite} and C{test_suite} are both present in a | |
320 module then C{testSuite} gets priority. | |
321 """ | |
322 from twisted.trial.test import mockcustomsuite3 | |
323 suite = self.loader.loadModule(mockcustomsuite3) | |
324 self.assertEqual('testSuite', getattr(suite, 'name', None)) | |
325 | |
326 | |
327 def test_customLoadRaisesAttributeError(self): | |
328 """ | |
329 Make sure that any C{AttributeError}s raised by C{testSuite} are not | |
330 swallowed by L{TestLoader}. | |
331 """ | |
332 def testSuite(): | |
333 raise AttributeError('should be reraised') | |
334 from twisted.trial.test import mockcustomsuite2 | |
335 mockcustomsuite2.testSuite, original = (testSuite, | |
336 mockcustomsuite2.testSuite) | |
337 try: | |
338 self.assertRaises(AttributeError, self.loader.loadModule, | |
339 mockcustomsuite2) | |
340 finally: | |
341 mockcustomsuite2.testSuite = original | |
342 | |
343 | |
344 # XXX - duplicated and modified from test_script | |
345 def assertSuitesEqual(self, test1, test2): | |
346 loader = runner.TestLoader() | |
347 names1 = testNames(test1) | |
348 names2 = testNames(test2) | |
349 names1.sort() | |
350 names2.sort() | |
351 self.assertEqual(names1, names2) | |
352 | |
353 def test_loadByNamesDuplicate(self): | |
354 """ | |
355 Check that loadByNames ignores duplicate names | |
356 """ | |
357 module = 'twisted.trial.test.test_test_visitor' | |
358 suite1 = self.loader.loadByNames([module, module], True) | |
359 suite2 = self.loader.loadByName(module, True) | |
360 self.assertSuitesEqual(suite1, suite2) | |
361 | |
362 def test_loadDifferentNames(self): | |
363 """ | |
364 Check that loadByNames loads all the names that it is given | |
365 """ | |
366 modules = ['goodpackage', 'package.test_module'] | |
367 suite1 = self.loader.loadByNames(modules) | |
368 suite2 = runner.TestSuite(map(self.loader.loadByName, modules)) | |
369 self.assertSuitesEqual(suite1, suite2) | |
370 | |
371 | |
372 | |
373 class ZipLoadingTest(LoaderTest): | |
374 def setUp(self): | |
375 from twisted.test.test_paths import zipit | |
376 LoaderTest.setUp(self) | |
377 zipit(self.parent, self.parent+'.zip') | |
378 self.parent += '.zip' | |
379 self.mangleSysPath(self.oldPath+[self.parent]) | |
380 | |
381 | |
382 | |
383 class PackageOrderingTest(packages.SysPathManglingTest): | |
384 def setUp(self): | |
385 self.resultingTests = [] | |
386 self.loader = runner.TestLoader() | |
387 self.topDir = self.mktemp() | |
388 parent = os.path.join(self.topDir, "uberpackage") | |
389 os.makedirs(parent) | |
390 file(os.path.join(parent, "__init__.py"), "wb").close() | |
391 packages.SysPathManglingTest.setUp(self, parent) | |
392 self.mangleSysPath(self.oldPath + [self.topDir]) | |
393 | |
394 def _trialSortAlgorithm(self, sorter): | |
395 """ | |
396 Right now, halfway by accident, trial sorts like this: | |
397 | |
398 1. all modules are grouped together in one list and sorted. | |
399 | |
400 2. within each module, the classes are grouped together in one list | |
401 and sorted. | |
402 | |
403 3. finally within each class, each test method is grouped together | |
404 in a list and sorted. | |
405 | |
406 This attempts to return a sorted list of testable thingies following | |
407 those rules, so that we can compare the behavior of loadPackage. | |
408 | |
409 The things that show as 'cases' are errors from modules which failed to | |
410 import, and test methods. Let's gather all those together. | |
411 """ | |
412 pkg = getModule('uberpackage') | |
413 testModules = [] | |
414 for testModule in pkg.walkModules(): | |
415 if testModule.name.split(".")[-1].startswith("test_"): | |
416 testModules.append(testModule) | |
417 sortedModules = util.dsu(testModules, sorter) # ONE | |
418 for modinfo in sortedModules: | |
419 # Now let's find all the classes. | |
420 module = modinfo.load(None) | |
421 if module is None: | |
422 yield modinfo | |
423 else: | |
424 testClasses = [] | |
425 for attrib in modinfo.iterAttributes(): | |
426 if runner.isTestCase(attrib.load()): | |
427 testClasses.append(attrib) | |
428 sortedClasses = util.dsu(testClasses, sorter) # TWO | |
429 for clsinfo in sortedClasses: | |
430 testMethods = [] | |
431 for attr in clsinfo.iterAttributes(): | |
432 if attr.name.split(".")[-1].startswith('test'): | |
433 testMethods.append(attr) | |
434 sortedMethods = util.dsu(testMethods, sorter) # THREE | |
435 for methinfo in sortedMethods: | |
436 yield methinfo | |
437 | |
438 | |
439 def loadSortedPackages(self, sorter=runner.name): | |
440 """ | |
441 Verify that packages are loaded in the correct order. | |
442 """ | |
443 import uberpackage | |
444 self.loader.sorter = sorter | |
445 suite = self.loader.loadPackage(uberpackage, recurse=True) | |
446 # XXX: Work around strange, unexplained Zope crap. | |
447 # jml, 2007-11-15. | |
448 suite = unittest.decorate(suite, ITestCase) | |
449 self.resultingTests = list(unittest._iterateTests(suite)) | |
450 manifest = list(self._trialSortAlgorithm(sorter)) | |
451 for number, (manifestTest, actualTest) in enumerate( | |
452 zip(manifest, self.resultingTests)): | |
453 self.assertEqual( | |
454 manifestTest.name, actualTest.id(), | |
455 "#%d: %s != %s" % | |
456 (number, manifestTest.name, actualTest.id())) | |
457 self.assertEqual(len(manifest), len(self.resultingTests)) | |
458 | |
459 | |
460 def test_sortPackagesDefaultOrder(self): | |
461 self.loadSortedPackages() | |
462 | |
463 | |
464 def test_sortPackagesSillyOrder(self): | |
465 def sillySorter(s): | |
466 # This has to work on fully-qualified class names and class | |
467 # objects, which is silly, but it's the "spec", such as it is. | |
468 # if isinstance(s, type) or isinstance(s, types.ClassType): | |
469 # return s.__module__+'.'+s.__name__ | |
470 n = runner.name(s) | |
471 d = md5.new(n).hexdigest() | |
472 return d | |
473 self.loadSortedPackages(sillySorter) | |
474 | |
475 | |
OLD | NEW |