summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore2
-rw-r--r--Makefile5
-rw-r--r--c/Makefile10
-rw-r--r--c/README72
-rw-r--r--c/SConstruct18
-rw-r--r--c/include/subunit/child.h28
-rw-r--r--c/lib/child.c29
-rw-r--r--c/tests/test_child.c102
-rw-r--r--python/subunit/__init__.py (renamed from lib/subunit/__init__.py)1
-rw-r--r--python/subunit/tests/TestUtil.py (renamed from lib/subunit/tests/TestUtil.py)0
-rw-r--r--python/subunit/tests/__init__.py (renamed from lib/subunit/tests/__init__.py)0
-rwxr-xr-xpython/subunit/tests/sample-script.py (renamed from lib/subunit/tests/sample-script.py)0
-rwxr-xr-xpython/subunit/tests/sample-two-script.py (renamed from lib/subunit/tests/sample-two-script.py)0
-rw-r--r--python/subunit/tests/test_test_protocol.py (renamed from lib/subunit/tests/test_test_protocol.py)6
14 files changed, 269 insertions, 4 deletions
diff --git a/.bzrignore b/.bzrignore
new file mode 100644
index 0000000..946369b
--- /dev/null
+++ b/.bzrignore
@@ -0,0 +1,2 @@
+./c/lib/child.os
+./c/tests/test_child
diff --git a/Makefile b/Makefile
index 2dd78c0..a0753a6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,13 @@
-PYTHONPATH:=$(shell pwd)/lib:${PYTHONPATH}
+PYTHONPATH:=$(shell pwd)/python:${PYTHONPATH}
all:
check:
# check the core python bindings.
PYTHONPATH=$(PYTHONPATH) python ./test_all.py $(TESTRULE)
+ # shell bindings
PYTHONPATH=$(PYTHONPATH) make -C shell check
+ # C bindings
+ PYTHONPATH=$(PYTHONPATH) make -C c check
.PHONY: all
diff --git a/c/Makefile b/c/Makefile
new file mode 100644
index 0000000..db6c5ce
--- /dev/null
+++ b/c/Makefile
@@ -0,0 +1,10 @@
+all:
+ scons
+
+check:
+ scons check
+
+clean:
+ scons -c
+
+.PHONY: all check clean
diff --git a/c/README b/c/README
new file mode 100644
index 0000000..b3a0bcc
--- /dev/null
+++ b/c/README
@@ -0,0 +1,72 @@
+#
+# subunit C bindings.
+# Copyright (C) 2006 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
+#
+
+This subtree contains an implementation of the subunit child protocol.
+Currently I have no plans to write a test runner in C, so I have not written
+an implementation of the parent protocol. [but will happily accept patches].
+This implementation is build using SCons and tested via 'check'.
+See the tests/ directory for the test programs.
+You can use `make check` or `scons check` to run the tests. I plan to write a
+'check' runner which uses these bindings to provide subunit output, at which
+point creating a trivial python test_c.py script which uses the pyunit gui to
+will be added to me todo list.
+
+The C protocol consists of four functions which you can use to output test
+metadata trivially. See lib/subunit_child.[ch] for details.
+
+However, this is not a test runner - subunit provides no support for [for
+instance] managing assertions, cleaning up on errors etc. You can look at
+'check' (http://check.sourceforge.net/) or
+'gunit' (http://kooditakomo.cs.tut.fi/projects/gunit/) for C unit test
+frameworks. I plan to write ui layers for both of these that use the subunit
+bindings for reporting.
+
+If you are a test environment maintainer - either homegrown, or 'check' or
+'gunit' or some oether, you will to know how the subunit calls should be used.
+Here is what a manually written test using the bindings might look like:
+
+
+void
+a_test(void) {
+ int result;
+ subunit_test_start("test name");
+ # determine if test passes or fails
+ result = SOME_VALUE;
+ if (!result) {
+ subunit_test_pass("test name");
+ } else {
+ subunit_test_failf("test name",
+ "Something went wrong running something:\n"
+ "exited with result: '%s'", result);
+ }
+}
+
+Which when run with a subunit test runner will generate something like:
+test name ... ok
+
+on success, and:
+
+test name ... FAIL
+
+======================================================================
+FAIL: test name
+----------------------------------------------------------------------
+RemoteError:
+Something went wrong running something:
+exited with result: '1'
diff --git a/c/SConstruct b/c/SConstruct
new file mode 100644
index 0000000..af4c0e5
--- /dev/null
+++ b/c/SConstruct
@@ -0,0 +1,18 @@
+# setup our tools
+env = Environment()
+def run_test_scripts(source, target, env, for_signature):
+ """Run all the sources as executable scripts which return 0 on success."""
+ # TODO: make this cross platform compatible.
+ return ["LD_LIBRARY_PATH=%s %s" % (env['LIBPATH'], a_source) for a_source in source]
+test_script_runner = Builder(generator=run_test_scripts)
+env.Append(BUILDERS = {'TestRC' : test_script_runner})
+
+
+# describe what we need
+subunit = SharedLibrary('lib/subunit', ['lib/child.c'])
+test_child = Program('tests/test_child.c',
+ LIBS=['check', 'subunit'],
+ CPPPATH='include',
+ LIBPATH='lib')
+env.TestRC('check', test_child, LIBPATH='lib')
+Default(subunit)
diff --git a/c/include/subunit/child.h b/c/include/subunit/child.h
new file mode 100644
index 0000000..e850c95
--- /dev/null
+++ b/c/include/subunit/child.h
@@ -0,0 +1,28 @@
+/**
+ *
+ * subunit C bindings.
+ * Copyright (C) 2006 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
+ **/
+
+
+/**
+ * subunit_test_start:
+ *
+ * Report that a test is starting.
+ * @name: test case name
+ */
+extern void subunit_test_start(char const * const name);
diff --git a/c/lib/child.c b/c/lib/child.c
new file mode 100644
index 0000000..afae611
--- /dev/null
+++ b/c/lib/child.c
@@ -0,0 +1,29 @@
+/**
+ *
+ * subunit C child-side bindings: report on tests being run.
+ * Copyright (C) 2006 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
+ **/
+
+#include <stdio.h>
+
+void
+subunit_test_start(char const * const name)
+{
+ fprintf(stdout, "test: %s\n", name);
+ /* flush to ensure that the test runner knows we have started. */
+ fflush(stdout);
+}
diff --git a/c/tests/test_child.c b/c/tests/test_child.c
new file mode 100644
index 0000000..e3a3d54
--- /dev/null
+++ b/c/tests/test_child.c
@@ -0,0 +1,102 @@
+/**
+ *
+ * subunit C bindings.
+ * Copyright (C) 2006 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
+ **/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <check.h>
+
+#include "subunit/child.h"
+
+START_TEST (test_start)
+{
+ /* test that the start function emits a correct test: line. */
+ int bytecount;
+ int old_stdout;
+ int new_stdout[2];
+ char buffer[100];
+ /* we need a socketpair to capture stdout in */
+ fail_if(pipe(new_stdout), "Failed to create a socketpair.");
+ /* backup stdout so we can replace it */
+ old_stdout = dup(1);
+ if (old_stdout == -1) {
+ close(new_stdout[0]);
+ close(new_stdout[1]);
+ fail("Failed to backup stdout before replacing.");
+ }
+ /* redirect stdout so we can analyse it */
+ if (dup2(new_stdout[1], 1) != 1) {
+ close(old_stdout);
+ close(new_stdout[0]);
+ close(new_stdout[1]);
+ fail("Failed to redirect stdout");
+ }
+ /* yes this can block. Its a test case with < 100 bytes of output.
+ * DEAL.
+ */
+ subunit_test_start("test case");
+ /* restore stdout now */
+ if (dup2(old_stdout, 1) != 1) {
+ close(old_stdout);
+ close(new_stdout[0]);
+ close(new_stdout[1]);
+ fail("Failed to restore stdout");
+ }
+ /* and we dont need the write side any more */
+ if (close(new_stdout[1])) {
+ close(new_stdout[0]);
+ fail("Failed to close write side of socketpair.");
+ }
+ /* get the output */
+ bytecount = read(new_stdout[0], buffer, 100);
+ if (0 > bytecount) {
+ close(new_stdout[0]);
+ fail("Failed to read captured output.");
+ }
+ buffer[bytecount]='\0';
+ /* and we dont need the read side any more */
+ fail_if(close(new_stdout[0]), "Failed to close write side of socketpair.");
+ /* compare with expected outcome */
+#define EXPECTED "test: test case\n"
+ fail_if(strcmp(EXPECTED, buffer), "Did not get expected output [%s], got [%s]", EXPECTED, buffer);
+#undef EXPECTED
+}
+END_TEST
+
+
+Suite *child_suite(void)
+{
+ Suite *s = suite_create("subunit_child");
+ TCase *tc_core = tcase_create("Core");
+ suite_add_tcase (s, tc_core);
+ tcase_add_test (tc_core, test_start);
+ return s;
+}
+
+int
+main(void)
+{
+ int nf;
+ Suite *s = child_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/lib/subunit/__init__.py b/python/subunit/__init__.py
index 69f8736..e9d5389 100644
--- a/lib/subunit/__init__.py
+++ b/python/subunit/__init__.py
@@ -279,6 +279,7 @@ class RemotedTestCase(unittest.TestCase):
cls = self.__class__
return "%s.%s" % (cls.__module__, cls.__name__)
+
class ExecTestCase(unittest.TestCase):
"""A test case which runs external scripts for test fixtures."""
diff --git a/lib/subunit/tests/TestUtil.py b/python/subunit/tests/TestUtil.py
index 7c6b5fb..7c6b5fb 100644
--- a/lib/subunit/tests/TestUtil.py
+++ b/python/subunit/tests/TestUtil.py
diff --git a/lib/subunit/tests/__init__.py b/python/subunit/tests/__init__.py
index 544d0e7..544d0e7 100644
--- a/lib/subunit/tests/__init__.py
+++ b/python/subunit/tests/__init__.py
diff --git a/lib/subunit/tests/sample-script.py b/python/subunit/tests/sample-script.py
index 223d2f5..223d2f5 100755
--- a/lib/subunit/tests/sample-script.py
+++ b/python/subunit/tests/sample-script.py
diff --git a/lib/subunit/tests/sample-two-script.py b/python/subunit/tests/sample-two-script.py
index d555084..d555084 100755
--- a/lib/subunit/tests/sample-two-script.py
+++ b/python/subunit/tests/sample-two-script.py
diff --git a/lib/subunit/tests/test_test_protocol.py b/python/subunit/tests/test_test_protocol.py
index 8971723..eb77e68 100644
--- a/lib/subunit/tests/test_test_protocol.py
+++ b/python/subunit/tests/test_test_protocol.py
@@ -561,14 +561,14 @@ class TestExecTestCase(unittest.TestCase):
class SampleExecTestCase(subunit.ExecTestCase):
def test_sample_method(self):
- """./lib/subunit/tests/sample-script.py"""
+ """./python/subunit/tests/sample-script.py"""
# the sample script runs three tests, one each
# that fails, errors and succeeds
def test_construct(self):
test = self.SampleExecTestCase("test_sample_method")
- self.assertEqual(test.script, "./lib/subunit/tests/sample-script.py")
+ self.assertEqual(test.script, "./python/subunit/tests/sample-script.py")
def test_run(self):
runner = MockTestProtocolServerClient()
@@ -597,7 +597,7 @@ class TestExecTestCase(unittest.TestCase):
class DoExecTestCase(subunit.ExecTestCase):
def test_working_script(self):
- """./lib/subunit/tests/sample-two-script.py"""
+ """./python/subunit/tests/sample-two-script.py"""
class TestIsolatedTestCase(unittest.TestCase):