From 319ec27236d40318819163ae10e897e4a3f7b50b Mon Sep 17 00:00:00 2001 From: Russ Allbery Date: Fri, 11 May 2012 21:16:22 +0100 Subject: [PATCH] Import of code from c-tap-harness This commit updates the code imported from c-tap-harness to d3fc03606efc8e76ff34f04470e6133db25a3982 (release/1.12) New files are: LICENSE NEWS README tests/runtests.c tests/tap/basic.c tests/tap/basic.h tests/tap/float.c tests/tap/float.h tests/tap/libtap.sh tests/tap/macros.h Change-Id: I4435bbb240f9db3cf2883cb0711f592f9d865f92 Reviewed-on: http://gerrit.openafs.org/7399 Tested-by: BuildBot Reviewed-by: Russ Allbery Reviewed-by: Derrick Brashear --- src/external/c-tap-harness-last | 1 + src/external/c-tap-harness/LICENSE | 138 ++ src/external/c-tap-harness/NEWS | 285 ++++ src/external/c-tap-harness/README | 228 ++++ src/external/c-tap-harness/tests/runtests.c | 1189 +++++++++++++++++ src/external/c-tap-harness/tests/tap/basic.c | 629 +++++++++ src/external/c-tap-harness/tests/tap/basic.h | 134 ++ src/external/c-tap-harness/tests/tap/float.c | 67 + src/external/c-tap-harness/tests/tap/float.h | 42 + .../c-tap-harness/tests/tap/libtap.sh | 246 ++++ src/external/c-tap-harness/tests/tap/macros.h | 88 ++ 11 files changed, 3047 insertions(+) create mode 100644 src/external/c-tap-harness-last create mode 100644 src/external/c-tap-harness/LICENSE create mode 100644 src/external/c-tap-harness/NEWS create mode 100644 src/external/c-tap-harness/README create mode 100644 src/external/c-tap-harness/tests/runtests.c create mode 100644 src/external/c-tap-harness/tests/tap/basic.c create mode 100644 src/external/c-tap-harness/tests/tap/basic.h create mode 100644 src/external/c-tap-harness/tests/tap/float.c create mode 100644 src/external/c-tap-harness/tests/tap/float.h create mode 100644 src/external/c-tap-harness/tests/tap/libtap.sh create mode 100644 src/external/c-tap-harness/tests/tap/macros.h diff --git a/src/external/c-tap-harness-last b/src/external/c-tap-harness-last new file mode 100644 index 000000000..34209570e --- /dev/null +++ b/src/external/c-tap-harness-last @@ -0,0 +1 @@ +d3fc03606efc8e76ff34f04470e6133db25a3982 diff --git a/src/external/c-tap-harness/LICENSE b/src/external/c-tap-harness/LICENSE new file mode 100644 index 000000000..5f9581671 --- /dev/null +++ b/src/external/c-tap-harness/LICENSE @@ -0,0 +1,138 @@ +The C TAP Harness package as a whole is: + + Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Russ Allbery + Copyright 2006, 2007, 2008, 2009, 2011, 2012 + The Board of Trustees of the Leland Stanford Junior University + +and released under the following license: + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +All individual files without an explicit exception below are released +under this license. Some files may have additional copyright holders as +noted in those files. + +Some files in this distribution are individually released under different +licenses, all of which are compatible with the above general package +license but which may require preservation of additional notices. All +required notices are preserved in this file. Of the files intended to be +copied into other packages, only docs/writing-tests has a different +license notice, and its requirements are met by preserving the license +section of that document in any derivative works. + +Collected copyright notices for the entire package: + + Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Russ Allbery + Copyright 2006, 2007, 2008, 2009, 2011, 2012 + The Board of Trustees of the Leland Stanford Junior University + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Free Software Foundation, Inc. + Copyright 1994 X Consortium + +The file docs/writing-tests is released under the following license: + + Copying and distribution of this file, with or without modification, are + permitted in any medium without royalty provided the copyright notice + and this notice are preserved. This file is offered as-is, without any + warranty. + +The files Makefile.in and aclocal.m4 are generated by GNU Automake and +released under the following copyright and license: + + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software + Foundation, Inc. This file is free software; the Free Software + Foundation gives unlimited permission to copy and/or distribute it, with + or without modifications, as long as this notice is preserved. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY, to the extent permitted by law; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. + +The file configure is generated by GNU Autoconf and is released under the +following copyright and license: + + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software + Foundation, Inc. This configure script is free software; the Free + Software Foundation gives unlimited permission to copy, distribute and + modify it. + +The files build-aux/compile, build-aux/depcomp, and build-aux/missing are +taken from GNU Automake and are released under the following copyright and +license: + + Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, + 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + + 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, 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. + + As a special exception to the GNU General Public License, if you + distribute this file as part of a program that contains a configuration + script generated by Autoconf, you may include it under the same + distribution terms that you use for the rest of that program. + +For the C TAP Harness distribution, the option described in the last +paragraph has been accepted and these files are distributed under the same +terms as the C TAP Harness package as a whole, as described at the top of +this file. + +The file build-aux/install-sh is released under the following copyright +and license: + + Copyright (C) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the X Consortium shall + not be used in advertising or otherwise to promote the sale, use or + other dealings in this Software without prior written authorization + from the X Consortium. + + FSF changes to this file are in the public domain. diff --git a/src/external/c-tap-harness/NEWS b/src/external/c-tap-harness/NEWS new file mode 100644 index 000000000..be4aba8a0 --- /dev/null +++ b/src/external/c-tap-harness/NEWS @@ -0,0 +1,285 @@ + User-Visible C TAP Harness Changes + +C TAP Harness 1.12 (2012-05-11) + + Fix additional uses of local in the shell TAP library for portability + to Solaris /bin/sh and document a bad interaction between backquotes + and double quotes for the puts, test_file_path, and test_tmpdir + functions. + + In the C TAP library, if bail is called after plan_lazy but before any + tests are run, don't output the plan or the summary of test results. + + Add the UNUSED macro (to mark possibly-usused variables for gcc) to + tests/tap/macros.h for use in the C TAP library. + + Make the __attribute__ handling in tests/tap/macros.h more aware of + different versions and compilers. All attributes are now suppressed + for GCC older than 2.96 (instead of 2.7), since __malloc__ became + available then. __alloc_size__ is suppressed for GCC older than 4.3. + Warnings about unknown diagnostics are suppressed for LLVM and Clang, + which pretend to be GCC but don't support all the same attributes. + +C TAP Harness 1.11 (2012-04-25) + + Reorganize the source package so that runtests.c is in the tests + directory and the C and shell TAP libraries are in tests/tap. Change + the include directives in the C TAP library source files accordingly. + This is somewhat confusing for the standalone package, but means that + the files are located in the same locations here as they would be in + packages into which they're copied, which simplifies instructions and + the build system. This also removes the need to build the C TAP + library with -I flags at the cost of requiring that it be located in a + tests subdirectory, allowing easier use of additional supporting + headers without requiring that all tests be built with a -I directive. + + Do not attempt to use feature-test macros unless compiled with gcc's + -ansi flag or PEDANTIC is defined. Defining _XOPEN_SOURCE 600 on + Solaris 10, which is required for isinf() if feature-test macros are + in use, causes compilation to fail unless the compiler is run in C99 + mode due to an ABI change. The basic TAP library doesn't care about + this distinction and doesn't want to force specific compiler flags, so + avoiding feature-test macros is a better fix. Thanks to Bob + Friesenhahn for the bug report. + + Do not use local in the shell TAP library. Solaris /bin/sh doesn't + support it, and the shell library is otherwise portable to that shell. + Instead, use a prefix of tap_ on all non-public variables. + + Move the __attribute__ and BEGIN_DECLS/END_DECLS macros from + tests/tap/basic.h to a new tests/tap/macros.h header file so that they + can be more easily reused by any other TAP add-on. Be sure to copy + tests/tap/macros.h into your source package and add it to the source + files for the libtap library when upgrading. + + Move the is_double C TAP test function into a separate source file. + Including this function may require linking with libm on some + platforms, which is undesireable if the package otherwise doesn't use + math functions. The new tests/tap/float.c and tests/tap/float.h files + need only be included in a package that wants to do floating point + tests. Users of is_double will now need to include tests/tap/float.h + in addition to tests/tap/basic.h (and link all clients of the libtap + library with -lm). + +C TAP Harness 1.10 (2012-02-29) + + Add bstrndup to the basic C TAP library. This is akin to strndup + (copying at most n characters of the string), but calls sysbail if + memory allocation fails. + +C TAP Harness 1.9 (2011-12-24) + + Add test_tmpdir and test_tmpdir_free functions to the basic C TAP + library and a test_tmpdir function to the shell TAP library. These + functions create a temporary directory under the build tests directory + for tests to use for transient files. + + runtests now frees all allocated resources on exit so that it can be + used to run test cases with valgrind memory allocation checking + without adding false positives. + +C TAP Harness 1.8 (2011-09-02) + + Add bmalloc, bcalloc, brealloc, and bstrdup functions to the basic C + TAP library. These functions call sysbail if memory allocation fails. + + If BUILD were not set when building runtests and the -b option was not + present, SOURCE and the -s option would be ignored when searching for + tests. Fix runtests to still honor SOURCE and -s when searching for + tests even in that case. + +C TAP Harness 1.7 (2011-04-28) + + Add a more complete usage message to runtests and add support for a -h + command-line flag to display the usage message. + +C TAP Harness 1.6 (2010-12-29) + + is_double() now takes a third argument, an epsilon. Two numbers are + considered equal if their absolute difference is less than epsilon. + is_double() also now treats wanted and seen values of NaN (not a + number) as equal. Thanks to PICCA Frédéric-Emmanuel for the proposed + changes. + + The ok_program function in the shell libtap.sh library no longer + strips text after a colon and a space from the program output if the + expected status is non-zero. Instead, if program output may contain + system-specific error messages after a colon and a space, put the new + function strip_colon_error before the program to do this stripping. + Thanks to Carsten Hey for the idea. + + strip_colon_error is now smarter about preserving an initial word + ending in a colon (which is generally the program name) while still + stripping error messages later in the line. + + The test_file_path function in the shell libtap.sh library now always + returns the empty string, rather than possible absolute paths starting + at /, if $BUILD and $SOURCE are not set. + + Flush standard error in the C TAP library before printing results for + more deterministic output. Thanks to Carsten Hey for the idea. + + All of C TAP Harness now compiles with gcc -ansi -pedantic and should + be fully C89-compatible. Note that either C99 or SUSv3 is required to + build C TAP Harness. (This should not be a problem on any modern + platform.) Based on work by Carsten Hey. + + Simplify and improve output formatting in the summary of failing tests + in some edge cases. + + Add explicit license statements to the files meant to be copied into + other packages rather than referring to LICENSE. + +C TAP Harness 1.5 (2010-08-25) + + In ok_program in the shell TAP library, strip error output after the + second colon, not after the first. This code helps comparing error + output that includes system error messages, but needs to skip past the + first colon, since it separates the program name from the error + message. + + runtests.c now builds without warnings with gcc -Wswitch-enum. + +C TAP Harness 1.4 (2010-07-07) + + Add a test_file_path() function to the basic C and shell TAP + libraries, which searches the build and source directories for a + particular file and returns the full path. This is a utility function + that can be used to find test data files. + +C TAP Harness 1.3 (2010-06-09) + + Add API documentation for the functions provided by the basic TAP C + library. The documentation is in POD and *roff format in docs/api and + installed as man pages in the (generally unused) case of make install. + + Add docs/writing-tests, which provides some basic instructions for how + to write TAP tests in Perl, C, and shell using the facilities provided + by C TAP Harness. This document is suitable for inclusion in packages + that use C TAP Harness as instructions for contributors. + + Add an okv() function to the C TAP library. This is the same as ok() + but takes the test description as a va_list to make it easier to reuse + the reporting infrastructure in other tests. + +C TAP Harness 1.2 (2010-04-13) + + Support giving the plan at any point in the test output rather than + requiring it be first. The TAP protocol permits giving the plan last + instead of first, but since it's just as easy to support providing the + plan in the middle of the test output, allow that as well. + + Add support for lazy planning to the basic TAP library. Instead of + calling plan at the start of the test, call plan_lazy instead, which + doesn't require specifying a test count. Then, the plan will + automatically be printed based on the last test number at the end of + the program. This is not the recommended approach for writing tests + since, should the test program exit in the middle for some reason, + everything will appear to succeed. But it can save time in writing + tests quickly and allows for dynamic numbers of tests. + + Add diag and sysdiag functions to the basic TAP library, which output + diagnostics to standard error preceded by the protocol-required # + character. + + Clean up data types in the basic C TAP library. Test numbers and + counts are now unsigned long, and ok_int compares longs. + + Add the GCC nonnull attribute to the bail functions in the TAP + library. + +C TAP Harness 1.1 (2009-08-15) + + Set an exit handler in libtap that prints a summary of the test + results at the end of a test script, similar to Perl's Test::More. + + When looking for 0..1 # skip plan lines indicating the whole test case + should be skipped, correctly compare "skip" case-insensitively. This + fixes interoperability with Perl's Test::More. + + Consume all output from the test case before closing its file + descriptor, even if the case is aborted due to bailing out or sending + an invalid test number. This prevents tests from spuriously dying + with SIGPIPE. + + Enable Automake silent rules. For a quieter build, pass the + --enable-silent-rules option to configure or build with make V=0. + +C TAP Harness 1.0 (2009-05-21) + + Initial public release based on the version of runtests.c and the + libtest library that shipped with remctl 2.13. The changes below are + relative to that version. + + Set the SOURCE and BUILD environment variables when running tests to + the roots of the source and build test directories if set at compile + time or via the -s and -b command-line options to runtests. + + Search for test programs first in the current directory and then in + the build and source directories, in that order, as specified by + SOURCE and BUILD or by the -s and -b options. This allows some tests + to be compiled and some shipped with the package and merged together + at run time by runtests, even if the build directory is not the source + directory. + + Support running a single test program with the -o command-line option. + This is mostly interesting to take advantage of the environment + variables and test searching algorithm described above. + + Add support for 0..1 # skip plan lines, indicating that the + entire test case should be skipped. + + Add support for aborting a test case with "Bail out!" and reporting + the reason given on that line. + + Add support for omitting the test number from an "ok" or "not ok" + line, in which case the number is assumed to be one more than the + previous number. + + Add support for todo tests, which are recorded as skipped if failing + and failed if they succeed unexpectedly. + + Omitting the space after "ok" or "not ok" line is now supported, and a + test number of 0 now results in an error. + + Recognize skip directives regardless of case. + + Change the reporting of reasons to abort the test case to use ABORTED + and the abort reason in parentheses for more consistent output. + + Rename test_init() to plan() and ok_int(), ok_double(), and + ok_string() to is_int(), is_double(), and is_string() in the C TAP + library to more closely match the function names in Perl's test + modules. + + Add is_hex() C TAP library function to compare two unsigned longs and + print mismatches in hex. + + Change all C library functions to take a test description + (printf-style) and to no longer take the test number. Instead, keep a + static count of the current test number. + + Add bail() and sysbail() C TAP library functions to bail out with the + right magic output string. + + Add skip_all() C TAP library function to skip all tests and exit. + + Stop exporting the printcount interface in the shell version of the + TAP library. Instead, provide plan, skip_all, ok, skip, ok_block, + skip_block, ok_program, and bail shell functions, similar to the C + library interface, with the ok* functions taking a test description as + the first argument. + + Show mismatch output from the is_*() functions before the "not ok" + line instead of after it. + + Add the initial "1.." to plan() output for better TAP compliance. + + Support either "-t" or ".t" as the ending of test cases. + + Remove the dependency on both config.h and the general portability + framework and instead include the necessary C headers directly. This + requires ANSI C. + + Remove the functions from libtap that assume libutil from rra-c-util. + Those library functions will be provided by that package. diff --git a/src/external/c-tap-harness/README b/src/external/c-tap-harness/README new file mode 100644 index 000000000..ddcfc914d --- /dev/null +++ b/src/external/c-tap-harness/README @@ -0,0 +1,228 @@ + C TAP Harness 1.12 + (C harness for running TAP-compliant tests) + + Written by Russ Allbery + + Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Russ Allbery . This software is distributed under a + BSD-style license. Please see the file LICENSE in the distribution for + more information. + +BLURB + + C TAP Harness is a pure-C implementation of TAP, the Test Anything + Protocol. TAP is the text-based protocol used by Perl's test suite. + This package provides a harness similar to Perl's Test::Harness for + running tests, with some additional features useful for test suites in + packages that use Autoconf and Automake, and C and shell libraries to + make writing TAP-compliant test programs easier. + +DESCRIPTION + + This package started as the runtests program I wrote for INN in 2000 to + serve as the basis for a new test suite using a test protocol similar to + that used for Perl modules. When I started maintaining additional C + packages, I adopted runtests for the test suite driver of those as well, + resulting in further improvements but also separate copies of the same + program in different distributions. The C TAP Harness distribution + merges all the various versions into a single code base that all my + packages can pull from. + + C TAP Harness provides a full TAP specification (apart from a few + possible edge cases) and has additional special features for supporting + builds outside the source directory. It's mostly useful for packages + using Autoconf and Automake and because it doesn't assume or require + Perl. + + The runtests program can be built with knowledge of the source and build + directory and pass that knowledge on to test scripts, and will search + for test scripts in both the source and build directory. This makes it + easier for packages using Autoconf and Automake and supporting + out-of-tree builds to build some test programs, ship others, and run + them all regardless of what tree they're in. It also makes it easier + for test cases to find their supporting files when they run. + + Also included in this package are C and shell libraries that provide + utility functions for writing test scripts that use TAP to report + exists. + +REQUIREMENTS + + C TAP Harness requires a C compiler to build. Any ISO C89 or later C + compiler on a system supporting the Single UNIX Specification, version 3 + (SUSv3) should be sufficient. This should not be a problem on any + modern system. The test suite and shell library require a + Bourne-compatible shell. Outside of the test suite, C TAP Harness has + no other prerequisites or requirements. + + To run the test suite, you will need Perl plus the Perl modules + Test::More and Test::Pod. Test::More comes with Perl 5.8 and later. + Test::Pod is available from CPAN and currently must be installed + separately, but the POD tests will be skipped without interfering with + the rest of the tests if it's not installed. + + To check spelling in the POD documentation, Pod::Spell (available from + CPAN) and either aspell or ispell with the american dictionary are also + required. The user's path is searched for aspell or ispell and aspell + is preferred. Spelling tests are disabled by default since spelling + dictionaries differ too much between systems. To enable those tests, + set RRA_MAINTAINER_TESTS to a true value. + + To bootstrap from a Git checkout, or if you change the Automake files + and need to regenerate Makefile.in, you will need Automake 1.11 or + later. For bootstrap or if you change configure.ac or any of the m4 + files it includes and need to regenerate configure or config.h.in, you + will need Autoconf 2.64 or later. Perl is also required to generate the + manual page from a fresh Git checkout. + +BUILDING AND TESTING + + You can build C TAP Harness and run its internal test suite with: + + ./configure + make + make check + + While there is a configure script, it exists just to drive the build + system and do some path substitution and isn't doing portability + probes. Pass --enable-silent-rules to configure for a quieter build + (similar to the Linux kernel). + + Use make warnings instead of make to build with full GCC compiler + warnings (requires a relatively current version of GCC). + + If a test fails, you can run a single test with verbose output via: + + ./runtests -b `pwd`/tests -s `pwd`/tests -o + + Do this instead of running the test program directly since it will + ensure that necessary environment variables are set up. You may need to + change the -s option if you build with a separate build directory from + the source directory. + +USING THE HARNESS + + While there is an install target that installs runtests in the default + binary directory (/usr/local/bin by default) and installs the man pages, + one normally wouldn't install anything from this package. Instead, the + code is intended to be copied into your package and refreshed from the + latest release of C TAP Harness for each release. + + You can obviously copy the code and integrate it however works best for + your package and your build system. Here's how I do it for my packages + as an example: + + * Create a tests directory and copy tests/runtests.c into it. Create a + tests/tap subdirectory and copy the portions of the TAP library (from + tests/tap) that I need for that package into it. The TAP library is + designed to let you drop in additional source and header files for + additional utility functions that are useful in your package. + + * Add code to my top-level Makefile.am (I always use a non-recursive + Makefile with subdir-objects set) to build runtests and the test + library: + + check_PROGRAMS = tests/runtests + tests_runtests_CPPFLAGS = -DSOURCE='"$(abs_top_srcdir)/tests"' \ + -DBUILD='"$(abs_top_builddir)/tests"' + check_LIBRARIES = tests/tap/libtap.a + tests_tap_libtap_a_CPPFLAGS = -I$(abs_top_srcdir)/tests + tests_tap_libtap_a_SOURCES = tests/tap/basic.c tests/tap/basic.h \ + tests/tap/float.c tests/tap/float.h tests/tap/macros.h + + Omit float.c and float.h from the last line if your package doesn't + need the is_double function. Building the build and source + directories into runtests will let tests/runtests -o to work + for users without requiring that they set any other variables, even if + they're doing an out-of-source build. + + Add additional source files and headers that should go into the TAP + library if you added extra utility functions for your package. + + * Add code to Makefile.am to run the test suite: + + check-local: $(check_PROGRAMS) + cd tests && ./runtests $(abs_top_srcdir)/tests/TESTS + + See the Makefile.am in this package for an example (although note that + it keeps runtests in an unusual location). + + * List the test programs in the TESTS file. This should have the name + of the test executable with the trailing "-t" or ".t" (you can use + either extension as you prefer) omitted. For any test programs that + need to be compiled, add build rules for them in Makefile.am, simliar + to: + + tests_libtap_c_basic_LDADD = tests/tap/libtap.a + + and add them to check_PROGRAMS. If you include the float.c add-on in + your libtap library, you will need to add -lm to the _LDADD setting + for all test programs linked against it. + + A more complex example from the remctl package that needs additional + libraries: + + tests_client_open_t_LDFLAGS = $(GSSAPI_LDFLAGS) + tests_client_open_t_LDADD = client/libremctl.la tests/tap/libtap.a \ + util/libutil.la $(GSSAPI_LIBS) + + If the test program doesn't need to be compiled, add it to EXTRA_DIST + so that it will be included in the distribution. + + * If you have test programs written in shell, copy tests/tap/libtap.sh + the tap subdirectory of your tests directory and add it to EXTRA_DIST. + Shell programs should start with: + + . "${SOURCE}/tap/libtap.sh" + + and can then use the functions defined in the library. + + * Optionally copy docs/writing-tests into your package somewhere, such + as tests/README, as instructions to contributors on how to write tests + for this framework. + + If you have configuration files that the user must create to enable some + of the tests, conventionally they go into tests/config. + + If you have data files that your test cases use, conventionally they go + into tests/data. You can then find the data directory relative to the + SOURCE environment variable (set by runtests) in your test program. If + you have data that's compiled or generated by Autoconf, it will be + relative to the BUILD environment variable. Don't forget to add test + data to EXTRA_DIST as necessary. + + For more TAP library add-ons, generally ones that rely on additional + portability code not shipped in this package or with narrower uses, see + the rra-c-util package: + + http://www.eyrie.org/~eagle/software/rra-c-util/ + + There are several additional TAP library add-ons in the tests/tap + directory in that package. It's also an example of how to use this test + harness in another package. + +HOMEPAGE AND SOURCE REPOSITORY + + The C TAP Harness web page at: + + http://www.eyrie.org/~eagle/software/c-tap-harness/ + + will always have the current version of this package, the current + documentation, and pointers to any additional resources. + + C TAP Harness is maintained using Git. You can access the current + source by cloning the repository at: + + git://git.eyrie.org/devel/c-tap-harness.git + + or view the repository via the web at: + + http://git.eyrie.org/?p=devel/c-tap-harness.git + + C TAP Harness is also available via github at: + + http://github.com/rra/c-tap-harness + + and the github wiki and issue tracker are available on an experimental + basis. If you like using the github facilities, try filing issues or + adding supplemental documentation there. diff --git a/src/external/c-tap-harness/tests/runtests.c b/src/external/c-tap-harness/tests/runtests.c new file mode 100644 index 000000000..424987568 --- /dev/null +++ b/src/external/c-tap-harness/tests/runtests.c @@ -0,0 +1,1189 @@ +/* + * Run a set of tests, reporting results. + * + * Usage: + * + * runtests [-b ] [-s ] + * runtests -o [-b ] [-s ] + * + * In the first case, expects a list of executables located in the given file, + * one line per executable. For each one, runs it as part of a test suite, + * reporting results. Test output should start with a line containing the + * number of tests (numbered from 1 to this number), optionally preceded by + * "1..", although that line may be given anywhere in the output. Each + * additional line should be in the following format: + * + * ok + * not ok + * ok # skip + * not ok # todo + * + * where is the number of the test. An optional comment is permitted + * after the number if preceded by whitespace. ok indicates success, not ok + * indicates failure. "# skip" and "# todo" are a special cases of a comment, + * and must start with exactly that formatting. They indicate the test was + * skipped for some reason (maybe because it doesn't apply to this platform) + * or is testing something known to currently fail. The text following either + * "# skip" or "# todo" and whitespace is the reason. + * + * As a special case, the first line of the output may be in the form: + * + * 1..0 # skip some reason + * + * which indicates that this entire test case should be skipped and gives a + * reason. + * + * Any other lines are ignored, although for compliance with the TAP protocol + * all lines other than the ones in the above format should be sent to + * standard error rather than standard output and start with #. + * + * This is a subset of TAP as documented in Test::Harness::TAP or + * TAP::Parser::Grammar, which comes with Perl. + * + * If the -o option is given, instead run a single test and display all of its + * output. This is intended for use with failing tests so that the person + * running the test suite can get more details about what failed. + * + * If built with the C preprocessor symbols SOURCE and BUILD defined, C TAP + * Harness will export those values in the environment so that tests can find + * the source and build directory and will look for tests under both + * directories. These paths can also be set with the -b and -s command-line + * options, which will override anything set at build time. + * + * Any bug reports, bug fixes, and improvements are very much welcome and + * should be sent to the e-mail address below. This program is part of C TAP + * Harness . + * + * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011 + * Russ Allbery + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. +*/ + +/* Required for fdopen(), getopt(), and putenv(). */ +#if defined(__STRICT_ANSI__) || defined(PEDANTIC) +# ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 500 +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* sys/time.h must be included before sys/resource.h on some platforms. */ +#include + +/* AIX doesn't have WCOREDUMP. */ +#ifndef WCOREDUMP +# define WCOREDUMP(status) ((unsigned)(status) & 0x80) +#endif + +/* + * The source and build versions of the tests directory. This is used to set + * the SOURCE and BUILD environment variables and find test programs, if set. + * Normally, this should be set as part of the build process to the test + * subdirectories of $(abs_top_srcdir) and $(abs_top_builddir) respectively. + */ +#ifndef SOURCE +# define SOURCE NULL +#endif +#ifndef BUILD +# define BUILD NULL +#endif + +/* Test status codes. */ +enum test_status { + TEST_FAIL, + TEST_PASS, + TEST_SKIP, + TEST_INVALID +}; + +/* Indicates the state of our plan. */ +enum plan_status { + PLAN_INIT, /* Nothing seen yet. */ + PLAN_FIRST, /* Plan seen before any tests. */ + PLAN_PENDING, /* Test seen and no plan yet. */ + PLAN_FINAL /* Plan seen after some tests. */ +}; + +/* Error exit statuses for test processes. */ +#define CHILDERR_DUP 100 /* Couldn't redirect stderr or stdout. */ +#define CHILDERR_EXEC 101 /* Couldn't exec child process. */ +#define CHILDERR_STDERR 102 /* Couldn't open stderr file. */ + +/* Structure to hold data for a set of tests. */ +struct testset { + char *file; /* The file name of the test. */ + char *path; /* The path to the test program. */ + enum plan_status plan; /* The status of our plan. */ + unsigned long count; /* Expected count of tests. */ + unsigned long current; /* The last seen test number. */ + unsigned int length; /* The length of the last status message. */ + unsigned long passed; /* Count of passing tests. */ + unsigned long failed; /* Count of failing lists. */ + unsigned long skipped; /* Count of skipped tests (passed). */ + unsigned long allocated; /* The size of the results table. */ + enum test_status *results; /* Table of results by test number. */ + unsigned int aborted; /* Whether the set as aborted. */ + int reported; /* Whether the results were reported. */ + int status; /* The exit status of the test. */ + unsigned int all_skipped; /* Whether all tests were skipped. */ + char *reason; /* Why all tests were skipped. */ +}; + +/* Structure to hold a linked list of test sets. */ +struct testlist { + struct testset *ts; + struct testlist *next; +}; + +/* + * Usage message. Should be used as a printf format with two arguments: the + * path to runtests, given twice. + */ +static const char usage_message[] = "\ +Usage: %s [-b ] [-s ] \n\ + %s -o [-b ] [-s ] \n\ +\n\ +Options:\n\ + -b Set the build directory to \n\ + -o Run a single test rather than a list of tests\n\ + -s Set the source directory to \n\ +\n\ +runtests normally runs each test listed in a file whose path is given as\n\ +its command-line argument. With the -o option, it instead runs a single\n\ +test and shows its complete output.\n"; + +/* + * Header used for test output. %s is replaced by the file name of the list + * of tests. + */ +static const char banner[] = "\n\ +Running all tests listed in %s. If any tests fail, run the failing\n\ +test program with runtests -o to see more details.\n\n"; + +/* Header for reports of failed tests. */ +static const char header[] = "\n\ +Failed Set Fail/Total (%) Skip Stat Failing Tests\n\ +-------------------------- -------------- ---- ---- ------------------------"; + +/* Include the file name and line number in malloc failures. */ +#define xmalloc(size) x_malloc((size), __FILE__, __LINE__) +#define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__) +#define xstrdup(p) x_strdup((p), __FILE__, __LINE__) + + +/* + * Report a fatal error, including the results of strerror, and exit. + */ +static void +sysdie(const char *format, ...) +{ + int oerrno; + va_list args; + + oerrno = errno; + fflush(stdout); + fprintf(stderr, "runtests: "); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, ": %s\n", strerror(oerrno)); + exit(1); +} + + +/* + * Allocate memory, reporting a fatal error and exiting on failure. + */ +static void * +x_malloc(size_t size, const char *file, int line) +{ + void *p; + + p = malloc(size); + if (p == NULL) + sysdie("failed to malloc %lu bytes at %s line %d", + (unsigned long) size, file, line); + return p; +} + + +/* + * Reallocate memory, reporting a fatal error and exiting on failure. + */ +static void * +x_realloc(void *p, size_t size, const char *file, int line) +{ + p = realloc(p, size); + if (p == NULL) + sysdie("failed to realloc %lu bytes at %s line %d", + (unsigned long) size, file, line); + return p; +} + + +/* + * Copy a string, reporting a fatal error and exiting on failure. + */ +static char * +x_strdup(const char *s, const char *file, int line) +{ + char *p; + size_t len; + + len = strlen(s) + 1; + p = malloc(len); + if (p == NULL) + sysdie("failed to strdup %lu bytes at %s line %d", + (unsigned long) len, file, line); + memcpy(p, s, len); + return p; +} + + +/* + * Given a struct timeval, return the number of seconds it represents as a + * double. Use difftime() to convert a time_t to a double. + */ +static double +tv_seconds(const struct timeval *tv) +{ + return difftime(tv->tv_sec, 0) + tv->tv_usec * 1e-6; +} + + +/* + * Given two struct timevals, return the difference in seconds. + */ +static double +tv_diff(const struct timeval *tv1, const struct timeval *tv0) +{ + return tv_seconds(tv1) - tv_seconds(tv0); +} + + +/* + * Given two struct timevals, return the sum in seconds as a double. + */ +static double +tv_sum(const struct timeval *tv1, const struct timeval *tv2) +{ + return tv_seconds(tv1) + tv_seconds(tv2); +} + + +/* + * Given a pointer to a string, skip any leading whitespace and return a + * pointer to the first non-whitespace character. + */ +static const char * +skip_whitespace(const char *p) +{ + while (isspace((unsigned char)(*p))) + p++; + return p; +} + + +/* + * Start a program, connecting its stdout to a pipe on our end and its stderr + * to /dev/null, and storing the file descriptor to read from in the two + * argument. Returns the PID of the new process. Errors are fatal. + */ +static pid_t +test_start(const char *path, int *fd) +{ + int fds[2], errfd; + pid_t child; + + if (pipe(fds) == -1) { + puts("ABORTED"); + fflush(stdout); + sysdie("can't create pipe"); + } + child = fork(); + if (child == (pid_t) -1) { + puts("ABORTED"); + fflush(stdout); + sysdie("can't fork"); + } else if (child == 0) { + /* In child. Set up our stdout and stderr. */ + errfd = open("/dev/null", O_WRONLY); + if (errfd < 0) + _exit(CHILDERR_STDERR); + if (dup2(errfd, 2) == -1) + _exit(CHILDERR_DUP); + close(fds[0]); + if (dup2(fds[1], 1) == -1) + _exit(CHILDERR_DUP); + + /* Now, exec our process. */ + if (execl(path, path, (char *) 0) == -1) + _exit(CHILDERR_EXEC); + } else { + /* In parent. Close the extra file descriptor. */ + close(fds[1]); + } + *fd = fds[0]; + return child; +} + + +/* + * Back up over the output saying what test we were executing. + */ +static void +test_backspace(struct testset *ts) +{ + unsigned int i; + + if (!isatty(STDOUT_FILENO)) + return; + for (i = 0; i < ts->length; i++) + putchar('\b'); + for (i = 0; i < ts->length; i++) + putchar(' '); + for (i = 0; i < ts->length; i++) + putchar('\b'); + ts->length = 0; +} + + +/* + * Read the plan line of test output, which should contain the range of test + * numbers. We may initialize the testset structure here if we haven't yet + * seen a test. Return true if initialization succeeded and the test should + * continue, false otherwise. + */ +static int +test_plan(const char *line, struct testset *ts) +{ + unsigned long i; + long n; + + /* + * Accept a plan without the leading 1.. for compatibility with older + * versions of runtests. This will only be allowed if we've not yet seen + * a test result. + */ + line = skip_whitespace(line); + if (strncmp(line, "1..", 3) == 0) + line += 3; + + /* + * Get the count, check it for validity, and initialize the struct. If we + * have something of the form "1..0 # skip foo", the whole file was + * skipped; record that. If we do skip the whole file, zero out all of + * our statistics, since they're no longer relevant. strtol is called + * with a second argument to advance the line pointer past the count to + * make it simpler to detect the # skip case. + */ + n = strtol(line, (char **) &line, 10); + if (n == 0) { + line = skip_whitespace(line); + if (*line == '#') { + line = skip_whitespace(line + 1); + if (strncasecmp(line, "skip", 4) == 0) { + line = skip_whitespace(line + 4); + if (*line != '\0') { + ts->reason = xstrdup(line); + ts->reason[strlen(ts->reason) - 1] = '\0'; + } + ts->all_skipped = 1; + ts->aborted = 1; + ts->count = 0; + ts->passed = 0; + ts->skipped = 0; + ts->failed = 0; + return 0; + } + } + } + if (n <= 0) { + puts("ABORTED (invalid test count)"); + ts->aborted = 1; + ts->reported = 1; + return 0; + } + if (ts->plan == PLAN_INIT && ts->allocated == 0) { + ts->count = n; + ts->allocated = n; + ts->plan = PLAN_FIRST; + ts->results = xmalloc(ts->count * sizeof(enum test_status)); + for (i = 0; i < ts->count; i++) + ts->results[i] = TEST_INVALID; + } else if (ts->plan == PLAN_PENDING) { + if ((unsigned long) n < ts->count) { + printf("ABORTED (invalid test number %lu)\n", ts->count); + ts->aborted = 1; + ts->reported = 1; + return 0; + } + ts->count = n; + if ((unsigned long) n > ts->allocated) { + ts->results = xrealloc(ts->results, n * sizeof(enum test_status)); + for (i = ts->allocated; i < ts->count; i++) + ts->results[i] = TEST_INVALID; + ts->allocated = n; + } + ts->plan = PLAN_FINAL; + } + return 1; +} + + +/* + * Given a single line of output from a test, parse it and return the success + * status of that test. Anything printed to stdout not matching the form + * /^(not )?ok \d+/ is ignored. Sets ts->current to the test number that just + * reported status. + */ +static void +test_checkline(const char *line, struct testset *ts) +{ + enum test_status status = TEST_PASS; + const char *bail; + char *end; + long number; + unsigned long i, current; + int outlen; + + /* Before anything, check for a test abort. */ + bail = strstr(line, "Bail out!"); + if (bail != NULL) { + bail = skip_whitespace(bail + strlen("Bail out!")); + if (*bail != '\0') { + size_t length; + + length = strlen(bail); + if (bail[length - 1] == '\n') + length--; + test_backspace(ts); + printf("ABORTED (%.*s)\n", (int) length, bail); + ts->reported = 1; + } + ts->aborted = 1; + return; + } + + /* + * If the given line isn't newline-terminated, it was too big for an + * fgets(), which means ignore it. + */ + if (line[strlen(line) - 1] != '\n') + return; + + /* If the line begins with a hash mark, ignore it. */ + if (line[0] == '#') + return; + + /* If we haven't yet seen a plan, look for one. */ + if (ts->plan == PLAN_INIT && isdigit((unsigned char)(*line))) { + if (!test_plan(line, ts)) + return; + } else if (strncmp(line, "1..", 3) == 0) { + if (ts->plan == PLAN_PENDING) { + if (!test_plan(line, ts)) + return; + } else { + puts("ABORTED (multiple plans)"); + ts->aborted = 1; + ts->reported = 1; + return; + } + } + + /* Parse the line, ignoring something we can't parse. */ + if (strncmp(line, "not ", 4) == 0) { + status = TEST_FAIL; + line += 4; + } + if (strncmp(line, "ok", 2) != 0) + return; + line = skip_whitespace(line + 2); + errno = 0; + number = strtol(line, &end, 10); + if (errno != 0 || end == line) + number = ts->current + 1; + current = number; + if (number <= 0 || (current > ts->count && ts->plan == PLAN_FIRST)) { + test_backspace(ts); + printf("ABORTED (invalid test number %lu)\n", current); + ts->aborted = 1; + ts->reported = 1; + return; + } + + /* We have a valid test result. Tweak the results array if needed. */ + if (ts->plan == PLAN_INIT || ts->plan == PLAN_PENDING) { + ts->plan = PLAN_PENDING; + if (current > ts->count) + ts->count = current; + if (current > ts->allocated) { + unsigned long n; + + n = (ts->allocated == 0) ? 32 : ts->allocated * 2; + if (n < current) + n = current; + ts->results = xrealloc(ts->results, n * sizeof(enum test_status)); + for (i = ts->allocated; i < n; i++) + ts->results[i] = TEST_INVALID; + ts->allocated = n; + } + } + + /* + * Handle directives. We should probably do something more interesting + * with unexpected passes of todo tests. + */ + while (isdigit((unsigned char)(*line))) + line++; + line = skip_whitespace(line); + if (*line == '#') { + line = skip_whitespace(line + 1); + if (strncasecmp(line, "skip", 4) == 0) + status = TEST_SKIP; + if (strncasecmp(line, "todo", 4) == 0) + status = (status == TEST_FAIL) ? TEST_SKIP : TEST_FAIL; + } + + /* Make sure that the test number is in range and not a duplicate. */ + if (ts->results[current - 1] != TEST_INVALID) { + test_backspace(ts); + printf("ABORTED (duplicate test number %lu)\n", current); + ts->aborted = 1; + ts->reported = 1; + return; + } + + /* Good results. Increment our various counters. */ + switch (status) { + case TEST_PASS: ts->passed++; break; + case TEST_FAIL: ts->failed++; break; + case TEST_SKIP: ts->skipped++; break; + case TEST_INVALID: break; + } + ts->current = current; + ts->results[current - 1] = status; + test_backspace(ts); + if (isatty(STDOUT_FILENO)) { + outlen = printf("%lu/%lu", current, ts->count); + ts->length = (outlen >= 0) ? outlen : 0; + fflush(stdout); + } +} + + +/* + * Print out a range of test numbers, returning the number of characters it + * took up. Takes the first number, the last number, the number of characters + * already printed on the line, and the limit of number of characters the line + * can hold. Add a comma and a space before the range if chars indicates that + * something has already been printed on the line, and print ... instead if + * chars plus the space needed would go over the limit (use a limit of 0 to + * disable this). + */ +static unsigned int +test_print_range(unsigned long first, unsigned long last, unsigned int chars, + unsigned int limit) +{ + unsigned int needed = 0; + unsigned long n; + + for (n = first; n > 0; n /= 10) + needed++; + if (last > first) { + for (n = last; n > 0; n /= 10) + needed++; + needed++; + } + if (chars > 0) + needed += 2; + if (limit > 0 && chars + needed > limit) { + needed = 0; + if (chars <= limit) { + if (chars > 0) { + printf(", "); + needed += 2; + } + printf("..."); + needed += 3; + } + } else { + if (chars > 0) + printf(", "); + if (last > first) + printf("%lu-", first); + printf("%lu", last); + } + return needed; +} + + +/* + * Summarize a single test set. The second argument is 0 if the set exited + * cleanly, a positive integer representing the exit status if it exited + * with a non-zero status, and a negative integer representing the signal + * that terminated it if it was killed by a signal. + */ +static void +test_summarize(struct testset *ts, int status) +{ + unsigned long i; + unsigned long missing = 0; + unsigned long failed = 0; + unsigned long first = 0; + unsigned long last = 0; + + if (ts->aborted) { + fputs("ABORTED", stdout); + if (ts->count > 0) + printf(" (passed %lu/%lu)", ts->passed, ts->count - ts->skipped); + } else { + for (i = 0; i < ts->count; i++) { + if (ts->results[i] == TEST_INVALID) { + if (missing == 0) + fputs("MISSED ", stdout); + if (first && i == last) + last = i + 1; + else { + if (first) + test_print_range(first, last, missing - 1, 0); + missing++; + first = i + 1; + last = i + 1; + } + } + } + if (first) + test_print_range(first, last, missing - 1, 0); + first = 0; + last = 0; + for (i = 0; i < ts->count; i++) { + if (ts->results[i] == TEST_FAIL) { + if (missing && !failed) + fputs("; ", stdout); + if (failed == 0) + fputs("FAILED ", stdout); + if (first && i == last) + last = i + 1; + else { + if (first) + test_print_range(first, last, failed - 1, 0); + failed++; + first = i + 1; + last = i + 1; + } + } + } + if (first) + test_print_range(first, last, failed - 1, 0); + if (!missing && !failed) { + fputs(!status ? "ok" : "dubious", stdout); + if (ts->skipped > 0) { + if (ts->skipped == 1) + printf(" (skipped %lu test)", ts->skipped); + else + printf(" (skipped %lu tests)", ts->skipped); + } + } + } + if (status > 0) + printf(" (exit status %d)", status); + else if (status < 0) + printf(" (killed by signal %d%s)", -status, + WCOREDUMP(ts->status) ? ", core dumped" : ""); + putchar('\n'); +} + + +/* + * Given a test set, analyze the results, classify the exit status, handle a + * few special error messages, and then pass it along to test_summarize() for + * the regular output. Returns true if the test set ran successfully and all + * tests passed or were skipped, false otherwise. + */ +static int +test_analyze(struct testset *ts) +{ + if (ts->reported) + return 0; + if (ts->all_skipped) { + if (ts->reason == NULL) + puts("skipped"); + else + printf("skipped (%s)\n", ts->reason); + return 1; + } else if (WIFEXITED(ts->status) && WEXITSTATUS(ts->status) != 0) { + switch (WEXITSTATUS(ts->status)) { + case CHILDERR_DUP: + if (!ts->reported) + puts("ABORTED (can't dup file descriptors)"); + break; + case CHILDERR_EXEC: + if (!ts->reported) + puts("ABORTED (execution failed -- not found?)"); + break; + case CHILDERR_STDERR: + if (!ts->reported) + puts("ABORTED (can't open /dev/null)"); + break; + default: + test_summarize(ts, WEXITSTATUS(ts->status)); + break; + } + return 0; + } else if (WIFSIGNALED(ts->status)) { + test_summarize(ts, -WTERMSIG(ts->status)); + return 0; + } else if (ts->plan != PLAN_FIRST && ts->plan != PLAN_FINAL) { + puts("ABORTED (no valid test plan)"); + ts->aborted = 1; + return 0; + } else { + test_summarize(ts, 0); + return (ts->failed == 0); + } +} + + +/* + * Runs a single test set, accumulating and then reporting the results. + * Returns true if the test set was successfully run and all tests passed, + * false otherwise. + */ +static int +test_run(struct testset *ts) +{ + pid_t testpid, child; + int outfd, status; + unsigned long i; + FILE *output; + char buffer[BUFSIZ]; + + /* Run the test program. */ + testpid = test_start(ts->path, &outfd); + output = fdopen(outfd, "r"); + if (!output) { + puts("ABORTED"); + fflush(stdout); + sysdie("fdopen failed"); + } + + /* Pass each line of output to test_checkline(). */ + while (!ts->aborted && fgets(buffer, sizeof(buffer), output)) + test_checkline(buffer, ts); + if (ferror(output) || ts->plan == PLAN_INIT) + ts->aborted = 1; + test_backspace(ts); + + /* + * Consume the rest of the test output, close the output descriptor, + * retrieve the exit status, and pass that information to test_analyze() + * for eventual output. + */ + while (fgets(buffer, sizeof(buffer), output)) + ; + fclose(output); + child = waitpid(testpid, &ts->status, 0); + if (child == (pid_t) -1) { + if (!ts->reported) { + puts("ABORTED"); + fflush(stdout); + } + sysdie("waitpid for %u failed", (unsigned int) testpid); + } + if (ts->all_skipped) + ts->aborted = 0; + status = test_analyze(ts); + + /* Convert missing tests to failed tests. */ + for (i = 0; i < ts->count; i++) { + if (ts->results[i] == TEST_INVALID) { + ts->failed++; + ts->results[i] = TEST_FAIL; + status = 0; + } + } + return status; +} + + +/* Summarize a list of test failures. */ +static void +test_fail_summary(const struct testlist *fails) +{ + struct testset *ts; + unsigned int chars; + unsigned long i, first, last, total; + + puts(header); + + /* Failed Set Fail/Total (%) Skip Stat Failing (25) + -------------------------- -------------- ---- ---- -------------- */ + for (; fails; fails = fails->next) { + ts = fails->ts; + total = ts->count - ts->skipped; + printf("%-26.26s %4lu/%-4lu %3.0f%% %4lu ", ts->file, ts->failed, + total, total ? (ts->failed * 100.0) / total : 0, + ts->skipped); + if (WIFEXITED(ts->status)) + printf("%4d ", WEXITSTATUS(ts->status)); + else + printf(" -- "); + if (ts->aborted) { + puts("aborted"); + continue; + } + chars = 0; + first = 0; + last = 0; + for (i = 0; i < ts->count; i++) { + if (ts->results[i] == TEST_FAIL) { + if (first != 0 && i == last) + last = i + 1; + else { + if (first != 0) + chars += test_print_range(first, last, chars, 19); + first = i + 1; + last = i + 1; + } + } + } + if (first != 0) + test_print_range(first, last, chars, 19); + putchar('\n'); + free(ts->file); + free(ts->path); + free(ts->results); + if (ts->reason != NULL) + free(ts->reason); + free(ts); + } +} + + +/* + * Given the name of a test, a pointer to the testset struct, and the source + * and build directories, find the test. We try first relative to the current + * directory, then in the build directory (if not NULL), then in the source + * directory. In each of those directories, we first try a "-t" extension and + * then a ".t" extension. When we find an executable program, we fill in the + * path member of the testset struct. If none of those paths are executable, + * just fill in the name of the test with "-t" appended. + * + * The caller is responsible for freeing the path member of the testset + * struct. + */ +static void +find_test(const char *name, struct testset *ts, const char *source, + const char *build) +{ + char *path; + const char *bases[4]; + unsigned int i; + + bases[0] = "."; + bases[1] = build; + bases[2] = source; + bases[3] = NULL; + + for (i = 0; i < 3; i++) { + if (bases[i] == NULL) + continue; + path = xmalloc(strlen(bases[i]) + strlen(name) + 4); + sprintf(path, "%s/%s-t", bases[i], name); + if (access(path, X_OK) != 0) + path[strlen(path) - 2] = '.'; + if (access(path, X_OK) == 0) + break; + free(path); + path = NULL; + } + if (path == NULL) { + path = xmalloc(strlen(name) + 3); + sprintf(path, "%s-t", name); + } + ts->path = path; +} + + +/* + * Run a batch of tests from a given file listing each test on a line by + * itself. Takes two additional parameters: the root of the source directory + * and the root of the build directory. Test programs will be first searched + * for in the current directory, then the build directory, then the source + * directory. The file must be rewindable. Returns true iff all tests + * passed. + */ +static int +test_batch(const char *testlist, const char *source, const char *build) +{ + FILE *tests; + unsigned int length, i; + unsigned int longest = 0; + char buffer[BUFSIZ]; + unsigned int line; + struct testset ts, *tmp; + struct timeval start, end; + struct rusage stats; + struct testlist *failhead = NULL; + struct testlist *failtail = NULL; + struct testlist *next; + unsigned long total = 0; + unsigned long passed = 0; + unsigned long skipped = 0; + unsigned long failed = 0; + unsigned long aborted = 0; + + /* + * Open our file of tests to run and scan it, checking for lines that + * are too long and searching for the longest line. + */ + tests = fopen(testlist, "r"); + if (!tests) + sysdie("can't open %s", testlist); + line = 0; + while (fgets(buffer, sizeof(buffer), tests)) { + line++; + length = strlen(buffer) - 1; + if (buffer[length] != '\n') { + fprintf(stderr, "%s:%u: line too long\n", testlist, line); + exit(1); + } + if (length > longest) + longest = length; + } + if (fseek(tests, 0, SEEK_SET) == -1) + sysdie("can't rewind %s", testlist); + + /* + * Add two to longest and round up to the nearest tab stop. This is how + * wide the column for printing the current test name will be. + */ + longest += 2; + if (longest % 8) + longest += 8 - (longest % 8); + + /* Start the wall clock timer. */ + gettimeofday(&start, NULL); + + /* + * Now, plow through our tests again, running each one. Check line + * length again out of paranoia. + */ + line = 0; + while (fgets(buffer, sizeof(buffer), tests)) { + line++; + length = strlen(buffer) - 1; + if (buffer[length] != '\n') { + fprintf(stderr, "%s:%u: line too long\n", testlist, line); + exit(1); + } + buffer[length] = '\0'; + fputs(buffer, stdout); + for (i = length; i < longest; i++) + putchar('.'); + if (isatty(STDOUT_FILENO)) + fflush(stdout); + memset(&ts, 0, sizeof(ts)); + ts.plan = PLAN_INIT; + ts.file = xstrdup(buffer); + find_test(buffer, &ts, source, build); + ts.reason = NULL; + if (test_run(&ts)) { + free(ts.file); + free(ts.path); + free(ts.results); + if (ts.reason != NULL) + free(ts.reason); + } else { + tmp = xmalloc(sizeof(struct testset)); + memcpy(tmp, &ts, sizeof(struct testset)); + if (!failhead) { + failhead = xmalloc(sizeof(struct testset)); + failhead->ts = tmp; + failhead->next = NULL; + failtail = failhead; + } else { + failtail->next = xmalloc(sizeof(struct testset)); + failtail = failtail->next; + failtail->ts = tmp; + failtail->next = NULL; + } + } + aborted += ts.aborted; + total += ts.count + ts.all_skipped; + passed += ts.passed; + skipped += ts.skipped + ts.all_skipped; + failed += ts.failed; + } + total -= skipped; + fclose(tests); + + /* Stop the timer and get our child resource statistics. */ + gettimeofday(&end, NULL); + getrusage(RUSAGE_CHILDREN, &stats); + + /* Print out our final results. */ + if (failhead != NULL) { + test_fail_summary(failhead); + while (failhead != NULL) { + next = failhead->next; + free(failhead); + failhead = next; + } + } + putchar('\n'); + if (aborted != 0) { + if (aborted == 1) + printf("Aborted %lu test set", aborted); + else + printf("Aborted %lu test sets", aborted); + printf(", passed %lu/%lu tests", passed, total); + } + else if (failed == 0) + fputs("All tests successful", stdout); + else + printf("Failed %lu/%lu tests, %.2f%% okay", failed, total, + (total - failed) * 100.0 / total); + if (skipped != 0) { + if (skipped == 1) + printf(", %lu test skipped", skipped); + else + printf(", %lu tests skipped", skipped); + } + puts("."); + printf("Files=%u, Tests=%lu", line, total); + printf(", %.2f seconds", tv_diff(&end, &start)); + printf(" (%.2f usr + %.2f sys = %.2f CPU)\n", + tv_seconds(&stats.ru_utime), tv_seconds(&stats.ru_stime), + tv_sum(&stats.ru_utime, &stats.ru_stime)); + return (failed == 0 && aborted == 0); +} + + +/* + * Run a single test case. This involves just running the test program after + * having done the environment setup and finding the test program. + */ +static void +test_single(const char *program, const char *source, const char *build) +{ + struct testset ts; + + memset(&ts, 0, sizeof(ts)); + find_test(program, &ts, source, build); + if (execl(ts.path, ts.path, (char *) 0) == -1) + sysdie("cannot exec %s", ts.path); +} + + +/* + * Main routine. Set the SOURCE and BUILD environment variables and then, + * given a file listing tests, run each test listed. + */ +int +main(int argc, char *argv[]) +{ + int option; + int status = 0; + int single = 0; + char *source_env = NULL; + char *build_env = NULL; + const char *list; + const char *source = SOURCE; + const char *build = BUILD; + + while ((option = getopt(argc, argv, "b:hos:")) != EOF) { + switch (option) { + case 'b': + build = optarg; + break; + case 'h': + printf(usage_message, argv[0], argv[0]); + exit(0); + break; + case 'o': + single = 1; + break; + case 's': + source = optarg; + break; + default: + exit(1); + } + } + if (argc - optind != 1) { + fprintf(stderr, usage_message, argv[0], argv[0]); + exit(1); + } + argc -= optind; + argv += optind; + + if (source != NULL) { + source_env = xmalloc(strlen("SOURCE=") + strlen(source) + 1); + sprintf(source_env, "SOURCE=%s", source); + if (putenv(source_env) != 0) + sysdie("cannot set SOURCE in the environment"); + } + if (build != NULL) { + build_env = xmalloc(strlen("BUILD=") + strlen(build) + 1); + sprintf(build_env, "BUILD=%s", build); + if (putenv(build_env) != 0) + sysdie("cannot set BUILD in the environment"); + } + + if (single) + test_single(argv[0], source, build); + else { + list = strrchr(argv[0], '/'); + if (list == NULL) + list = argv[0]; + else + list++; + printf(banner, list); + status = test_batch(argv[0], source, build) ? 0 : 1; + } + + /* For valgrind cleanliness. */ + if (source_env != NULL) { + putenv((char *) "SOURCE="); + free(source_env); + } + if (build_env != NULL) { + putenv((char *) "BUILD="); + free(build_env); + } + exit(status); +} diff --git a/src/external/c-tap-harness/tests/tap/basic.c b/src/external/c-tap-harness/tests/tap/basic.c new file mode 100644 index 000000000..e8196fc87 --- /dev/null +++ b/src/external/c-tap-harness/tests/tap/basic.c @@ -0,0 +1,629 @@ +/* + * Some utility routines for writing tests. + * + * Here are a variety of utility routines for writing tests compatible with + * the TAP protocol. All routines of the form ok() or is*() take a test + * number and some number of appropriate arguments, check to be sure the + * results match the expected output using the arguments, and print out + * something appropriate for that test number. Other utility routines help in + * constructing more complex tests, skipping tests, reporting errors, setting + * up the TAP output format, or finding things in the test environment. + * + * This file is part of C TAP Harness. The current version plus supporting + * documentation is at . + * + * Copyright 2009, 2010, 2011, 2012 Russ Allbery + * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 + * The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include +#include + +#include + +/* Windows provides mkdir and rmdir under different names. */ +#ifdef _WIN32 +# define mkdir(p, m) _mkdir(p) +# define rmdir(p) _rmdir(p) +#endif + +/* + * The test count. Always contains the number that will be used for the next + * test status. + */ +unsigned long testnum = 1; + +/* + * Status information stored so that we can give a test summary at the end of + * the test case. We store the planned final test and the count of failures. + * We can get the highest test count from testnum. + * + * We also store the PID of the process that called plan() and only summarize + * results when that process exits, so as to not misreport results in forked + * processes. + * + * If _lazy is true, we're doing lazy planning and will print out the plan + * based on the last test number at the end of testing. + */ +static unsigned long _planned = 0; +static unsigned long _failed = 0; +static pid_t _process = 0; +static int _lazy = 0; + + +/* + * Our exit handler. Called on completion of the test to report a summary of + * results provided we're still in the original process. This also handles + * printing out the plan if we used plan_lazy(), although that's suppressed if + * we never ran a test (due to an early bail, for example). + */ +static void +finish(void) +{ + unsigned long highest = testnum - 1; + + if (_planned == 0 && !_lazy) + return; + fflush(stderr); + if (_process != 0 && getpid() == _process) { + if (_lazy && highest > 0) { + printf("1..%lu\n", highest); + _planned = highest; + } + if (_planned > highest) + printf("# Looks like you planned %lu test%s but only ran %lu\n", + _planned, (_planned > 1 ? "s" : ""), highest); + else if (_planned < highest) + printf("# Looks like you planned %lu test%s but ran %lu extra\n", + _planned, (_planned > 1 ? "s" : ""), highest - _planned); + else if (_failed > 0) + printf("# Looks like you failed %lu test%s of %lu\n", _failed, + (_failed > 1 ? "s" : ""), _planned); + else if (_planned > 1) + printf("# All %lu tests successful or skipped\n", _planned); + else + printf("# %lu test successful or skipped\n", _planned); + } +} + + +/* + * Initialize things. Turns on line buffering on stdout and then prints out + * the number of tests in the test suite. + */ +void +plan(unsigned long count) +{ + if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) + fprintf(stderr, "# cannot set stdout to line buffered: %s\n", + strerror(errno)); + fflush(stderr); + printf("1..%lu\n", count); + testnum = 1; + _planned = count; + _process = getpid(); + atexit(finish); +} + + +/* + * Initialize things for lazy planning, where we'll automatically print out a + * plan at the end of the program. Turns on line buffering on stdout as well. + */ +void +plan_lazy(void) +{ + if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) + fprintf(stderr, "# cannot set stdout to line buffered: %s\n", + strerror(errno)); + testnum = 1; + _process = getpid(); + _lazy = 1; + atexit(finish); +} + + +/* + * Skip the entire test suite and exits. Should be called instead of plan(), + * not after it, since it prints out a special plan line. + */ +void +skip_all(const char *format, ...) +{ + fflush(stderr); + printf("1..0 # skip"); + if (format != NULL) { + va_list args; + + putchar(' '); + va_start(args, format); + vprintf(format, args); + va_end(args); + } + putchar('\n'); + exit(0); +} + + +/* + * Print the test description. + */ +static void +print_desc(const char *format, va_list args) +{ + printf(" - "); + vprintf(format, args); +} + + +/* + * Takes a boolean success value and assumes the test passes if that value + * is true and fails if that value is false. + */ +void +ok(int success, const char *format, ...) +{ + fflush(stderr); + printf("%sok %lu", success ? "" : "not ", testnum++); + if (!success) + _failed++; + if (format != NULL) { + va_list args; + + va_start(args, format); + print_desc(format, args); + va_end(args); + } + putchar('\n'); +} + + +/* + * Same as ok(), but takes the format arguments as a va_list. + */ +void +okv(int success, const char *format, va_list args) +{ + fflush(stderr); + printf("%sok %lu", success ? "" : "not ", testnum++); + if (!success) + _failed++; + if (format != NULL) + print_desc(format, args); + putchar('\n'); +} + + +/* + * Skip a test. + */ +void +skip(const char *reason, ...) +{ + fflush(stderr); + printf("ok %lu # skip", testnum++); + if (reason != NULL) { + va_list args; + + va_start(args, reason); + putchar(' '); + vprintf(reason, args); + va_end(args); + } + putchar('\n'); +} + + +/* + * Report the same status on the next count tests. + */ +void +ok_block(unsigned long count, int status, const char *format, ...) +{ + unsigned long i; + + fflush(stderr); + for (i = 0; i < count; i++) { + printf("%sok %lu", status ? "" : "not ", testnum++); + if (!status) + _failed++; + if (format != NULL) { + va_list args; + + va_start(args, format); + print_desc(format, args); + va_end(args); + } + putchar('\n'); + } +} + + +/* + * Skip the next count tests. + */ +void +skip_block(unsigned long count, const char *reason, ...) +{ + unsigned long i; + + fflush(stderr); + for (i = 0; i < count; i++) { + printf("ok %lu # skip", testnum++); + if (reason != NULL) { + va_list args; + + va_start(args, reason); + putchar(' '); + vprintf(reason, args); + va_end(args); + } + putchar('\n'); + } +} + + +/* + * Takes an expected integer and a seen integer and assumes the test passes + * if those two numbers match. + */ +void +is_int(long wanted, long seen, const char *format, ...) +{ + fflush(stderr); + if (wanted == seen) + printf("ok %lu", testnum++); + else { + printf("# wanted: %ld\n# seen: %ld\n", wanted, seen); + printf("not ok %lu", testnum++); + _failed++; + } + if (format != NULL) { + va_list args; + + va_start(args, format); + print_desc(format, args); + va_end(args); + } + putchar('\n'); +} + + +/* + * Takes a string and what the string should be, and assumes the test passes + * if those strings match (using strcmp). + */ +void +is_string(const char *wanted, const char *seen, const char *format, ...) +{ + if (wanted == NULL) + wanted = "(null)"; + if (seen == NULL) + seen = "(null)"; + fflush(stderr); + if (strcmp(wanted, seen) == 0) + printf("ok %lu", testnum++); + else { + printf("# wanted: %s\n# seen: %s\n", wanted, seen); + printf("not ok %lu", testnum++); + _failed++; + } + if (format != NULL) { + va_list args; + + va_start(args, format); + print_desc(format, args); + va_end(args); + } + putchar('\n'); +} + + +/* + * Takes an expected unsigned long and a seen unsigned long and assumes the + * test passes if the two numbers match. Otherwise, reports them in hex. + */ +void +is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) +{ + fflush(stderr); + if (wanted == seen) + printf("ok %lu", testnum++); + else { + printf("# wanted: %lx\n# seen: %lx\n", (unsigned long) wanted, + (unsigned long) seen); + printf("not ok %lu", testnum++); + _failed++; + } + if (format != NULL) { + va_list args; + + va_start(args, format); + print_desc(format, args); + va_end(args); + } + putchar('\n'); +} + + +/* + * Bail out with an error. + */ +void +bail(const char *format, ...) +{ + va_list args; + + fflush(stderr); + fflush(stdout); + printf("Bail out! "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + exit(1); +} + + +/* + * Bail out with an error, appending strerror(errno). + */ +void +sysbail(const char *format, ...) +{ + va_list args; + int oerrno = errno; + + fflush(stderr); + fflush(stdout); + printf("Bail out! "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf(": %s\n", strerror(oerrno)); + exit(1); +} + + +/* + * Report a diagnostic to stderr. + */ +void +diag(const char *format, ...) +{ + va_list args; + + fflush(stderr); + fflush(stdout); + printf("# "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); +} + + +/* + * Report a diagnostic to stderr, appending strerror(errno). + */ +void +sysdiag(const char *format, ...) +{ + va_list args; + int oerrno = errno; + + fflush(stderr); + fflush(stdout); + printf("# "); + va_start(args, format); + vprintf(format, args); + va_end(args); + printf(": %s\n", strerror(oerrno)); +} + + +/* + * Allocate cleared memory, reporting a fatal error with bail on failure. + */ +void * +bcalloc(size_t n, size_t size) +{ + void *p; + + p = calloc(n, size); + if (p == NULL) + sysbail("failed to calloc %lu", (unsigned long)(n * size)); + return p; +} + + +/* + * Allocate memory, reporting a fatal error with bail on failure. + */ +void * +bmalloc(size_t size) +{ + void *p; + + p = malloc(size); + if (p == NULL) + sysbail("failed to malloc %lu", (unsigned long) size); + return p; +} + + +/* + * Reallocate memory, reporting a fatal error with bail on failure. + */ +void * +brealloc(void *p, size_t size) +{ + p = realloc(p, size); + if (p == NULL) + sysbail("failed to realloc %lu bytes", (unsigned long) size); + return p; +} + + +/* + * Copy a string, reporting a fatal error with bail on failure. + */ +char * +bstrdup(const char *s) +{ + char *p; + size_t len; + + len = strlen(s) + 1; + p = malloc(len); + if (p == NULL) + sysbail("failed to strdup %lu bytes", (unsigned long) len); + memcpy(p, s, len); + return p; +} + + +/* + * Copy up to n characters of a string, reporting a fatal error with bail on + * failure. Don't use the system strndup function, since it may not exist and + * the TAP library doesn't assume any portability support. + */ +char * +bstrndup(const char *s, size_t n) +{ + const char *p; + char *copy; + size_t length; + + /* Don't assume that the source string is nul-terminated. */ + for (p = s; (size_t) (p - s) < n && *p != '\0'; p++) + ; + length = p - s; + copy = malloc(length + 1); + if (p == NULL) + sysbail("failed to strndup %lu bytes", (unsigned long) length); + memcpy(copy, s, length); + copy[length] = '\0'; + return copy; +} + + +/* + * Locate a test file. Given the partial path to a file, look under BUILD and + * then SOURCE for the file and return the full path to the file. Returns + * NULL if the file doesn't exist. A non-NULL return should be freed with + * test_file_path_free(). + * + * This function uses sprintf because it attempts to be independent of all + * other portability layers. The use immediately after a memory allocation + * should be safe without using snprintf or strlcpy/strlcat. + */ +char * +test_file_path(const char *file) +{ + char *base; + char *path = NULL; + size_t length; + const char *envs[] = { "BUILD", "SOURCE", NULL }; + int i; + + for (i = 0; envs[i] != NULL; i++) { + base = getenv(envs[i]); + if (base == NULL) + continue; + length = strlen(base) + 1 + strlen(file) + 1; + path = bmalloc(length); + sprintf(path, "%s/%s", base, file); + if (access(path, R_OK) == 0) + break; + free(path); + path = NULL; + } + return path; +} + + +/* + * Free a path returned from test_file_path(). This function exists primarily + * for Windows, where memory must be freed from the same library domain that + * it was allocated from. + */ +void +test_file_path_free(char *path) +{ + if (path != NULL) + free(path); +} + + +/* + * Create a temporary directory, tmp, under BUILD if set and the current + * directory if it does not. Returns the path to the temporary directory in + * newly allocated memory, and calls bail on any failure. The return value + * should be freed with test_tmpdir_free. + * + * This function uses sprintf because it attempts to be independent of all + * other portability layers. The use immediately after a memory allocation + * should be safe without using snprintf or strlcpy/strlcat. + */ +char * +test_tmpdir(void) +{ + const char *build; + char *path = NULL; + size_t length; + + build = getenv("BUILD"); + if (build == NULL) + build = "."; + length = strlen(build) + strlen("/tmp") + 1; + path = bmalloc(length); + sprintf(path, "%s/tmp", build); + if (access(path, X_OK) < 0) + if (mkdir(path, 0777) < 0) + sysbail("error creating temporary directory %s", path); + return path; +} + + +/* + * Free a path returned from test_tmpdir() and attempt to remove the + * directory. If we can't delete the directory, don't worry; something else + * that hasn't yet cleaned up may still be using it. + */ +void +test_tmpdir_free(char *path) +{ + rmdir(path); + if (path != NULL) + free(path); +} diff --git a/src/external/c-tap-harness/tests/tap/basic.h b/src/external/c-tap-harness/tests/tap/basic.h new file mode 100644 index 000000000..fa4adafe2 --- /dev/null +++ b/src/external/c-tap-harness/tests/tap/basic.h @@ -0,0 +1,134 @@ +/* + * Basic utility routines for the TAP protocol. + * + * This file is part of C TAP Harness. The current version plus supporting + * documentation is at . + * + * Copyright 2009, 2010, 2011, 2012 Russ Allbery + * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 + * The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef TAP_BASIC_H +#define TAP_BASIC_H 1 + +#include +#include /* va_list */ +#include /* size_t */ + +/* + * Used for iterating through arrays. ARRAY_SIZE returns the number of + * elements in the array (useful for a < upper bound in a for loop) and + * ARRAY_END returns a pointer to the element past the end (ISO C99 makes it + * legal to refer to such a pointer as long as it's never dereferenced). + */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)]) + +BEGIN_DECLS + +/* + * The test count. Always contains the number that will be used for the next + * test status. + */ +extern unsigned long testnum; + +/* Print out the number of tests and set standard output to line buffered. */ +void plan(unsigned long count); + +/* + * Prepare for lazy planning, in which the plan will be printed automatically + * at the end of the test program. + */ +void plan_lazy(void); + +/* Skip the entire test suite. Call instead of plan. */ +void skip_all(const char *format, ...) + __attribute__((__noreturn__, __format__(printf, 1, 2))); + +/* + * Basic reporting functions. The okv() function is the same as ok() but + * takes the test description as a va_list to make it easier to reuse the + * reporting infrastructure when writing new tests. + */ +void ok(int success, const char *format, ...) + __attribute__((__format__(printf, 2, 3))); +void okv(int success, const char *format, va_list args); +void skip(const char *reason, ...) + __attribute__((__format__(printf, 1, 2))); + +/* Report the same status on, or skip, the next count tests. */ +void ok_block(unsigned long count, int success, const char *format, ...) + __attribute__((__format__(printf, 3, 4))); +void skip_block(unsigned long count, const char *reason, ...) + __attribute__((__format__(printf, 2, 3))); + +/* Check an expected value against a seen value. */ +void is_int(long wanted, long seen, const char *format, ...) + __attribute__((__format__(printf, 3, 4))); +void is_string(const char *wanted, const char *seen, const char *format, ...) + __attribute__((__format__(printf, 3, 4))); +void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) + __attribute__((__format__(printf, 3, 4))); + +/* Bail out with an error. sysbail appends strerror(errno). */ +void bail(const char *format, ...) + __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); +void sysbail(const char *format, ...) + __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); + +/* Report a diagnostic to stderr prefixed with #. */ +void diag(const char *format, ...) + __attribute__((__nonnull__, __format__(printf, 1, 2))); +void sysdiag(const char *format, ...) + __attribute__((__nonnull__, __format__(printf, 1, 2))); + +/* Allocate memory, reporting a fatal error with bail on failure. */ +void *bcalloc(size_t, size_t) + __attribute__((__alloc_size__(1, 2), __malloc__)); +void *bmalloc(size_t) + __attribute__((__alloc_size__(1), __malloc__)); +void *brealloc(void *, size_t) + __attribute__((__alloc_size__(2), __malloc__)); +char *bstrdup(const char *) + __attribute__((__malloc__, __nonnull__)); +char *bstrndup(const char *, size_t) + __attribute__((__malloc__, __nonnull__)); + +/* + * Find a test file under BUILD or SOURCE, returning the full path. The + * returned path should be freed with test_file_path_free(). + */ +char *test_file_path(const char *file) + __attribute__((__malloc__, __nonnull__)); +void test_file_path_free(char *path); + +/* + * Create a temporary directory relative to BUILD and return the path. The + * returned path should be freed with test_tmpdir_free. + */ +char *test_tmpdir(void) + __attribute__((__malloc__)); +void test_tmpdir_free(char *path); + +END_DECLS + +#endif /* TAP_BASIC_H */ diff --git a/src/external/c-tap-harness/tests/tap/float.c b/src/external/c-tap-harness/tests/tap/float.c new file mode 100644 index 000000000..67dd555f3 --- /dev/null +++ b/src/external/c-tap-harness/tests/tap/float.c @@ -0,0 +1,67 @@ +/* + * Utility routines for writing floating point tests. + * + * Currently provides only one function, which checks whether a double is + * equal to an expected value within a given epsilon. This is broken into a + * separate source file from the rest of the basic C TAP library because it + * may require linking with -lm on some platforms, and the package may not + * otherwise care about floating point. + * + * This file is part of C TAP Harness. The current version plus supporting + * documentation is at . + * + * Copyright 2008, 2010, 2012 Russ Allbery + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Required for isnan() and isinf(). */ +#if defined(__STRICT_ANSI__) || defined(PEDANTIC) +# ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 600 +# endif +#endif + +#include +#include +#include + +#include +#include + +/* + * Takes an expected double and a seen double and assumes the test passes if + * those two numbers are within delta of each other. + */ +void +is_double(double wanted, double seen, double epsilon, const char *format, ...) +{ + va_list args; + + va_start(args, format); + fflush(stderr); + if ((isnan(wanted) && isnan(seen)) + || (isinf(wanted) && isinf(seen) && wanted == seen) + || fabs(wanted - seen) <= epsilon) + okv(1, format, args); + else { + printf("# wanted: %g\n# seen: %g\n", wanted, seen); + okv(0, format, args); + } +} diff --git a/src/external/c-tap-harness/tests/tap/float.h b/src/external/c-tap-harness/tests/tap/float.h new file mode 100644 index 000000000..746453564 --- /dev/null +++ b/src/external/c-tap-harness/tests/tap/float.h @@ -0,0 +1,42 @@ +/* + * Floating point check function for the TAP protocol. + * + * This file is part of C TAP Harness. The current version plus supporting + * documentation is at . + * + * Copyright 2008, 2010, 2012 Russ Allbery + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef TAP_FLOAT_H +#define TAP_FLOAT_H 1 + +#include + +BEGIN_DECLS + +/* Check an expected value against a seen value within epsilon. */ +void is_double(double wanted, double seen, double epsilon, + const char *format, ...) + __attribute__((__format__(printf, 4, 5))); + +END_DECLS + +#endif /* TAP_FLOAT_H */ diff --git a/src/external/c-tap-harness/tests/tap/libtap.sh b/src/external/c-tap-harness/tests/tap/libtap.sh new file mode 100644 index 000000000..f9347d80b --- /dev/null +++ b/src/external/c-tap-harness/tests/tap/libtap.sh @@ -0,0 +1,246 @@ +# Shell function library for test cases. +# +# Note that while many of the functions in this library could benefit from +# using "local" to avoid possibly hammering global variables, Solaris /bin/sh +# doesn't support local and this library aspires to be portable to Solaris +# Bourne shell. Instead, all private variables are prefixed with "tap_". +# +# This file provides a TAP-compatible shell function library useful for +# writing test cases. It is part of C TAP Harness, which can be found at +# . +# +# Written by Russ Allbery +# Copyright 2009, 2010, 2011, 2012 Russ Allbery +# Copyright 2006, 2007, 2008 +# The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# Print out the number of test cases we expect to run. +plan () { + count=1 + planned="$1" + failed=0 + echo "1..$1" + trap finish 0 +} + +# Prepare for lazy planning. +plan_lazy () { + count=1 + planned=0 + failed=0 + trap finish 0 +} + +# Report the test status on exit. +finish () { + tap_highest=`expr "$count" - 1` + if [ "$planned" = 0 ] ; then + echo "1..$tap_highest" + planned="$tap_highest" + fi + tap_looks='# Looks like you' + if [ "$planned" -gt 0 ] ; then + if [ "$planned" -gt "$tap_highest" ] ; then + if [ "$planned" -gt 1 ] ; then + echo "$tap_looks planned $planned tests but only ran" \ + "$tap_highest" + else + echo "$tap_looks planned $planned test but only ran" \ + "$tap_highest" + fi + elif [ "$planned" -lt "$tap_highest" ] ; then + tap_extra=`expr "$tap_highest" - "$planned"` + if [ "$planned" -gt 1 ] ; then + echo "$tap_looks planned $planned tests but ran" \ + "$tap_extra extra" + else + echo "$tap_looks planned $planned test but ran" \ + "$tap_extra extra" + fi + elif [ "$failed" -gt 0 ] ; then + if [ "$failed" -gt 1 ] ; then + echo "$tap_looks failed $failed tests of $planned" + else + echo "$tap_looks failed $failed test of $planned" + fi + elif [ "$planned" -gt 1 ] ; then + echo "# All $planned tests successful or skipped" + else + echo "# $planned test successful or skipped" + fi + fi +} + +# Skip the entire test suite. Should be run instead of plan. +skip_all () { + tap_desc="$1" + if [ -n "$tap_desc" ] ; then + echo "1..0 # skip $tap_desc" + else + echo "1..0 # skip" + fi + exit 0 +} + +# ok takes a test description and a command to run and prints success if that +# command is successful, false otherwise. The count starts at 1 and is +# updated each time ok is printed. +ok () { + tap_desc="$1" + if [ -n "$tap_desc" ] ; then + tap_desc=" - $tap_desc" + fi + shift + if "$@" ; then + echo ok "$count$tap_desc" + else + echo not ok "$count$tap_desc" + failed=`expr $failed + 1` + fi + count=`expr $count + 1` +} + +# Skip the next test. Takes the reason why the test is skipped. +skip () { + echo "ok $count # skip $*" + count=`expr $count + 1` +} + +# Report the same status on a whole set of tests. Takes the count of tests, +# the description, and then the command to run to determine the status. +ok_block () { + tap_i=$count + tap_end=`expr $count + $1` + shift + while [ "$tap_i" -lt "$tap_end" ] ; do + ok "$@" + tap_i=`expr $tap_i + 1` + done +} + +# Skip a whole set of tests. Takes the count and then the reason for skipping +# the test. +skip_block () { + tap_i=$count + tap_end=`expr $count + $1` + shift + while [ "$tap_i" -lt "$tap_end" ] ; do + skip "$@" + tap_i=`expr $tap_i + 1` + done +} + +# Portable variant of printf '%s\n' "$*". In the majority of cases, this +# function is slower than printf, because the latter is often implemented +# as a builtin command. The value of the variable IFS is ignored. +# +# This macro must not be called via backticks inside double quotes, since this +# will result in bizarre escaping behavior and lots of extra backslashes on +# Solaris. +puts () { + cat << EOH +$@ +EOH +} + +# Run a program expected to succeed, and print ok if it does and produces the +# correct output. Takes the description, expected exit status, the expected +# output, the command to run, and then any arguments for that command. +# Standard output and standard error are combined when analyzing the output of +# the command. +# +# If the command may contain system-specific error messages in its output, +# add strip_colon_error before the command to post-process its output. +ok_program () { + tap_desc="$1" + shift + tap_w_status="$1" + shift + tap_w_output="$1" + shift + tap_output=`"$@" 2>&1` + tap_status=$? + if [ $tap_status = $tap_w_status ] \ + && [ x"$tap_output" = x"$tap_w_output" ] ; then + ok "$tap_desc" true + else + echo "# saw: ($tap_status) $tap_output" + echo "# not: ($tap_w_status) $tap_w_output" + ok "$tap_desc" false + fi +} + +# Strip a colon and everything after it off the output of a command, as long +# as that colon comes after at least one whitespace character. (This is done +# to avoid stripping the name of the program from the start of an error +# message.) This is used to remove system-specific error messages (coming +# from strerror, for example). +strip_colon_error() { + tap_output=`"$@" 2>&1` + tap_status=$? + tap_output=`puts "$tap_output" | sed 's/^\([^ ]* [^:]*\):.*/\1/'` + puts "$tap_output" + return $tap_status +} + +# Bail out with an error message. +bail () { + echo 'Bail out!' "$@" + exit 1 +} + +# Output a diagnostic on standard error, preceded by the required # mark. +diag () { + echo '#' "$@" +} + +# Search for the given file first in $BUILD and then in $SOURCE and echo the +# path where the file was found, or the empty string if the file wasn't +# found. +# +# This macro uses puts, so don't run it using backticks inside double quotes +# or bizarre quoting behavior will happen with Solaris sh. +test_file_path () { + if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then + puts "$BUILD/$1" + elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then + puts "$SOURCE/$1" + else + echo '' + fi +} + +# Create $BUILD/tmp for use by tests for storing temporary files and return +# the path (via standard output). +# +# This macro uses puts, so don't run it using backticks inside double quotes +# or bizarre quoting behavior will happen with Solaris sh. +test_tmpdir () { + if [ -z "$BUILD" ] ; then + tap_tmpdir="./tmp" + else + tap_tmpdir="$BUILD"/tmp + fi + if [ ! -d "$tap_tmpdir" ] ; then + mkdir "$tap_tmpdir" || bail "Error creating $tap_tmpdir" + fi + puts "$tap_tmpdir" +} diff --git a/src/external/c-tap-harness/tests/tap/macros.h b/src/external/c-tap-harness/tests/tap/macros.h new file mode 100644 index 000000000..33fee42d9 --- /dev/null +++ b/src/external/c-tap-harness/tests/tap/macros.h @@ -0,0 +1,88 @@ +/* + * Helpful macros for TAP header files. + * + * This is not, strictly speaking, related to TAP, but any TAP add-on is + * probably going to need these macros, so define them in one place so that + * everyone can pull them in. + * + * This file is part of C TAP Harness. The current version plus supporting + * documentation is at . + * + * Copyright 2008, 2012 Russ Allbery + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef TAP_MACROS_H +#define TAP_MACROS_H 1 + +/* + * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7 + * could you use the __format__ form of the attributes, which is what we use + * (to avoid confusion with other macros), and only with gcc 2.96 can you use + * the attribute __malloc__. 2.96 is very old, so don't bother trying to get + * the other attributes to work with GCC versions between 2.7 and 2.96. + */ +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) +# define __attribute__(spec) /* empty */ +# endif +#endif + +/* + * We use __alloc_size__, but it was only available in fairly recent versions + * of GCC. Suppress warnings about the unknown attribute if GCC is too old. + * We know that we're GCC at this point, so we can use the GCC variadic macro + * extension, which will still work with versions of GCC too old to have C99 + * variadic macro support. + */ +#if !defined(__attribute__) && !defined(__alloc_size__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) +# define __alloc_size__(spec, args...) /* empty */ +# endif +#endif + +/* + * LLVM and Clang pretend to be GCC but don't support all of the __attribute__ + * settings that GCC does. For them, suppress warnings about unknown + * attributes on declarations. This unfortunately will affect the entire + * compilation context, but there's no push and pop available. + */ +#if !defined(__attribute__) && (defined(__llvm__) || defined(__clang__)) +# pragma GCC diagnostic ignored "-Wattributes" +#endif + +/* Used for unused parameters to silence gcc warnings. */ +#define UNUSED __attribute__((__unused__)) + +/* + * BEGIN_DECLS is used at the beginning of declarations so that C++ + * compilers don't mangle their names. END_DECLS is used at the end. + */ +#undef BEGIN_DECLS +#undef END_DECLS +#ifdef __cplusplus +# define BEGIN_DECLS extern "C" { +# define END_DECLS } +#else +# define BEGIN_DECLS /* empty */ +# define END_DECLS /* empty */ +#endif + +#endif /* TAP_MACROS_H */ -- 2.39.5