1import unittest
2
3import gc
4import sys
5import weakref
6from unittest.test.support import LoggingResult, TestEquality
7
8
9### Support code for Test_TestSuite
10################################################################
11
12class Test(object):
13    class Foo(unittest.TestCase):
14        def test_1(self): pass
15        def test_2(self): pass
16        def test_3(self): pass
17        def runTest(self): pass
18
19def _mk_TestSuite(*names):
20    return unittest.TestSuite(Test.Foo(n) for n in names)
21
22################################################################
23
24
25class Test_TestSuite(unittest.TestCase, TestEquality):
26
27    ### Set up attributes needed by inherited tests
28    ################################################################
29
30    # Used by TestEquality.test_eq
31    eq_pairs = [(unittest.TestSuite(), unittest.TestSuite())
32               ,(unittest.TestSuite(), unittest.TestSuite([]))
33               ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_1'))]
34
35    # Used by TestEquality.test_ne
36    ne_pairs = [(unittest.TestSuite(), _mk_TestSuite('test_1'))
37               ,(unittest.TestSuite([]), _mk_TestSuite('test_1'))
38               ,(_mk_TestSuite('test_1', 'test_2'), _mk_TestSuite('test_1', 'test_3'))
39               ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_2'))]
40
41    ################################################################
42    ### /Set up attributes needed by inherited tests
43
44    ### Tests for TestSuite.__init__
45    ################################################################
46
47    # "class TestSuite([tests])"
48    #
49    # The tests iterable should be optional
50    def test_init__tests_optional(self):
51        suite = unittest.TestSuite()
52
53        self.assertEqual(suite.countTestCases(), 0)
54        # countTestCases() still works after tests are run
55        suite.run(unittest.TestResult())
56        self.assertEqual(suite.countTestCases(), 0)
57
58    # "class TestSuite([tests])"
59    # ...
60    # "If tests is given, it must be an iterable of individual test cases
61    # or other test suites that will be used to build the suite initially"
62    #
63    # TestSuite should deal with empty tests iterables by allowing the
64    # creation of an empty suite
65    def test_init__empty_tests(self):
66        suite = unittest.TestSuite([])
67
68        self.assertEqual(suite.countTestCases(), 0)
69        # countTestCases() still works after tests are run
70        suite.run(unittest.TestResult())
71        self.assertEqual(suite.countTestCases(), 0)
72
73    # "class TestSuite([tests])"
74    # ...
75    # "If tests is given, it must be an iterable of individual test cases
76    # or other test suites that will be used to build the suite initially"
77    #
78    # TestSuite should allow any iterable to provide tests
79    def test_init__tests_from_any_iterable(self):
80        def tests():
81            yield unittest.FunctionTestCase(lambda: None)
82            yield unittest.FunctionTestCase(lambda: None)
83
84        suite_1 = unittest.TestSuite(tests())
85        self.assertEqual(suite_1.countTestCases(), 2)
86
87        suite_2 = unittest.TestSuite(suite_1)
88        self.assertEqual(suite_2.countTestCases(), 2)
89
90        suite_3 = unittest.TestSuite(set(suite_1))
91        self.assertEqual(suite_3.countTestCases(), 2)
92
93        # countTestCases() still works after tests are run
94        suite_1.run(unittest.TestResult())
95        self.assertEqual(suite_1.countTestCases(), 2)
96        suite_2.run(unittest.TestResult())
97        self.assertEqual(suite_2.countTestCases(), 2)
98        suite_3.run(unittest.TestResult())
99        self.assertEqual(suite_3.countTestCases(), 2)
100
101    # "class TestSuite([tests])"
102    # ...
103    # "If tests is given, it must be an iterable of individual test cases
104    # or other test suites that will be used to build the suite initially"
105    #
106    # Does TestSuite() also allow other TestSuite() instances to be present
107    # in the tests iterable?
108    def test_init__TestSuite_instances_in_tests(self):
109        def tests():
110            ftc = unittest.FunctionTestCase(lambda: None)
111            yield unittest.TestSuite([ftc])
112            yield unittest.FunctionTestCase(lambda: None)
113
114        suite = unittest.TestSuite(tests())
115        self.assertEqual(suite.countTestCases(), 2)
116        # countTestCases() still works after tests are run
117        suite.run(unittest.TestResult())
118        self.assertEqual(suite.countTestCases(), 2)
119
120    ################################################################
121    ### /Tests for TestSuite.__init__
122
123    # Container types should support the iter protocol
124    def test_iter(self):
125        test1 = unittest.FunctionTestCase(lambda: None)
126        test2 = unittest.FunctionTestCase(lambda: None)
127        suite = unittest.TestSuite((test1, test2))
128
129        self.assertEqual(list(suite), [test1, test2])
130
131    # "Return the number of tests represented by the this test object.
132    # ...this method is also implemented by the TestSuite class, which can
133    # return larger [greater than 1] values"
134    #
135    # Presumably an empty TestSuite returns 0?
136    def test_countTestCases_zero_simple(self):
137        suite = unittest.TestSuite()
138
139        self.assertEqual(suite.countTestCases(), 0)
140
141    # "Return the number of tests represented by the this test object.
142    # ...this method is also implemented by the TestSuite class, which can
143    # return larger [greater than 1] values"
144    #
145    # Presumably an empty TestSuite (even if it contains other empty
146    # TestSuite instances) returns 0?
147    def test_countTestCases_zero_nested(self):
148        class Test1(unittest.TestCase):
149            def test(self):
150                pass
151
152        suite = unittest.TestSuite([unittest.TestSuite()])
153
154        self.assertEqual(suite.countTestCases(), 0)
155
156    # "Return the number of tests represented by the this test object.
157    # ...this method is also implemented by the TestSuite class, which can
158    # return larger [greater than 1] values"
159    def test_countTestCases_simple(self):
160        test1 = unittest.FunctionTestCase(lambda: None)
161        test2 = unittest.FunctionTestCase(lambda: None)
162        suite = unittest.TestSuite((test1, test2))
163
164        self.assertEqual(suite.countTestCases(), 2)
165        # countTestCases() still works after tests are run
166        suite.run(unittest.TestResult())
167        self.assertEqual(suite.countTestCases(), 2)
168
169    # "Return the number of tests represented by the this test object.
170    # ...this method is also implemented by the TestSuite class, which can
171    # return larger [greater than 1] values"
172    #
173    # Make sure this holds for nested TestSuite instances, too
174    def test_countTestCases_nested(self):
175        class Test1(unittest.TestCase):
176            def test1(self): pass
177            def test2(self): pass
178
179        test2 = unittest.FunctionTestCase(lambda: None)
180        test3 = unittest.FunctionTestCase(lambda: None)
181        child = unittest.TestSuite((Test1('test2'), test2))
182        parent = unittest.TestSuite((test3, child, Test1('test1')))
183
184        self.assertEqual(parent.countTestCases(), 4)
185        # countTestCases() still works after tests are run
186        parent.run(unittest.TestResult())
187        self.assertEqual(parent.countTestCases(), 4)
188        self.assertEqual(child.countTestCases(), 2)
189
190    # "Run the tests associated with this suite, collecting the result into
191    # the test result object passed as result."
192    #
193    # And if there are no tests? What then?
194    def test_run__empty_suite(self):
195        events = []
196        result = LoggingResult(events)
197
198        suite = unittest.TestSuite()
199
200        suite.run(result)
201
202        self.assertEqual(events, [])
203
204    # "Note that unlike TestCase.run(), TestSuite.run() requires the
205    # "result object to be passed in."
206    def test_run__requires_result(self):
207        suite = unittest.TestSuite()
208
209        try:
210            suite.run()
211        except TypeError:
212            pass
213        else:
214            self.fail("Failed to raise TypeError")
215
216    # "Run the tests associated with this suite, collecting the result into
217    # the test result object passed as result."
218    def test_run(self):
219        events = []
220        result = LoggingResult(events)
221
222        class LoggingCase(unittest.TestCase):
223            def run(self, result):
224                events.append('run %s' % self._testMethodName)
225
226            def test1(self): pass
227            def test2(self): pass
228
229        tests = [LoggingCase('test1'), LoggingCase('test2')]
230
231        unittest.TestSuite(tests).run(result)
232
233        self.assertEqual(events, ['run test1', 'run test2'])
234
235    # "Add a TestCase ... to the suite"
236    def test_addTest__TestCase(self):
237        class Foo(unittest.TestCase):
238            def test(self): pass
239
240        test = Foo('test')
241        suite = unittest.TestSuite()
242
243        suite.addTest(test)
244
245        self.assertEqual(suite.countTestCases(), 1)
246        self.assertEqual(list(suite), [test])
247        # countTestCases() still works after tests are run
248        suite.run(unittest.TestResult())
249        self.assertEqual(suite.countTestCases(), 1)
250
251    # "Add a ... TestSuite to the suite"
252    def test_addTest__TestSuite(self):
253        class Foo(unittest.TestCase):
254            def test(self): pass
255
256        suite_2 = unittest.TestSuite([Foo('test')])
257
258        suite = unittest.TestSuite()
259        suite.addTest(suite_2)
260
261        self.assertEqual(suite.countTestCases(), 1)
262        self.assertEqual(list(suite), [suite_2])
263        # countTestCases() still works after tests are run
264        suite.run(unittest.TestResult())
265        self.assertEqual(suite.countTestCases(), 1)
266
267    # "Add all the tests from an iterable of TestCase and TestSuite
268    # instances to this test suite."
269    #
270    # "This is equivalent to iterating over tests, calling addTest() for
271    # each element"
272    def test_addTests(self):
273        class Foo(unittest.TestCase):
274            def test_1(self): pass
275            def test_2(self): pass
276
277        test_1 = Foo('test_1')
278        test_2 = Foo('test_2')
279        inner_suite = unittest.TestSuite([test_2])
280
281        def gen():
282            yield test_1
283            yield test_2
284            yield inner_suite
285
286        suite_1 = unittest.TestSuite()
287        suite_1.addTests(gen())
288
289        self.assertEqual(list(suite_1), list(gen()))
290
291        # "This is equivalent to iterating over tests, calling addTest() for
292        # each element"
293        suite_2 = unittest.TestSuite()
294        for t in gen():
295            suite_2.addTest(t)
296
297        self.assertEqual(suite_1, suite_2)
298
299    # "Add all the tests from an iterable of TestCase and TestSuite
300    # instances to this test suite."
301    #
302    # What happens if it doesn't get an iterable?
303    def test_addTest__noniterable(self):
304        suite = unittest.TestSuite()
305
306        try:
307            suite.addTests(5)
308        except TypeError:
309            pass
310        else:
311            self.fail("Failed to raise TypeError")
312
313    def test_addTest__noncallable(self):
314        suite = unittest.TestSuite()
315        self.assertRaises(TypeError, suite.addTest, 5)
316
317    def test_addTest__casesuiteclass(self):
318        suite = unittest.TestSuite()
319        self.assertRaises(TypeError, suite.addTest, Test_TestSuite)
320        self.assertRaises(TypeError, suite.addTest, unittest.TestSuite)
321
322    def test_addTests__string(self):
323        suite = unittest.TestSuite()
324        self.assertRaises(TypeError, suite.addTests, "foo")
325
326    def test_function_in_suite(self):
327        def f(_):
328            pass
329        suite = unittest.TestSuite()
330        suite.addTest(f)
331
332        # when the bug is fixed this line will not crash
333        suite.run(unittest.TestResult())
334
335    def test_remove_test_at_index(self):
336        if not unittest.BaseTestSuite._cleanup:
337            raise unittest.SkipTest("Suite cleanup is disabled")
338
339        suite = unittest.TestSuite()
340
341        suite._tests = [1, 2, 3]
342        suite._removeTestAtIndex(1)
343
344        self.assertEqual([1, None, 3], suite._tests)
345
346    def test_remove_test_at_index_not_indexable(self):
347        if not unittest.BaseTestSuite._cleanup:
348            raise unittest.SkipTest("Suite cleanup is disabled")
349
350        suite = unittest.TestSuite()
351        suite._tests = None
352
353        # if _removeAtIndex raises for noniterables this next line will break
354        suite._removeTestAtIndex(2)
355
356    def assert_garbage_collect_test_after_run(self, TestSuiteClass):
357        if not unittest.BaseTestSuite._cleanup:
358            raise unittest.SkipTest("Suite cleanup is disabled")
359
360        class Foo(unittest.TestCase):
361            def test_nothing(self):
362                pass
363
364        test = Foo('test_nothing')
365        wref = weakref.ref(test)
366
367        suite = TestSuiteClass([wref()])
368        suite.run(unittest.TestResult())
369
370        del test
371
372        # for the benefit of non-reference counting implementations
373        gc.collect()
374
375        self.assertEqual(suite._tests, [None])
376        self.assertIsNone(wref())
377
378    def test_garbage_collect_test_after_run_BaseTestSuite(self):
379        self.assert_garbage_collect_test_after_run(unittest.BaseTestSuite)
380
381    def test_garbage_collect_test_after_run_TestSuite(self):
382        self.assert_garbage_collect_test_after_run(unittest.TestSuite)
383
384    def test_basetestsuite(self):
385        class Test(unittest.TestCase):
386            wasSetUp = False
387            wasTornDown = False
388            @classmethod
389            def setUpClass(cls):
390                cls.wasSetUp = True
391            @classmethod
392            def tearDownClass(cls):
393                cls.wasTornDown = True
394            def testPass(self):
395                pass
396            def testFail(self):
397                fail
398        class Module(object):
399            wasSetUp = False
400            wasTornDown = False
401            @staticmethod
402            def setUpModule():
403                Module.wasSetUp = True
404            @staticmethod
405            def tearDownModule():
406                Module.wasTornDown = True
407
408        Test.__module__ = 'Module'
409        sys.modules['Module'] = Module
410        self.addCleanup(sys.modules.pop, 'Module')
411
412        suite = unittest.BaseTestSuite()
413        suite.addTests([Test('testPass'), Test('testFail')])
414        self.assertEqual(suite.countTestCases(), 2)
415
416        result = unittest.TestResult()
417        suite.run(result)
418        self.assertFalse(Module.wasSetUp)
419        self.assertFalse(Module.wasTornDown)
420        self.assertFalse(Test.wasSetUp)
421        self.assertFalse(Test.wasTornDown)
422        self.assertEqual(len(result.errors), 1)
423        self.assertEqual(len(result.failures), 0)
424        self.assertEqual(result.testsRun, 2)
425        self.assertEqual(suite.countTestCases(), 2)
426
427
428    def test_overriding_call(self):
429        class MySuite(unittest.TestSuite):
430            called = False
431            def __call__(self, *args, **kw):
432                self.called = True
433                unittest.TestSuite.__call__(self, *args, **kw)
434
435        suite = MySuite()
436        result = unittest.TestResult()
437        wrapper = unittest.TestSuite()
438        wrapper.addTest(suite)
439        wrapper(result)
440        self.assertTrue(suite.called)
441
442        # reusing results should be permitted even if abominable
443        self.assertFalse(result._testRunEntered)
444
445
446if __name__ == '__main__':
447    unittest.main()
448