1# Copyright 2013 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Utilities for dealing with the python unittest module.""" 6 7import fnmatch 8import sys 9import unittest 10 11 12class _TextTestResult(unittest._TextTestResult): 13 """A test result class that can print formatted text results to a stream. 14 15 Results printed in conformance with gtest output format, like: 16 [ RUN ] autofill.AutofillTest.testAutofillInvalid: "test desc." 17 [ OK ] autofill.AutofillTest.testAutofillInvalid 18 [ RUN ] autofill.AutofillTest.testFillProfile: "test desc." 19 [ OK ] autofill.AutofillTest.testFillProfile 20 [ RUN ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test." 21 [ OK ] autofill.AutofillTest.testFillProfileCrazyCharacters 22 """ 23 def __init__(self, stream, descriptions, verbosity): 24 unittest._TextTestResult.__init__(self, stream, descriptions, verbosity) 25 self._fails = set() 26 27 def _GetTestURI(self, test): 28 return '%s.%s.%s' % (test.__class__.__module__, 29 test.__class__.__name__, 30 test._testMethodName) 31 32 def getDescription(self, test): 33 return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription()) 34 35 def startTest(self, test): 36 unittest.TestResult.startTest(self, test) 37 self.stream.writeln('[ RUN ] %s' % self.getDescription(test)) 38 39 def addSuccess(self, test): 40 unittest.TestResult.addSuccess(self, test) 41 self.stream.writeln('[ OK ] %s' % self._GetTestURI(test)) 42 43 def addError(self, test, err): 44 unittest.TestResult.addError(self, test, err) 45 self.stream.writeln('[ ERROR ] %s' % self._GetTestURI(test)) 46 self._fails.add(self._GetTestURI(test)) 47 48 def addFailure(self, test, err): 49 unittest.TestResult.addFailure(self, test, err) 50 self.stream.writeln('[ FAILED ] %s' % self._GetTestURI(test)) 51 self._fails.add(self._GetTestURI(test)) 52 53 def getRetestFilter(self): 54 return ':'.join(self._fails) 55 56 57class TextTestRunner(unittest.TextTestRunner): 58 """Test Runner for displaying test results in textual format. 59 60 Results are displayed in conformance with google test output. 61 """ 62 63 def __init__(self, verbosity=1): 64 unittest.TextTestRunner.__init__(self, stream=sys.stderr, 65 verbosity=verbosity) 66 67 def _makeResult(self): 68 return _TextTestResult(self.stream, self.descriptions, self.verbosity) 69 70 71def GetTestsFromSuite(suite): 72 """Returns all the tests from a given test suite.""" 73 tests = [] 74 for x in suite: 75 if isinstance(x, unittest.TestSuite): 76 tests += GetTestsFromSuite(x) 77 else: 78 tests += [x] 79 return tests 80 81 82def GetTestNamesFromSuite(suite): 83 """Returns a list of every test name in the given suite.""" 84 return map(lambda x: GetTestName(x), GetTestsFromSuite(suite)) 85 86 87def GetTestName(test): 88 """Gets the test name of the given unittest test.""" 89 return '.'.join([test.__class__.__module__, 90 test.__class__.__name__, 91 test._testMethodName]) 92 93 94def FilterTestSuite(suite, gtest_filter): 95 """Returns a new filtered tests suite based on the given gtest filter. 96 97 See http://code.google.com/p/googletest/wiki/AdvancedGuide 98 for gtest_filter specification. 99 """ 100 return unittest.TestSuite(FilterTests(GetTestsFromSuite(suite), gtest_filter)) 101 102 103def FilterTests(all_tests, gtest_filter): 104 """Filter a list of tests based on the given gtest filter. 105 106 Args: 107 all_tests: List of tests (unittest.TestSuite) 108 gtest_filter: Filter to apply. 109 110 Returns: 111 Filtered subset of the given list of tests. 112 """ 113 test_names = [GetTestName(test) for test in all_tests] 114 filtered_names = FilterTestNames(test_names, gtest_filter) 115 return [test for test in all_tests if GetTestName(test) in filtered_names] 116 117 118def FilterTestNames(all_tests, gtest_filter): 119 """Filter a list of test names based on the given gtest filter. 120 121 See http://code.google.com/p/googletest/wiki/AdvancedGuide 122 for gtest_filter specification. 123 124 Args: 125 all_tests: List of test names. 126 gtest_filter: Filter to apply. 127 128 Returns: 129 Filtered subset of the given list of test names. 130 """ 131 pattern_groups = gtest_filter.split('-') 132 positive_patterns = pattern_groups[0].split(':') 133 negative_patterns = None 134 if len(pattern_groups) > 1: 135 negative_patterns = pattern_groups[1].split(':') 136 137 tests = [] 138 for test in all_tests: 139 # Test name must by matched by one positive pattern. 140 for pattern in positive_patterns: 141 if fnmatch.fnmatch(test, pattern): 142 break 143 else: 144 continue 145 # Test name must not be matched by any negative patterns. 146 for pattern in negative_patterns or []: 147 if fnmatch.fnmatch(test, pattern): 148 break 149 else: 150 tests += [test] 151 return tests 152