1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 import StringIO, sys, types
7 from twisted.trial import unittest, runner
8 from twisted.scripts import trial
9 from twisted.python import util, deprecate, versions
10 from twisted.python.compat import set
11 from twisted.python.filepath import FilePath
13 from twisted.trial.test.test_loader import testNames
15 pyunit = __import__('unittest')
18 def sibpath(filename):
19 """For finding files in twisted/trial/test"""
20 return util.sibpath(__file__, filename)
24 class ForceGarbageCollection(unittest.TestCase):
26 Tests for the --force-gc option.
30 self.config = trial.Options()
32 self.patch(gc, 'collect', self.collect)
33 test = pyunit.FunctionTestCase(self.simpleTest)
34 self.test = runner.TestSuite([test, test])
39 A simple test method that records that it was run.
41 self.log.append('test')
46 A replacement for gc.collect that logs calls to itself.
48 self.log.append('collect')
53 Return a L{runner.TrialRunner} object that is safe to use in tests.
55 runner = trial._makeRunner(self.config)
56 runner.stream = StringIO.StringIO()
60 def test_forceGc(self):
62 Passing the --force-gc option to the trial script forces the garbage
63 collector to run before and after each test.
65 self.config['force-gc'] = True
66 self.config.postOptions()
67 runner = self.makeRunner()
69 self.assertEqual(self.log, ['collect', 'test', 'collect',
70 'collect', 'test', 'collect'])
73 def test_unforceGc(self):
75 By default, no garbage collection is forced.
77 self.config.postOptions()
78 runner = self.makeRunner()
80 self.assertEqual(self.log, ['test', 'test'])
84 class TestSuiteUsed(unittest.TestCase):
86 Check the category of tests suite used by the loader.
91 Create a trial configuration object.
93 self.config = trial.Options()
96 def test_defaultSuite(self):
98 By default, the loader should use L{runner.DestructiveTestSuite}
100 loader = trial._getLoader(self.config)
101 self.assertEqual(loader.suiteFactory, runner.DestructiveTestSuite)
104 def test_untilFailureSuite(self):
106 The C{until-failure} configuration uses the L{runner.TestSuite} to keep
107 instances alive across runs.
109 self.config['until-failure'] = True
110 loader = trial._getLoader(self.config)
111 self.assertEqual(loader.suiteFactory, runner.TestSuite)
115 class TestModuleTest(unittest.TestCase):
117 self.config = trial.Options()
122 def test_testNames(self):
124 Check that the testNames helper method accurately collects the
125 names of tests in suite.
127 self.assertEqual(testNames(self), [self.id()])
129 def assertSuitesEqual(self, test1, names):
130 loader = runner.TestLoader()
131 names1 = testNames(test1)
132 names2 = testNames(runner.TestSuite(map(loader.loadByName, names)))
135 self.assertEqual(names1, names2)
137 def test_baseState(self):
138 self.assertEqual(0, len(self.config['tests']))
140 def test_testmoduleOnModule(self):
142 Check that --testmodule loads a suite which contains the tests
143 referred to in test-case-name inside its parameter.
145 self.config.opt_testmodule(sibpath('moduletest.py'))
146 self.assertSuitesEqual(trial._getSuite(self.config),
147 ['twisted.trial.test.test_test_visitor'])
149 def test_testmoduleTwice(self):
151 When the same module is specified with two --testmodule flags, it
152 should only appear once in the suite.
154 self.config.opt_testmodule(sibpath('moduletest.py'))
155 self.config.opt_testmodule(sibpath('moduletest.py'))
156 self.assertSuitesEqual(trial._getSuite(self.config),
157 ['twisted.trial.test.test_test_visitor'])
159 def test_testmoduleOnSourceAndTarget(self):
161 If --testmodule is specified twice, once for module A and once for
162 a module which refers to module A, then make sure module A is only
165 self.config.opt_testmodule(sibpath('moduletest.py'))
166 self.config.opt_testmodule(sibpath('test_test_visitor.py'))
167 self.assertSuitesEqual(trial._getSuite(self.config),
168 ['twisted.trial.test.test_test_visitor'])
170 def test_testmoduleOnSelfModule(self):
172 When given a module that refers to *itself* in the test-case-name
173 variable, check that --testmodule only adds the tests once.
175 self.config.opt_testmodule(sibpath('moduleself.py'))
176 self.assertSuitesEqual(trial._getSuite(self.config),
177 ['twisted.trial.test.moduleself'])
179 def test_testmoduleOnScript(self):
181 Check that --testmodule loads tests referred to in test-case-name
184 self.config.opt_testmodule(sibpath('scripttest.py'))
185 self.assertSuitesEqual(trial._getSuite(self.config),
186 ['twisted.trial.test.test_test_visitor',
187 'twisted.trial.test.test_class'])
189 def test_testmoduleOnNonexistentFile(self):
191 Check that --testmodule displays a meaningful error message when
192 passed a non-existent filename.
194 buffy = StringIO.StringIO()
195 stderr, sys.stderr = sys.stderr, buffy
196 filename = 'test_thisbetternoteverexist.py'
198 self.config.opt_testmodule(filename)
199 self.assertEqual(0, len(self.config['tests']))
200 self.assertEqual("File %r doesn't exist\n" % (filename,),
205 def test_testmoduleOnEmptyVars(self):
207 Check that --testmodule adds no tests to the suite for modules
208 which lack test-case-name buffer variables.
210 self.config.opt_testmodule(sibpath('novars.py'))
211 self.assertEqual(0, len(self.config['tests']))
213 def test_testmoduleOnModuleName(self):
215 Check that --testmodule does *not* support module names as arguments
216 and that it displays a meaningful error message.
218 buffy = StringIO.StringIO()
219 stderr, sys.stderr = sys.stderr, buffy
220 moduleName = 'twisted.trial.test.test_script'
222 self.config.opt_testmodule(moduleName)
223 self.assertEqual(0, len(self.config['tests']))
224 self.assertEqual("File %r doesn't exist\n" % (moduleName,),
229 def test_parseLocalVariable(self):
230 declaration = '-*- test-case-name: twisted.trial.test.test_tests -*-'
231 localVars = trial._parseLocalVariables(declaration)
232 self.assertEqual({'test-case-name':
233 'twisted.trial.test.test_tests'},
236 def test_trailingSemicolon(self):
237 declaration = '-*- test-case-name: twisted.trial.test.test_tests; -*-'
238 localVars = trial._parseLocalVariables(declaration)
239 self.assertEqual({'test-case-name':
240 'twisted.trial.test.test_tests'},
243 def test_parseLocalVariables(self):
244 declaration = ('-*- test-case-name: twisted.trial.test.test_tests; '
246 localVars = trial._parseLocalVariables(declaration)
247 self.assertEqual({'test-case-name':
248 'twisted.trial.test.test_tests',
252 def test_surroundingGuff(self):
253 declaration = ('## -*- test-case-name: '
254 'twisted.trial.test.test_tests -*- #')
255 localVars = trial._parseLocalVariables(declaration)
256 self.assertEqual({'test-case-name':
257 'twisted.trial.test.test_tests'},
260 def test_invalidLine(self):
261 self.failUnlessRaises(ValueError, trial._parseLocalVariables,
264 def test_invalidDeclaration(self):
265 self.failUnlessRaises(ValueError, trial._parseLocalVariables,
267 self.failUnlessRaises(ValueError, trial._parseLocalVariables,
268 '-*- foo: bar; qux -*-')
269 self.failUnlessRaises(ValueError, trial._parseLocalVariables,
270 '-*- foo: bar: baz; qux: qax -*-')
272 def test_variablesFromFile(self):
273 localVars = trial.loadLocalVariables(sibpath('moduletest.py'))
274 self.assertEqual({'test-case-name':
275 'twisted.trial.test.test_test_visitor'},
278 def test_noVariablesInFile(self):
279 localVars = trial.loadLocalVariables(sibpath('novars.py'))
280 self.assertEqual({}, localVars)
282 def test_variablesFromScript(self):
283 localVars = trial.loadLocalVariables(sibpath('scripttest.py'))
285 {'test-case-name': ('twisted.trial.test.test_test_visitor,'
286 'twisted.trial.test.test_class')},
289 def test_getTestModules(self):
290 modules = trial.getTestModules(sibpath('moduletest.py'))
291 self.assertEqual(modules, ['twisted.trial.test.test_test_visitor'])
293 def test_getTestModules_noVars(self):
294 modules = trial.getTestModules(sibpath('novars.py'))
295 self.assertEqual(len(modules), 0)
297 def test_getTestModules_multiple(self):
298 modules = trial.getTestModules(sibpath('scripttest.py'))
299 self.assertEqual(set(modules),
300 set(['twisted.trial.test.test_test_visitor',
301 'twisted.trial.test.test_class']))
303 def test_looksLikeTestModule(self):
304 for filename in ['test_script.py', 'twisted/trial/test/test_script.py']:
305 self.failUnless(trial.isTestFile(filename),
306 "%r should be a test file" % (filename,))
307 for filename in ['twisted/trial/test/moduletest.py',
308 sibpath('scripttest.py'), sibpath('test_foo.bat')]:
309 self.failIf(trial.isTestFile(filename),
310 "%r should *not* be a test file" % (filename,))
313 class WithoutModuleTests(unittest.TestCase):
315 Test the C{without-module} flag.
320 Create a L{trial.Options} object to be used in the tests, and save
323 self.config = trial.Options()
324 self.savedModules = dict(sys.modules)
329 Restore C{sys.modules}.
331 for module in ('imaplib', 'smtplib'):
332 if module in self.savedModules:
333 sys.modules[module] = self.savedModules[module]
335 sys.modules.pop(module, None)
338 def _checkSMTP(self):
340 Try to import the C{smtplib} module, and return it.
346 def _checkIMAP(self):
348 Try to import the C{imaplib} module, and return it.
354 def test_disableOneModule(self):
356 Check that after disabling a module, it can't be imported anymore.
358 self.config.parseOptions(["--without-module", "smtplib"])
359 self.assertRaises(ImportError, self._checkSMTP)
360 # Restore sys.modules
361 del sys.modules["smtplib"]
362 # Then the function should succeed
363 self.assertIsInstance(self._checkSMTP(), types.ModuleType)
366 def test_disableMultipleModules(self):
368 Check that several modules can be disabled at once.
370 self.config.parseOptions(["--without-module", "smtplib,imaplib"])
371 self.assertRaises(ImportError, self._checkSMTP)
372 self.assertRaises(ImportError, self._checkIMAP)
373 # Restore sys.modules
374 del sys.modules["smtplib"]
375 del sys.modules["imaplib"]
376 # Then the functions should succeed
377 self.assertIsInstance(self._checkSMTP(), types.ModuleType)
378 self.assertIsInstance(self._checkIMAP(), types.ModuleType)
381 def test_disableAlreadyImportedModule(self):
383 Disabling an already imported module should produce a warning.
385 self.assertIsInstance(self._checkSMTP(), types.ModuleType)
386 self.assertWarns(RuntimeWarning,
387 "Module 'smtplib' already imported, disabling anyway.",
389 self.config.parseOptions, ["--without-module", "smtplib"])
390 self.assertRaises(ImportError, self._checkSMTP)
394 class CoverageTests(unittest.TestCase):
396 Tests for the I{coverage} option.
398 if getattr(sys, 'gettrace', None) is None:
400 "Cannot test trace hook installation without inspection API.")
404 Arrange for the current trace hook to be restored when the
407 self.addCleanup(sys.settrace, sys.gettrace())
410 def test_tracerInstalled(self):
412 L{trial.Options} handles C{"--coverage"} by installing a trace
413 hook to record coverage information.
415 options = trial.Options()
416 options.parseOptions(["--coverage"])
417 self.assertEqual(sys.gettrace(), options.tracer.globaltrace)
420 def test_coverdirDefault(self):
422 L{trial.Options.coverdir} returns a L{FilePath} based on the default
423 for the I{temp-directory} option if that option is not specified.
425 options = trial.Options()
428 FilePath(".").descendant([options["temp-directory"], "coverage"]))
431 def test_coverdirOverridden(self):
433 If a value is specified for the I{temp-directory} option,
434 L{trial.Options.coverdir} returns a child of that path.
437 options = trial.Options()
438 options.parseOptions(["--temp-directory", path])
440 options.coverdir(), FilePath(path).child("coverage"))
443 class ExtraTests(unittest.TestCase):
445 Tests for the I{extra} option.
449 self.config = trial.Options()
456 def assertDeprecationWarning(self, deprecatedCallable, warnings):
458 Check for a deprecation warning
460 self.assertEqual(len(warnings), 1)
461 self.assertEqual(warnings[0]['category'], DeprecationWarning)
462 self.assertEqual(warnings[0]['message'],
463 deprecate.getDeprecationWarningString(
464 deprecatedCallable, versions.Version('Twisted', 11, 0, 0)))
467 def test_extraDeprecation(self):
469 Check that --extra will emit a deprecation warning
471 self.config.opt_extra('some.sample.test')
472 self.assertDeprecationWarning(self.config.opt_extra,
473 self.flushWarnings([self.test_extraDeprecation]))
475 def test_xDeprecation(self):
477 Check that -x will emit a deprecation warning
479 self.config.opt_x('some.sample.text')
480 self.assertDeprecationWarning(self.config.opt_extra,
481 self.flushWarnings([self.test_xDeprecation]))