aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/TESTS3
-rw-r--r--tests/data/perl.conf5
-rwxr-xr-xtests/perl/module-version-t183
-rw-r--r--tests/portable/asprintf-t.c1
-rw-r--r--tests/portable/snprintf-t.c4
-rw-r--r--tests/portable/strlcat-t.c78
-rw-r--r--tests/portable/strlcat.c2
-rw-r--r--tests/portable/strlcpy-t.c70
-rw-r--r--tests/portable/strlcpy.c2
-rw-r--r--tests/runtests.c204
-rw-r--r--tests/tap/basic.c12
-rw-r--r--tests/tap/basic.h8
-rw-r--r--tests/tap/kerberos.c31
-rw-r--r--tests/tap/kerberos.h8
-rw-r--r--tests/tap/macros.h8
-rw-r--r--tests/tap/messages.c4
-rw-r--r--tests/tap/perl/Test/RRA.pm104
-rw-r--r--tests/tap/perl/Test/RRA/Automake.pm166
-rw-r--r--tests/tap/perl/Test/RRA/Config.pm138
-rw-r--r--tests/tap/perl/Test/RRA/ModuleVersion.pm295
-rw-r--r--tests/tap/process.c9
-rw-r--r--tests/tap/string.h2
-rw-r--r--tests/util/messages-t.c5
-rwxr-xr-xtests/util/xmalloc-t32
-rw-r--r--tests/util/xmalloc.c7
25 files changed, 901 insertions, 480 deletions
diff --git a/tests/TESTS b/tests/TESTS
index d947e97..76bd4ae 100644
--- a/tests/TESTS
+++ b/tests/TESTS
@@ -5,13 +5,12 @@ client/rekey
docs/pod
docs/pod-spelling
perl/minimum-version
+perl/module-version
perl/strict
portable/asprintf
portable/mkstemp
portable/setenv
portable/snprintf
-portable/strlcat
-portable/strlcpy
server/admin
server/backend
server/keytab
diff --git a/tests/data/perl.conf b/tests/data/perl.conf
index eaf7443..0c1e34e 100644
--- a/tests/data/perl.conf
+++ b/tests/data/perl.conf
@@ -1,6 +1,9 @@
# Configuration for Perl tests. -*- perl -*-
-# No special configuration yet.
+# Wallet::Schema's version number is used to version the database schema and
+# requires upgrade SQL files for each version bump. Until this is replaced
+# with some better system, exclude it from version checking.
+@MODULE_VERSION_IGNORE = qw(perl/lib/Wallet/Schema.pm);
# File must end with this line.
1;
diff --git a/tests/perl/module-version-t b/tests/perl/module-version-t
new file mode 100755
index 0000000..f1ebf0f
--- /dev/null
+++ b/tests/perl/module-version-t
@@ -0,0 +1,183 @@
+#!/usr/bin/perl
+#
+# Check or update the version of embedded Perl modules.
+#
+# Examines all module files (*.pm) under the perl/lib directory, if it exists,
+# and verifies that their $VERSION is set to the same value as the current
+# version number as determined by the NEWS file at the top level of the source
+# tree (or the current directory if not being run as a test).
+#
+# When given the --update option, instead fixes all of the Perl modules found
+# to have the correct version.
+
+use 5.006;
+use strict;
+use warnings;
+
+# SOURCE may not be set if we're running this script manually to update
+# version numbers. If it isn't, assume we're being run from the top of the
+# tree.
+BEGIN {
+ if ($ENV{SOURCE}) {
+ unshift(@INC, "$ENV{SOURCE}/tap/perl");
+ } else {
+ unshift(@INC, 'tests/tap/perl');
+ }
+}
+
+use Getopt::Long qw(GetOptions);
+use Test::RRA qw(skip_unless_automated);
+use Test::RRA::Automake qw(automake_setup);
+use Test::RRA::ModuleVersion qw(test_module_versions update_module_versions);
+
+# Return the current version and, optionally, the package name from the NEWS
+# file. Munges the version to be appropriate for Perl if necessary.
+#
+# Returns: Scalar: The version number of the latest version in NEWS
+# List: The version number and the package name
+# Throws: Text exception if NEWS is not found or doesn't contain a version
+sub news_version {
+ my ($package, $version, $news);
+ for my $path ('NEWS', '../NEWS') {
+ if (-f $path) {
+ open($news, q{<}, $path) or die "$0: cannot open $path: $!\n";
+ }
+ }
+ if (!$news) {
+ die "$0: cannot find NEWS file\n";
+ }
+ SCAN:
+ while (defined(my $line = <$news>)) {
+ ## no critic (RegularExpressions::ProhibitEscapedMetacharacters)
+ if ($line =~ m{ \A ([\w\s-]+) \s ([\d.]+) \s \( }xms) {
+ ($package, $version) = ($1, $2);
+ last SCAN;
+ }
+ ## use critic
+ }
+ close($news) or die "$0: error reading from NEWS: $!\n";
+ if (!defined($version)) {
+ die "$0: cannot find version number in NEWS\n";
+ }
+
+ # Munge the version for Perl purposes by ensuring that each component
+ # has two digits and by dropping the second period.
+ $version =~ s{ [.] (\d) (?= [.] | \z ) }{.0$1}xmsg;
+ $version =~ s{ ([.] \d+) [.] (\d+) }{$1$2}xms;
+
+ # Return the appropriate value based on context.
+ return wantarray ? ($version, $package) : $version;
+}
+
+# Parse command-line arguments.
+my $update;
+Getopt::Long::config('bundling', 'no_ignore_case');
+GetOptions('update|u' => \$update) or exit 1;
+
+# If we're not updating, set up for Automake testing. Otherwise, we assume
+# we're running from the top of the source tree.
+if (!$update) {
+ automake_setup();
+}
+
+# Get the package name and version.
+my ($version, $package) = news_version();
+
+# rra-c-util itself checks the versions of the testing support modules instead
+# of an embedded tree of Perl modules.
+my $root = ($package eq 'rra-c-util') ? 'tests/tap/perl' : 'perl/lib';
+
+# Main routine. We run as either a test suite or as a script to update all of
+# the module versions, selecting based on whether we got the -u / --update
+# command-line option.
+if ($update) {
+ update_module_versions($root, $version);
+} else {
+ skip_unless_automated('Module version tests');
+ test_module_versions($root, $version);
+}
+exit 0;
+__END__
+
+=for stopwords
+Allbery sublicense MERCHANTABILITY NONINFRINGEMENT rra-c-util
+
+=head1 NAME
+
+module-version-t - Check or update versions of embedded Perl modules
+
+=head1 SYNOPSIS
+
+B<module-version-t> [B<--update>]
+
+=head1 REQUIREMENTS
+
+Perl 5.6.2 or later.
+
+=head1 DESCRIPTION
+
+This script has a dual purpose as either a test script or a utility script.
+The intent is to assist with maintaining consistent versions between a larger
+primarily C project and any embedded Perl modules, supporting both the package
+keyword syntax introduced in Perl 5.12 or the older explicit setting of a
+$VERSION variable.
+
+As a test, it reads the current version of a package from the F<NEWS> file and
+then looks for any Perl modules in F<perl/lib>. (As a special exception, if
+the package name as determined from the F<NEWS> file is C<rra-c-util>, it
+looks for Perl modules in F<tests/tap/perl> instead.) If it finds any, it
+checks that the version number of the Perl module matches the version number
+of the package from the F<NEWS> file. These test results are reported with
+Test::More, suitable for any TAP harness.
+
+As a utility script, when run with the B<--update> option, it similarly finds
+all Perl modules in F<perl/lib> (or F<tests/tap/perl> per above) and then
+rewrites their version setting to match the version of the package as
+determined from the F<NEWS> file.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-u>, B<--update>
+
+Rather than test the Perl modules for the correct version, update all Perl
+modules found in the tree under F<perl/lib> to the current version from the
+NEWS file.
+
+=back
+
+=head1 AUTHOR
+
+Russ Allbery <eagle@eyrie.org>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2014, 2016 Russ Allbery <eagle@eyrie.org>
+
+Copyright 2013 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.
+
+=head1 SEE ALSO
+
+This module is maintained in the rra-c-util package. The current version is
+available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+
+=cut
diff --git a/tests/portable/asprintf-t.c b/tests/portable/asprintf-t.c
index c61c14a..e556d95 100644
--- a/tests/portable/asprintf-t.c
+++ b/tests/portable/asprintf-t.c
@@ -16,6 +16,7 @@
*/
#include <config.h>
+#include <portable/macros.h>
#include <portable/system.h>
#include <tests/tap/basic.h>
diff --git a/tests/portable/snprintf-t.c b/tests/portable/snprintf-t.c
index 270d2e1..cc8cf00 100644
--- a/tests/portable/snprintf-t.c
+++ b/tests/portable/snprintf-t.c
@@ -26,7 +26,9 @@
* Disable the requirement that format strings be literals. We need variable
* formats for easy testing.
*/
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) || defined(__clang__)
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
/*
* Intentionally don't add the printf attribute here since we pass a
diff --git a/tests/portable/strlcat-t.c b/tests/portable/strlcat-t.c
deleted file mode 100644
index 58aba58..0000000
--- a/tests/portable/strlcat-t.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * strlcat test suite.
- *
- * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
- *
- * Written by Russ Allbery <eagle@eyrie.org>
- *
- * The authors hereby relinquish any claim to any copyright that they may have
- * in this work, whether granted under contract or by operation of law or
- * international treaty, and hereby commit to the public, at large, that they
- * shall not, at any time in the future, seek to enforce any copyright in this
- * work against any person or entity, or prevent any person or entity from
- * copying, publishing, distributing or creating derivative works of this
- * work.
- */
-
-#include <config.h>
-#include <portable/system.h>
-
-#include <tests/tap/basic.h>
-
-size_t test_strlcat(char *, const char *, size_t);
-
-
-int
-main(void)
-{
- char buffer[10] = "";
-
- plan(27);
-
- is_int(3, test_strlcat(buffer, "foo", sizeof(buffer)),
- "strlcat into empty buffer");
- is_string("foo", buffer, "...with right output");
- is_int(7, test_strlcat(buffer, " bar", sizeof(buffer)),
- "...and append more");
- is_string("foo bar", buffer, "...and output is still correct");
- is_int(9, test_strlcat(buffer, "!!", sizeof(buffer)),
- "...and append to buffer limit");
- is_string("foo bar!!", buffer, "...output is still correct");
- is_int(10, test_strlcat(buffer, "!", sizeof(buffer)),
- "...append one more character");
- is_string("foo bar!!", buffer, "...and output didn't change");
- ok(buffer[9] == '\0', "...buffer still nul-terminated");
- buffer[0] = '\0';
- is_int(11, test_strlcat(buffer, "hello world", sizeof(buffer)),
- "append single long string");
- is_string("hello wor", buffer, "...string truncates properly");
- ok(buffer[9] == '\0', "...buffer still nul-terminated");
- buffer[0] = '\0';
- is_int(7, test_strlcat(buffer, "sausage", 5), "lie about buffer length");
- is_string("saus", buffer, "...contents are correct");
- is_int(14, test_strlcat(buffer, "bacon eggs", sizeof(buffer)),
- "...add more up to real size");
- is_string("sausbacon", buffer, "...and result is correct");
-
- /* Make sure that with a size of 0, the destination isn't changed. */
- is_int(11, test_strlcat(buffer, "!!", 0), "no change with size of 0");
- is_string("sausbacon", buffer, "...and content is the same");
-
- /* Now play with empty strings. */
- is_int(9, test_strlcat(buffer, "", 0),
- "correct count when appending empty string");
- is_string("sausbacon", buffer, "...and contents are unchanged");
- buffer[0] = '\0';
- is_int(0, test_strlcat(buffer, "", sizeof(buffer)),
- "correct count when appending empty string to empty buffer");
- is_string("", buffer, "...and buffer content is correct");
- is_int(3, test_strlcat(buffer, "foo", 2), "append to length 2 buffer");
- is_string("f", buffer, "...and got only a single character");
- ok(buffer[1] == '\0', "...and buffer is still nul-terminated");
- is_int(1, test_strlcat(buffer, "", sizeof(buffer)),
- "append an empty string");
- ok(buffer[1] == '\0', "...and buffer is still nul-terminated");
-
- return 0;
-}
diff --git a/tests/portable/strlcat.c b/tests/portable/strlcat.c
deleted file mode 100644
index 8983bd8..0000000
--- a/tests/portable/strlcat.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define TESTING 1
-#include <portable/strlcat.c>
diff --git a/tests/portable/strlcpy-t.c b/tests/portable/strlcpy-t.c
deleted file mode 100644
index 6652a7c..0000000
--- a/tests/portable/strlcpy-t.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * strlcpy test suite.
- *
- * The canonical version of this file is maintained in the rra-c-util package,
- * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
- *
- * Written by Russ Allbery <eagle@eyrie.org>
- *
- * The authors hereby relinquish any claim to any copyright that they may have
- * in this work, whether granted under contract or by operation of law or
- * international treaty, and hereby commit to the public, at large, that they
- * shall not, at any time in the future, seek to enforce any copyright in this
- * work against any person or entity, or prevent any person or entity from
- * copying, publishing, distributing or creating derivative works of this
- * work.
- */
-
-#include <config.h>
-#include <portable/system.h>
-
-#include <tests/tap/basic.h>
-
-size_t test_strlcpy(char *, const char *, size_t);
-
-
-int
-main(void)
-{
- char buffer[10];
-
- plan(23);
-
- is_int(3, test_strlcpy(buffer, "foo", sizeof(buffer)), "simple strlcpy");
- is_string("foo", buffer, "...result is correct");
- is_int(9, test_strlcpy(buffer, "hello wor", sizeof(buffer)),
- "strlcpy exact length of buffer");
- is_string("hello wor", buffer, "...result is correct");
- is_int(10, test_strlcpy(buffer, "world hell", sizeof(buffer)),
- "strlcpy one more than buffer length");
- is_string("world hel", buffer, "...result is correct");
- ok(buffer[9] == '\0', "...buffer is nul-terminated");
- is_int(11, test_strlcpy(buffer, "hello world", sizeof(buffer)),
- "strlcpy more than buffer length");
- is_string("hello wor", buffer, "...result is correct");
- ok(buffer[9] == '\0', "...buffer is nul-terminated");
-
- /* Make sure that with a size of 0, the destination isn't changed. */
- is_int(3, test_strlcpy(buffer, "foo", 0), "buffer unchanged if size 0");
- is_string("hello wor", buffer, "...contents still the same");
-
- /* Now play with empty strings. */
- is_int(0, test_strlcpy(buffer, "", 0), "copy empty string with size 0");
- is_string("hello wor", buffer, "...buffer unchanged");
- is_int(0, test_strlcpy(buffer, "", sizeof(buffer)),
- "copy empty string into full buffer");
- is_string("", buffer, "...buffer now empty string");
- is_int(3, test_strlcpy(buffer, "foo", 2),
- "copy string into buffer of size 2");
- is_string("f", buffer, "...got one character");
- ok(buffer[1] == '\0', "...buffer is nul-terminated");
- is_int(0, test_strlcpy(buffer, "", 1),
- "copy empty string into buffer of size 1");
- ok(buffer[0] == '\0', "...buffer is empty string");
-
- /* Finally, check using strlcpy as strlen. */
- is_int(3, test_strlcpy(NULL, "foo", 0), "use strlcpy as strlen");
- is_int(11, test_strlcpy(NULL, "hello world", 0), "...again");
-
- return 0;
-}
diff --git a/tests/portable/strlcpy.c b/tests/portable/strlcpy.c
deleted file mode 100644
index d444595..0000000
--- a/tests/portable/strlcpy.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define TESTING 1
-#include <portable/strlcpy.c>
diff --git a/tests/runtests.c b/tests/runtests.c
index a9d2373..42a73ea 100644
--- a/tests/runtests.c
+++ b/tests/runtests.c
@@ -3,15 +3,19 @@
*
* Usage:
*
- * runtests [-b <build-dir>] [-s <source-dir>] <test-list>
- * runtests -o [-b <build-dir>] [-s <source-dir>] <test>
+ * runtests [-hv] [-b <build-dir>] [-s <source-dir>] -l <test-list>
+ * runtests [-hv] [-b <build-dir>] [-s <source-dir>] <test> [<test> ...]
+ * runtests -o [-h] [-b <build-dir>] [-s <source-dir>] <test>
*
* 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:
+ * reporting results. In the second case, use the same infrastructure, but
+ * run only the tests listed on the command line.
+ *
+ * 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 <number>
* not ok <number>
@@ -50,12 +54,16 @@
* directories. These paths can also be set with the -b and -s command-line
* options, which will override anything set at build time.
*
+ * If the -v option is given, or the C_TAP_VERBOSE environment variable is set,
+ * display the full output of each test as it runs rather than showing a
+ * summary of the results of each test.
+ *
* 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 <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
* Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
- * 2014 Russ Allbery <eagle@eyrie.org>
+ * 2014, 2015 Russ Allbery <eagle@eyrie.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -146,6 +154,12 @@ enum test_status {
TEST_INVALID
};
+/* Really, just a boolean, but this is more self-documenting. */
+enum test_verbose {
+ CONCISE = 0,
+ VERBOSE = 1
+};
+
/* Indicates the state of our plan. */
enum plan_status {
PLAN_INIT, /* Nothing seen yet. */
@@ -192,16 +206,18 @@ struct testlist {
* split into variables to satisfy the pedantic ISO C90 limit on strings.
*/
static const char usage_message[] = "\
-Usage: %s [-b <build-dir>] [-s <source-dir>] <test> ...\n\
- %s [-b <build-dir>] [-s <source-dir>] -l <test-list>\n\
- %s -o [-b <build-dir>] [-s <source-dir>] <test>\n\
-\n%s";
-static const char usage_extra[] = "\
+Usage: %s [-hv] [-b <build-dir>] [-s <source-dir>] <test> ...\n\
+ %s [-hv] [-b <build-dir>] [-s <source-dir>] -l <test-list>\n\
+ %s -o [-h] [-b <build-dir>] [-s <source-dir>] <test>\n\
+\n\
Options:\n\
-b <build-dir> Set the build directory to <build-dir>\n\
+%s";
+static const char usage_extra[] = "\
-l <list> Take the list of tests to run from <test-list>\n\
-o Run a single test rather than a list of tests\n\
-s <source-dir> Set the source directory to <source-dir>\n\
+ -v Show the full output of each test\n\
\n\
runtests normally runs each test listed on the command line. With the -l\n\
option, it instead runs every test listed in a file. With the -o option,\n\
@@ -246,8 +262,10 @@ Failed Set Fail/Total (%) Skip Stat Failing Tests\n\
* variadic macro support.
*/
#if !defined(__attribute__) && !defined(__alloc_size__)
-# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
-# define __alloc_size__(spec, args...) /* empty */
+# if defined(__GNUC__) && !defined(__clang__)
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+# define __alloc_size__(spec, args...) /* empty */
+# endif
# endif
#endif
@@ -591,13 +609,28 @@ resize_results(struct testset *ts, unsigned long n)
/*
+ * Report an invalid test number and set the appropriate flags. Pulled into a
+ * separate function since we do this in several places.
+ */
+static void
+invalid_test_number(struct testset *ts, long n, enum test_verbose verbose)
+{
+ if (!verbose)
+ test_backspace(ts);
+ printf("ABORTED (invalid test number %ld)\n", n);
+ ts->aborted = 1;
+ ts->reported = 1;
+}
+
+
+/*
* 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)
+test_plan(const char *line, struct testset *ts, enum test_verbose verbose)
{
long n;
@@ -654,10 +687,7 @@ test_plan(const char *line, struct testset *ts)
* range.
*/
if (ts->plan == PLAN_PENDING && (unsigned long) n < ts->count) {
- test_backspace(ts);
- printf("ABORTED (invalid test number %lu)\n", ts->count);
- ts->aborted = 1;
- ts->reported = 1;
+ invalid_test_number(ts, (long) ts->count, verbose);
return 0;
}
@@ -665,8 +695,8 @@ test_plan(const char *line, struct testset *ts)
* Otherwise, allocated or resize the results if needed and update count,
* and then record that we've seen a plan.
*/
- resize_results(ts, n);
- ts->count = n;
+ resize_results(ts, (unsigned long) n);
+ ts->count = (unsigned long) n;
if (ts->plan == PLAN_INIT)
ts->plan = PLAN_FIRST;
else if (ts->plan == PLAN_PENDING)
@@ -682,7 +712,8 @@ test_plan(const char *line, struct testset *ts)
* reported status.
*/
static void
-test_checkline(const char *line, struct testset *ts)
+test_checkline(const char *line, struct testset *ts,
+ enum test_verbose verbose)
{
enum test_status status = TEST_PASS;
const char *bail;
@@ -701,7 +732,8 @@ test_checkline(const char *line, struct testset *ts)
length = strlen(bail);
if (bail[length - 1] == '\n')
length--;
- test_backspace(ts);
+ if (!verbose)
+ test_backspace(ts);
printf("ABORTED (%.*s)\n", (int) length, bail);
ts->reported = 1;
}
@@ -722,14 +754,15 @@ test_checkline(const char *line, struct testset *ts)
/* 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))
+ if (!test_plan(line, ts, verbose))
return;
} else if (strncmp(line, "1..", 3) == 0) {
if (ts->plan == PLAN_PENDING) {
- if (!test_plan(line, ts))
+ if (!test_plan(line, ts, verbose))
return;
} else {
- test_backspace(ts);
+ if (!verbose)
+ test_backspace(ts);
puts("ABORTED (multiple plans)");
ts->aborted = 1;
ts->reported = 1;
@@ -748,13 +781,14 @@ test_checkline(const char *line, struct testset *ts)
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;
+ current = ts->current + 1;
+ else if (number <= 0) {
+ invalid_test_number(ts, number, verbose);
+ return;
+ } else
+ current = (unsigned long) number;
+ if (current > ts->count && ts->plan == PLAN_FIRST) {
+ invalid_test_number(ts, (long) current, verbose);
return;
}
@@ -783,7 +817,8 @@ test_checkline(const char *line, struct testset *ts)
/* Make sure that the test number is in range and not a duplicate. */
if (ts->results[current - 1] != TEST_INVALID) {
- test_backspace(ts);
+ if (!verbose)
+ test_backspace(ts);
printf("ABORTED (duplicate test number %lu)\n", current);
ts->aborted = 1;
ts->reported = 1;
@@ -799,13 +834,13 @@ test_checkline(const char *line, struct testset *ts)
}
ts->current = current;
ts->results[current - 1] = status;
- if (isatty(STDOUT_FILENO)) {
+ if (!verbose && isatty(STDOUT_FILENO)) {
test_backspace(ts);
if (ts->plan == PLAN_PENDING)
outlen = printf("%lu/?", current);
else
outlen = printf("%lu/%lu", current, ts->count);
- ts->length = (outlen >= 0) ? outlen : 0;
+ ts->length = (outlen >= 0) ? (unsigned int) outlen : 0;
fflush(stdout);
}
}
@@ -821,7 +856,7 @@ test_checkline(const char *line, struct testset *ts)
* disable this).
*/
static unsigned int
-test_print_range(unsigned long first, unsigned long last, unsigned int chars,
+test_print_range(unsigned long first, unsigned long last, unsigned long chars,
unsigned int limit)
{
unsigned int needed = 0;
@@ -991,7 +1026,7 @@ test_analyze(struct testset *ts)
* false otherwise.
*/
static int
-test_run(struct testset *ts)
+test_run(struct testset *ts, enum test_verbose verbose)
{
pid_t testpid, child;
int outfd, status;
@@ -1008,12 +1043,19 @@ test_run(struct testset *ts)
sysdie("fdopen failed");
}
- /* Pass each line of output to test_checkline(). */
- while (!ts->aborted && fgets(buffer, sizeof(buffer), output))
- test_checkline(buffer, ts);
+ /*
+ * Pass each line of output to test_checkline(), and print the line if
+ * verbosity is requested.
+ */
+ while (!ts->aborted && fgets(buffer, sizeof(buffer), output)) {
+ if (verbose)
+ printf("%s", buffer);
+ test_checkline(buffer, ts, verbose);
+ }
if (ferror(output) || ts->plan == PLAN_INIT)
ts->aborted = 1;
- test_backspace(ts);
+ if (!verbose)
+ test_backspace(ts);
/*
* Consume the rest of the test output, close the output descriptor,
@@ -1021,7 +1063,8 @@ test_run(struct testset *ts)
* for eventual output.
*/
while (fgets(buffer, sizeof(buffer), output))
- ;
+ if (verbose)
+ printf("%s", buffer);
fclose(output);
child = waitpid(testpid, &ts->status, 0);
if (child == (pid_t) -1) {
@@ -1129,7 +1172,7 @@ is_valid_test(const char *path)
static char *
find_test(const char *name, const char *source, const char *build)
{
- char *path;
+ char *path = NULL;
const char *bases[3], *suffix, *base;
unsigned int i, j;
const char *suffixes[3] = { "-t", ".t", "" };
@@ -1161,7 +1204,8 @@ find_test(const char *name, const char *source, const char *build)
/*
* Read a list of tests from a file, returning the list of tests as a struct
- * testlist. Reports an error to standard error and exits if the list of
+ * testlist, or NULL if there were no tests (such as a file containing only
+ * comments). Reports an error to standard error and exits if the list of
* tests cannot be read.
*/
static struct testlist *
@@ -1171,6 +1215,7 @@ read_test_list(const char *filename)
unsigned int line;
size_t length;
char buffer[BUFSIZ];
+ const char *testname;
struct testlist *listhead, *current;
/* Create the initial container list that will hold our results. */
@@ -1193,6 +1238,15 @@ read_test_list(const char *filename)
exit(1);
}
buffer[length] = '\0';
+
+ /* Skip comments, leading spaces, and blank lines. */
+ testname = skip_whitespace(buffer);
+ if (strlen(testname) == 0)
+ continue;
+ if (testname[0] == '#')
+ continue;
+
+ /* Allocate the new testset structure. */
if (current == NULL)
current = listhead;
else {
@@ -1201,10 +1255,16 @@ read_test_list(const char *filename)
}
current->ts = xcalloc(1, sizeof(struct testset));
current->ts->plan = PLAN_INIT;
- current->ts->file = xstrdup(buffer);
+ current->ts->file = xstrdup(testname);
}
fclose(file);
+ /* If there were no tests, current is still NULL. */
+ if (current == NULL) {
+ free(listhead);
+ return NULL;
+ }
+
/* Return the results. */
return listhead;
}
@@ -1213,7 +1273,8 @@ read_test_list(const char *filename)
/*
* Build a list of tests from command line arguments. Takes the argv and argc
* representing the command line arguments and returns a newly allocated test
- * list. The caller is responsible for freeing.
+ * list, or NULL if there were no tests. The caller is responsible for
+ * freeing.
*/
static struct testlist *
build_test_list(char *argv[], int argc)
@@ -1238,6 +1299,12 @@ build_test_list(char *argv[], int argc)
current->ts->file = xstrdup(argv[i]);
}
+ /* If there were no tests, current is still NULL. */
+ if (current == NULL) {
+ free(listhead);
+ return NULL;
+ }
+
/* Return the results. */
return listhead;
}
@@ -1263,11 +1330,11 @@ free_testset(struct testset *ts)
* frees the test list that's passed in.
*/
static int
-test_batch(struct testlist *tests, const char *source, const char *build)
+test_batch(struct testlist *tests, const char *source, const char *build,
+ enum test_verbose verbose)
{
- size_t length;
- unsigned int i;
- unsigned int longest = 0;
+ size_t length, i;
+ size_t longest = 0;
unsigned int count = 0;
struct testset *ts;
struct timeval start, end;
@@ -1306,15 +1373,20 @@ test_batch(struct testlist *tests, const char *source, const char *build)
/* Print out the name of the test file. */
fputs(ts->file, stdout);
- for (i = strlen(ts->file); i < longest; i++)
- putchar('.');
+ if (verbose)
+ fputs("\n\n", stdout);
+ else
+ for (i = strlen(ts->file); i < longest; i++)
+ putchar('.');
if (isatty(STDOUT_FILENO))
fflush(stdout);
/* Run the test. */
ts->path = find_test(ts->file, source, build);
- succeeded = test_run(ts);
+ succeeded = test_run(ts, verbose);
fflush(stdout);
+ if (verbose)
+ putchar('\n');
/* Record cumulative statistics. */
aborted += ts->aborted;
@@ -1416,23 +1488,25 @@ main(int argc, char *argv[])
int option;
int status = 0;
int single = 0;
+ enum test_verbose verbose = CONCISE;
char *source_env = NULL;
char *build_env = NULL;
+ const char *program;
const char *shortlist;
const char *list = NULL;
const char *source = SOURCE;
const char *build = BUILD;
struct testlist *tests;
- while ((option = getopt(argc, argv, "b:hl:os:")) != EOF) {
+ program = argv[0];
+ while ((option = getopt(argc, argv, "b:hl:os:v")) != EOF) {
switch (option) {
case 'b':
build = optarg;
break;
case 'h':
- printf(usage_message, argv[0], argv[0], argv[0], usage_extra);
+ printf(usage_message, program, program, program, usage_extra);
exit(0);
- break;
case 'l':
list = optarg;
break;
@@ -1442,6 +1516,9 @@ main(int argc, char *argv[])
case 's':
source = optarg;
break;
+ case 'v':
+ verbose = VERBOSE;
+ break;
default:
exit(1);
}
@@ -1449,10 +1526,17 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
if ((list == NULL && argc < 1) || (list != NULL && argc > 0)) {
- fprintf(stderr, usage_message, argv[0], argv[0], argv[0], usage_extra);
+ fprintf(stderr, usage_message, program, program, program, usage_extra);
exit(1);
}
+ /*
+ * If C_TAP_VERBOSE is set in the environment, that also turns on verbose
+ * mode.
+ */
+ if (getenv("C_TAP_VERBOSE") != NULL)
+ verbose = VERBOSE;
+
/* Set SOURCE and BUILD environment variables. */
if (source != NULL) {
source_env = concat("SOURCE=", source, (const char *) 0);
@@ -1476,10 +1560,10 @@ main(int argc, char *argv[])
shortlist++;
printf(banner, shortlist);
tests = read_test_list(list);
- status = test_batch(tests, source, build) ? 0 : 1;
+ status = test_batch(tests, source, build, verbose) ? 0 : 1;
} else {
tests = build_test_list(argv, argc);
- status = test_batch(tests, source, build) ? 0 : 1;
+ status = test_batch(tests, source, build, verbose) ? 0 : 1;
}
/* For valgrind cleanliness, free all our memory. */
diff --git a/tests/tap/basic.c b/tests/tap/basic.c
index 92a749b..4f8be04 100644
--- a/tests/tap/basic.c
+++ b/tests/tap/basic.c
@@ -12,7 +12,8 @@
* This file is part of C TAP Harness. The current version plus supporting
* documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
- * Copyright 2009, 2010, 2011, 2012, 2013, 2014 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015
+ * Russ Allbery <eagle@eyrie.org>
* Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2013, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
@@ -105,7 +106,7 @@ static struct cleanup_func *cleanup_funcs = NULL;
/*
* Registered diag files. Any output found in these files will be printed out
* as if it were passed to diag() before any other output we do. This allows
- * background processes to log to a file and have that output interleved with
+ * background processes to log to a file and have that output interleaved with
* the test output.
*/
struct diag_file {
@@ -192,7 +193,7 @@ check_diag_files(void)
struct diag_file *file;
fpos_t where;
size_t length;
- int incomplete;
+ int size, incomplete;
/*
* Walk through each file and read each line of output available. The
@@ -216,7 +217,8 @@ check_diag_files(void)
/* Continue until we get EOF or an incomplete line of data. */
incomplete = 0;
while (!feof(file->file) && !incomplete) {
- if (fgets(file->buffer, file->bufsize, file->file) == NULL) {
+ size = file->bufsize > INT_MAX ? INT_MAX : (int) file->bufsize;
+ if (fgets(file->buffer, size, file->file) == NULL) {
if (ferror(file->file))
sysbail("cannot read from %s", file->name);
continue;
@@ -807,7 +809,7 @@ bstrndup(const char *s, size_t n)
/* Don't assume that the source string is nul-terminated. */
for (p = s; (size_t) (p - s) < n && *p != '\0'; p++)
;
- length = p - s;
+ length = (size_t) (p - s);
copy = malloc(length + 1);
if (p == NULL)
sysbail("failed to strndup %lu bytes", (unsigned long) length);
diff --git a/tests/tap/basic.h b/tests/tap/basic.h
index c002df9..4ecaaec 100644
--- a/tests/tap/basic.h
+++ b/tests/tap/basic.h
@@ -4,7 +4,8 @@
* This file is part of C TAP Harness. The current version plus supporting
* documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
- * Copyright 2009, 2010, 2011, 2012, 2013, 2014 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015
+ * Russ Allbery <eagle@eyrie.org>
* Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
@@ -72,7 +73,8 @@ void skip_all(const char *format, ...)
*/
int ok(int success, const char *format, ...)
__attribute__((__format__(printf, 2, 3)));
-int okv(int success, const char *format, va_list args);
+int okv(int success, const char *format, va_list args)
+ __attribute__((__format__(printf, 2, 0)));
void skip(const char *reason, ...)
__attribute__((__format__(printf, 1, 2)));
@@ -155,7 +157,7 @@ void test_tmpdir_free(char *path);
* registered functions will be run during atexit handling (and are therefore
* subject to all the same constraints and caveats as atexit functions).
*
- * The function must return void and will be passed two argument, an int that
+ * The function must return void and will be passed two arguments: an int that
* will be true if the test completed successfully and false otherwise, and an
* int that will be true if the cleanup function is run in the primary process
* (the one that called plan or plan_lazy) and false otherwise.
diff --git a/tests/tap/kerberos.c b/tests/tap/kerberos.c
index 578a858..6a5025a 100644
--- a/tests/tap/kerberos.c
+++ b/tests/tap/kerberos.c
@@ -55,7 +55,9 @@
* Disable the requirement that format strings be literals, since it's easier
* to handle the possible patterns for kinit commands as an array.
*/
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) || defined(__clang__)
+# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
/*
@@ -219,6 +221,8 @@ kerberos_free(void)
free(config->userprinc);
free(config->username);
free(config->password);
+ free(config->pkinit_principal);
+ free(config->pkinit_cert);
free(config);
config = NULL;
}
@@ -351,6 +355,31 @@ kerberos_setup(enum kerberos_needs needs)
test_file_path_free(path);
/*
+ * If we have PKINIT configuration, read it and fill out the relevant
+ * members of our config struct.
+ */
+ path = test_file_path("config/pkinit-principal");
+ if (path != NULL)
+ file = fopen(path, "r");
+ if (file != NULL) {
+ if (fgets(buffer, sizeof(buffer), file) == NULL)
+ bail("cannot read %s", path);
+ if (buffer[strlen(buffer) - 1] != '\n')
+ bail("no newline in %s", path);
+ buffer[strlen(buffer) - 1] = '\0';
+ fclose(file);
+ test_file_path_free(path);
+ path = test_file_path("config/pkinit-cert");
+ if (path != NULL) {
+ config->pkinit_principal = bstrdup(buffer);
+ config->pkinit_cert = bstrdup(path);
+ }
+ }
+ test_file_path_free(path);
+ if (config->pkinit_cert == NULL && (needs & TAP_KRB_NEEDS_PKINIT) != 0)
+ skip_all("PKINIT tests not configured");
+
+ /*
* Register the cleanup function so that the caller doesn't have to do
* explicit cleanup.
*/
diff --git a/tests/tap/kerberos.h b/tests/tap/kerberos.h
index 8be0add..26f45f9 100644
--- a/tests/tap/kerberos.h
+++ b/tests/tap/kerberos.h
@@ -46,17 +46,21 @@ struct kerberos_config {
char *username; /* The local (non-realm) part of principal. */
char *realm; /* The realm part of the principal. */
char *password; /* The password. */
+ char *pkinit_principal; /* Principal for PKINIT authentication. */
+ char *pkinit_cert; /* Path to certificates for PKINIT. */
};
/*
* Whether to skip all tests (by calling skip_all) in kerberos_setup if
- * certain configuration information isn't available.
+ * certain configuration information isn't available. "_BOTH" means that the
+ * tests require both keytab and password, but PKINIT is not required.
*/
enum kerberos_needs {
TAP_KRB_NEEDS_NONE = 0x00,
TAP_KRB_NEEDS_KEYTAB = 0x01,
TAP_KRB_NEEDS_PASSWORD = 0x02,
- TAP_KRB_NEEDS_BOTH = 0x01 | 0x02
+ TAP_KRB_NEEDS_BOTH = 0x01 | 0x02,
+ TAP_KRB_NEEDS_PKINIT = 0x04
};
BEGIN_DECLS
diff --git a/tests/tap/macros.h b/tests/tap/macros.h
index 04cc420..139cff0 100644
--- a/tests/tap/macros.h
+++ b/tests/tap/macros.h
@@ -8,7 +8,7 @@
* This file is part of C TAP Harness. The current version plus supporting
* documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
- * Copyright 2008, 2012, 2013 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2008, 2012, 2013, 2015 Russ Allbery <eagle@eyrie.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -53,8 +53,10 @@
* variadic macro support.
*/
#if !defined(__attribute__) && !defined(__alloc_size__)
-# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
-# define __alloc_size__(spec, args...) /* empty */
+# if defined(__GNUC__) && !defined(__clang__)
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+# define __alloc_size__(spec, args...) /* empty */
+# endif
# endif
#endif
diff --git a/tests/tap/messages.c b/tests/tap/messages.c
index 45b0566..9c28789 100644
--- a/tests/tap/messages.c
+++ b/tests/tap/messages.c
@@ -8,7 +8,7 @@
* The canonical version of this file is maintained in the rra-c-util package,
* which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
*
- * Copyright 2002, 2004, 2005 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2002, 2004, 2005, 2015 Russ Allbery <eagle@eyrie.org>
* Copyright 2006, 2007, 2009, 2012, 2014
* The Board of Trustees of the Leland Stanford Junior University
*
@@ -47,7 +47,7 @@ char *errors = NULL;
* An error handler that appends all errors to the errors global. Used by
* error_capture.
*/
-static void
+static void __attribute__((__format__(printf, 2, 0)))
message_log_buffer(int len UNUSED, const char *fmt, va_list args,
int error UNUSED)
{
diff --git a/tests/tap/perl/Test/RRA.pm b/tests/tap/perl/Test/RRA.pm
index bb7de7d..8608e31 100644
--- a/tests/tap/perl/Test/RRA.pm
+++ b/tests/tap/perl/Test/RRA.pm
@@ -5,31 +5,6 @@
# by both C packages with Automake and by stand-alone Perl modules. See
# Test::RRA::Automake for additional functions specifically for C Automake
# distributions.
-#
-# The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
-#
-# Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2013, 2014
-# 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.
package Test::RRA;
@@ -56,7 +31,7 @@ BEGIN {
# This version should match the corresponding rra-c-util release, but with
# two digits for the minor version, including a leading zero if necessary,
# so that it will sort properly.
- $VERSION = '5.05';
+ $VERSION = '5.10';
}
# Skip this test unless author tests are requested. Takes a short description
@@ -153,7 +128,7 @@ __END__
=for stopwords
Allbery Allbery's DESC bareword sublicense MERCHANTABILITY NONINFRINGEMENT
-rra-c-util
+rra-c-util CPAN
=head1 NAME
@@ -176,46 +151,45 @@ Test::RRA - Support functions for Perl tests
=head1 DESCRIPTION
-This module collects utility functions that are useful for Perl test
-scripts. It assumes Russ Allbery's Perl module layout and test
-conventions and will only be useful for other people if they use the
-same conventions.
+This module collects utility functions that are useful for Perl test scripts.
+It assumes Russ Allbery's Perl module layout and test conventions and will
+only be useful for other people if they use the same conventions.
=head1 FUNCTIONS
-None of these functions are imported by default. The ones used by a
-script should be explicitly imported.
+None of these functions are imported by default. The ones used by a script
+should be explicitly imported.
=over 4
=item skip_unless_author(DESC)
-Checks whether AUTHOR_TESTING is set in the environment and skips the
-whole test (by calling C<plan skip_all> from Test::More) if it is not.
-DESC is a description of the tests being skipped. A space and C<only run
-for author> will be appended to it and used as the skip reason.
+Checks whether AUTHOR_TESTING is set in the environment and skips the whole
+test (by calling C<plan skip_all> from Test::More) if it is not. DESC is a
+description of the tests being skipped. A space and C<only run for author>
+will be appended to it and used as the skip reason.
=item skip_unless_automated(DESC)
-Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are
-set in the environment and skips the whole test (by calling C<plan
-skip_all> from Test::More) if they are not. This should be used by tests
-that should not run during end-user installs of the module, but which
-should run as part of CPAN smoke testing and release testing.
+Checks whether AUTHOR_TESTING, AUTOMATED_TESTING, or RELEASE_TESTING are set
+in the environment and skips the whole test (by calling C<plan skip_all> from
+Test::More) if they are not. This should be used by tests that should not run
+during end-user installs of the module, but which should run as part of CPAN
+smoke testing and release testing.
DESC is a description of the tests being skipped. A space and C<normally
skipped> will be appended to it and used as the skip reason.
=item use_prereq(MODULE[, VERSION][, IMPORT ...])
-Attempts to load MODULE with the given VERSION and import arguments. If
-this fails for any reason, the test will be skipped (by calling C<plan
-skip_all> from Test::More) with a skip reason saying that MODULE is
-required for the test.
+Attempts to load MODULE with the given VERSION and import arguments. If this
+fails for any reason, the test will be skipped (by calling C<plan skip_all>
+from Test::More) with a skip reason saying that MODULE is required for the
+test.
VERSION will be passed to C<use> as a version bareword if it looks like a
-version number. The remaining IMPORT arguments will be passed as the
-value of an array.
+version number. The remaining IMPORT arguments will be passed as the value of
+an array.
=back
@@ -228,33 +202,33 @@ Russ Allbery <eagle@eyrie.org>
Copyright 2013, 2014 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:
+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 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.
+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.
=head1 SEE ALSO
Test::More(3), Test::RRA::Automake(3), Test::RRA::Config(3)
-This module is maintained in the rra-c-util package. The current version
-is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+This module is maintained in the rra-c-util package. The current version is
+available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
-The functions to control when tests are run use environment variables
-defined by the L<Lancaster
+The functions to control when tests are run use environment variables defined
+by the L<Lancaster
Consensus|https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md>.
=cut
diff --git a/tests/tap/perl/Test/RRA/Automake.pm b/tests/tap/perl/Test/RRA/Automake.pm
index a064ed9..c6399ec 100644
--- a/tests/tap/perl/Test/RRA/Automake.pm
+++ b/tests/tap/perl/Test/RRA/Automake.pm
@@ -9,31 +9,6 @@
#
# All the functions here assume that BUILD and SOURCE are set in the
# environment. This is normally done via the C TAP Harness runtests wrapper.
-#
-# The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
-#
-# Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2013
-# 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.
package Test::RRA::Automake;
@@ -87,13 +62,13 @@ BEGIN {
# This version should match the corresponding rra-c-util release, but with
# two digits for the minor version, including a leading zero if necessary,
# so that it will sort properly.
- $VERSION = '5.05';
+ $VERSION = '5.10';
}
# Perl directories to skip globally for perl_dirs. We ignore the perl
# directory if it exists since, in my packages, it is treated as a Perl module
# distribution and has its own standalone test suite.
-my @GLOBAL_SKIP = qw(.git perl);
+my @GLOBAL_SKIP = qw(.git _build perl);
# The temporary directory created by test_tmpdir, if any. If this is set,
# attempt to remove the directory stored here on program exit (but ignore
@@ -126,7 +101,15 @@ sub automake_setup {
my ($vol, $dirs) = File::Spec->splitpath($start, 1);
my @dirs = File::Spec->splitdir($dirs);
pop(@dirs);
- if ($dirs[-1] eq File::Spec->updir) {
+
+ # Simplify relative paths at the end of the directory.
+ my $ups = 0;
+ my $i = $#dirs;
+ while ($i > 2 && $dirs[$i] eq File::Spec->updir) {
+ $ups++;
+ $i--;
+ }
+ for (1 .. $ups) {
pop(@dirs);
pop(@dirs);
}
@@ -196,7 +179,7 @@ sub perl_dirs {
# Build the list of top-level directories to test.
opendir(my $rootdir, q{.}) or BAIL_OUT("cannot open .: $!");
- my @dirs = grep { -d $_ && !$skip{$_} } readdir($rootdir);
+ my @dirs = grep { -d && !$skip{$_} } readdir($rootdir);
closedir($rootdir);
@dirs = File::Spec->no_upwards(@dirs);
@@ -288,8 +271,8 @@ END {
__END__
=for stopwords
-Allbery Automake Automake-aware Automake-based rra-c-util ARGS
-subdirectories sublicense MERCHANTABILITY NONINFRINGEMENT umask
+Allbery Automake Automake-aware Automake-based rra-c-util ARGS subdirectories
+sublicense MERCHANTABILITY NONINFRINGEMENT umask
=head1 NAME
@@ -309,75 +292,71 @@ Test::RRA::Automake - Automake-aware support functions for Perl tests
=head1 DESCRIPTION
This module collects utility functions that are useful for test scripts
-written in Perl and included in a C Automake-based package. They assume
-the layout of a package that uses rra-c-util and C TAP Harness for the
-test structure.
+written in Perl and included in a C Automake-based package. They assume the
+layout of a package that uses rra-c-util and C TAP Harness for the test
+structure.
Loading this module will also add the directories C<perl/blib/arch> and
-C<perl/blib/lib> to the Perl library search path, relative to BUILD if
-that environment variable is set. This is harmless for C Automake
-projects that don't contain an embedded Perl module, and for those
-projects that do, this will allow subsequent C<use> calls to find modules
-that are built as part of the package build process.
+C<perl/blib/lib> to the Perl library search path, relative to BUILD if that
+environment variable is set. This is harmless for C Automake projects that
+don't contain an embedded Perl module, and for those projects that do, this
+will allow subsequent C<use> calls to find modules that are built as part of
+the package build process.
The automake_setup() function should be called before calling any other
functions provided by this module.
=head1 FUNCTIONS
-None of these functions are imported by default. The ones used by a
-script should be explicitly imported. On failure, all of these functions
-call BAIL_OUT (from Test::More).
+None of these functions are imported by default. The ones used by a script
+should be explicitly imported. On failure, all of these functions call
+BAIL_OUT (from Test::More).
=over 4
=item automake_setup([ARGS])
-Verifies that the BUILD and SOURCE environment variables are set and
-then changes directory to the top of the source tree (which is one
-directory up from the SOURCE path, since SOURCE points to the top of
-the tests directory).
+Verifies that the BUILD and SOURCE environment variables are set and then
+changes directory to the top of the source tree (which is one directory up
+from the SOURCE path, since SOURCE points to the top of the tests directory).
-If ARGS is given, it should be a reference to a hash of configuration
-options. Only one option is supported: C<chdir_build>. If it is set
-to a true value, automake_setup() changes directories to the top of
-the build tree instead.
+If ARGS is given, it should be a reference to a hash of configuration options.
+Only one option is supported: C<chdir_build>. If it is set to a true value,
+automake_setup() changes directories to the top of the build tree instead.
=item perl_dirs([ARGS])
Returns a list of directories that may contain Perl scripts that should be
-tested by test scripts that test all Perl in the source tree (such as
-syntax or coding style checks). The paths will be simple directory names
-relative to the current directory or two-part directory names under the
-F<tests> directory. (Directories under F<tests> are broken out separately
-since it's common to want to apply different policies to different
-subdirectories of F<tests>.)
-
-If ARGS is given, it should be a reference to a hash of configuration
-options. Only one option is supported: C<skip>, whose value should be a
-reference to an array of additional top-level directories or directories
-starting with C<tests/> that should be skipped.
+tested by test scripts that test all Perl in the source tree (such as syntax
+or coding style checks). The paths will be simple directory names relative to
+the current directory or two-part directory names under the F<tests>
+directory. (Directories under F<tests> are broken out separately since it's
+common to want to apply different policies to different subdirectories of
+F<tests>.)
+
+If ARGS is given, it should be a reference to a hash of configuration options.
+Only one option is supported: C<skip>, whose value should be a reference to an
+array of additional top-level directories or directories starting with
+C<tests/> that should be skipped.
=item test_file_path(FILE)
-Given FILE, which should be a relative path, locates that file relative to
-the test directory in either the source or build tree. FILE will be
-checked for relative to the environment variable BUILD first, and then
-relative to SOURCE. test_file_path() returns the full path to FILE or
-calls BAIL_OUT if FILE could not be found.
+Given FILE, which should be a relative path, locates that file relative to the
+test directory in either the source or build tree. FILE will be checked for
+relative to the environment variable BUILD first, and then relative to SOURCE.
+test_file_path() returns the full path to FILE or calls BAIL_OUT if FILE could
+not be found.
=item test_tmpdir()
-Create a temporary directory for tests to use for transient files and
-return the path to that directory. The directory is created relative to
-the BUILD environment variable, which must be set. Permissions on the
-directory are set using the current umask. test_tmpdir() returns the full
-path to the temporary directory or calls BAIL_OUT if it could not be
-created.
+Create a temporary directory for tests to use for transient files and return
+the path to that directory. The directory is created relative to the BUILD
+environment variable, which must be set. Permissions on the directory are set
+using the current umask. test_tmpdir() returns the full path to the temporary
+directory or calls BAIL_OUT if it could not be created.
-The directory is automatically removed if possible on program exit.
-Failure to remove the directory on exit is reported with diag() and
-otherwise ignored.
+The directory is automatically removed if possible on program exit. Failure
+to remove the directory on exit is reported with diag() and otherwise ignored.
=back
@@ -387,35 +366,36 @@ Russ Allbery <eagle@eyrie.org>
=head1 COPYRIGHT AND LICENSE
-Copyright 2013 The Board of Trustees of the Leland Stanford Junior
-University
+Copyright 2014, 2015 Russ Allbery <eagle@eyrie.org>
+
+Copyright 2013 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:
+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 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.
+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.
=head1 SEE ALSO
Test::More(3), Test::RRA(3), Test::RRA::Config(3)
+This module is maintained in the rra-c-util package. The current version is
+available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+
The C TAP Harness test driver and libraries for TAP-based C testing are
available from L<http://www.eyrie.org/~eagle/software/c-tap-harness/>.
-This module is maintained in the rra-c-util package. The current version
-is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
-
=cut
diff --git a/tests/tap/perl/Test/RRA/Config.pm b/tests/tap/perl/Test/RRA/Config.pm
index 3e77650..a5b0d0d 100644
--- a/tests/tap/perl/Test/RRA/Config.pm
+++ b/tests/tap/perl/Test/RRA/Config.pm
@@ -4,9 +4,6 @@
# configuration file to store some package-specific data. This module loads
# that configuration and provides the namespace for the configuration
# settings.
-#
-# The canonical version of this file is maintained in the rra-c-util package,
-# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
package Test::RRA::Config;
@@ -30,22 +27,23 @@ BEGIN {
@ISA = qw(Exporter);
@EXPORT_OK = qw(
$COVERAGE_LEVEL @COVERAGE_SKIP_TESTS @CRITIC_IGNORE $LIBRARY_PATH
- $MINIMUM_VERSION %MINIMUM_VERSION @POD_COVERAGE_EXCLUDE @STRICT_IGNORE
- @STRICT_PREREQ
+ $MINIMUM_VERSION %MINIMUM_VERSION @MODULE_VERSION_IGNORE
+ @POD_COVERAGE_EXCLUDE @STRICT_IGNORE @STRICT_PREREQ
);
# This version should match the corresponding rra-c-util release, but with
# two digits for the minor version, including a leading zero if necessary,
# so that it will sort properly.
- $VERSION = '5.05';
+ $VERSION = '5.10';
}
# If BUILD or SOURCE are set in the environment, look for data/perl.conf under
# those paths for a C Automake package. Otherwise, look in t/data/perl.conf
-# for a standalone Perl module. Don't use Test::RRA::Automake since it may
-# not exist.
+# for a standalone Perl module or tests/data/perl.conf for Perl tests embedded
+# in a larger distribution. Don't use Test::RRA::Automake since it may not
+# exist.
our $PATH;
-for my $base ($ENV{BUILD}, $ENV{SOURCE}, 't') {
+for my $base ($ENV{BUILD}, $ENV{SOURCE}, 't', 'tests') {
next if !defined($base);
my $path = "$base/data/perl.conf";
if (-r $path) {
@@ -64,6 +62,7 @@ our @CRITIC_IGNORE;
our $LIBRARY_PATH;
our $MINIMUM_VERSION = '5.008';
our %MINIMUM_VERSION;
+our @MODULE_VERSION_IGNORE;
our @POD_COVERAGE_EXCLUDE;
our @STRICT_IGNORE;
our @STRICT_PREREQ;
@@ -78,8 +77,8 @@ if (!do($PATH)) {
__END__
=for stopwords
-Allbery rra-c-util Automake perlcritic .libs namespace subdirectory
-sublicense MERCHANTABILITY NONINFRINGEMENT
+Allbery rra-c-util Automake perlcritic .libs namespace subdirectory sublicense
+MERCHANTABILITY NONINFRINGEMENT regexes
=head1 NAME
@@ -92,19 +91,17 @@ Test::RRA::Config - Perl test configuration
=head1 DESCRIPTION
-Test::RRA::Config encapsulates per-package configuration for generic Perl
-test programs that are shared between multiple packages using the
-rra-c-util infrastructure. It handles locating and loading the test
-configuration file for both C Automake packages and stand-alone Perl
-modules.
+Test::RRA::Config encapsulates per-package configuration for generic Perl test
+programs that are shared between multiple packages using the rra-c-util
+infrastructure. It handles locating and loading the test configuration file
+for both C Automake packages and stand-alone Perl modules.
Test::RRA::Config looks for a file named F<data/perl.conf> relative to the
-root of the test directory. That root is taken from the environment
-variables BUILD or SOURCE (in that order) if set, which will be the case
-for C Automake packages using C TAP Harness. If neither is set, it
-expects the root of the test directory to be a directory named F<t>
-relative to the current directory, which will be the case for stand-alone
-Perl modules.
+root of the test directory. That root is taken from the environment variables
+BUILD or SOURCE (in that order) if set, which will be the case for C Automake
+packages using C TAP Harness. If neither is set, it expects the root of the
+test directory to be a directory named F<t> relative to the current directory,
+which will be the case for stand-alone Perl modules.
The following variables are supported:
@@ -112,70 +109,75 @@ The following variables are supported:
=item $COVERAGE_LEVEL
-The coverage level achieved by the test suite for Perl test coverage
-testing using Test::Strict, as a percentage. The test will fail if test
-coverage less than this percentage is achieved. If not given, defaults
-to 100.
+The coverage level achieved by the test suite for Perl test coverage testing
+using Test::Strict, as a percentage. The test will fail if test coverage less
+than this percentage is achieved. If not given, defaults to 100.
=item @COVERAGE_SKIP_TESTS
Directories under F<t> whose tests should be skipped when doing coverage
-testing. This can be tests that won't contribute to coverage or tests
-that don't run properly under Devel::Cover for some reason (such as ones
-that use taint checking). F<docs> and F<style> will always be skipped
-regardless of this setting.
+testing. This can be tests that won't contribute to coverage or tests that
+don't run properly under Devel::Cover for some reason (such as ones that use
+taint checking). F<docs> and F<style> will always be skipped regardless of
+this setting.
=item @CRITIC_IGNORE
-Additional directories to ignore when doing recursive perlcritic testing.
-The contents of this directory must be either top-level directory names or
+Additional directories to ignore when doing recursive perlcritic testing. The
+contents of this directory must be either top-level directory names or
directory names starting with F<tests/>.
=item $LIBRARY_PATH
Add this directory (or a F<.libs> subdirectory) relative to the top of the
-source tree to LD_LIBRARY_PATH when checking the syntax of Perl modules.
-This may be required to pick up libraries that are used by in-tree Perl
-modules so that Perl scripts can pass a syntax check.
+source tree to LD_LIBRARY_PATH when checking the syntax of Perl modules. This
+may be required to pick up libraries that are used by in-tree Perl modules so
+that Perl scripts can pass a syntax check.
=item $MINIMUM_VERSION
-Default minimum version requirement for included Perl scripts. If not
-given, defaults to 5.008.
+Default minimum version requirement for included Perl scripts. If not given,
+defaults to 5.008.
=item %MINIMUM_VERSION
Minimum version exceptions for specific directories. The keys should be
minimum versions of Perl to enforce. The value for each key should be a
-reference to an array of either top-level directory names or directory
-names starting with F<tests/>. All files in those directories will have
-that minimum Perl version constraint imposed instead of $MINIMUM_VERSION.
+reference to an array of either top-level directory names or directory names
+starting with F<tests/>. All files in those directories will have that
+minimum Perl version constraint imposed instead of $MINIMUM_VERSION.
+
+=item @MODULE_VERSION_IGNORE
+
+File names to ignore when checking that all modules in a distribution have the
+same version. Sometimes, some specific modules need separate, special version
+handling, such as modules defining database schemata for DBIx::Class, and
+can't follow the version of the larger package.
=item @POD_COVERAGE_EXCLUDE
Regexes that match method names that should be excluded from POD coverage
-testing. Normally, all methods have to be documented in the POD for a
-Perl module, but methods matching any of these regexes will be considered
-private and won't require documentation.
+testing. Normally, all methods have to be documented in the POD for a Perl
+module, but methods matching any of these regexes will be considered private
+and won't require documentation.
=item @STRICT_IGNORE
-Additional directories to ignore when doing recursive Test::Strict testing
-for C<use strict> and C<use warnings>. The contents of this directory
-must be either top-level directory names or directory names starting with
-F<tests/>.
+Additional directories to ignore when doing recursive Test::Strict testing for
+C<use strict> and C<use warnings>. The contents of this directory must be
+either top-level directory names or directory names starting with F<tests/>.
=item @STRICT_PREREQ
A list of Perl modules that have to be available in order to do meaningful
Test::Strict testing. If any of the modules cannot be loaded via C<use>,
-Test::Strict checking will be skipped. There is currently no way to
-require specific versions of the modules.
+Test::Strict checking will be skipped. There is currently no way to require
+specific versions of the modules.
=back
-No variables are exported by default, but the variables can be imported
-into the local namespace to avoid long variable names.
+No variables are exported by default, but the variables can be imported into
+the local namespace to avoid long variable names.
=head1 AUTHOR
@@ -186,31 +188,31 @@ Russ Allbery <eagle@eyrie.org>
Copyright 2013, 2014 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:
+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 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.
+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.
=head1 SEE ALSO
-perlcritic(1), Test::MinimumVersion(3), Test::RRA(3),
-Test::RRA::Automake(3), Test::Strict(3)
+perlcritic(1), Test::MinimumVersion(3), Test::RRA(3), Test::RRA::Automake(3),
+Test::Strict(3)
-This module is maintained in the rra-c-util package. The current version
-is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+This module is maintained in the rra-c-util package. The current version is
+available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
The C TAP Harness test driver and libraries for TAP-based C testing are
available from L<http://www.eyrie.org/~eagle/software/c-tap-harness/>.
diff --git a/tests/tap/perl/Test/RRA/ModuleVersion.pm b/tests/tap/perl/Test/RRA/ModuleVersion.pm
new file mode 100644
index 0000000..f02877a
--- /dev/null
+++ b/tests/tap/perl/Test/RRA/ModuleVersion.pm
@@ -0,0 +1,295 @@
+# Check Perl module versions for consistency.
+#
+# This module contains the common code for testing and updating Perl module
+# versions for consistency within a Perl module distribution and within a
+# larger package that contains both Perl modules and other code.
+
+package Test::RRA::ModuleVersion;
+
+use 5.006;
+use strict;
+use warnings;
+
+use Exporter;
+use File::Find qw(find);
+use Test::More;
+use Test::RRA::Config qw(@MODULE_VERSION_IGNORE);
+
+# For Perl 5.006 compatibility.
+## no critic (ClassHierarchies::ProhibitExplicitISA)
+
+# Declare variables that should be set in BEGIN for robustness.
+our (@EXPORT_OK, @ISA, $VERSION);
+
+# Set $VERSION and everything export-related in a BEGIN block for robustness
+# against circular module loading (not that we load any modules, but
+# consistency is good).
+BEGIN {
+ @ISA = qw(Exporter);
+ @EXPORT_OK = qw(test_module_versions update_module_versions);
+
+ # This version should match the corresponding rra-c-util release, but with
+ # two digits for the minor version, including a leading zero if necessary,
+ # so that it will sort properly.
+ $VERSION = '5.10';
+}
+
+# A regular expression matching the version string for a module using the
+# package syntax from Perl 5.12 and later. $1 will contain all of the line
+# contents prior to the actual version string, $2 will contain the version
+# itself, and $3 will contain the rest of the line.
+our $REGEX_VERSION_PACKAGE = qr{
+ ( # prefix ($1)
+ \A \s* # whitespace
+ package \s+ # package keyword
+ [\w\:\']+ \s+ # package name
+ )
+ ( v? [\d._]+ ) # the version number itself ($2)
+ ( # suffix ($3)
+ \s* ;
+ )
+}xms;
+
+# A regular expression matching a $VERSION string in a module. $1 will
+# contain all of the line contents prior to the actual version string, $2 will
+# contain the version itself, and $3 will contain the rest of the line.
+our $REGEX_VERSION_OLD = qr{
+ ( # prefix ($1)
+ \A .* # any prefix, such as "our"
+ [\$*] # scalar or typeglob
+ [\w\:\']*\b # optional package name
+ VERSION\b # version variable
+ \s* = \s* # assignment
+ )
+ [\"\']? # optional leading quote
+ ( v? [\d._]+ ) # the version number itself ($2)
+ [\"\']? # optional trailing quote
+ ( # suffix ($3)
+ \s*
+ ;
+ )
+}xms;
+
+# Find all the Perl modules shipped in this package, if any, and returns the
+# list of file names.
+#
+# $dir - The root directory to search
+#
+# Returns: List of file names
+sub _module_files {
+ my ($dir) = @_;
+ return if !-d $dir;
+ my @files;
+ my %ignore = map { $_ => 1 } @MODULE_VERSION_IGNORE;
+ my $wanted = sub {
+ if ($_ eq 'blib') {
+ $File::Find::prune = 1;
+ return;
+ }
+ if (m{ [.] pm \z }xms && !$ignore{$File::Find::name}) {
+ push(@files, $File::Find::name);
+ }
+ return;
+ };
+ find($wanted, $dir);
+ return @files;
+}
+
+# Given a module file, read it for the version value and return the value.
+#
+# $file - File to check, which should be a Perl module
+#
+# Returns: The version of the module
+# Throws: Text exception on I/O failure or inability to find version
+sub _module_version {
+ my ($file) = @_;
+ open(my $data, q{<}, $file) or die "$0: cannot open $file: $!\n";
+ while (defined(my $line = <$data>)) {
+ if ( $line =~ $REGEX_VERSION_PACKAGE
+ || $line =~ $REGEX_VERSION_OLD)
+ {
+ my ($prefix, $version, $suffix) = ($1, $2, $3);
+ close($data) or die "$0: error reading from $file: $!\n";
+ return $version;
+ }
+ }
+ close($data) or die "$0: error reading from $file: $!\n";
+ die "$0: cannot find version number in $file\n";
+}
+
+# Given a module file and the new version for that module, update the version
+# in that module to the new one.
+#
+# $file - Perl module file whose version should be updated
+# $version - The new version number
+#
+# Returns: undef
+# Throws: Text exception on I/O failure or inability to find version
+sub _update_module_version {
+ my ($file, $version) = @_;
+ open(my $in, q{<}, $file) or die "$0: cannot open $file: $!\n";
+ open(my $out, q{>}, "$file.new")
+ or die "$0: cannot create $file.new: $!\n";
+
+ # If the version starts with v, use it without quotes. Otherwise, quote
+ # it to prevent removal of trailing zeroes.
+ if ($version !~ m{ \A v }xms) {
+ $version = "'$version'";
+ }
+
+ # Scan for the version and replace it.
+ SCAN:
+ while (defined(my $line = <$in>)) {
+ if ( $line =~ s{ $REGEX_VERSION_PACKAGE }{$1$version$3}xms
+ || $line =~ s{ $REGEX_VERSION_OLD }{$1$version$3}xms)
+ {
+ print {$out} $line or die "$0: cannot write to $file.new: $!\n";
+ last SCAN;
+ }
+ print {$out} $line or die "$0: cannot write to $file.new: $!\n";
+ }
+
+ # Copy the rest of the input file to the output file.
+ print {$out} <$in> or die "$0: cannot write to $file.new: $!\n";
+ close($out) or die "$0: cannot flush $file.new: $!\n";
+ close($in) or die "$0: error reading from $file: $!\n";
+
+ # All done. Rename the new file over top of the old file.
+ rename("$file.new", $file)
+ or die "$0: cannot rename $file.new to $file: $!\n";
+ return;
+}
+
+# Act as a test suite. Find all of the Perl modules under the provided root,
+# if any, and check that the version for each module matches the version.
+# Reports results with Test::More and sets up a plan based on the number of
+# modules found.
+#
+# $root - Directory under which to look for Perl modules
+# $version - The version all those modules should have
+#
+# Returns: undef
+# Throws: Text exception on fatal errors
+sub test_module_versions {
+ my ($root, $version) = @_;
+ my @modules = _module_files($root);
+
+ # Output the plan. Skip the test if there were no modules found.
+ if (@modules) {
+ plan tests => scalar(@modules);
+ } else {
+ plan skip_all => 'No Perl modules found';
+ return;
+ }
+
+ # For each module, get the module version and compare.
+ for my $module (@modules) {
+ my $module_version = _module_version($module);
+ is($module_version, $version, "Version for $module");
+ }
+ return;
+}
+
+# Update the versions of all modules to the current distribution version.
+#
+# $root - Directory under which to look for Perl modules
+# $version - The version all those modules should have
+#
+# Returns: undef
+# Throws: Text exception on fatal errors
+sub update_module_versions {
+ my ($root, $version) = @_;
+ my @modules = _module_files($root);
+ for my $module (@modules) {
+ _update_module_version($module, $version);
+ }
+ return;
+}
+
+1;
+__END__
+
+=for stopwords
+Allbery sublicense MERCHANTABILITY NONINFRINGEMENT rra-c-util versioning
+
+=head1 NAME
+
+Test::RRA::ModuleVersion - Check Perl module versions for consistency
+
+=head1 SYNOPSIS
+
+ use Test::RRA::ModuleVersion
+ qw(test_module_versions update_module_versions);
+
+ # Ensure all modules under perl/lib have a version of 3.12.
+ test_module_versions('perl/lib', '3.12');
+
+ # Update the version of those modules to 3.12.
+ update_module_versions('perl/lib', 3.12');
+
+=head1 DESCRIPTION
+
+This module provides functions to test and update the versions of Perl
+modules. It helps with enforcing consistency of versioning across all modules
+in a Perl distribution or embedded in a larger project containing non-Perl
+code. The calling script provides the version with which to be consistent
+and the root directory under which modules are found.
+
+=head1 FUNCTIONS
+
+None of these functions are imported by default. The ones used by a script
+should be explicitly imported.
+
+=over 4
+
+=item test_module_versions(ROOT, VERSION)
+
+Tests the version of all Perl modules under ROOT to ensure they match VERSION,
+reporting the results with Test::More. If the test configuration loaded by
+Test::RRA::Config contains a @MODULE_VERSION_EXCLUDE variable, the module
+files listed there will be ignored for this test. This function also sets up
+a plan based on the number of modules, so should be the only testing function
+called in a test script.
+
+=item update_module_versions(ROOT, VERSION)
+
+Update the version of all Perl modules found under ROOT to VERSION, except for
+any listed in a @MODULE_VERSION_EXCLUDE variable set in the test configuration
+loaded by Test::RRA::Config.
+
+=back
+
+=head1 AUTHOR
+
+Russ Allbery <eagle@eyrie.org>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2016 Russ Allbery <eagle@eyrie.org>
+
+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.
+
+=head1 SEE ALSO
+
+Test::More(3), Test::RRA::Config(3)
+
+This module is maintained in the rra-c-util package. The current version
+is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>.
+
+=cut
diff --git a/tests/tap/process.c b/tests/tap/process.c
index 6461fb4..8c22324 100644
--- a/tests/tap/process.c
+++ b/tests/tap/process.c
@@ -47,8 +47,11 @@
# include <sys/select.h>
#endif
#include <sys/stat.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
#include <sys/wait.h>
+#include <time.h>
#include <tests/tap/basic.h>
#include <tests/tap/process.h>
@@ -229,6 +232,10 @@ process_free(struct process *process)
{
struct process **prev;
+ /* Do nothing if called with a NULL argument. */
+ if (process == NULL)
+ return;
+
/* Remove the process from the global list. */
prev = &processes;
while (*prev != NULL && *prev != process)
diff --git a/tests/tap/string.h b/tests/tap/string.h
index cc51945..d58f75d 100644
--- a/tests/tap/string.h
+++ b/tests/tap/string.h
@@ -42,7 +42,7 @@ BEGIN_DECLS
void basprintf(char **, const char *, ...)
__attribute__((__nonnull__, __format__(printf, 2, 3)));
void bvasprintf(char **, const char *, va_list)
- __attribute__((__nonnull__));
+ __attribute__((__nonnull__, __format__(printf, 2, 0)));
END_DECLS
diff --git a/tests/util/messages-t.c b/tests/util/messages-t.c
index f60fa6a..1098314 100644
--- a/tests/util/messages-t.c
+++ b/tests/util/messages-t.c
@@ -5,7 +5,7 @@
* which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
*
* Written by Russ Allbery <eagle@eyrie.org>
- * Copyright 2002, 2004, 2005 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2002, 2004, 2005, 2015 Russ Allbery <eagle@eyrie.org>
* Copyright 2009, 2010, 2011, 2012
* The Board of Trustees of the Leland Stanford Junior University
*
@@ -92,7 +92,8 @@ static void test11(void *data UNUSED) {
sysdie("fatal");
}
-static void log_msg(size_t len, const char *format, va_list args, int error) {
+static void __attribute__((__format__(printf, 2, 0)))
+log_msg(size_t len, const char *format, va_list args, int error) {
fprintf(stderr, "%lu %d ", (unsigned long) len, error);
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
diff --git a/tests/util/xmalloc-t b/tests/util/xmalloc-t
index d52c448..af604ed 100755
--- a/tests/util/xmalloc-t
+++ b/tests/util/xmalloc-t
@@ -99,46 +99,46 @@ ok_xmalloc "vasprintf large" 0 "" "v" "30000000" "0"
# We assume that there are enough miscellaneous allocations that an allocation
# exactly as large as the limit will always fail.
ok_xmalloc "malloc fail" 1 \
- "failed to malloc 30000000 bytes at xmalloc.c line 38" \
+ "failed to malloc 30000000 bytes at xmalloc.c line 41" \
"m" "30000000" "30000000"
ok_xmalloc "realloc fail" 1 \
- "failed to realloc 30000000 bytes at xmalloc.c line 66" \
+ "failed to realloc 30000000 bytes at xmalloc.c line 69" \
"r" "30000000" "30000000"
ok_xmalloc "reallocarray fail" 1 \
- "failed to reallocarray 30000000 bytes at xmalloc.c line 96" \
+ "failed to reallocarray 30000000 bytes at xmalloc.c line 99" \
"y" "30000000" "30000000"
ok_xmalloc "strdup fail" 1 \
- "failed to strdup 30000000 bytes at xmalloc.c line 127" \
+ "failed to strdup 30000000 bytes at xmalloc.c line 130" \
"s" "30000000" "30000000"
ok_xmalloc "strndup fail" 1 \
- "failed to strndup 30000000 bytes at xmalloc.c line 173" \
+ "failed to strndup 30000000 bytes at xmalloc.c line 176" \
"n" "30000000" "30000000"
ok_xmalloc "calloc fail" 1 \
- "failed to calloc 30000000 bytes at xmalloc.c line 197" \
+ "failed to calloc 30000000 bytes at xmalloc.c line 200" \
"c" "30000000" "30000000"
ok_xmalloc "asprintf fail" 1 \
- "failed to asprintf 30000000 bytes at xmalloc.c line 221" \
+ "failed to asprintf 30000000 bytes at xmalloc.c line 224" \
"a" "30000000" "30000000"
ok_xmalloc "vasprintf fail" 1 \
- "failed to vasprintf 30000000 bytes at xmalloc.c line 240" \
+ "failed to vasprintf 30000000 bytes at xmalloc.c line 243" \
"v" "30000000" "30000000"
# Check our custom error handler.
-ok_xmalloc "malloc custom" 1 "malloc 30000000 xmalloc.c 38" \
+ok_xmalloc "malloc custom" 1 "malloc 30000000 xmalloc.c 41" \
"M" "30000000" "30000000"
-ok_xmalloc "realloc custom" 1 "realloc 30000000 xmalloc.c 66" \
+ok_xmalloc "realloc custom" 1 "realloc 30000000 xmalloc.c 69" \
"R" "30000000" "30000000"
-ok_xmalloc "reallocarray custom" 1 "reallocarray 30000000 xmalloc.c 96" \
+ok_xmalloc "reallocarray custom" 1 "reallocarray 30000000 xmalloc.c 99" \
"Y" "30000000" "30000000"
-ok_xmalloc "strdup custom" 1 "strdup 30000000 xmalloc.c 127" \
+ok_xmalloc "strdup custom" 1 "strdup 30000000 xmalloc.c 130" \
"S" "30000000" "30000000"
-ok_xmalloc "strndup custom" 1 "strndup 30000000 xmalloc.c 173" \
+ok_xmalloc "strndup custom" 1 "strndup 30000000 xmalloc.c 176" \
"N" "30000000" "30000000"
-ok_xmalloc "calloc custom" 1 "calloc 30000000 xmalloc.c 197" \
+ok_xmalloc "calloc custom" 1 "calloc 30000000 xmalloc.c 200" \
"C" "30000000" "30000000"
-ok_xmalloc "asprintf custom" 1 "asprintf 30000000 xmalloc.c 221" \
+ok_xmalloc "asprintf custom" 1 "asprintf 30000000 xmalloc.c 224" \
"A" "30000000" "30000000"
-ok_xmalloc "vasprintf custom" 1 "vasprintf 30000000 xmalloc.c 240" \
+ok_xmalloc "vasprintf custom" 1 "vasprintf 30000000 xmalloc.c 243" \
"V" "30000000" "30000000"
# Check the smaller ones again just for grins.
diff --git a/tests/util/xmalloc.c b/tests/util/xmalloc.c
index e222612..84ba081 100644
--- a/tests/util/xmalloc.c
+++ b/tests/util/xmalloc.c
@@ -34,7 +34,10 @@
#include <ctype.h>
#include <errno.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <time.h>
/* Linux requires sys/time.h be included before sys/resource.h. */
#include <sys/resource.h>
@@ -261,7 +264,7 @@ test_asprintf(size_t size)
/* Wrapper around vasprintf to do the va_list stuff. */
-static void
+static void __attribute__((__format__(printf, 2, 3)))
xvasprintf_wrapper(char **strp, const char *format, ...)
{
va_list args;