Add a tap2subunit filter program.
authorRobert Collins <robertc@robertcollins.net>
Sun, 7 Dec 2008 23:29:06 +0000 (10:29 +1100)
committerRobert Collins <robertc@robertcollins.net>
Sun, 7 Dec 2008 23:29:06 +0000 (10:29 +1100)
README
SConstruct
filters/SConscript [new file with mode: 0644]
filters/tap2subunit [new file with mode: 0755]
python/subunit/__init__.py
python/subunit/tests/__init__.py
python/subunit/tests/test_tap2subunit.py [new file with mode: 0644]
runtests.py

diff --git a/README b/README
index de99994d6a5ae8d61cfccb81e3873d20a304b69a..1f7f7a23a9bdfd6ae33409c143737373df151584 100644 (file)
--- a/README
+++ b/README
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
+Subunit
+-------
 
 Subunit is attempting to extend unittest with a clean and simple api to
 run arbitrary external test suites and return the results to standard
 python unittest.
 
-Subunit comes in two parts: There is a parent-process component and a
-child procecss component. The parent component pretends to be a xUnit
-test suite in whatever language you are using for the parent. Currently
-there is only one implementation of the parent : Python.
-Secondly there is the child component that runs in the child process and
-reports to the parent as tests begin and end. There are currently 3
-implementations of the child - Python, C and shell.
-Look in the python/, shell/ or c/ directories for the sources in each
-languages.
+Subunit comes in three parts:
+ * Protocol writers (clients)
+ * Protocol readers (servers)
+ * Filters
+The reader component acts as a test suite in the language that it is written
+for. Currently subunit only provides a Python protocol reader.
 
-Using subunit:
+Writers are used to output test results in subunit form. Writers are typically
+test suite runners or test suite result objects in specific languages.
+Currently subunit provides writers for Python, C, C++, and shell.
+
+Filters provide translation filtering capabilities and can be used to modify a
+stream on-the-fly. Currently subunit provides a single filter - tap2subunit.
+
+The subunit code is organised at the top level by directories, for language
+bindings, and additionally the filters directory for filters.
+
+Using subunit in Python
+-----------------------
 
 1) As a runner for external tests (potentially in other languages)
 2) As a process boundary for unittest TestCases to prevent them fiddling with
@@ -119,6 +130,8 @@ Some requirements:
   After the test has run, tests should still exist as discrete objects, so that
   anything taking a reference to them doesn't get 50 copies of the same object.
 
+Sample subunit wire contents
+----------------------------
 
 test: test foo works
 success: test foo works.
@@ -138,11 +151,13 @@ a writeln to stdout
 FAILURE: tar a file.
 -------------------
 ..
-]..  space is eatern.
+]..  space is eaten.
 foo.c:34 WARNING foo is not defined.
 ========================
 
-control protocol:
+
+Subunit protocol description
+----------------------------
 test|testing|test:|testing: test label
 success|success:|successful|successful: test label
 success|success:|successful|successful: test label [
@@ -168,6 +183,7 @@ xfail[:] test label [
 unexpected output on stdout -> stdout.
 exit w/0 or last test -> error
 
+
 TODO:
 def run:
     do a fork,
index d4af06c726f2baa51828ff6aff0c977e5fe729cb..0ef29fee91d4d9d5e728afadf394664894129d78 100644 (file)
@@ -38,6 +38,6 @@ env.Append(BUILDERS = {'TestRC' : test_script_runner,
 # tests
 tests.append(env.TestPython('check_python', 'runtests.py', PYTHONPATH='python'))
 
-SConscript(dirs=['c', 'c++', 'python', 'shell'])
+SConscript(dirs=['c', 'c++', 'filters', 'python', 'shell'])
 
 env.Alias('check', tests)
diff --git a/filters/SConscript b/filters/SConscript
new file mode 100644 (file)
index 0000000..0285dd1
--- /dev/null
@@ -0,0 +1,19 @@
+Import('*')
+# describe what we need for filters
+
+EnsurePythonVersion(2, 4)
+
+import distutils.sysconfig
+import os.path
+
+# distutils default prefix is the common path between
+# distutils.sysconfig.get_python_lib and distutils.sysconfig.get_python_inc
+prefix = os.path.commonprefix([
+    distutils.sysconfig.get_python_lib(),
+    distutils.sysconfig.get_python_inc(),
+    ])
+# suffix to install .py files to is distutils.sysconfig.get_python_lib()
+# after the common prefix
+python_suffix = distutils.sysconfig.get_python_lib()[len(prefix):]
+# install path for python is then in DESTDIR + python_suffix
+python_installdir = DESTDIR + python_suffix + '/subunit'
diff --git a/filters/tap2subunit b/filters/tap2subunit
new file mode 100755 (executable)
index 0000000..f2335f7
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+#  subunit: extensions to python unittest to get test results from subprocesses.
+#  Copyright (C) 2005  Robert Collins <robertc@robertcollins.net>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""A filter that reads a TAP stream and outputs a subunit stream."""
+
+import sys
+
+from subunit import TAP2SubUnit
+return TAP2SubUnit(sys.stdin, sys.stdout)
index cde57077cf22ae33c50f01025294ec001121c588..4d2d60908ee09aecc81588d6477e94b3c209296a 100644 (file)
@@ -21,6 +21,7 @@ import os
 from StringIO import StringIO
 import subprocess
 import sys
+import re
 import unittest
 
 def test_suite():
@@ -422,3 +423,111 @@ def run_isolated(klass, self, result):
         os.waitpid(pid, 0)
         # TODO return code evaluation.
     return result
+
+
+def TAP2SubUnit(tap, subunit):
+    """Filter a TAP pipe into a subunit pipe.
+    
+    :param tap: A tap pipe/stream/file object.
+    :param subunit: A pipe/stream/file object to write subunit results to.
+    :return: The exit code to exit with.
+    """
+    BEFORE_PLAN = 0
+    AFTER_PLAN = 1
+    SKIP_STREAM = 2
+    client = TestProtocolClient(subunit)
+    state = BEFORE_PLAN
+    plan_start = 1
+    plan_stop = 0
+    def _skipped_test(subunit, plan_start):
+        # Some tests were skipped.
+        subunit.write('test test %d\n' % plan_start)
+        subunit.write('error test %d [\n' % plan_start)
+        subunit.write('test missing from TAP output\n')
+        subunit.write(']\n')
+        return plan_start + 1
+    # Test data for the next test to emit
+    test_name = None
+    log = []
+    result = None
+    def _emit_test():
+        "write out a test"
+        if test_name is None:
+            return
+        subunit.write("test %s\n" % test_name)
+        if not log:
+            subunit.write("%s %s\n" % (result, test_name))
+        else:
+            subunit.write("%s %s [\n" % (result, test_name))
+        if log:
+            for line in log:
+                subunit.write("%s\n" % line)
+            subunit.write("]\n")
+        del log[:]
+    for line in tap:
+        if state == BEFORE_PLAN:
+            match = re.match("(\d+)\.\.(\d+)\s*(?:\#\s+(.*))?\n", line)
+            if match:
+                state = AFTER_PLAN
+                _, plan_stop, comment = match.groups()
+                plan_stop = int(plan_stop)
+                if plan_start > plan_stop and plan_stop == 0:
+                    # skipped file
+                    state = SKIP_STREAM
+                    subunit.write("test file skip\n")
+                    subunit.write("skip file skip [\n")
+                    subunit.write("%s\n" % comment)
+                    subunit.write("]\n")
+                continue
+        # not a plan line, or have seen one before
+        #match = re.match("(ok|not ok)\s+(\d+)?\s*([^#]*)\s*(?:#\s+(.*))\n", line)
+        match = re.match("(ok|not ok)(?:\s+(\d+)?)?(?:\s+([^#]*[^#\s]+)\s*)?(?:\s+#\s+(TODO|SKIP)(?:\s+(.*))?)?\n", line)
+        if match:
+            # new test, emit current one.
+            _emit_test()
+            status, number, description, directive, directive_comment = match.groups()
+            # status, number, description = match.groups()
+            if status == 'ok':
+                result = 'success'
+            else:
+                result = 'fail'
+            if description is None:
+                description = ''
+            else:
+                description = ' ' + description
+            if directive is not None:
+                if directive == 'TODO':
+                    result = 'xfail'
+                elif directive == 'SKIP':
+                    result = 'skip'
+                if directive_comment is not None:
+                    log.append(directive_comment)
+            if number is not None:
+                number = int(number)
+                while plan_start < number:
+                    plan_start = _skipped_test(subunit, plan_start)
+            test_name = "test %d%s" % (plan_start, description)
+            plan_start += 1
+            continue
+        match = re.match("Bail out\!(?:\s*(.*))?\n", line)
+        if match:
+            reason, = match.groups()
+            if reason is None:
+                extra = ''
+            else:
+                extra = ' %s' % reason
+            _emit_test()
+            test_name = "Bail out!%s" % extra
+            result = "error"
+            state = SKIP_STREAM
+            continue
+        match = re.match("\#.*\n", line)
+        if match:
+            log.append(line[:-1])
+            continue
+        subunit.write(line)
+    _emit_test()
+    while plan_start <= plan_stop:
+        # record missed tests
+        plan_start = _skipped_test(subunit, plan_start)
+    return 0
index 544d0e704fcdea7dcbe253b71a5bd046f2a28eee..7f501c7649a06776c1bc34f60a8cfdee45a24837 100644 (file)
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
-from subunit.tests import TestUtil, test_test_protocol
+from subunit.tests import (
+    TestUtil,
+    test_tap2subunit,
+    test_test_protocol,
+    )
 
 def test_suite():
     result = TestUtil.TestSuite()
     result.addTest(test_test_protocol.test_suite())
+    result.addTest(test_tap2subunit.test_suite())
     return result
diff --git a/python/subunit/tests/test_tap2subunit.py b/python/subunit/tests/test_tap2subunit.py
new file mode 100644 (file)
index 0000000..7d26509
--- /dev/null
@@ -0,0 +1,433 @@
+#
+#  subunit: extensions to python unittest to get test results from subprocesses.
+#  Copyright (C) 2005  Robert Collins <robertc@robertcollins.net>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""Tests for TAP2SubUnit."""
+
+import unittest
+from StringIO import StringIO
+import os
+import subunit
+import sys
+
+
+class TestTAP2SubUnit(unittest.TestCase):
+    """Tests for TAP2SubUnit.
+
+    These tests test TAP string data in, and subunit string data out.
+    This is ok because the subunit protocol is intended to be stable,
+    but it might be easier/pithier to write tests against TAP string in,
+    parsed subunit objects out (by hooking the subunit stream to a subunit
+    protocol server.
+    """
+
+    def setUp(self):
+        self.tap = StringIO()
+        self.subunit = StringIO()
+
+    def test_skip_entire_file(self):
+        # A file
+        # 1..- # Skipped: comment
+        # results in a single skipped test.
+        self.tap.write("1..0 # Skipped: entire file skipped\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test file skip",
+            "skip file skip [",
+            "Skipped: entire file skipped",
+            "]",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_test_pass(self):
+        # A file
+        # ok
+        # results in a passed test with name 'test 1'
+        self.tap.write("ok\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1",
+            "success test 1",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_test_number_pass(self):
+        # A file
+        # ok 1
+        # results in a passed test with name 'test 1'
+        self.tap.write("ok 1\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1",
+            "success test 1",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_test_number_description_pass(self):
+        # A file
+        # ok 1 - There is a description
+        # results in a passed test with name 'test 1 - There is a description'
+        self.tap.write("ok 1 - There is a description\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1 - There is a description",
+            "success test 1 - There is a description",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_test_description_pass(self):
+        # A file
+        # ok There is a description
+        # results in a passed test with name 'test 1 There is a description'
+        self.tap.write("ok There is a description\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1 There is a description",
+            "success test 1 There is a description",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_SKIP_skip(self):
+        # A file
+        # ok # SKIP
+        # results in a skkip test with name 'test 1'
+        self.tap.write("ok # SKIP\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1",
+            "skip test 1",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_number_description_SKIP_skip_comment(self):
+        # A file
+        # ok 1 foo  # SKIP Not done yet
+        # results in a skip test with name 'test 1 foo' and a log of
+        # Not done yet
+        self.tap.write("ok 1 foo  # SKIP Not done yet\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1 foo",
+            "skip test 1 foo [",
+            "Not done yet",
+            "]",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_SKIP_skip_comment(self):
+        # A file
+        # ok # SKIP Not done yet
+        # results in a skip test with name 'test 1' and a log of Not done yet
+        self.tap.write("ok # SKIP Not done yet\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1",
+            "skip test 1 [",
+            "Not done yet",
+            "]",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_TODO_xfail(self):
+        # A file
+        # ok # TODO
+        # results in a xfail test with name 'test 1'
+        self.tap.write("ok # TODO\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1",
+            "xfail test 1",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_ok_TODO_xfail_comment(self):
+        # A file
+        # ok # TODO Not done yet
+        # results in a xfail test with name 'test 1' and a log of Not done yet
+        self.tap.write("ok # TODO Not done yet\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1",
+            "xfail test 1 [",
+            "Not done yet",
+            "]",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_bail_out_errors(self):
+        # A file with line in it
+        # Bail out! COMMENT
+        # is treated as an error
+        self.tap.write("ok 1 foo\n")
+        self.tap.write("Bail out! Lifejacket engaged\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            "test test 1 foo",
+            "success test 1 foo",
+            "test Bail out! Lifejacket engaged",
+            "error Bail out! Lifejacket engaged",
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_missing_test_at_end_with_plan_adds_error(self):
+        # A file
+        # 1..3
+        # ok first test
+        # not ok third test
+        # results in three tests, with the third being created
+        self.tap.write('1..3\n')
+        self.tap.write('ok first test\n')
+        self.tap.write('not ok second test\n')
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 first test',
+            'success test 1 first test',
+            'test test 2 second test',
+            'fail test 2 second test',
+            'test test 3',
+            'error test 3 [',
+            'test missing from TAP output',
+            ']',
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_missing_test_with_plan_adds_error(self):
+        # A file
+        # 1..3
+        # ok first test
+        # not ok 3 third test
+        # results in three tests, with the second being created
+        self.tap.write('1..3\n')
+        self.tap.write('ok first test\n')
+        self.tap.write('not ok 3 third test\n')
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 first test',
+            'success test 1 first test',
+            'test test 2',
+            'error test 2 [',
+            'test missing from TAP output',
+            ']',
+            'test test 3 third test',
+            'fail test 3 third test',
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_missing_test_no_plan_adds_error(self):
+        # A file
+        # ok first test
+        # not ok 3 third test
+        # results in three tests, with the second being created
+        self.tap.write('ok first test\n')
+        self.tap.write('not ok 3 third test\n')
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 first test',
+            'success test 1 first test',
+            'test test 2',
+            'error test 2 [',
+            'test missing from TAP output',
+            ']',
+            'test test 3 third test',
+            'fail test 3 third test',
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_four_tests_in_a_row_trailing_plan(self):
+        # A file
+        # ok 1 - first test in a script with no plan at all
+        # not ok 2 - second
+        # ok 3 - third
+        # not ok 4 - fourth
+        # 1..4
+        # results in four tests numbered and named
+        self.tap.write('ok 1 - first test in a script with no plan at all\n')
+        self.tap.write('not ok 2 - second\n')
+        self.tap.write('ok 3 - third\n')
+        self.tap.write('not ok 4 - fourth\n')
+        self.tap.write('1..4\n')
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 - first test in a script with no plan at all',
+            'success test 1 - first test in a script with no plan at all',
+            'test test 2 - second',
+            'fail test 2 - second',
+            'test test 3 - third',
+            'success test 3 - third',
+            'test test 4 - fourth',
+            'fail test 4 - fourth'
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_four_tests_in_a_row_with_plan(self):
+        # A file
+        # 1..4
+        # ok 1 - first test in a script with no plan at all
+        # not ok 2 - second
+        # ok 3 - third
+        # not ok 4 - fourth
+        # results in four tests numbered and named
+        self.tap.write('1..4\n')
+        self.tap.write('ok 1 - first test in a script with no plan at all\n')
+        self.tap.write('not ok 2 - second\n')
+        self.tap.write('ok 3 - third\n')
+        self.tap.write('not ok 4 - fourth\n')
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 - first test in a script with no plan at all',
+            'success test 1 - first test in a script with no plan at all',
+            'test test 2 - second',
+            'fail test 2 - second',
+            'test test 3 - third',
+            'success test 3 - third',
+            'test test 4 - fourth',
+            'fail test 4 - fourth'
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_four_tests_in_a_row_no_plan(self):
+        # A file
+        # ok 1 - first test in a script with no plan at all
+        # not ok 2 - second
+        # ok 3 - third
+        # not ok 4 - fourth
+        # results in four tests numbered and named
+        self.tap.write('ok 1 - first test in a script with no plan at all\n')
+        self.tap.write('not ok 2 - second\n')
+        self.tap.write('ok 3 - third\n')
+        self.tap.write('not ok 4 - fourth\n')
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 - first test in a script with no plan at all',
+            'success test 1 - first test in a script with no plan at all',
+            'test test 2 - second',
+            'fail test 2 - second',
+            'test test 3 - third',
+            'success test 3 - third',
+            'test test 4 - fourth',
+            'fail test 4 - fourth'
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_todo_and_skip(self):
+        # A file
+        # not ok 1 - a fail but # TODO but is TODO
+        # not ok 2 - another fail # SKIP instead
+        # results in two tests, numbered and commented.
+        self.tap.write("not ok 1 - a fail but # TODO but is TODO\n")
+        self.tap.write("not ok 2 - another fail # SKIP instead\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1 - a fail but',
+            'xfail test 1 - a fail but [',
+            'but is TODO',
+            ']',
+            'test test 2 - another fail',
+            'skip test 2 - another fail [',
+            'instead',
+            ']',
+            ],
+            self.subunit.getvalue().splitlines())
+
+    def test_leading_comments_add_to_next_test_log(self):
+        # A file
+        # # comment
+        # ok 
+        # ok
+        # results in a single test with the comment included
+        # in the first test and not the second.
+        self.tap.write("# comment\n")
+        self.tap.write("ok\n")
+        self.tap.write("ok\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1',
+            'success test 1 [',
+            '# comment',
+            ']',
+            'test test 2',
+            'success test 2',
+            ],
+            self.subunit.getvalue().splitlines())
+    
+    def test_trailing_comments_are_included_in_last_test_log(self):
+        # A file
+        # ok foo
+        # ok foo
+        # # comment
+        # results in a two tests, with the second having the comment
+        # attached to its log.
+        self.tap.write("ok\n")
+        self.tap.write("ok\n")
+        self.tap.write("# comment\n")
+        self.tap.seek(0)
+        result = subunit.TAP2SubUnit(self.tap, self.subunit)
+        self.assertEqual(0, result)
+        self.assertEqual([
+            'test test 1',
+            'success test 1',
+            'test test 2',
+            'success test 2 [',
+            '# comment',
+            ']',
+            ],
+            self.subunit.getvalue().splitlines())
+
+
+def test_suite():
+    loader = subunit.tests.TestUtil.TestLoader()
+    result = loader.loadTestsFromName(__name__)
+    return result
index 49b4af416e7f4345c1ce61dede9bf64c4601e8df..c043a6d4149933cf700ff7f3e2262fb8f56d3355 100755 (executable)
@@ -95,7 +95,7 @@ def test_suite():
 
 
 class filteringVisitor(TestVisitor):
-    """I accruse all the testCases I visit that pass a regexp filter on id
+    """I accrue all the testCases I visit that pass a regexp filter on id
     into my suite
     """