2 # subunit: extensions to python unittest to get test results from subprocesses.
3 # Copyright (C) 2008 Robert Collins <robertc@robertcollins.net>
6 # Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
7 # license at the users choice. A copy of both licenses are available in the
8 # project source as Apache-2.0 and BSD. You may not use this file except in
9 # compliance with one of these two licences.
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # license you chose for the specific language governing permissions and
15 # limitations under that license.
18 """Filter a subunit stream to include/exclude tests.
20 The default is to strip successful tests.
22 Tests can be filtered by Python regular expressions with --with and --without,
23 which match both the test name and the error text (if any). The result
24 contains tests which match any of the --with expressions and none of the
25 --without expressions. For case-insensitive matching prepend '(?i)'.
26 Remember to quote shell metacharacters.
29 from optparse
import OptionParser
39 from subunit
.filters
import filter_by_result
40 from subunit
.test_results
import (
47 def make_options(description
):
48 parser
= OptionParser(description
=__doc__
)
49 parser
.add_option("--error", action
="store_false",
50 help="include errors", default
=False, dest
="error")
51 parser
.add_option("-e", "--no-error", action
="store_true",
52 help="exclude errors", dest
="error")
53 parser
.add_option("--failure", action
="store_false",
54 help="include failures", default
=False, dest
="failure")
55 parser
.add_option("-f", "--no-failure", action
="store_true",
56 help="exclude failures", dest
="failure")
57 parser
.add_option("--passthrough", action
="store_false",
58 help="Show all non subunit input.", default
=False, dest
="no_passthrough")
59 parser
.add_option("--no-passthrough", action
="store_true",
60 help="Hide all non subunit input.", default
=False, dest
="no_passthrough")
61 parser
.add_option("-s", "--success", action
="store_false",
62 help="include successes", dest
="success")
63 parser
.add_option("--no-success", action
="store_true",
64 help="exclude successes", default
=True, dest
="success")
65 parser
.add_option("--no-skip", action
="store_true",
66 help="exclude skips", dest
="skip")
67 parser
.add_option("--xfail", action
="store_false",
68 help="include expected falures", default
=True, dest
="xfail")
69 parser
.add_option("--no-xfail", action
="store_true",
70 help="exclude expected falures", default
=True, dest
="xfail")
72 "--with-tag", type=str,
73 help="include tests with these tags", action
="append", dest
="with_tags")
75 "--without-tag", type=str,
76 help="exclude tests with these tags", action
="append", dest
="without_tags")
77 parser
.add_option("-m", "--with", type=str,
78 help="regexp to include (case-sensitive by default)",
79 action
="append", dest
="with_regexps")
80 parser
.add_option("--fixup-expected-failures", type=str,
81 help="File with list of test ids that are expected to fail; on failure "
82 "their result will be changed to xfail; on success they will be "
83 "changed to error.", dest
="fixup_expected_failures", action
="append")
84 parser
.add_option("--without", type=str,
85 help="regexp to exclude (case-sensitive by default)",
86 action
="append", dest
="without_regexps")
87 parser
.add_option("-F", "--only-genuine-failures", action
="callback",
88 callback
=only_genuine_failures_callback
,
89 help="Only pass through failures and exceptions.")
93 def only_genuine_failures_callback(option
, opt
, value
, parser
):
94 parser
.rargs
.insert(0, '--no-passthrough')
95 parser
.rargs
.insert(0, '--no-xfail')
96 parser
.rargs
.insert(0, '--no-skip')
97 parser
.rargs
.insert(0, '--no-success')
100 def _compile_re_from_list(l
):
101 return re
.compile("|".join(l
), re
.MULTILINE
)
104 def _make_regexp_filter(with_regexps
, without_regexps
):
105 """Make a callback that checks tests against regexps.
107 with_regexps and without_regexps are each either a list of regexp strings,
110 with_re
= with_regexps
and _compile_re_from_list(with_regexps
)
111 without_re
= without_regexps
and _compile_re_from_list(without_regexps
)
113 def check_regexps(test
, outcome
, err
, details
, tags
):
114 """Check if this test and error match the regexp filters."""
115 test_str
= str(test
) + outcome
+ str(err
) + str(details
)
116 if with_re
and not with_re
.search(test_str
):
118 if without_re
and without_re
.search(test_str
):
124 def _make_result(output
, options
, predicate
):
125 """Make the result that we'll send the test outcomes to."""
126 fixup_expected_failures
= set()
127 for path
in options
.fixup_expected_failures
or ():
128 fixup_expected_failures
.update(read_test_list(path
))
129 return TestResultFilter(
130 TestProtocolClient(output
),
131 filter_error
=options
.error
,
132 filter_failure
=options
.failure
,
133 filter_success
=options
.success
,
134 filter_skip
=options
.skip
,
135 filter_xfail
=options
.xfail
,
136 filter_predicate
=predicate
,
137 fixup_expected_failures
=fixup_expected_failures
)
141 parser
= make_options(__doc__
)
142 (options
, args
) = parser
.parse_args()
144 regexp_filter
= _make_regexp_filter(
145 options
.with_regexps
, options
.without_regexps
)
146 tag_filter
= make_tag_filter(options
.with_tags
, options
.without_tags
)
147 filter_predicate
= and_predicates([regexp_filter
, tag_filter
])
150 lambda output_to
: _make_result(sys
.stdout
, options
, filter_predicate
),
152 passthrough
=(not options
.no_passthrough
),
157 if __name__
== '__main__':