From ee4a263c10328674572e512a9b73ae74bf54447e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 16 May 2008 14:22:25 +1000 Subject: [PATCH] Turned libtap into a proper ccan package. Fixed up ccan_tools dir, not other package's tests. --- ccan_tools/Makefile | 6 +- ccan_tools/libtap/src/tap.h | 80 ------- ccan_tools/run_tests.c | 6 +- {ccan_tools/libtap/src => tap}/Makefile.am | 0 {ccan_tools/libtap/src => tap}/Makefile.in | 0 tap/_info.c | 58 +++++ {ccan_tools/libtap/src => tap}/tap.3 | 0 {ccan_tools/libtap/src => tap}/tap.c | 2 +- tap/tap.h | 246 +++++++++++++++++++++ tap/test/run.c | 116 ++++++++++ 10 files changed, 425 insertions(+), 89 deletions(-) delete mode 100644 ccan_tools/libtap/src/tap.h rename {ccan_tools/libtap/src => tap}/Makefile.am (100%) rename {ccan_tools/libtap/src => tap}/Makefile.in (100%) create mode 100644 tap/_info.c rename {ccan_tools/libtap/src => tap}/tap.3 (100%) rename {ccan_tools/libtap/src => tap}/tap.c (99%) create mode 100644 tap/tap.h create mode 100644 tap/test/run.c diff --git a/ccan_tools/Makefile b/ccan_tools/Makefile index 058baf74..0c2bf6d1 100644 --- a/ccan_tools/Makefile +++ b/ccan_tools/Makefile @@ -1,10 +1,7 @@ -ccan_tools/run_tests: ccan_tools/run_tests.o ccan_tools/libtap/src/tap.o ccan_tools/talloc/talloc.o +ccan_tools/run_tests: ccan_tools/run_tests.o tap/tap.o ccan_tools/talloc/talloc.o ccan_tools/doc_extract: ccan_tools/doc_extract.c ccan_tools/talloc/talloc.o -ccan_tools/libtap/src/tap.o: - cd ccan_tools/libtap && ./configure && make - ccan_tools/talloc/talloc.o: cd ccan_tools/talloc && ./configure && make @@ -12,5 +9,4 @@ ccan_tools/namespacize: ccan_tools/namespacize.c ccan_tools/talloc/talloc.o ccan_tools-clean: rm -f run_tests doc_extract - @cd ccan_tools/libtap && make clean @cd ccan_tools/talloc && make clean diff --git a/ccan_tools/libtap/src/tap.h b/ccan_tools/libtap/src/tap.h deleted file mode 100644 index 9a14c696..00000000 --- a/ccan_tools/libtap/src/tap.h +++ /dev/null @@ -1,80 +0,0 @@ -/*- - * Copyright (c) 2004 Nik Clayton - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(__GNUC__) -# error "Needs gcc or C99 compiler for variadic macros." -#else - -# define ok(e, ...) ((e) ? \ - _gen_result(1, __func__, __FILE__, __LINE__, \ - __VA_ARGS__) : \ - _gen_result(0, __func__, __FILE__, __LINE__, \ - __VA_ARGS__)) - -# define ok1(e) ((e) ? \ - _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ - _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) - -# define pass(...) ok(1, __VA_ARGS__) -# define fail(...) ok(0, __VA_ARGS__) - -# define skip_if(cond, n, ...) \ - if (cond) skip((n), __VA_ARGS__); \ - else - -# define skip_start(test, n, ...) \ - do { \ - if((test)) { \ - skip(n, __VA_ARGS__); \ - continue; \ - } - -# define skip_end } while(0) - -#ifndef PRINTF_ATTRIBUTE -#ifdef __GNUC__ -#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) -#else -#define PRINTF_ATTRIBUTE(a1, a2) -#endif -#endif - -unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...) - PRINTF_ATTRIBUTE(5, 6); - -void plan_no_plan(void); -void plan_skip_all(char *); -void plan_tests(unsigned int); - -void diag(char *, ...) PRINTF_ATTRIBUTE(1, 2); - -void skip(unsigned int, char *, ...) PRINTF_ATTRIBUTE(2, 3); - -void todo_start(char *, ...) PRINTF_ATTRIBUTE(1, 2); -void todo_end(void); - -int exit_status(void); -#endif /* C99 or gcc */ diff --git a/ccan_tools/run_tests.c b/ccan_tools/run_tests.c index 642df2eb..c7526449 100644 --- a/ccan_tools/run_tests.c +++ b/ccan_tools/run_tests.c @@ -4,11 +4,11 @@ #include #include #include -#include "libtap/src/tap.h" +#include "tap/tap.h" #include "talloc/talloc.h" #include "../string/string.h" -#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I. -Iccan_tools/libtap/src/" +#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I." /* FIXME: Use build bug later. */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -56,7 +56,7 @@ static char *obj_list(void) list = talloc_asprintf_append(list, "%s ", i->name); /* FIXME */ - list = talloc_asprintf_append(list, "ccan_tools/libtap/src/tap.o"); + list = talloc_asprintf_append(list, "tap/tap.o"); return list; } diff --git a/ccan_tools/libtap/src/Makefile.am b/tap/Makefile.am similarity index 100% rename from ccan_tools/libtap/src/Makefile.am rename to tap/Makefile.am diff --git a/ccan_tools/libtap/src/Makefile.in b/tap/Makefile.in similarity index 100% rename from ccan_tools/libtap/src/Makefile.in rename to tap/Makefile.in diff --git a/tap/_info.c b/tap/_info.c new file mode 100644 index 00000000..7f415a23 --- /dev/null +++ b/tap/_info.c @@ -0,0 +1,58 @@ +#include +#include +#include "config.h" + +/** + * tap - Test Anything Protocol + * + * The tap package produces simple-to-parse mainly-human-readable test + * output to assist in the writing of test cases. It is based on the + * (now-defunct) libtap, which is based on Perl's CPAN TAP module. Its + * output can be parsed by a harness such as CPAN's Prove. + * + * CCAN testcases are expected to output the TAP format, usually using + * this package. + * + * For more information about TAP, see: + * http://en.wikipedia.org/wiki/Test_Anything_Protocol + * + * Based on the original libtap, Copyright (c) 2004 Nik Clayton. + * + * Example: + * #include + * #include "tap/tap.h" + * + * // Run some simple (but overly chatty) tests on strcmp(). + * int main(int argc, char *argv[]) + * { + * const char a[] = "a", another_a[] = "a"; + * const char b[] = "b"; + * const char ab[] = "ab"; + * + * plan_tests(4); + * diag("Testing different pointers (%p/%p) with same contents", + * a, another_a); + * ok1(strcmp(a, another_a) == 0); + * + * diag("'a' comes before 'b'"); + * ok1(strcmp(a, b) < 0); + * ok1(strcmp(b, a) > 0); + * + * diag("'ab' comes after 'a'"); + * ok1(strcmp(ab, a) > 0); + * return exit_status(); + * } + */ +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) + return 0; + + if (strcmp(argv[1], "license") == 0) + return "BSD"; + + return 1; +} diff --git a/ccan_tools/libtap/src/tap.3 b/tap/tap.3 similarity index 100% rename from ccan_tools/libtap/src/tap.3 rename to tap/tap.3 diff --git a/ccan_tools/libtap/src/tap.c b/tap/tap.c similarity index 99% rename from ccan_tools/libtap/src/tap.c rename to tap/tap.c index 01a79c7c..4bbd977b 100644 --- a/ccan_tools/libtap/src/tap.c +++ b/tap/tap.c @@ -357,7 +357,7 @@ skip(unsigned int n, char *fmt, ...) LOCK; va_start(ap, fmt); - asprintf(&skip_msg, fmt, ap); + vasprintf(&skip_msg, fmt, ap); va_end(ap); while(n-- > 0) { diff --git a/tap/tap.h b/tap/tap.h new file mode 100644 index 00000000..f854d3e3 --- /dev/null +++ b/tap/tap.h @@ -0,0 +1,246 @@ +/*- + * Copyright (c) 2004 Nik Clayton + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * plan_tests - announce the number of tests you plan to run + * @tests: the number of tests + * + * This should be the first call in your test program: it allows tracing + * of failures which mean that not all tests are run. + * + * If you don't know how many tests will actually be run, assume all of them + * and use skip() if you don't actually run some tests. + * + * Example: + * plan_tests(13); + */ +void plan_tests(unsigned int tests); + +#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(__GNUC__) +# error "Needs gcc or C99 compiler for variadic macros." +#else + +/** + * ok1 - Simple conditional test + * @e: the expression which we expect to be true. + * + * This is the simplest kind of test: if the expression is true, the + * test passes. The name of the test which is printed will simply be + * file name, line number, and the expression itself. + * + * Example: + * ok1(init_subsystem() == 1); + */ +# define ok1(e) ((e) ? \ + _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ + _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) + +/** + * ok - Conditional test with a name + * @e: the expression which we expect to be true. + * @...: the printf-style name of the test. + * + * If the expression is true, the test passes. The name of the test will be + * the filename, line number, and the printf-style string. This can be clearer + * than simply the expression itself. + * + * Example: + * ok1(init_subsystem() == 1); + * ok(init_subsystem() == 0, "Second initialization should fail"); + */ +# define ok(e, ...) ((e) ? \ + _gen_result(1, __func__, __FILE__, __LINE__, \ + __VA_ARGS__) : \ + _gen_result(0, __func__, __FILE__, __LINE__, \ + __VA_ARGS__)) + +/** + * pass - Note that a test passed + * @...: the printf-style name of the test. + * + * For complicated code paths, it can be easiest to simply call pass() in one + * branch and fail() in another. + * + * Example: + * x = do_something(); + * if (!checkable(x) || check_value(x)) + * pass("do_something() returned a valid value"); + * else + * fail("do_something() returned an invalid value"); + */ +# define pass(...) ok(1, __VA_ARGS__) + +/** + * fail - Note that a test failed + * @...: the printf-style name of the test. + * + * For complicated code paths, it can be easiest to simply call pass() in one + * branch and fail() in another. + */ +# define fail(...) ok(0, __VA_ARGS__) + +/* I don't find these to be useful. */ +# define skip_if(cond, n, ...) \ + if (cond) skip((n), __VA_ARGS__); \ + else + +# define skip_start(test, n, ...) \ + do { \ + if((test)) { \ + skip(n, __VA_ARGS__); \ + continue; \ + } + +# define skip_end } while(0) + +#ifndef PRINTF_ATTRIBUTE +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) +#else +#define PRINTF_ATTRIBUTE(a1, a2) +#endif +#endif + +unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...) + PRINTF_ATTRIBUTE(5, 6); + +/** + * diag - print a diagnostic message (use instead of printf/fprintf) + * @fmt: the format of the printf-style message + * + * diag ensures that the output will not be considered to be a test + * result by the TAP test harness. It will append '\n' for you. + * + * Example: + * diag("Now running complex tests"); + */ +void diag(char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); + +/** + * skip - print a diagnostic message (use instead of printf/fprintf) + * @n: number of tests you're skipping. + * @fmt: the format of the reason you're skipping the tests. + * + * Sometimes tests cannot be run because the test system lacks some feature: + * you should explicitly document that you're skipping tests using skip(). + * + * From the Test::More documentation: + * If it's something the user might not be able to do, use SKIP. This + * includes optional modules that aren't installed, running under an OS that + * doesn't have some feature (like fork() or symlinks), or maybe you need an + * Internet connection and one isn't available. + * + * Example: + * #ifdef HAVE_SOME_FEATURE + * ok1(test_some_feature()); + * #else + * skip(1, "Don't have SOME_FEATURE"); + * #endif + */ +void skip(unsigned int n, char *fmt, ...) PRINTF_ATTRIBUTE(2, 3); + +/** + * todo_start - mark tests that you expect to fail. + * @fmt: the reason they currently fail. + * + * It's extremely useful to write tests before you implement the matching fix + * or features: surround these tests by todo_start()/todo_end(). These tests + * will still be run, but with additional output that indicates that they are + * expected to fail. + * + * This way, should a test start to succeed unexpectedly, tools like prove(1) + * will indicate this and you can move the test out of the todo block. This + * is much more useful than simply commenting out (or '#if 0') the tests. + * + * From the Test::More documentation: + * If it's something the programmer hasn't done yet, use TODO. This is for + * any code you haven't written yet, or bugs you have yet to fix, but want to + * put tests in your testing script (always a good idea). + * + * Example: + * todo_start("dwim() not returning true yet"); + * ok(dwim(), "Did what the user wanted"); + * todo_end(); + */ +void todo_start(char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); + +/** + * todo_end - end of tests you expect to fail. + * + * See todo_start(). + */ +void todo_end(void); + +/** + * exit_status - the value that main should return. + * + * For maximum compatability your test program should return a particular exit + * code (ie. 0 if all tests were run, and every test which was expected to + * succeed succeeded). + * + * Example: + * exit(exit_status()); + */ +int exit_status(void); + +/** + * plan_no_plan - I have no idea how many tests I'm going to run. + * + * In some situations you may not know how many tests you will be running, or + * you are developing your test program, and do not want to update the + * plan_tests() call every time you make a change. For those situations use + * plan_no_plan() instead of plan_tests(). It indicates to the test harness + * that an indeterminate number of tests will be run. + * + * Remember, if you fail to plan, you plan to fail. + * + * Example: + * plan_no_plan(); + * while (random() % 2) + * ok1(some_test()); + * exit(exit_status()); + */ +void plan_no_plan(void); + +/** + * plan_skip_all - Indicate that you will skip all tests. + * @reason: the string indicating why you can't run any tests. + * + * If your test program detects at run time that some required functionality + * is missing (for example, it relies on a database connection which is not + * present, or a particular configuration option that has not been included + * in the running kernel) use plan_skip_all() instead of plan_tests(). + * + * Example: + * if (!have_some_feature) { + * plan_skip_all("Need some_feature support"); + * exit(exit_status()); + * } + * plan_tests(13); + */ +void plan_skip_all(char *reason); + +#endif /* C99 or gcc */ diff --git a/tap/test/run.c b/tap/test/run.c new file mode 100644 index 00000000..91f22e91 --- /dev/null +++ b/tap/test/run.c @@ -0,0 +1,116 @@ +/* We use the fact that pipes have a buffer greater than the size of + * any output, and change stdout and stderr to use that. + * + * Since we don't use libtap for output, this looks like one big test. */ +#include "tap/tap.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* We dup stderr to here. */ +static int stderrfd; + +/* Simple replacement for err() */ +static void failmsg(const char *fmt, ...) +{ + char buf[1024]; + va_list ap; + + /* Write into buffer. */ + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + write(stderrfd, "# ", 2); + write(stderrfd, buf, strlen(buf)); + write(stderrfd, "\n", 1); + _exit(1); +} + +static void expect(int fd, const char *str) +{ + char buffer[PIPE_BUF]; + int r; + + r = read(fd, buffer, sizeof(buffer)); + if (r < 0) + failmsg("reading from pipe"); + + if (strlen(str) != r || strncmp(str, buffer, r) != 0) + failmsg("Expected '%s' got '%.*s'", + str, r, buffer); +} + +int main(int argc, char *argv[]) +{ + int p[2]; + int stdoutfd; + + printf("1..1\n"); + stderrfd = dup(STDERR_FILENO); + if (stderrfd < 0) + err(1, "dup of stderr failed"); + + stdoutfd = dup(STDOUT_FILENO); + if (stdoutfd < 0) + err(1, "dup of stdout failed"); + + if (pipe(p) != 0) + failmsg("pipe failed"); + + if (dup2(p[1], STDERR_FILENO) < 0 || dup2(p[1], STDOUT_FILENO) < 0) + failmsg("Duplicating file descriptor"); + + plan_tests(10); + expect(p[0], "1..10\n"); + + ok(1, "msg1"); + expect(p[0], "ok 1 - msg1\n"); + + ok(0, "msg2"); + expect(p[0], "not ok 2 - msg2\n" + "# Failed test (tap/test/run.c:main() at line 75)\n"); + + ok1(true); + expect(p[0], "ok 3 - true\n"); + + ok1(false); + expect(p[0], "not ok 4 - false\n" + "# Failed test (tap/test/run.c:main() at line 82)\n"); + + pass("passed"); + expect(p[0], "ok 5 - passed\n"); + + fail("failed"); + expect(p[0], "not ok 6 - failed\n" + "# Failed test (tap/test/run.c:main() at line 89)\n"); + + skip(2, "skipping %s", "test"); + expect(p[0], "ok 7 # skip skipping test\n" + "ok 8 # skip skipping test\n"); + + todo_start("todo"); + ok1(false); + expect(p[0], "not ok 9 - false # TODO todo\n" + "# Failed (TODO) test (tap/test/run.c:main() at line 98)\n"); + ok1(true); + expect(p[0], "ok 10 - true # TODO todo\n"); + todo_end(); + + if (exit_status() != 3) + failmsg("Expected exit status 3, not %i", exit_status()); + +#if 0 + /* Manually run the atexit command. */ + _cleanup(); + expect(p[0], "# Looks like you failed 2 tests of 9.\n"); +#endif + + write(stdoutfd, "ok 1 - All passed\n", strlen("ok 1 - All passed\n")); + _exit(0); +} -- 2.39.2