| # Copyright 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Utilities for dealing with the python unittest module.""" |
| |
| import fnmatch |
| import re |
| import sys |
| import unittest |
| |
| |
| class _TextTestResult(unittest._TextTestResult): |
| """A test result class that can print formatted text results to a stream. |
| |
| Results printed in conformance with gtest output format, like: |
| [ RUN ] autofill.AutofillTest.testAutofillInvalid: "test desc." |
| [ OK ] autofill.AutofillTest.testAutofillInvalid |
| [ RUN ] autofill.AutofillTest.testFillProfile: "test desc." |
| [ OK ] autofill.AutofillTest.testFillProfile |
| [ RUN ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test." |
| [ OK ] autofill.AutofillTest.testFillProfileCrazyCharacters |
| """ |
| def __init__(self, stream, descriptions, verbosity): |
| unittest._TextTestResult.__init__(self, stream, descriptions, verbosity) |
| self._fails = set() |
| |
| def _GetTestURI(self, test): |
| return '%s.%s.%s' % (test.__class__.__module__, |
| test.__class__.__name__, |
| test._testMethodName) |
| |
| def getDescription(self, test): |
| return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription()) |
| |
| def startTest(self, test): |
| unittest.TestResult.startTest(self, test) |
| self.stream.writeln('[ RUN ] %s' % self.getDescription(test)) |
| |
| def addSuccess(self, test): |
| unittest.TestResult.addSuccess(self, test) |
| self.stream.writeln('[ OK ] %s' % self._GetTestURI(test)) |
| |
| def addError(self, test, err): |
| unittest.TestResult.addError(self, test, err) |
| self.stream.writeln('[ ERROR ] %s' % self._GetTestURI(test)) |
| self._fails.add(self._GetTestURI(test)) |
| |
| def addFailure(self, test, err): |
| unittest.TestResult.addFailure(self, test, err) |
| self.stream.writeln('[ FAILED ] %s' % self._GetTestURI(test)) |
| self._fails.add(self._GetTestURI(test)) |
| |
| def getRetestFilter(self): |
| return ':'.join(self._fails) |
| |
| |
| class TextTestRunner(unittest.TextTestRunner): |
| """Test Runner for displaying test results in textual format. |
| |
| Results are displayed in conformance with google test output. |
| """ |
| |
| def __init__(self, verbosity=1): |
| unittest.TextTestRunner.__init__(self, stream=sys.stderr, |
| verbosity=verbosity) |
| |
| def _makeResult(self): |
| return _TextTestResult(self.stream, self.descriptions, self.verbosity) |
| |
| |
| def GetTestsFromSuite(suite): |
| """Returns all the tests from a given test suite.""" |
| tests = [] |
| for x in suite: |
| if isinstance(x, unittest.TestSuite): |
| tests += GetTestsFromSuite(x) |
| else: |
| tests += [x] |
| return tests |
| |
| |
| def GetTestNamesFromSuite(suite): |
| """Returns a list of every test name in the given suite.""" |
| return map(lambda x: GetTestName(x), GetTestsFromSuite(suite)) |
| |
| |
| def GetTestName(test): |
| """Gets the test name of the given unittest test.""" |
| return '.'.join([test.__class__.__module__, |
| test.__class__.__name__, |
| test._testMethodName]) |
| |
| |
| def FilterTestSuite(suite, gtest_filter): |
| """Returns a new filtered tests suite based on the given gtest filter. |
| |
| See https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md |
| for gtest_filter specification. |
| """ |
| return unittest.TestSuite(FilterTests(GetTestsFromSuite(suite), gtest_filter)) |
| |
| |
| def FilterTests(all_tests, gtest_filter): |
| """Filter a list of tests based on the given gtest filter. |
| |
| Args: |
| all_tests: List of tests (unittest.TestSuite) |
| gtest_filter: Filter to apply. |
| |
| Returns: |
| Filtered subset of the given list of tests. |
| """ |
| test_names = [GetTestName(test) for test in all_tests] |
| filtered_names = FilterTestNames(test_names, gtest_filter) |
| return [test for test in all_tests if GetTestName(test) in filtered_names] |
| |
| |
| def FilterTestNames(all_tests, gtest_filter): |
| """Filter a list of test names based on the given gtest filter. |
| |
| See https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md |
| for gtest_filter specification. |
| |
| Args: |
| all_tests: List of test names. |
| gtest_filter: Filter to apply. |
| |
| Returns: |
| Filtered subset of the given list of test names. |
| """ |
| pattern_groups = gtest_filter.split('-') |
| positive_patterns = ['*'] |
| if pattern_groups[0]: |
| positive_patterns = pattern_groups[0].split(':') |
| negative_patterns = [] |
| if len(pattern_groups) > 1: |
| negative_patterns = pattern_groups[1].split(':') |
| |
| neg_pats = None |
| if negative_patterns: |
| neg_pats = re.compile('|'.join(fnmatch.translate(p) for p in |
| negative_patterns)) |
| |
| tests = [] |
| test_set = set() |
| for pattern in positive_patterns: |
| pattern_tests = [ |
| test for test in all_tests |
| if (fnmatch.fnmatch(test, pattern) |
| and not (neg_pats and neg_pats.match(test)) |
| and test not in test_set)] |
| tests.extend(pattern_tests) |
| test_set.update(pattern_tests) |
| return tests |