diff options
-rw-r--r-- | .bzrignore | 2 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | c/Makefile | 10 | ||||
-rw-r--r-- | c/README | 72 | ||||
-rw-r--r-- | c/SConstruct | 18 | ||||
-rw-r--r-- | c/include/subunit/child.h | 28 | ||||
-rw-r--r-- | c/lib/child.c | 29 | ||||
-rw-r--r-- | c/tests/test_child.c | 102 | ||||
-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-x | python/subunit/tests/sample-script.py (renamed from lib/subunit/tests/sample-script.py) | 0 | ||||
-rwxr-xr-x | python/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 @@ -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): |