summaryrefslogtreecommitdiff
path: root/lib/subunit/filters/subunit-filter
blob: 7f5620f151d0bae68d5424dd99b1f6f344ca2772 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env python
#  subunit: extensions to python unittest to get test results from subprocesses.
#  Copyright (C) 2008  Robert Collins <robertc@robertcollins.net>
#            (C) 2009  Martin Pool
#
#  Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
#  license at the users choice. A copy of both licenses are available in the
#  project source as Apache-2.0 and BSD. You may not use this file except in
#  compliance with one of these two licences.
#  
#  Unless required by applicable law or agreed to in writing, software
#  distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
#  license you chose for the specific language governing permissions and
#  limitations under that license.
#

"""Filter a subunit stream to include/exclude tests.

The default is to strip successful tests.

Tests can be filtered by Python regular expressions with --with and --without,
which match both the test name and the error text (if any).  The result
contains tests which match any of the --with expressions and none of the
--without expressions.  For case-insensitive matching prepend '(?i)'.
Remember to quote shell metacharacters.
"""

from optparse import OptionParser
import sys
import re

from subunit import (
    DiscardStream,
    ProtocolTestCase,
    TestProtocolClient,
    read_test_list,
    )
from subunit.test_results import TestResultFilter

parser = OptionParser(description=__doc__)
parser.add_option("--error", action="store_false",
    help="include errors", default=False, dest="error")
parser.add_option("-e", "--no-error", action="store_true",
    help="exclude errors", dest="error")
parser.add_option("--failure", action="store_false",
    help="include failures", default=False, dest="failure")
parser.add_option("-f", "--no-failure", action="store_true",
    help="exclude failures", dest="failure")
parser.add_option("--passthrough", action="store_false",
    help="Show all non subunit input.", default=False, dest="no_passthrough")
parser.add_option("--no-passthrough", action="store_true",
    help="Hide all non subunit input.", default=False, dest="no_passthrough")
parser.add_option("-s", "--success", action="store_false",
    help="include successes", dest="success")
parser.add_option("--no-success", action="store_true",
    help="exclude successes", default=True, dest="success")
parser.add_option("--no-skip", action="store_true",
    help="exclude skips", dest="skip")
parser.add_option("--xfail", action="store_false",
    help="include expected falures", default=True, dest="xfail")
parser.add_option("--no-xfail", action="store_true",
    help="exclude expected falures", default=True, dest="xfail")
parser.add_option("-m", "--with", type=str,
    help="regexp to include (case-sensitive by default)",
    action="append", dest="with_regexps")
parser.add_option("--fixup-expected-failures", type=str,
    help="File with list of test ids that are expected to fail; on failure "
         "their result will be changed to xfail; on success they will be "
         "changed to error.", dest="fixup_expected_failures", action="append")
parser.add_option("--without", type=str,
    help="regexp to exclude (case-sensitive by default)",
    action="append", dest="without_regexps")

def only_genuine_failures_callback(option, opt, value, parser):
    parser.rargs.insert(0, '--no-passthrough')
    parser.rargs.insert(0, '--no-xfail')
    parser.rargs.insert(0, '--no-skip')
    parser.rargs.insert(0, '--no-success')

parser.add_option("-F", "--only-genuine-failures", action="callback",
    callback=only_genuine_failures_callback,
    help="Only pass through failures and exceptions.")

(options, args) = parser.parse_args()

def _compile_re_from_list(l):
    return re.compile("|".join(l), re.MULTILINE)


def _make_regexp_filter(with_regexps, without_regexps):
    """Make a callback that checks tests against regexps.

    with_regexps and without_regexps are each either a list of regexp strings,
    or None.
    """
    with_re = with_regexps and _compile_re_from_list(with_regexps)
    without_re = without_regexps and _compile_re_from_list(without_regexps)

    def check_regexps(test, outcome, err, details):
        """Check if this test and error match the regexp filters."""
        test_str = str(test) + outcome + str(err) + str(details)
        if with_re and not with_re.search(test_str):
            return False
        if without_re and without_re.search(test_str):
            return False
        return True
    return check_regexps


regexp_filter = _make_regexp_filter(options.with_regexps,
        options.without_regexps)
fixup_expected_failures = set()
for path in options.fixup_expected_failures or ():
    fixup_expected_failures.update(read_test_list(path))
result = TestProtocolClient(sys.stdout)
result = TestResultFilter(result, filter_error=options.error,
    filter_failure=options.failure, filter_success=options.success,
    filter_skip=options.skip, filter_xfail=options.xfail,
    filter_predicate=regexp_filter,
    fixup_expected_failures=fixup_expected_failures)
if options.no_passthrough:
    passthrough_stream = DiscardStream()
else:
    passthrough_stream = None
test = ProtocolTestCase(sys.stdin, passthrough=passthrough_stream)
test.run(result)
sys.exit(0)