diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/subunit/filter_scripts/__init__.py | 0 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit2csv.py | 31 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit2disk.py | 29 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit2gtk.py | 236 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit2junitxml.py | 41 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit2pyunit.py | 67 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_1to2.py | 42 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_2to1.py | 53 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_filter.py | 175 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_ls.py | 65 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_notify.py | 53 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_output.py | 28 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_stats.py | 38 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/subunit_tags.py | 33 | ||||
-rwxr-xr-x | python/subunit/filter_scripts/tap2subunit.py | 33 | ||||
-rw-r--r-- | python/subunit/tests/test_subunit_filter.py | 5 |
16 files changed, 925 insertions, 4 deletions
diff --git a/python/subunit/filter_scripts/__init__.py b/python/subunit/filter_scripts/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/python/subunit/filter_scripts/__init__.py diff --git a/python/subunit/filter_scripts/subunit2csv.py b/python/subunit/filter_scripts/subunit2csv.py new file mode 100755 index 0000000..c8e48a5 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2csv.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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 d 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. +# + +"""Turn a subunit stream into a CSV""" + +from testtools import StreamToExtendedDecorator + +from subunit.filters import run_filter_script +from subunit.test_results import CsvResult + + +def main(): + run_filter_script(lambda output: StreamToExtendedDecorator( + CsvResult(output)), __doc__, protocol_version=2) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2disk.py b/python/subunit/filter_scripts/subunit2disk.py new file mode 100755 index 0000000..da1c09c --- /dev/null +++ b/python/subunit/filter_scripts/subunit2disk.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Subunit Contributors +# +# 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. + + +"""Export a stream to files and directories on disk.""" + +import sys + +from subunit._to_disk import to_disk + + +def main(): + sys.exit(to_disk()) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2gtk.py b/python/subunit/filter_scripts/subunit2gtk.py new file mode 100755 index 0000000..bcfd1e7 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2gtk.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +### The GTK progress bar __init__ function is derived from the pygtk tutorial: +# The PyGTK Tutorial is Copyright (C) 2001-2005 John Finlay. +# +# The GTK Tutorial is Copyright (C) 1997 Ian Main. +# +# Copyright (C) 1998-1999 Tony Gale. +# +# Permission is granted to make and distribute verbatim copies of this manual +# provided the copyright notice and this permission notice are preserved on all +# copies. +# +# Permission is granted to copy and distribute modified versions of this +# document under the conditions for verbatim copying, provided that this +# copyright notice is included exactly as in the original, and that the entire +# resulting derived work is distributed under the terms of a permission notice +# identical to this one. +# +# Permission is granted to copy and distribute translations of this document +# into another language, under the above conditions for modified versions. +# +# If you are intending to incorporate this document into a published work, +# please contact the maintainer, and we will make an effort to ensure that you +# have the most up to date information available. +# +# There is no guarantee that this document lives up to its intended purpose. +# This is simply provided as a free resource. As such, the authors and +# maintainers of the information provided within can not make any guarantee +# that the information is even accurate. + +"""Display a subunit stream in a gtk progress window.""" + +import sys +import threading +import unittest + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, GObject + +from testtools import StreamToExtendedDecorator + +from subunit import ( + PROGRESS_POP, + PROGRESS_PUSH, + PROGRESS_SET, + ByteStreamToStreamResult, + ) +from subunit.progress_model import ProgressModel + + +class GTKTestResult(unittest.TestResult): + + def __init__(self): + super(GTKTestResult, self).__init__() + # Instance variables (in addition to TestResult) + self.window = None + self.run_label = None + self.ok_label = None + self.not_ok_label = None + self.total_tests = None + + self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL) + self.window.set_resizable(True) + + self.window.connect("destroy", Gtk.main_quit) + self.window.set_title("Tests...") + self.window.set_border_width(0) + + vbox = Gtk.VBox(False, 5) + vbox.set_border_width(10) + self.window.add(vbox) + vbox.show() + + # Create a centering alignment object + align = Gtk.Alignment.new(0.5, 0.5, 0, 0) + vbox.pack_start(align, False, False, 5) + align.show() + + # Create the ProgressBar + self.pbar = Gtk.ProgressBar() + align.add(self.pbar) + self.pbar.set_text("Running") + self.pbar.show() + self.progress_model = ProgressModel() + + separator = Gtk.HSeparator() + vbox.pack_start(separator, False, False, 0) + separator.show() + + # rows, columns, homogeneous + table = Gtk.Table(2, 3, False) + vbox.pack_start(table, False, True, 0) + table.show() + # Show summary details about the run. Could use an expander. + label = Gtk.Label(label="Run:") + table.attach(label, 0, 1, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + label.show() + self.run_label = Gtk.Label(label="N/A") + table.attach(self.run_label, 1, 2, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + self.run_label.show() + + label = Gtk.Label(label="OK:") + table.attach(label, 0, 1, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + label.show() + self.ok_label = Gtk.Label(label="N/A") + table.attach(self.ok_label, 1, 2, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + self.ok_label.show() + + label = Gtk.Label(label="Not OK:") + table.attach(label, 0, 1, 3, 4, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + label.show() + self.not_ok_label = Gtk.Label(label="N/A") + table.attach(self.not_ok_label, 1, 2, 3, 4, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 5, 5) + self.not_ok_label.show() + + self.window.show() + # For the demo. + self.window.set_keep_above(True) + self.window.present() + + def stopTest(self, test): + super(GTKTestResult, self).stopTest(test) + GObject.idle_add(self._stopTest) + + def _stopTest(self): + self.progress_model.advance() + if self.progress_model.width() == 0: + self.pbar.pulse() + else: + pos = self.progress_model.pos() + width = self.progress_model.width() + percentage = (pos / float(width)) + self.pbar.set_fraction(percentage) + + def stopTestRun(self): + try: + super(GTKTestResult, self).stopTestRun() + except AttributeError: + pass + GObject.idle_add(self.pbar.set_text, 'Finished') + + def addError(self, test, err): + super(GTKTestResult, self).addError(test, err) + GObject.idle_add(self.update_counts) + + def addFailure(self, test, err): + super(GTKTestResult, self).addFailure(test, err) + GObject.idle_add(self.update_counts) + + def addSuccess(self, test): + super(GTKTestResult, self).addSuccess(test) + GObject.idle_add(self.update_counts) + + def addSkip(self, test, reason): + super(GTKTestResult, self).addSkip(test, reason) + GObject.idle_add(self.update_counts) + + def addExpectedFailure(self, test, err): + super(GTKTestResult, self).addExpectedFailure(test, err) + GObject.idle_add(self.update_counts) + + def addUnexpectedSuccess(self, test): + super(GTKTestResult, self).addUnexpectedSuccess(test) + GObject.idle_add(self.update_counts) + + def progress(self, offset, whence): + if whence == PROGRESS_PUSH: + self.progress_model.push() + elif whence == PROGRESS_POP: + self.progress_model.pop() + elif whence == PROGRESS_SET: + self.total_tests = offset + self.progress_model.set_width(offset) + else: + self.total_tests += offset + self.progress_model.adjust_width(offset) + + def time(self, a_datetime): + # We don't try to estimate completion yet. + pass + + def update_counts(self): + self.run_label.set_text(str(self.testsRun)) + bad = len(self.failures + self.errors) + self.ok_label.set_text(str(self.testsRun - bad)) + self.not_ok_label.set_text(str(bad)) + + +def main(): + GObject.threads_init() + result = StreamToExtendedDecorator(GTKTestResult()) + test = ByteStreamToStreamResult(sys.stdin, non_subunit_name='stdout') + # Get setup + while Gtk.events_pending(): + Gtk.main_iteration() + + # Start IO + def run_and_finish(): + test.run(result) + result.stopTestRun() + t = threading.Thread(target=run_and_finish) + t.daemon = True + result.startTestRun() + t.start() + Gtk.main() + if result.decorated.wasSuccessful(): + exit_code = 0 + else: + exit_code = 1 + sys.exit(exit_code) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2junitxml.py b/python/subunit/filter_scripts/subunit2junitxml.py new file mode 100755 index 0000000..db85040 --- /dev/null +++ b/python/subunit/filter_scripts/subunit2junitxml.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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 get aggregate statistics.""" + + +import sys + +from testtools import StreamToExtendedDecorator + +from subunit.filters import run_filter_script + +try: + from junitxml import JUnitXmlResult +except ImportError: + sys.stderr.write("python-junitxml (https://launchpad.net/pyjunitxml or " + "http://pypi.python.org/pypi/junitxml) is required for this filter.") + raise + + +def main(): + run_filter_script( + lambda output: StreamToExtendedDecorator( + JUnitXmlResult(output)), __doc__, protocol_version=2) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit2pyunit.py b/python/subunit/filter_scripts/subunit2pyunit.py new file mode 100755 index 0000000..2a040ec --- /dev/null +++ b/python/subunit/filter_scripts/subunit2pyunit.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +"""Display a subunit stream through python's unittest test runner.""" + +from operator import methodcaller +from optparse import OptionParser +import sys +import unittest + +from testtools import StreamToExtendedDecorator, DecorateTestCaseResult, StreamResultRouter + +from subunit import ByteStreamToStreamResult +from subunit.filters import find_stream +from subunit.test_results import CatFiles + + +def main(): + parser = OptionParser(description=__doc__) + parser.add_option("--no-passthrough", action="store_true", + help="Hide all non subunit input.", + default=False, dest="no_passthrough") + parser.add_option("--progress", action="store_true", + help="Use bzrlib's test reporter (requires bzrlib)", + default=False) + (options, args) = parser.parse_args() + test = ByteStreamToStreamResult( + find_stream(sys.stdin, args), non_subunit_name='stdout') + + def wrap_result(result): + result = StreamToExtendedDecorator(result) + if not options.no_passthrough: + result = StreamResultRouter(result) + result.add_rule(CatFiles(sys.stdout), 'test_id', test_id=None) + return result + test = DecorateTestCaseResult(test, wrap_result, + before_run=methodcaller('startTestRun'), + after_run=methodcaller('stopTestRun')) + if options.progress: + from bzrlib.tests import TextTestRunner + from bzrlib import ui + ui.ui_factory = ui.make_ui_for_terminal(None, sys.stdout, sys.stderr) + runner = TextTestRunner() + else: + runner = unittest.TextTestRunner(verbosity=2) + if runner.run(test).wasSuccessful(): + exit_code = 0 + else: + exit_code = 1 + sys.exit(exit_code) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_1to2.py b/python/subunit/filter_scripts/subunit_1to2.py new file mode 100755 index 0000000..085c0fe --- /dev/null +++ b/python/subunit/filter_scripts/subunit_1to2.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +"""Convert a version 1 subunit stream to version 2 stream.""" + +from optparse import OptionParser +import sys + +from testtools import ExtendedToStreamDecorator + +from subunit import StreamResultToBytes +from subunit.filters import find_stream, run_tests_from_stream + + +def make_options(description): + parser = OptionParser(description=__doc__) + return parser + + +def main(): + parser = make_options(__doc__) + (options, args) = parser.parse_args() + run_tests_from_stream(find_stream(sys.stdin, args), + ExtendedToStreamDecorator(StreamResultToBytes(sys.stdout))) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_2to1.py b/python/subunit/filter_scripts/subunit_2to1.py new file mode 100755 index 0000000..1f2716a --- /dev/null +++ b/python/subunit/filter_scripts/subunit_2to1.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +"""Convert a version 2 subunit stream to a version 1 stream.""" + +from optparse import OptionParser +import sys + +from testtools import ( + StreamToExtendedDecorator, + StreamResultRouter, + ) + +from subunit import ByteStreamToStreamResult, TestProtocolClient +from subunit.filters import find_stream +from subunit.test_results import CatFiles + + +def make_options(description): + parser = OptionParser(description=__doc__) + return parser + + +def main(): + parser = make_options(__doc__) + (options, args) = parser.parse_args() + case = ByteStreamToStreamResult( + find_stream(sys.stdin, args), non_subunit_name='stdout') + result = StreamToExtendedDecorator(TestProtocolClient(sys.stdout)) + result = StreamResultRouter(result) + cat = CatFiles(sys.stdout) + result.add_rule(cat, 'test_id', test_id=None) + result.startTestRun() + case.run(result) + result.stopTestRun() + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_filter.py b/python/subunit/filter_scripts/subunit_filter.py new file mode 100755 index 0000000..951672f --- /dev/null +++ b/python/subunit/filter_scripts/subunit_filter.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 200-2013 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 testtools import ExtendedToStreamDecorator, StreamToExtendedDecorator + +from subunit import ( + StreamResultToBytes, + read_test_list, + ) +from subunit.filters import filter_by_result, find_stream +from subunit.test_results import ( + and_predicates, + make_tag_filter, + TestResultFilter, + ) + + +def make_options(description): + 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="Forward non-subunit input as 'stdout'.", default=False, + dest="no_passthrough") + parser.add_option("--no-passthrough", action="store_true", + help="Discard 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 failures", default=True, dest="xfail") + parser.add_option("--no-xfail", action="store_true", + help="exclude expected failures", default=True, dest="xfail") + parser.add_option( + "--with-tag", type=str, + help="include tests with these tags", action="append", dest="with_tags") + parser.add_option( + "--without-tag", type=str, + help="exclude tests with these tags", action="append", dest="without_tags") + 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") + parser.add_option("-F", "--only-genuine-failures", action="callback", + callback=only_genuine_failures_callback, + help="Only pass through failures and exceptions.") + parser.add_option("--rename", action="append", nargs=2, + help="Apply specified regex subsitutions to test names.", + dest="renames", default=[]) + return parser + + +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') + + +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, tags): + """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 + + +def _compile_rename(patterns): + def rename(name): + for (from_pattern, to_pattern) in patterns: + name = re.sub(from_pattern, to_pattern, name) + return name + return rename + + +def _make_result(output, options, predicate): + """Make the result that we'll send the test outcomes to.""" + fixup_expected_failures = set() + for path in options.fixup_expected_failures or (): + fixup_expected_failures.update(read_test_list(path)) + return StreamToExtendedDecorator(TestResultFilter( + ExtendedToStreamDecorator( + StreamResultToBytes(output)), + filter_error=options.error, + filter_failure=options.failure, + filter_success=options.success, + filter_skip=options.skip, + filter_xfail=options.xfail, + filter_predicate=predicate, + fixup_expected_failures=fixup_expected_failures, + rename=_compile_rename(options.renames))) + + +def main(): + parser = make_options(__doc__) + (options, args) = parser.parse_args() + + regexp_filter = _make_regexp_filter( + options.with_regexps, options.without_regexps) + tag_filter = make_tag_filter(options.with_tags, options.without_tags) + filter_predicate = and_predicates([regexp_filter, tag_filter]) + + filter_by_result( + lambda output_to: _make_result(sys.stdout, options, filter_predicate), + output_path=None, + passthrough=(not options.no_passthrough), + forward=False, + protocol_version=2, + input_stream=find_stream(sys.stdin, args)) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_ls.py b/python/subunit/filter_scripts/subunit_ls.py new file mode 100755 index 0000000..0eee267 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_ls.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2008 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +"""List tests in a subunit stream.""" + +from optparse import OptionParser +import sys + +from testtools import ( + CopyStreamResult, StreamResultRouter, + StreamSummary) + +from subunit import ByteStreamToStreamResult +from subunit.filters import find_stream +from subunit.test_results import ( + CatFiles, + TestIdPrintingResult, + ) + + +def main(): + parser = OptionParser(description=__doc__) + parser.add_option("--times", action="store_true", + help="list the time each test took (requires a timestamped stream)", + default=False) + parser.add_option("--exists", action="store_true", + help="list tests that are reported as existing (as well as ran)", + default=False) + parser.add_option("--no-passthrough", action="store_true", + help="Hide all non subunit input.", default=False, dest="no_passthrough") + (options, args) = parser.parse_args() + test = ByteStreamToStreamResult( + find_stream(sys.stdin, args), non_subunit_name="stdout") + result = TestIdPrintingResult(sys.stdout, options.times, options.exists) + if not options.no_passthrough: + result = StreamResultRouter(result) + cat = CatFiles(sys.stdout) + result.add_rule(cat, 'test_id', test_id=None) + summary = StreamSummary() + result = CopyStreamResult([result, summary]) + result.startTestRun() + test.run(result) + result.stopTestRun() + if summary.wasSuccessful(): + exit_code = 0 + else: + exit_code = 1 + sys.exit(exit_code) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_notify.py b/python/subunit/filter_scripts/subunit_notify.py new file mode 100755 index 0000000..44ca758 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_notify.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org> +# +# 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. +# + +"""Notify the user of a finished test run.""" + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Notify +from testtools import StreamToExtendedDecorator + +from subunit import TestResultStats +from subunit.filters import run_filter_script + +if not Notify.init("Subunit-notify"): + sys.exit(1) + + +def notify_of_result(result): + result = result.decorated + if result.failed_tests > 0: + summary = "Test run failed" + else: + summary = "Test run successful" + body = "Total tests: %d; Passed: %d; Failed: %d" % ( + result.total_tests, + result.passed_tests, + result.failed_tests, + ) + nw = Notify.Notification(summary, body) + nw.show() + + +def main(): + run_filter_script( + lambda output:StreamToExtendedDecorator(TestResultStats(output)), + __doc__, notify_of_result, protocol_version=2) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_output.py b/python/subunit/filter_scripts/subunit_output.py new file mode 100755 index 0000000..a587e87 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_output.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2013 Subunit Contributors +# +# 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. + + +"""A command-line tool to generate a subunit result byte-stream.""" + +import sys + +from subunit._output import output_main + +def main(): + sys.exit(output_main()) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_stats.py b/python/subunit/filter_scripts/subunit_stats.py new file mode 100755 index 0000000..53814d1 --- /dev/null +++ b/python/subunit/filter_scripts/subunit_stats.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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 get aggregate statistics.""" + +import sys + +from testtools import StreamToExtendedDecorator + +from subunit import TestResultStats +from subunit.filters import run_filter_script + + +def main(): + result = TestResultStats(sys.stdout) + + def show_stats(r): + r.decorated.formatStats() + + run_filter_script( + lambda output:StreamToExtendedDecorator(result), + __doc__, show_stats, protocol_version=2, passthrough_subunit=False) + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/subunit_tags.py b/python/subunit/filter_scripts/subunit_tags.py new file mode 100755 index 0000000..31b45cc --- /dev/null +++ b/python/subunit/filter_scripts/subunit_tags.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +"""A filter to change tags on a subunit stream. + +subunit-tags foo -> adds foo +subunit-tags foo -bar -> adds foo and removes bar +""" + +import sys + +from subunit import tag_stream + + +def main(): + sys.exit(tag_stream(sys.stdin, sys.stdout, sys.argv[1:])) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/filter_scripts/tap2subunit.py b/python/subunit/filter_scripts/tap2subunit.py new file mode 100755 index 0000000..d39e8ce --- /dev/null +++ b/python/subunit/filter_scripts/tap2subunit.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# subunit: extensions to python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# 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. +# + +"""A filter that reads a TAP stream and outputs a subunit stream. + +More information on TAP is available at +http://testanything.org/wiki/index.php/Main_Page. +""" + +import sys + +from subunit import TAP2SubUnit + + +def main(): + sys.exit(TAP2SubUnit(sys.stdin, sys.stdout)) + + +if __name__ == '__main__': + main() diff --git a/python/subunit/tests/test_subunit_filter.py b/python/subunit/tests/test_subunit_filter.py index 7ca0081..d14415a 100644 --- a/python/subunit/tests/test_subunit_filter.py +++ b/python/subunit/tests/test_subunit_filter.py @@ -301,10 +301,7 @@ xfail todo class TestFilterCommand(TestCase): def run_command(self, args, stream): - root = os.path.dirname( - os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) - script_path = os.path.join(root, 'filters', 'subunit-filter') - command = [sys.executable, script_path] + list(args) + command = ['subunit-filter'] + list(args) ps = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |