dc3fd8aedb84cdab68ca7a5dac8c8455247b69ba
[amitay/samba.git] / lib / subunit / python / subunit / filters.py
1 #  subunit: extensions to python unittest to get test results from subprocesses.
2 #  Copyright (C) 2009  Robert Collins <robertc@robertcollins.net>
3 #
4 #  Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
5 #  license at the users choice. A copy of both licenses are available in the
6 #  project source as Apache-2.0 and BSD. You may not use this file except in
7 #  compliance with one of these two licences.
8 #  
9 #  Unless required by applicable law or agreed to in writing, software
10 #  distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
11 #  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
12 #  license you chose for the specific language governing permissions and
13 #  limitations under that license.
14 #
15
16
17 from optparse import OptionParser
18 import sys
19
20 from subunit import DiscardStream, ProtocolTestCase
21
22
23 def make_options(description):
24     parser = OptionParser(description=description)
25     parser.add_option(
26         "--no-passthrough", action="store_true",
27         help="Hide all non subunit input.", default=False,
28         dest="no_passthrough")
29     parser.add_option(
30         "-o", "--output-to",
31         help="Send the output to this path rather than stdout.")
32     parser.add_option(
33         "-f", "--forward", action="store_true", default=False,
34         help="Forward subunit stream on stdout.")
35     return parser
36
37
38 def run_tests_from_stream(input_stream, result, passthrough_stream=None,
39                           forward_stream=None):
40     """Run tests from a subunit input stream through 'result'.
41
42     :param input_stream: A stream containing subunit input.
43     :param result: A TestResult that will receive the test events.
44     :param passthrough_stream: All non-subunit input received will be
45         sent to this stream.  If not provided, uses the ``TestProtocolServer``
46         default, which is ``sys.stdout``.
47     :param forward_stream: All subunit input received will be forwarded
48         to this stream.  If not provided, uses the ``TestProtocolServer``
49         default, which is to not forward any input.
50     """
51     test = ProtocolTestCase(
52         input_stream, passthrough=passthrough_stream,
53         forward=forward_stream)
54     result.startTestRun()
55     test.run(result)
56     result.stopTestRun()
57
58
59 def filter_by_result(result_factory, output_path, passthrough, forward,
60                      input_stream=sys.stdin):
61     """Filter an input stream using a test result.
62
63     :param result_factory: A callable that when passed an output stream
64         returns a TestResult.  It is expected that this result will output
65         to the given stream.
66     :param output_path: A path send output to.  If None, output will be go
67         to ``sys.stdout``.
68     :param passthrough: If True, all non-subunit input will be sent to
69         ``sys.stdout``.  If False, that input will be discarded.
70     :param forward: If True, all subunit input will be forwarded directly to
71         ``sys.stdout`` as well as to the ``TestResult``.
72     :param input_stream: The source of subunit input.  Defaults to
73         ``sys.stdin``.
74     :return: A test result with the resultts of the run.
75     """
76     if passthrough:
77         passthrough_stream = sys.stdout
78     else:
79         passthrough_stream = DiscardStream()
80
81     if forward:
82         forward_stream = sys.stdout
83     else:
84         forward_stream = DiscardStream()
85
86     if output_path is None:
87         output_to = sys.stdout
88     else:
89         output_to = file(output_path, 'wb')
90
91     try:
92         result = result_factory(output_to)
93         run_tests_from_stream(
94             input_stream, result, passthrough_stream, forward_stream)
95     finally:
96         if output_path:
97             output_to.close()
98     return result
99
100
101 def run_filter_script(result_factory, description, post_run_hook=None):
102     """Main function for simple subunit filter scripts.
103
104     Many subunit filter scripts take a stream of subunit input and use a
105     TestResult to handle the events generated by that stream.  This function
106     wraps a lot of the boiler-plate around that by making a script with
107     options for handling passthrough information and stream forwarding, and
108     that will exit with a successful return code (i.e. 0) if the input stream
109     represents a successful test run.
110
111     :param result_factory: A callable that takes an output stream and returns
112         a test result that outputs to that stream.
113     :param description: A description of the filter script.
114     """
115     parser = make_options(description)
116     (options, args) = parser.parse_args()
117     result = filter_by_result(
118         result_factory, options.output_to, not options.no_passthrough,
119         options.forward)
120     if post_run_hook:
121         post_run_hook(result)
122     if result.wasSuccessful():
123         sys.exit(0)
124     else:
125         sys.exit(1)