]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Reimplement the tests similarly to libpcap. [skip appveyor] 1280/head
authorDenis Ovsienko <[email protected]>
Fri, 7 Feb 2025 11:52:39 +0000 (11:52 +0000)
committerDenis Ovsienko <[email protected]>
Fri, 7 Feb 2025 11:52:39 +0000 (11:52 +0000)
Import TESTlib.pm, TESTst.pm and TESTmt.pm from libpcap.  In TESTrun use
strict and warnings, also address all Perl issues that manifest because
of that, remove old code that the imported files make redundant and
clean the rest up.  Ibid., remove the core dump file before every test
and apply the "only this one test" mode even if the test does not come
from the TESTLIST file; focus on tcpdump specifics and have the imported
files handle all test/result logistics.

The latter among other things places all temporary test files in a
proper temporary directory rather than the source tree, which in turn
eliminates the tests/NEW and tests/DIFF temporary directories, which
also includes *.out.raw.stderr files; the .passed and .failed files have
been gone since commit b82970c in 2020.  This way, the tests/.gitignore
file no longer has a purpose, so remove it and the associated exemption
for TEST_DIST in Makefile.  Remove failure-outputs.txt from the
top-level .gitignore as well.  Prune "make distclean" as well.

Merge tests/*.tests into TESTrun: these are a part of the source tree
rather than volatile external data, so instead of implementing the
required run-time logistics just place the Perl data structures in the
only Perl script that uses them.  Convert "config_set" and
"config_unset" using "skip" and equivalent Perl expressions.

Since these changes rewrite most of TESTrun, reindent and reformat it to
match the code style of the new files.

14 files changed:
.gitignore
CHANGES
Makefile.in
tests/.gitignore [deleted file]
tests/TESTlib.pm [new file with mode: 0644]
tests/TESTmt.pm [new file with mode: 0644]
tests/TESTrun
tests/TESTst.pm [new file with mode: 0644]
tests/crypto.tests [deleted file]
tests/isis-seg-fault-1-v.tests [deleted file]
tests/lmp-v.tests [deleted file]
tests/non-bsd.tests [deleted file]
tests/smb.tests [deleted file]
tests/time.tests [deleted file]

index 66a3a83e860e524a99788a44b4a172ee9dd8bfe1..e9ba5c7be2fdb8b88dc1e002d7247ea4cf3876bb 100644 (file)
@@ -22,7 +22,6 @@
 /tcpdump
 /tcpdump.1
 /tcpdump-*.tar.gz
-failure-outputs.txt
 /autom4te.cache/
 *.VC.db
 *.VC.opendb
diff --git a/CHANGES b/CHANGES
index 7349617bde63739287a08c222af833320de1511d..4749af81fe9fe73e43c33d83cc8f17792820039f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -80,6 +80,7 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
       tests: On HP-UX use "diff -c" by default.
       autogen.sh: Allow to configure Autoconf warnings.
       autogen.sh: Delete all trailing blank lines at end of configure.
+      Reimplement the tests similarly to libpcap.
     Documentation:
       man: Clarify the "any" pseudo-interface further.
 
index bd2b80bcfe3ca89436bb42cc5b860218924c581e..72f557e9947e1d1f7685eee2c9d9f5bc329621dc 100644 (file)
@@ -373,7 +373,7 @@ EXTRA_DIST = \
        stime.awk \
        tcpdump.1.in
 
-TEST_DIST= `git -C "$$DIR" ls-files tests | grep -v 'tests/\..*'`
+TEST_DIST= `git -C "$$DIR" ls-files tests`
 
 RELEASE_FILES = $(CSRC) $(HDR) $(LIBNETDISSECT_SRC) $(EXTRA_DIST) $(TEST_DIST)
 
@@ -425,9 +425,8 @@ clean:
 distclean: clean
        rm -f Makefile config.cache config.log config.status \
            config.h os-proto.h stamp-h stamp-h.in $(PROG).1 \
-           libnetdissect.a tests/.failed tests/.passed \
-           tests/failure-outputs.txt
-       rm -rf autom4te.cache tests/DIFF tests/NEW
+           libnetdissect.a
+       rm -rf autom4te.cache
 
 check: tcpdump
        $(srcdir)/tests/TESTrun
diff --git a/tests/.gitignore b/tests/.gitignore
deleted file mode 100644 (file)
index 543951f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-.failed
-.passed
-DIFF
-NEW
-*.out.raw.stderr
diff --git a/tests/TESTlib.pm b/tests/TESTlib.pm
new file mode 100644 (file)
index 0000000..b35c07e
--- /dev/null
@@ -0,0 +1,284 @@
+require 5.8.4; # Solaris 10
+use strict;
+use warnings FATAL => qw(uninitialized);
+use Config;
+use File::Temp qw(tempdir);
+
+# TESTrun helper functions (common to all projects).
+
+# TESTst.pm or TESTmt.pm
+use subs qw(
+       get_next_result
+       my_tmp_id
+       start_tests
+);
+
+# The characters are inspired by PHPUnit format, but are not exactly the same.
+use constant {
+       CHAR_SKIPPED => 'S',
+       CHAR_PASSED => '.',
+       CHAR_FAILED => 'F',
+       CHAR_TIMED_OUT => 'T',
+};
+
+my $results_to_print;
+my $results_printed;
+my $max_result_digits;
+my $max_results_per_line;
+my $flush_after_newline;
+my $tmpdir;
+my %config;
+
+sub init_tmpdir {
+       my $prefix = shift;
+       # No File::Temp->newdir() in Perl 5.8.4.
+       $tmpdir = tempdir (
+               "${prefix}_XXXXXXXX",
+               TMPDIR => 1,
+               CLEANUP => 1
+       );
+}
+
+sub mytmpfile {
+       return sprintf '%s/%s-%s', $tmpdir, my_tmp_id, shift;
+}
+
+sub get_njobs {
+       my $njobs;
+       if (! defined $ENV{TESTRUN_JOBS}) {
+               $njobs = 1;
+       } elsif ($ENV{TESTRUN_JOBS} =~ /^\d+\z/) {
+               $njobs = int ($ENV{TESTRUN_JOBS});
+       } else {
+               $njobs = 0;
+       }
+       die "ERROR: '$ENV{TESTRUN_JOBS}' is not a valid value for TESTRUN_JOBS" if ! $njobs;
+       return $njobs;
+}
+
+sub get_diff_flags {
+       return defined $ENV{DIFF_FLAGS} ? $ENV{DIFF_FLAGS} :
+       $^O eq 'hpux' ? '-c' :
+       '-u';
+}
+
+# Parse config.h into a hash for later use.
+sub read_config_h {
+       my $config_h = shift;
+       %config = {};
+       my $re_define_uint = qr/^#define ([0-9_A-Z]+) ([0-9]+)$/;
+       my $re_define_str = qr/^#define ([0-9_A-Z]+) "(.+)"$/;
+       open (my $fh, '<', $config_h) || die "failed opening '$config_h'";
+       while (<$fh>) {
+               $config{$1} = $2 if /$re_define_uint/o || /$re_define_str/o;
+       }
+       close ($fh) || die "failed closing '$config_h'";
+}
+
+# This is a simpler version of the PHP function.
+sub file_put_contents {
+       my ($filename, $contents) = @_;
+       open (my $fh, '>', $filename) || die "failed opening '$filename'";
+       print $fh $contents;
+       close ($fh) || die "failed closing '$filename'";
+}
+
+# Idem.
+sub file_get_contents {
+       my $filename = shift;
+       open (my $fh, '<', $filename) || die "failed opening '$filename'";
+       my $ret = '';
+       $ret .= $_ while (<$fh>);
+       close ($fh) || die "failed closing '$filename'";
+       return $ret;
+}
+
+sub string_in_file {
+       my ($string, $filename) = @_;
+       my $ret = 0;
+       open (my $fh, '<', $filename) || die "failed opening '$filename'";
+       while (<$fh>) {
+               if (-1 != index $_, $string) {
+                       $ret = 1;
+                       last;
+               }
+       }
+       close ($fh) || die "failed closing '$filename'";
+       return $ret;
+}
+
+sub skip_os {
+       my $name = shift;
+       return $^O eq $name ? "is $name" : '';
+}
+
+sub skip_os_not {
+       my $name = shift;
+       return $^O ne $name ? "is not $name" : '';
+}
+
+sub skip_config_def1 {
+       my $symbol = shift;
+       return (defined $config{$symbol} && $config{$symbol} eq '1') ?
+               "$symbol==1" : '';
+}
+
+sub skip_config_undef {
+       my $symbol = shift;
+       return (! defined $config{$symbol} || $config{$symbol} ne '1') ?
+               "${symbol}!=1" : '';
+}
+
+sub skip_config_have_decl {
+       my ($name, $value) = @_;
+       $name = 'HAVE_DECL_' . $name;
+       # "Unlike the other ‘AC_CHECK_*S’ macros, when a symbol is not declared,
+       # HAVE_DECL_symbol is defined to ‘0’ instead of leaving HAVE_DECL_symbol
+       # undeclared." -- GNU Autoconf manual.
+       #
+       # (This requires the CMake leg to do the same for the same symbol.)
+       die "no $name in config.h" unless defined $config{$name};
+       return int ($config{$name}) == $value ? "$name==$value" : '';
+}
+
+sub result_skipped {
+       return {
+               char => CHAR_SKIPPED,
+               skip => shift
+       };
+}
+
+sub result_passed {
+       return {char => CHAR_PASSED};
+}
+
+sub result_failed {
+       return {
+               char => CHAR_FAILED,
+               failure => {
+                       reason => shift,
+                       details => shift
+               }
+       };
+}
+
+sub result_timed_out {
+       return {
+               char => CHAR_TIMED_OUT,
+               failure => {reason => shift}
+       };
+}
+
+sub run_skip_test {
+       my $test = shift;
+       return result_skipped $test->{skip};
+}
+
+# <------------------------- $maxcols -------------------------->
+# ............................................ 0000 / 0000 (000%)
+#                          $max_result_digits >----< >----<
+# <--------- $max_results_per_line ---------->
+sub init_results_processing {
+       my $maxcols = 80;
+       $results_to_print = shift;
+       if ($Config{useithreads}) {
+               # When using threads, STDOUT becomes line-buffered on TTYs, which is
+               # not good for interactive progress monitoring.
+               STDOUT->autoflush (1) if -t STDOUT;
+               $flush_after_newline = ! -t STDOUT;
+       }
+       $results_printed = 0;
+       $max_result_digits = 1 + int (log ($results_to_print) / log (10));
+       $max_results_per_line = $maxcols - 11 - 2 * $max_result_digits;
+}
+
+# Produce a results map in PHPUnit output format.
+sub print_result_char {
+       print shift;
+       if (++$results_printed > $results_to_print) {
+               die "Internal error: unexpected results after 100%!";
+       }
+       my $results_dangling = $results_printed % $max_results_per_line;
+       if ($results_dangling) {
+               return if $results_printed < $results_to_print;
+               # Complete the dangling line to keep the progress column aligned.
+               print ' ' for (1 .. $max_results_per_line - $results_dangling);
+       }
+       printf " %*u / %*u (%3u%%)\n",
+               $max_result_digits,
+               $results_printed,
+               $max_result_digits,
+               $results_to_print,
+               100 * $results_printed / $results_to_print;
+       # When using threads, STDOUT becomes block-buffered on pipes, which is
+       # not good for CI progress monitoring.
+       STDOUT->flush if $flush_after_newline;
+}
+
+sub print_result {
+       printf "    %-40s: %s\n", @_;
+}
+
+sub test_and_report {
+       my @tests = @_;
+       start_tests (@tests);
+       init_results_processing scalar @tests;
+       my $ret = 0;
+       # key: test label, value: reason for skipping
+       my %skipped;
+       # key: test label, value: hash of
+       # * reason (mandatory, string)
+       # * details (optional, [multi-line] string)
+       my %failed;
+       my $passedcount = 0;
+
+       # Ordering of the results is the same as ordering of the tests.  Print the
+       # results map immediately and buffer any skipped/failed test details for the
+       # post-map diagnostics.
+       while (defined (my $result = get_next_result)) {
+               print_result_char ($result->{char});
+               if (defined $result->{skip}) {
+                       $skipped{$result->{label}} = $result->{skip};
+               } elsif (defined $result->{failure}) {
+                       $failed{$result->{label}} = $result->{failure};
+               } else {
+                       $passedcount++;
+               }
+       }
+
+       print "\n";
+       if (%skipped) {
+               print "Skipped tests:\n";
+               print_result $_, $skipped{$_} foreach (sort keys %skipped);
+               print "\n";
+       }
+       if (%failed) {
+               $ret = 1;
+               print "Failed tests:\n";
+               foreach (sort keys %failed) {
+                       print_result $_, $failed{$_}{reason};
+                       print $failed{$_}{details} if defined $failed{$_}{details};
+               }
+               print "\n";
+       }
+
+       # scalar (%hash) returns incorrect value on Perl 5.8.4.
+       my $skippedcount = scalar keys %skipped;
+       my $failedcount = scalar keys %failed;
+       print "------------------------------------------------\n";
+       printf "%4u tests skipped\n", $skippedcount;
+       printf "%4u tests failed\n", $failedcount;
+       printf "%4u tests passed\n", $passedcount;
+
+       if ($skippedcount + $failedcount + $passedcount != $results_to_print) {
+               printf STDERR "Internal error: statistics bug (%u + %u + %u != %u)\n",
+                       $skippedcount,
+                       $failedcount,
+                       $passedcount,
+                       $results_to_print;
+               $ret = 2;
+       }
+       return $ret;
+}
+
+1;
diff --git a/tests/TESTmt.pm b/tests/TESTmt.pm
new file mode 100644 (file)
index 0000000..e9f72f2
--- /dev/null
@@ -0,0 +1,71 @@
+require 5.10.1; # Debian 6
+use strict;
+use warnings FATAL => qw(uninitialized);
+use threads;
+use Thread::Queue;
+# TESTlib.pm
+use subs qw(get_njobs);
+
+# TESTrun helper functions (multithreaded implementation).
+
+my $njobs;
+my $tmpid;
+my @tests;
+my @result_queues;
+my @tester_threads;
+my $next_to_dequeue;
+
+sub my_tmp_id {
+       return $tmpid;
+}
+
+# Iterate over the list of tests, pick tests that belong to the current job,
+# run one test at a time and send the result to the job's results queue.
+sub tester_thread_func {
+       my $jobid = shift;
+       $tmpid = sprintf 'job%03u', $jobid;
+       for (my $i = $jobid; $i < scalar @tests; $i += $njobs) {
+               my $test = $tests[$i];
+               my $result = $test->{func} ($test);
+               $result->{label} = $test->{label};
+               $result_queues[$jobid]->enqueue ($result);
+       }
+       # Instead of detaching let the receiver join, this works around File::Temp
+       # not cleaning up.
+       # No Thread::Queue->end() in Perl 5.10.1, so use an undef to mark the end.
+       $result_queues[$jobid]->enqueue (undef);
+}
+
+sub start_tests {
+       $njobs = get_njobs;
+       print "INFO: This Perl supports threads, using $njobs tester thread(s).\n";
+       @tests = @_;
+       for (0 .. $njobs - 1) {
+               $result_queues[$_] = Thread::Queue->new;
+               $tester_threads[$_] =  threads->create (\&tester_thread_func, $_);
+       }
+       $next_to_dequeue = 0;
+}
+
+# Here ordering of the results is the same as ordering of the tests because
+# this function starts at job 0 and continues round-robin, which reverses the
+# interleaving done in the thread function above; also because every attempt
+# to dequeue blocks until it returns exactly one result.
+sub get_next_result {
+       for (0 .. $njobs - 1) {
+               my $jobid = $next_to_dequeue;
+               $next_to_dequeue = ($next_to_dequeue + 1) % $njobs;
+               # Skip queues that have already ended.
+               next unless defined $result_queues[$jobid];
+               my $result = $result_queues[$jobid]->dequeue;
+               # A test result?
+               return $result if defined $result;
+               # No, an end-of-queue marker.
+               $result_queues[$jobid] = undef;
+               $tester_threads[$jobid]->join;
+       }
+       # No results after one complete round, therefore done.
+       return undef;
+}
+
+1;
index da3edcfd894f7f2118b856cb7dc3e2543c47df52..ef57e92b5d37c555a10ca22d123a45607e4255b8 100755 (executable)
@@ -1,21 +1,59 @@
 #!/usr/bin/env perl
 
+BEGIN {
+       require 5.8.4; # Solaris 10
+       use Config;
+       use FindBin;
+       if (defined $ENV{TESTRUN_PERL}) {
+               my $newperl = $ENV{TESTRUN_PERL};
+               delete $ENV{TESTRUN_PERL};
+               print "INFO: Re-launching using TESTRUN_PERL='$newperl'.\n";
+               exec ($newperl, $FindBin::RealBin . '/' . $FindBin::RealScript, @ARGV);
+               die 'ERROR: Failed to re-launch.';
+       }
+       require $FindBin::RealBin . '/TEST' . ($Config{useithreads} ? 'mt' : 'st') . '.pm';
+}
+
+use strict;
+use warnings FATAL => qw(uninitialized);
+require $FindBin::RealBin . '/TESTlib.pm';
+# TESTlib.pm
+use subs qw(
+       file_get_contents
+       get_diff_flags
+       init_tmpdir
+       mytmpfile
+       read_config_h
+       result_failed
+       result_passed
+       result_skipped
+       result_timed_out
+       run_skip_test
+       skip_config_def1
+       skip_config_undef
+       skip_os
+       test_and_report
+);
+
 #
 # Were we told where to find tcpdump?
 #
-if (!($TCPDUMP = $ENV{TCPDUMP_BIN})) {
-    #
-    # No.  Use the appropriate path.
-    #
-    if ($^O eq 'MSWin32') {
-        #
-        # XXX - assume, for now, a Visual Studio debug build, so that
-        # tcpdump is in the Debug subdirectory.
-        #
-        $TCPDUMP = "Debug\\tcpdump.exe"
-    } else {
-        $TCPDUMP = "./tcpdump"
-    }
+my $TCPDUMP;
+if (defined $ENV{TCPDUMP_BIN}) {
+       $TCPDUMP = $ENV{TCPDUMP_BIN};
+} else {
+       #
+       # No.  Use the appropriate path.
+       #
+       if ($^O eq 'MSWin32') {
+               #
+               # XXX - assume, for now, a Visual Studio debug build, so that
+               # tcpdump is in the Debug subdirectory.
+               #
+               $TCPDUMP = "Debug\\tcpdump.exe"
+       } else {
+               $TCPDUMP = "./tcpdump"
+       }
 }
 
 #
@@ -24,497 +62,673 @@ if (!($TCPDUMP = $ENV{TCPDUMP_BIN})) {
 use constant true => 1;
 use constant false => 0;
 
-use File::Basename;
-use POSIX qw( WEXITSTATUS WIFEXITED);
-use Cwd qw(abs_path getcwd);
-use File::Path qw(mkpath);   # mkpath works with ancient perl, as well as newer perl
+use POSIX qw(WEXITSTATUS WIFEXITED);
 use File::Spec;
 
-# these are created in the directory where we are run, which might be
-# a build directory.
-my $newdir = "tests/NEW";
-my $diffdir= "tests/DIFF";
-mkpath($newdir);
-mkpath($diffdir);
-my $origdir = getcwd();
-my $srcdir  = $ENV{'srcdir'} || ".";
-# Default to unified context diff (on HP-UX diff does not support it, so
-# default to the closest alternative) and allow to fall back to another diff
-# format if necessary.
-my $diff_flags = defined $ENV{'DIFF_FLAGS'} ? $ENV{'DIFF_FLAGS'} :
-       $^O eq 'hpux' ? '-c' :
-       '-u';
+# These filenames use a prefix and are relative to the temporary directory.
+my $filename_stdout = 'stdout.txt';
+my $filename_stderr = 'stderr.txt';
+my $filename_diags = 'diags.txt';
+
+my $diff_flags = get_diff_flags;
 
 #
 # Force UTC, so time stamps are printed in a standard time zone, and
 # tests don't have to be run in the time zone in which the output
 # file was generated.
 #
-$ENV{'TZ'}='GMT0';
+$ENV{TZ} = 'GMT0';
 
 #
 # Get the tests directory from $0.
-#
-my $testsdir = dirname($0);
-
-#
 # Convert it to an absolute path, so it works even after we do a cd.
 #
-$testsdir = abs_path($testsdir);
+my $testsdir = $FindBin::RealBin;
+my $fn_testlist = "${testsdir}/TESTLIST";
+
 print "Running tests from ${testsdir}\n";
 print "with ${TCPDUMP}, version:\n";
-system "${TCPDUMP} --version";
-
-unshift(@INC, $testsdir);
-
-$passedcount = 0;
-$failedcount = 0;
-$skippedcount = 0;
-#
-my $failureoutput=$origdir . "/tests/failure-outputs.txt";
-
-# truncate the output file
-open(FAILUREOUTPUT, ">" . $failureoutput);
-close(FAILUREOUTPUT);
-
-$confighhash = undef;
-
-sub showfile {
-    local($path) = @_;
-
-    #
-    # XXX - just do this directly in Perl?
-    #
-    if ($^O eq 'MSWin32') {
-        my $winpath = File::Spec->canonpath($path);
-        system "type $winpath";
-    } else {
-        system "cat $path";
-    }
+system ("${TCPDUMP} --version") == 0 or die "ERROR: '$TCPDUMP --version' failed to run\n";
+
+sub pipe_tcpdump {
+       my $option = shift;
+       open (OPT_PIPE, "$TCPDUMP $option |") or die "ERROR: piping tcpdump $option failed at open\n";
+       my $ret = <OPT_PIPE>;
+       close (OPT_PIPE) or die "ERROR: piping tcpdump $option failed at close\n";
+       return $ret;
 }
 
-sub runtest {
-    local($name, $input, $output, $options) = @_;
-    my $r;
-
-    $outputbase = basename($output);
-    my $coredump = false;
-    my $status = 0;
-    my $linecount = 0;
-    my $rawstderrlog = "${newdir}/${outputbase}.raw.stderr";
-    my $stderrlog = "${newdir}/${outputbase}.stderr";
-    my $diffstat = 0;
-    my $errdiffstat = 0;
-
-    # we used to do this as a nice pipeline, but the problem is that $r fails to
-    # to be set properly if the tcpdump core dumps.
-    #
-    # Furthermore, on Windows, fc can't read the standard input, so we
-    # can't do it as a pipeline in any case.
-    if (index($options, "SPECIAL_t") != -1) {
-        # Hack to keep specific time options for tcp-handshake-micro-t, etc.
-        # -t, -tt, etc.
-        $options =~ s/ SPECIAL_t//;
-    } else {
-        # No specific time option, use -tttt
-        $options .= " -tttt";
-    }
-    $r = system "$TCPDUMP -# -n -r $input $options >${newdir}/${outputbase} 2>${rawstderrlog}";
-
-    if($r != 0) {
-        #
-        # Something other than "tcpdump opened the file, read it, and
-        # dissected all the packets".  What happened?
-        #
-        # We write out an exit status after whatever the subprocess
-        # wrote out, so it shows up when we diff the expected output
-        # with it.
-        #
-        open(OUTPUT, ">>"."${newdir}/$outputbase") || die "fail to open $outputbase\n";
-        if($r == -1) {
-            # failed to start due to error.
-            $status = $!;
-            printf OUTPUT "FAILED TO RUN: status: %d\n", $status;
-        } else {
-            if ($^O eq 'MSWin32' or $^O eq 'msys') {
-                #
-                # On Windows, the return value of system is the lower 8
-                # bits of the exit status of the process, shifted left
-                # 8 bits.
-                #
-                # If the process crashed, rather than exiting, the
-                # exit status will be one of the EXCEPTION_ values
-                # listed in the documentation for the GetExceptionCode()
-                # macro.
-                #
-                # Those are defined as STATUS_ values, which should have
-                # 0xC in the topmost 4 bits (being fatal error
-                # statuses); some of them have a value that fits in
-                # the lower 8 bits.  We could, I guess, assume that
-                # any value that 1) isn't returned by tcpdump and 2)
-                # corresponds to the lower 8 bits of a STATUS_ value
-                # used as an EXCEPTION_ value indicates that tcpdump
-                # exited with that exception.
-                #
-                # However, as we're running tcpdump with system, which
-                # runs the command through cmd.exe, and as cmd.exe
-                # doesn't map the command's exit code to its own exit
-                # code in any straightforward manner, we can't get
-                # that information in any case, so there's no point
-                # in trying to interpret it in that fashion.
-                #
-                $status = $r >> 8;
-            } else {
-                #
-                # On UN*Xes, the return status is a POSIX as filled in
-                # by wait() or waitpid().
-                #
-                # POSIX offers some calls for analyzing it, such as
-                # WIFSIGNALED() to test whether it indicates that the
-                # process was terminated by a signal, WTERMSIG() to
-                # get the signal number from it, WIFEXITED() to test
-                # whether it indicates that the process exited normally,
-                # and WEXITSTATUS() to get the exit status from it.
-                #
-                # POSIX doesn't standardize core dumps, so the POSIX
-                # calls can't test whether a core dump occurred.
-                # However, all the UN*Xes we are likely to encounter
-                # follow Research UNIX in this regard, with the exit
-                # status containing either 0 or a signal number in
-                # the lower 7 bits, with 0 meaning "exited rather
-                # than being terminated by a signal", the "core dumped"
-                # flag in the 0x80 bit, and, if the signal number is
-                # 0, the exit status in the next 8 bits up.
-                #
-                # This should be cleaned up to use the POSIX calls
-                # from the Perl library - and to define an additional
-                # WCOREDUMP() call to test the "core dumped" bit and
-                # use that.
-                #
-                # But note also that, as we're running tcpdump with
-                # system, which runs the command through a shell, if
-                # tcpdump crashes, we'll only know that if the shell
-                # maps the signal indication and uses that as its
-                # exit status.
-                #
-                # The good news is that the Bourne shell, and compatible
-                # shells, have traditionally done that.  If the process
-                # for which the shell reports the exit status terminates
-                # with a signal, it adds 128 to the signal number and
-                # returns that as its exit status.  (This is why the
-                # "this is now working right" behavior described in a
-                # comment below is occurring.)
-                #
-                # As tcpdump itself never returns with an exit status
-                # >= 128, we can try checking for an exit status with
-                # the 0x80 bit set and, if we have one, get the signal
-                # number from the lower 7 bits of the exit status.  We
-                # can't get the "core dumped" indication from the
-                # shell's exit status; all we can do is check whether
-                # there's a core file.
-                #
-                if( $r & 128 ) {
-                    $coredump = $r & 127;
-                }
-                if( WIFEXITED($r)) {
-                    $status = WEXITSTATUS($r);
-                }
-            }
-
-            if($coredump || $status) {
-                printf OUTPUT "EXIT CODE %08x: dump:%d code: %d\n", $r, $coredump, $status;
-            } else {
-                printf OUTPUT "EXIT CODE %08x\n", $r;
-            }
-            $r = 0;
-        }
-        close(OUTPUT);
-    }
-    if($r == 0) {
-        #
-        # Compare tcpdump's output with what we think it should be.
-        # If tcpdump failed to produce output, we've produced our own
-        # "output" above, with the exit status.
-        #
-        if ($^O eq 'MSWin32') {
-            my $winoutput = File::Spec->canonpath($output);
-            my $winnewdir = File::Spec->canonpath($newdir);
-            my $windiffdir = File::Spec->canonpath($diffdir);
-            $r = system "fc /lb1000 /t /1 $winoutput ${winnewdir}\\$outputbase >${windiffdir}\\$outputbase.diff";
-            $diffstat = $r >> 8;
-        } else {
-            $r = system "diff $diff_flags $output ${newdir}/$outputbase >${diffdir}/$outputbase.diff";
-            $diffstat = WEXITSTATUS($r);
-        }
-    }
-
-    # process the standard error file, sanitize "reading from" line,
-    # and count lines
-    $linecount = 0;
-    open(ERRORRAW, "<" . $rawstderrlog);
-    open(ERROROUT, ">" . $stderrlog);
-    while(<ERRORRAW>) {
-        next if /^$/;  # blank lines are boring
-        if(/^(reading from file )(.*)(,.*)$/) {
-            my $filename = basename($2);
-            print ERROROUT "${1}${filename}${3}\n";
-            next;
-        }
-        print ERROROUT;
-        $linecount++;
-    }
-    close(ERROROUT);
-    close(ERRORRAW);
-
-    if ( -f "$output.stderr" ) {
-        #
-        # Compare the standard error with what we think it should be.
-        #
-        if ($^O eq 'MSWin32') {
-            my $winoutput = File::Spec->canonpath($output);
-            my $windiffdir = File::Spec->canonpath($diffdir);
-            my $canonstderrlog = File::Spec->canonpath($stderrlog);
-            $nr = system "fc /lb1000 /t /1 $winoutput.stderr $canonstderrlog >${windiffdir}\\$outputbase.stderr.diff";
-            $errdiffstat = $nr >> 8;
-        } else {
-            $nr = system "diff $output.stderr $stderrlog >${diffdir}/$outputbase.stderr.diff";
-            $errdiffstat = WEXITSTATUS($nr);
-        }
-        if($r == 0) {
-            $r = $nr;
-        }
-    }
-
-    if($r == 0) {
-        if($linecount == 0 && $status == 0) {
-            unlink($stderrlog);
-        } else {
-            $errdiffstat = 1;
-        }
-    }
-
-    if($r == 0) {
-        if($linecount == 0) {
-            printf "    %-40s: passed\n", $name;
-        } else {
-            printf "    %-40s: passed with error messages:\n", $name;
-            showfile($stderrlog);
-        }
-        unlink "${diffdir}/$outputbase.diff";
-        return 0;
-    }
-    # must have failed!
-    printf "    %-40s: TEST FAILED(exit core=%d/diffstat=%d,%d/r=%d)", $name, $coredump, $diffstat, $errdiffstat, $r;
-    open FOUT, '>>tests/failure-outputs.txt';
-    printf FOUT "\nFailed test: $name\n\n";
-    close FOUT;
-    if(-f "${diffdir}/$outputbase.diff") {
-        #
-        # XXX - just do this directly in Perl?
-        #
-        if ($^O eq 'MSWin32') {
-            my $windiffdir = File::Spec->canonpath($diffdir);
-            system "type ${windiffdir}\\$outputbase.diff >> tests\\failure-outputs.txt";
-        } else {
-            system "cat ${diffdir}/$outputbase.diff >> tests/failure-outputs.txt";
-        }
-    }
-
-    if($r == -1) {
-        print " (failed to execute: $!)\n";
-        return(30);
-    }
-
-    # this is not working right, $r == 0x8b00 when there is a core dump.
-    # clearly, we need some platform specific perl magic to take this apart, so look for "core"
-    # too.
-    # In particular, on Solaris 10 SPARC an alignment problem results in SIGILL,
-    # a core dump and $r set to 0x00008a00 ($? == 138 in the shell).
-    if($r & 127 || -f "core") {
-        my $with = ($r & 128) ? 'with' : 'without';
-        if(-f "core") {
-            $with = "with";
-        }
-        printf " (terminated with signal %u, %s coredump)", ($r & 127), $with;
-        if($linecount == 0) {
-            print "\n";
-        } else {
-            print " with error messages:\n";
-            showfile($stderrlog);
-        }
-        return(($r & 128) ? 10 : 20);
-    }
-    if($linecount == 0) {
-        print "\n";
-    } else {
-        print " with error messages:\n";
-        showfile($stderrlog);
-    }
-    return(5);
-}
+# Get the type of floating-point arithmetic we're doing.
+my $fptype = pipe_tcpdump ('--fp-type') == '9877.895' ? 1 : 2;
+printf "%s --fp-type => %s\n", $TCPDUMP, $fptype;
 
-sub loadconfighash {
-    if(defined($confighhash)) {
-        return $confighhash;
-    }
-
-    $main::confighhash = {};
-
-    # this could be loaded once perhaps.
-    open(CONFIG_H, "config.h") || die "Can not open config.h: $!\n";
-    while(<CONFIG_H>) {
-        chomp;
-        if(/^\#define (.*) 1/) {
-            $main::confighhash->{$1} = 1;
-        }
-    }
-    close(CONFIG_H);
-
-    # also run tcpdump --fp-type to get the type of floating-point
-    # arithmetic we're doing, setting a HAVE_{fptype} key based
-    # on the value it prints
-    open(FPTYPE_PIPE, "$TCPDUMP --fp-type |") or die("piping tcpdump --fp-type failed\n");
-    my $fptype_val = <FPTYPE_PIPE>;
-    close(FPTYPE_PIPE);
-    my $have_fptype;
-    if($fptype_val == "9877.895") {
-        $have_fptype = "HAVE_FPTYPE1";
-    } else {
-        $have_fptype = "HAVE_FPTYPE2";
-    }
-    printf "$TCPDUMP --fp-type => %s\n", $have_fptype;
-    $main::confighhash->{$have_fptype} = 1;
-
-    # run tcpdump --time-t-size to get the size of size_t in bits
-    open(TIMETSIZE_PIPE, "$TCPDUMP --time-t-size |") or die("piping tcpdump --time-t-size failed\n");
-    my $time_t_size = <TIMETSIZE_PIPE>;
-    close(TIMETSIZE_PIPE);
-    my $have_time_t_64;
-    if($time_t_size == "64") {
-        $have_time_t_64 = "HAVE_TIME_T_64";
-    }
-    printf "$TCPDUMP --time-t-size => %s\n", $time_t_size;
-    $main::confighhash->{$have_time_t_64} = 1;
-
-    # and check whether this is OpenBSD, as one test fails in OpenBSD
-    # due to the sad hellscape of low-numbered DLT_ values, due to
-    # 12 meaning "OpenBSD loopback" rather than "raw IP" on OpenBSD
-    if($^O eq "openbsd") {
-        $main::confighhash->{"IS_OPENBSD"} = 1;
-    }
-
-    return $main::confighhash;
-}
+# Get the size of size_t in bits.
+my $time_t_size = int (pipe_tcpdump '--time-t-size');
+printf "%s --time-t-size => %s\n", $TCPDUMP, $time_t_size;
 
+# Enable all shared skip functions to be able to declare the tests below.
+read_config_h (defined $ENV{CONFIG_H} ? $ENV{CONFIG_H} : './config.h');
 
-sub runOneComplexTest {
-    local($testconfig) = @_;
-
-    my $output = $testconfig->{output};
-    my $input  = $testconfig->{input};
-    my $name   = $testconfig->{name};
-    my $options= $testconfig->{args};
-    my $foundit = 1;
-    my $unfoundit=1;
-
-    my $configset = $testconfig->{config_set};
-    my $configunset = $testconfig->{config_unset};
-    my $ch = loadconfighash();
-
-    if(defined($configset)) {
-        $foundit = ($ch->{$configset} == 1);
-    }
-    if(defined($configunset)) {
-        $unfoundit=($ch->{$configunset} != 1);
-    }
-
-    if(!$foundit) {
-        printf "    %-40s: skipped (%s not set)\n", $name, $configset;
-        $skippedcount++;
-        return 0;
-    }
-
-    if(!$unfoundit) {
-        printf "    %-40s: skipped (%s set)\n", $name, $configunset;
-        $skippedcount++;
-        return 0;
-    }
-
-    # EXPAND any occurrences of @TESTDIR@ to $testsdir
-    $options =~ s/\@TESTDIR\@/$testsdir/;
-
-    my $result = runtest($name,
-                         $testsdir . "/" . $input,
-                         $testsdir . "/" . $output,
-                         $options);
-
-    if($result == 0) {
-        $passedcount++;
-    } else {
-        $failedcount++;
-    }
+sub skip_fptype_not {
+       my $val = shift;
+       return $fptype != $val ? "fp-type!=$val" : '';
 }
 
-# *.tests files are PERL hash definitions.  They should create an array of hashes
-# one per test, and place it into the variable @testlist.
-sub runComplexTests {
-    my @files = glob( $testsdir . '/*.tests' );
-    foreach $file (@files) {
-        my @testlist = undef;
-        my $definitions;
-        print "FILE: ${file}\n";
-        open(FILE, "<".$file) || die "can not open $file: $!";
-        {
-            local $/ = undef;
-            $definitions = <FILE>;
-        }
-        close(FILE);
-        eval $definitions;
-        if(defined($testlist)) {
-            foreach $test (@$testlist) {
-                runOneComplexTest($test);
-            }
-        } else {
-            warn "File: ${file} could not be loaded as PERL: $!";
-        }
-    }
+sub skip_time_t_not {
+       my $val = shift;
+       return $time_t_size != $val ? "time_t is not ${val}-bit" : '';
 }
 
-sub runSimpleTests {
-
-    local($only)=@_;
-
-    open(TESTLIST, "<" . "${testsdir}/TESTLIST") || die "no ${testsdir}/TESTFILE: $!\n";
-    while(<TESTLIST>) {
-        next if /^\#/;
-        next if /^$/;
-
-        unlink("core");
-        ($name, $input, $output, @options) = split;
-        next if(defined($only) && $only ne $name);
+my @decode_tests = (
+       # -------- formerly crypto.tests --------
+       # Only attempt OpenSSL-specific tests when compiled with the library.
+       # Reading the secret(s) from a file does not work with Capsicum.
+
+       {
+               skip => skip_config_undef ('HAVE_LIBCRYPTO'),
+               name => 'esp1',
+               input => '02-sunrise-sunset-esp.pcap',
+               output => 'esp1.out',
+               args => '-E "[email protected] 3des-cbc-hmac96:0x4043434545464649494a4a4c4c4f4f515152525454575758"'
+       },
+
+       {
+               skip => skip_config_undef ('HAVE_LIBCRYPTO'),
+               name => 'esp2',
+               input => '08-sunrise-sunset-esp2.pcap',
+               output => 'esp2.out',
+               args => '-E "[email protected] 3des-cbc-hmac96:0x43434545464649494a4a4c4c4f4f51515252545457575840,[email protected] 3des-cbc-hmac96:0x434545464649494a4a4c4c4f4f5151525254545757584043"'
+       },
+
+       {
+               skip => skip_config_undef ('HAVE_LIBCRYPTO'),
+               name => 'esp3',
+               input => '02-sunrise-sunset-esp.pcap',
+               output => 'esp1.out',
+               args => '-E "3des-cbc-hmac96:0x4043434545464649494a4a4c4c4f4f515152525454575758"',
+       },
+
+       {
+               skip => (skip_config_undef ('HAVE_LIBCRYPTO') || skip_config_def1 ('HAVE_CAPSICUM')),
+               name => 'esp4',
+               input => '08-sunrise-sunset-esp2.pcap',
+               output => 'esp2.out',
+               args => "-E 'file ${testsdir}/esp-secrets.txt'",
+       },
+
+       {
+               skip => (skip_config_undef ('HAVE_LIBCRYPTO') || skip_config_def1 ('HAVE_CAPSICUM')),
+               name => 'esp5',
+               input => '08-sunrise-sunset-aes.pcap',
+               output => 'esp5.out',
+               args => "-E 'file ${testsdir}/esp-secrets.txt'",
+       },
+
+       {
+               skip => (skip_config_undef ('HAVE_LIBCRYPTO') || skip_config_def1 ('HAVE_CAPSICUM')),
+               name => 'espudp1',
+               input => 'espudp1.pcap',
+               output => 'espudp1.out',
+               args => "-E 'file ${testsdir}/esp-secrets.txt'",
+       },
+
+       {
+               skip => (skip_config_undef ('HAVE_LIBCRYPTO') || skip_config_def1 ('HAVE_CAPSICUM')),
+               name => 'ikev2pI2',
+               input => 'ikev2pI2.pcap',
+               output => 'ikev2pI2.out',
+               args => "-v -v -v -v -E 'file ${testsdir}/ikev2pI2-secrets.txt'",
+       },
+
+       {
+               skip => (skip_config_undef ('HAVE_LIBCRYPTO') || skip_config_def1 ('HAVE_CAPSICUM')),
+               name => 'isakmp4',
+               input => 'isakmp4500.pcap',
+               output => 'isakmp4.out',
+               args => "-E 'file ${testsdir}/esp-secrets.txt'",
+       },
+
+       {
+               skip => skip_config_undef ('HAVE_LIBCRYPTO'),
+               name => 'bgp-as-path-oobr-ssl',
+               input => 'bgp-as-path-oobr.pcap',
+               output => 'bgp-as-path-oobr-ssl.out',
+               args => '-vvv -e'
+       },
+
+       {
+               skip => skip_config_undef ('HAVE_LIBCRYPTO'),
+               name => 'bgp-aigp-oobr-ssl',
+               input => 'bgp-aigp-oobr.pcap',
+               output => 'bgp-aigp-oobr-ssl.out',
+               args => '-vvv -e'
+       },
+
+       {
+               skip => skip_config_def1 ('HAVE_LIBCRYPTO'),
+               name => 'bgp-as-path-oobr-nossl',
+               input => 'bgp-as-path-oobr.pcap',
+               output => 'bgp-as-path-oobr-nossl.out',
+               args => '-vvv -e'
+       },
+
+       {
+               skip => skip_config_def1 ('HAVE_LIBCRYPTO'),
+               name => 'bgp-aigp-oobr-nossl',
+               input => 'bgp-aigp-oobr.pcap',
+               output => 'bgp-aigp-oobr-nossl.out',
+               args => '-vvv -e'
+       },
+
+       # -------- formerly isis-seg-fault-1-v.tests --------
+       # This "verbose" ISIS protocol test involves a float calculation that
+       # may produce a slightly different result depending on the compiler and
+       # the version of the instruction set for which it's generating code (see
+       # GitHub issue #333 for another example). The test is done only if we have
+       # a floating-point type, as reported by "./tcpdump --fp-type", of FPTYPE1.
+       #
+       # XXX - this works on my 32-bit x86 Linux virtual machine, so do this
+       # regardless of the floating-point type, so always do this.  If it
+       # fails on some platform, we'll need to tweak tcpdump and tests/TESTrun
+       # to check for *that* floating-point difference.
+
+       {
+               name => 'isis-seg-fault-1-v',
+               input => 'isis-seg-fault-1.pcapng',
+               output => 'isis-seg-fault-1-v.out',
+               args => '-v'
+       },
+
+       # -------- formerly lmp-v.tests --------
+       # The "verbose" Link Management Protocol test involves a float calculation that
+       # may produce a slightly different result depending on the compiler and the
+       # version of the instruction set for which it's generating code (see GitHub
+       # issue #333). The test is done with an output file that depends on the
+       # floating-point type, as reported by "./tcpdump --fp-type".
+
+       {
+               skip => skip_fptype_not (1),
+               name => 'lmp-v-fptype1',
+               input => 'lmp.pcap',
+               output => 'lmp-v-fptype1.out',
+               args => '-T lmp -v'
+       },
+       {
+               skip => skip_fptype_not (2),
+               name => 'lmp-v-fptype2',
+               input => 'lmp.pcap',
+               output => 'lmp-v-fptype2.out',
+               args => '-T lmp -v'
+       },
+
+       # -------- formerly non-bsd.tests --------
+       # This specific test fails on OpenBSD because the .pcap file uses DLT_RAW,
+       # which OpenBSD treats as DLT_LOOP.
+
+       {
+               skip => skip_os ('openbsd'),
+               name => 'heap-overflow-1',
+               input => 'heap-overflow-1.pcap',
+               output => 'heap-overflow-1.out',
+               args => '-v'
+       },
+
+       # -------- formerly smb.tests --------
+       # Only attempt OpenSSL-specific tests when compiled with the library.
+       # Reading the secret(s) from a file does not work with Capsicum.
+
+       # EAP tests
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'eapon1',
+               input => 'eapon1.pcap',
+               output => 'eapon1.out',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'eapon1-nosmb',
+               input => 'eapon1.pcap',
+               output => 'eapon1-nosmb.out',
+       },
+
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'eapon1-v',
+               input => 'eapon1.pcap',
+               output => 'eapon1-v.out',
+               args => '-v'
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'eapon1-v-nosmb',
+               input => 'eapon1.pcap',
+               output => 'eapon1-v-nosmb.out',
+               args => '-v'
+       },
+
+       # IPX/Netware packets
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'ipx',
+               input => 'ipx.pcap',
+               output => 'ipx.out',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'ipx-nosmb',
+               input => 'ipx.pcap',
+               output => 'ipx-nosmb.out',
+       },
+
+       # bad packets from Otto Airamo and Antti Levomäki
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'nbns-valgrind',
+               input => 'nbns-valgrind.pcap',
+               output => 'nbns-valgrind.out',
+               args => '-vvv -e',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'nbns-valgrind-nosmb',
+               input => 'nbns-valgrind.pcap',
+               output => 'nbns-valgrind-nosmb.out',
+               args => '-vvv -e',
+       },
+
+       # bad packets from Junjie Wang
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'smb_print_trans-oobr1',
+               input => 'smb_print_trans-oobr1.pcap',
+               output => 'smb_print_trans-oobr1.out',
+               args => '-vv',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'smb_print_trans-oobr1-nosmb',
+               input => 'smb_print_trans-oobr1.pcap',
+               output => 'smb_print_trans-oobr1-nosmb.out',
+               args => '-vv',
+       },
+
+       # bad packets from Philippe Antoine
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'smb_print_trans-oobr2',
+               input => 'smb_print_trans-oobr2.pcap',
+               output => 'smb_print_trans-oobr2.out',
+               args => '-vv',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'smb_print_trans-oobr2-nosmb',
+               input => 'smb_print_trans-oobr2.pcap',
+               output => 'smb_print_trans-oobr2-nosmb.out',
+               args => '-vv',
+       },
+
+       # bad packets from Luis Rocha
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'smb_data_print-oobr',
+               input => 'smb_data_print-oobr.pcapng',
+               output => 'smb_data_print-oobr.out',
+               args => '-vv',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'smb_data_print-oobr-nosmb',
+               input => 'smb_data_print-oobr.pcapng',
+               output => 'smb_data_print-oobr-nosmb.out',
+               args => '-vv',
+       },
+
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'smb_data_print-segv',
+               input => 'smb_data_print-segv.pcap',
+               output => 'smb_data_print-segv.out',
+               args => '-vv',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'smb_data_print-segv-nosmb',
+               input => 'smb_data_print-segv.pcap',
+               output => 'smb_data_print-segv-nosmb.out',
+               args => '-vv',
+       },
+
+       # WCCP redirect over GRE
+       {
+               skip => skip_config_undef ('ENABLE_SMB'),
+               name => 'wccp_redirect_gre',
+               input => 'wccp_redirect_gre.pcap',
+               output => 'wccp_redirect_gre.out',
+               args => '-v',
+       },
+
+       {
+               skip => skip_config_def1 ('ENABLE_SMB'),
+               name => 'wccp_redirect_gre-nosmb',
+               input => 'wccp_redirect_gre.pcap',
+               output => 'wccp_redirect_gre-nosmb.out',
+               args => '-v',
+       },
+
+       # -------- formerly time.tests --------
+       # The packet time when > 2038-01-19T03:14:07Z cannot be correctly printed
+       # if time_t size is 32 bits (overflow).
+       # Some tests are run only if time_t is 64-bit. it depends on the
+       # output of "./tcpdump --time-t-size" (32 or 64).
+
+       # A 32-bit unsigned time_t goes until 2106-02-07T06:28:15Z.
+       # All values above require a pcapng file.
+
+       {
+               name => 'time_2038',
+               input => 'time_2038.pcap',
+               output => 'time_2038.out',
+               args => '-q'
+       },
+       {
+               name => 'time_2038_max',
+               input => 'time_2038_max.pcap',
+               output => 'time_2038_max.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2038_overflow',
+               input => 'time_2038_overflow.pcap',
+               output => 'time_2038_overflow.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2039',
+               input => 'time_2039.pcap',
+               output => 'time_2039.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2106',
+               input => 'time_2106.pcap',
+               output => 'time_2106.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2106_max',
+               input => 'time_2106_max.pcap',
+               output => 'time_2106_max.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2106_overflow',
+               input => 'time_2106_overflow.pcapng',
+               output => 'time_2106_overflow.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2107',
+               input => 'time_2107.pcapng',
+               output => 'time_2107.out',
+               args => '-q'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2106_overflow-tt',
+               input => 'time_2106_overflow.pcapng',
+               output => 'time_2106_overflow-tt.out',
+               args => '-tt -q SPECIAL_t'
+       },
+       {
+               skip => skip_time_t_not (64),
+               name => 'time_2107-tt',
+               input => 'time_2107.pcapng',
+               output => 'time_2107-tt.out',
+               args => '-tt -q SPECIAL_t'
+       },
+);
+
+sub decode_exit_status {
+       my $r = shift;
+       my $status;
+       my $coredump = false;
+       if ($^O eq 'MSWin32' or $^O eq 'msys') {
+               #
+               # On Windows, the return value of system is the lower 8
+               # bits of the exit status of the process, shifted left
+               # 8 bits.
+               #
+               # If the process crashed, rather than exiting, the
+               # exit status will be one of the EXCEPTION_ values
+               # listed in the documentation for the GetExceptionCode()
+               # macro.
+               #
+               # Those are defined as STATUS_ values, which should have
+               # 0xC in the topmost 4 bits (being fatal error
+               # statuses); some of them have a value that fits in
+               # the lower 8 bits.  We could, I guess, assume that
+               # any value that 1) isn't returned by tcpdump and 2)
+               # corresponds to the lower 8 bits of a STATUS_ value
+               # used as an EXCEPTION_ value indicates that tcpdump
+               # exited with that exception.
+               #
+               # However, as we're running tcpdump with system, which
+               # runs the command through cmd.exe, and as cmd.exe
+               # doesn't map the command's exit code to its own exit
+               # code in any straightforward manner, we can't get
+               # that information in any case, so there's no point
+               # in trying to interpret it in that fashion.
+               #
+               $status = $r >> 8;
+       } else {
+               #
+               # On UN*Xes, the return status is a POSIX as filled in
+               # by wait() or waitpid().
+               #
+               # POSIX offers some calls for analyzing it, such as
+               # WIFSIGNALED() to test whether it indicates that the
+               # process was terminated by a signal, WTERMSIG() to
+               # get the signal number from it, WIFEXITED() to test
+               # whether it indicates that the process exited normally,
+               # and WEXITSTATUS() to get the exit status from it.
+               #
+               # POSIX doesn't standardize core dumps, so the POSIX
+               # calls can't test whether a core dump occurred.
+               # However, all the UN*Xes we are likely to encounter
+               # follow Research UNIX in this regard, with the exit
+               # status containing either 0 or a signal number in
+               # the lower 7 bits, with 0 meaning "exited rather
+               # than being terminated by a signal", the "core dumped"
+               # flag in the 0x80 bit, and, if the signal number is
+               # 0, the exit status in the next 8 bits up.
+               #
+               # This should be cleaned up to use the POSIX calls
+               # from the Perl library - and to define an additional
+               # WCOREDUMP() call to test the "core dumped" bit and
+               # use that.
+               #
+               # But note also that, as we're running tcpdump with
+               # system, which runs the command through a shell, if
+               # tcpdump crashes, we'll only know that if the shell
+               # maps the signal indication and uses that as its
+               # exit status.
+               #
+               # The good news is that the Bourne shell, and compatible
+               # shells, have traditionally done that.  If the process
+               # for which the shell reports the exit status terminates
+               # with a signal, it adds 128 to the signal number and
+               # returns that as its exit status.  (This is why the
+               # "this is now working right" behavior described in a
+               # comment below is occurring.)
+               #
+               # As tcpdump itself never returns with an exit status
+               # >= 128, we can try checking for an exit status with
+               # the 0x80 bit set and, if we have one, get the signal
+               # number from the lower 7 bits of the exit status.  We
+               # can't get the "core dumped" indication from the
+               # shell's exit status; all we can do is check whether
+               # there's a core file.
+               #
+               $coredump = $r & 127 if ($r & 128);
+               # This works as intended only if the caller has removed any
+               # pre-existing core dumps before running the command.
+               $coredump = 'present' if (! $coredump && -f 'core');
+               $status = WEXITSTATUS ($r) if WIFEXITED ($r);
+       }
+       return ($status, $coredump);
+}
 
-        my $options = join(" ", @options);
-        my $hash = { name => $name,
-                     input=> $input,
-                     output=>$output,
-                     args => $options };
+sub run_decode_test {
+       my $test = shift;
+       my $input = $testsdir . '/' . $test->{input};
+       my $output = $testsdir . '/' . $test->{output};
+
+       # we used to do this as a nice pipeline, but the problem is that $r fails to
+       # to be set properly if the tcpdump core dumps.
+       #
+       # Furthermore, on Windows, fc can't read the standard input, so we
+       # can't do it as a pipeline in any case.
+
+       unlink 'core';
+       my $cmdline = sprintf (
+               '%s -# -n -r "%s" %s >"%s" 2>"%s"',
+               $TCPDUMP,
+               $input,
+               $test->{options},
+               mytmpfile ($filename_stdout),
+               mytmpfile ($filename_stderr)
+       );
+       my $r = system $cmdline;
+
+       return result_failed ('failed to run tcpdump', $!) if $r == -1;
+
+       if ($r != 0) {
+               #
+               # Something other than "failed to start".
+               # Something other than "tcpdump opened the file, read it, and
+               # dissected all the packets".  What happened?
+               #
+               my ($status, $coredump) = decode_exit_status $r;
+               return result_failed (
+                       ($coredump || $status) ?
+                       sprintf ('exit code 0x%08x (dump: %d, code: %d)', $r, $coredump, $status) :
+                       sprintf ('exit code 0x%08x', $r),
+                       file_get_contents mytmpfile $filename_stderr
+               );
+       }
+
+       #
+       # $r == 0
+       # Compare tcpdump's output with what we think it should be.
+       #
+       my $diffstat;
+       if ($^O eq 'MSWin32') {
+               $cmdline = sprintf (
+                       'fc /lb1000 /t /1 %s %s >%s',
+                       File::Spec->canonpath ($output),
+                       mytmpfile ($filename_stdout),
+                       mytmpfile ($filename_diags)
+               );
+               $diffstat = system ($cmdline) >> 8;
+       } else {
+               $cmdline = sprintf (
+                       'diff %s "%s" "%s" >"%s" 2>&1',
+                       $diff_flags,
+                       $output,
+                       mytmpfile ($filename_stdout),
+                       mytmpfile ($filename_diags)
+               );
+               $diffstat = WEXITSTATUS (system $cmdline);
+       }
+       return result_failed (
+               "diff exited with $diffstat",
+               file_get_contents mytmpfile $filename_diags
+       ) if $diffstat;
+
+       # Anything other than the "reading from" line on stderr fails the test.
+       my $failed = false;
+       my $filename = mytmpfile $filename_stderr;
+       open (ERRORRAW, '<', $filename) || die "ERROR: failed opening ${filename}: $!\n";
+       while (<ERRORRAW>) {
+               next if /^reading from file /o;
+               $failed = true;
+               last;
+       }
+       close (ERRORRAW) || die "ERROR: failed closing '$filename'";;
+       return result_failed (
+               'stderr present',
+               file_get_contents mytmpfile $filename_stderr
+       ) if $failed;
+
+       return result_passed;
+}
 
-        runOneComplexTest($hash);
-    }
+sub request_test {
+       my $testconfig = shift;
+
+       return {
+               label => $testconfig->{name},
+               func => \&run_skip_test,
+               skip => $testconfig->{skip},
+       } if defined $testconfig->{skip} && $testconfig->{skip} ne '';
+
+       my $options = defined ($testconfig->{args}) ? $testconfig->{args} : '';
+       if (index ($options, 'SPECIAL_t') != -1) {
+               # Hack to keep specific time options for tcp-handshake-micro-t, etc.
+               # -t, -tt, etc.
+               $options =~ s/ SPECIAL_t//o;
+       } else {
+               # No specific time option, use -tttt
+               $options .= ' -tttt';
+       }
+
+       return {
+               label => $testconfig->{name},
+               func => \&run_decode_test,
+               input => $testconfig->{input},
+               options => $options,
+               output => $testconfig->{output},
+       };
 }
 
-if(scalar(@ARGV) == 0) {
-    runSimpleTests();
-    runComplexTests();
-} else {
-    runSimpleTests($ARGV[0]);
+open (TESTLIST, '<', $fn_testlist) || die "ERROR: failed opening ${fn_testlist}: $!\n";
+while (<TESTLIST>) {
+       next if /^\#/o || /^$/o;
+       my ($name, $input, $output, @options) = split;
+       push @decode_tests, {
+               name => $name,
+               input => $input,
+               output => $output,
+               args => join (' ', @options)
+       };
 }
+close (TESTLIST) || die "ERROR failed closing '$fn_testlist'";
 
-# exit with number of failing tests.
-print "------------------------------------------------\n";
-printf("%4u tests skipped\n",$skippedcount);
-printf("%4u tests failed\n",$failedcount);
-printf("%4u tests passed\n",$passedcount);
+my $only_one = @ARGV == 1 ? $ARGV[0] : undef;
+my @ready_to_run;
+for (@decode_tests) {
+       next if defined ($only_one) && $only_one ne $_->{name};
+       push @ready_to_run, request_test $_
+}
 
-showfile(${failureoutput});
-exit $failedcount;
+if (! scalar @ready_to_run) {
+       die "ERROR: Unknown test case '${only_one}'" if defined $only_one;
+       die 'Internal error: no tests defined to run!'
+}
+init_tmpdir 'tcpdump_TESTrun';
+exit test_and_report @ready_to_run;
diff --git a/tests/TESTst.pm b/tests/TESTst.pm
new file mode 100644 (file)
index 0000000..ffdcb67
--- /dev/null
@@ -0,0 +1,31 @@
+require 5.8.4; # Solaris 10
+use strict;
+use warnings FATAL => qw(uninitialized);
+# TESTlib.pm
+use subs qw(get_njobs);
+
+# TESTrun helper functions (single-threaded implementation).
+
+my @tests;
+
+sub my_tmp_id {
+       return 'main';
+}
+
+sub start_tests {
+       print "INFO: This Perl does not support threads.\n";
+       my $njobs = get_njobs;
+       die "ERROR: Impossible to run $njobs tester threads!" if $njobs > 1;
+       @tests = @_;
+}
+
+# Here ordering of the results is obviously the same as ordering of the tests.
+sub get_next_result {
+       my $test = shift @tests;
+       return undef unless defined $test;
+       my $result = $test->{func} ($test);
+       $result->{label} = $test->{label};
+       return $result;
+}
+
+1;
diff --git a/tests/crypto.tests b/tests/crypto.tests
deleted file mode 100644 (file)
index b7bf22d..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-# -*- perl -*-
-
-# Only attempt OpenSSL-specific tests when compiled with the library.
-# Reading the secret(s) from a file does not work with Capsicum.
-
-$testlist = [
-    {
-        config_set => 'HAVE_LIBCRYPTO',
-        name => 'esp1',
-        input => '02-sunrise-sunset-esp.pcap',
-        output => 'esp1.out',
-        args   => '-E "[email protected] 3des-cbc-hmac96:0x4043434545464649494a4a4c4c4f4f515152525454575758"'
-    },
-
-    {
-        config_set => 'HAVE_LIBCRYPTO',
-        name => 'esp2',
-        input => '08-sunrise-sunset-esp2.pcap',
-        output => 'esp2.out',
-        args   => '-E "[email protected] 3des-cbc-hmac96:0x43434545464649494a4a4c4c4f4f51515252545457575840,[email protected] 3des-cbc-hmac96:0x434545464649494a4a4c4c4f4f5151525254545757584043"'
-    },
-
-    {
-        config_set => 'HAVE_LIBCRYPTO',
-        name => 'esp3',
-        input => '02-sunrise-sunset-esp.pcap',
-        output => 'esp1.out',
-        args   => '-E "3des-cbc-hmac96:0x4043434545464649494a4a4c4c4f4f515152525454575758"',
-    },
-
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        config_unset => 'HAVE_CAPSICUM',
-        name => 'esp4',
-        input => '08-sunrise-sunset-esp2.pcap',
-        output => 'esp2.out',
-        args   => '-E "file @TESTDIR@/esp-secrets.txt"',
-    },
-
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        config_unset => 'HAVE_CAPSICUM',
-        name => 'esp5',
-        input => '08-sunrise-sunset-aes.pcap',
-        output => 'esp5.out',
-        args   => '-E "file @TESTDIR@/esp-secrets.txt"',
-    },
-
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        config_unset => 'HAVE_CAPSICUM',
-        name => 'espudp1',
-        input => 'espudp1.pcap',
-        output => 'espudp1.out',
-        args   => '-E "file @TESTDIR@/esp-secrets.txt"',
-    },
-
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        config_unset => 'HAVE_CAPSICUM',
-        name => 'ikev2pI2',
-        input => 'ikev2pI2.pcap',
-        output => 'ikev2pI2.out',
-        args   => '-v -v -v -v -E "file @TESTDIR@/ikev2pI2-secrets.txt"',
-    },
-
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        config_unset => 'HAVE_CAPSICUM',
-        name => 'isakmp4',
-        input => 'isakmp4500.pcap',
-        output => 'isakmp4.out',
-        args   => '-E "file @TESTDIR@/esp-secrets.txt"',
-    },
-
-    #bgp-as-path-oobr-ssl ${testsdir}/bgp-as-path-oobr.pcap ${testsdir}/bgp-as-path-oobr-ssl.out '-vvv -e'
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        name => 'bgp-as-path-oobr-ssl',
-        input => 'bgp-as-path-oobr.pcap',
-        output => 'bgp-as-path-oobr-ssl.out',
-        args   => '-vvv -e'
-    },
-
-    # bgp-aigp-oobr-ssl ${testsdir}/bgp-aigp-oobr.pcap ${testsdir}/bgp-aigp-oobr-ssl.out '-vvv -e'
-    {
-        config_set   => 'HAVE_LIBCRYPTO',
-        name => 'bgp-aigp-oobr-ssl',
-        input => 'bgp-aigp-oobr.pcap',
-        output => 'bgp-aigp-oobr-ssl.out',
-        args   => '-vvv -e'
-    },
-
-    # bgp-as-path-oobr-nossl ${testsdir}/bgp-as-path-oobr.pcap ${testsdir}/bgp-as-path-oobr-nossl.out '-vvv -e'
-    {
-        config_unset   => 'HAVE_LIBCRYPTO',
-        name => 'bgp-as-path-oobr-nossl',
-        input => 'bgp-as-path-oobr.pcap',
-        output => 'bgp-as-path-oobr-nossl.out',
-        args   => '-vvv -e'
-    },
-
-    # bgp-aigp-oobr-nossl ${testsdir}/bgp-aigp-oobr.pcap ${testsdir}/bgp-aigp-oobr-nossl.out '-vvv -e'
-    {
-        config_unset   => 'HAVE_LIBCRYPTO',
-        name => 'bgp-aigp-oobr-nossl',
-        input => 'bgp-aigp-oobr.pcap',
-        output => 'bgp-aigp-oobr-nossl.out',
-        args   => '-vvv -e'
-    },
-
-];
-
-1;
diff --git a/tests/isis-seg-fault-1-v.tests b/tests/isis-seg-fault-1-v.tests
deleted file mode 100644 (file)
index 15b62b2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- perl -*-
-
-# This "verbose" ISIS protocol test involves a float calculation that
-# may produce a slightly different result depending on the compiler and
-# the version of the instruction set for which it's generating code (see
-# GitHub issue #333 for another example). The test is done only if we have
-# a floating-point type, as reported by "./tcpdump --fp-type", of FPTYPE1.
-#
-# XXX - this works on my 32-bit x86 Linux virtual machine, so do this
-# regardless of the floating-point type, so always do this.  If it
-# fails on some platform, we'll need to tweak tcpdump and tests/TESTrun
-# to check for *that* floating-point difference.
-
-$testlist = [
-    {
-        name => 'isis-seg-fault-1-v',
-        input => 'isis-seg-fault-1.pcapng',
-        output => 'isis-seg-fault-1-v.out',
-        args   => '-v'
-    },
-];
-
-1;
diff --git a/tests/lmp-v.tests b/tests/lmp-v.tests
deleted file mode 100644 (file)
index bfc9d3a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- perl -*-
-
-# The "verbose" Link Management Protocol test involves a float calculation that
-# may produce a slightly different result depending on the compiler and the
-# version of the instruction set for which it's generating code (see GitHub
-# issue #333). The test is done with an output file that depends on the
-# floating-point type, as reported by "./tcpdump --fp-type".
-
-$testlist = [
-    {
-        config_set => 'HAVE_FPTYPE1',
-        name => 'lmp-v-fptype1',
-        input => 'lmp.pcap',
-        output => 'lmp-v-fptype1.out',
-        args   => '-T lmp -v'
-    },
-    {
-        config_set => 'HAVE_FPTYPE2',
-        name => 'lmp-v-fptype2',
-        input => 'lmp.pcap',
-        output => 'lmp-v-fptype2.out',
-        args   => '-T lmp -v'
-    },
-];
-
-1;
diff --git a/tests/non-bsd.tests b/tests/non-bsd.tests
deleted file mode 100644 (file)
index f44610e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- perl -*-
-
-$testlist = [
-    # This specific test fails on OpenBSD because the .pcap file uses DLT_RAW,
-    # which OpenBSD treats as DLT_LOOP.
-    {
-        config_unset => 'IS_OPENBSD',
-        name => 'heap-overflow-1',
-        input => 'heap-overflow-1.pcap',
-        output => 'heap-overflow-1.out',
-        args   => '-v'
-    },
-];
-
-1;
diff --git a/tests/smb.tests b/tests/smb.tests
deleted file mode 100644 (file)
index 895ab8d..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-# -*- perl -*-
-
-# Only attempt OpenSSL-specific tests when compiled with the library.
-# Reading the secret(s) from a file does not work with Capsicum.
-
-$testlist = [
-
-# EAP tests
-    {
-        config_set => 'ENABLE_SMB',
-        name => 'eapon1',
-        input => 'eapon1.pcap',
-        output => 'eapon1.out',
-    },
-
-    {
-        config_unset => 'ENABLE_SMB',
-        name => 'eapon1-nosmb',
-        input => 'eapon1.pcap',
-        output => 'eapon1-nosmb.out',
-    },
-
-    {
-        config_set => 'ENABLE_SMB',
-        name => 'eapon1-v',
-        input => 'eapon1.pcap',
-        output => 'eapon1-v.out',
-        args   => '-v'
-    },
-
-    {
-        config_unset => 'ENABLE_SMB',
-        name => 'eapon1-v-nosmb',
-        input => 'eapon1.pcap',
-        output => 'eapon1-v-nosmb.out',
-        args   => '-v'
-    },
-
-# IPX/Netware packets
-    {
-        config_set => 'ENABLE_SMB',
-        name => 'ipx',
-        input => 'ipx.pcap',
-        output => 'ipx.out',
-    },
-
-    {
-        config_unset => 'ENABLE_SMB',
-        name => 'ipx-nosmb',
-        input => 'ipx.pcap',
-        output => 'ipx-nosmb.out',
-    },
-
-# bad packets from Otto Airamo and Antti Levomäki
-    {
-        config_set   => 'ENABLE_SMB',
-        name => 'nbns-valgrind',
-        input => 'nbns-valgrind.pcap',
-        output => 'nbns-valgrind.out',
-        args   => '-vvv -e',
-    },
-
-    {
-        config_unset   => 'ENABLE_SMB',
-        name => 'nbns-valgrind-nosmb',
-        input => 'nbns-valgrind.pcap',
-        output => 'nbns-valgrind-nosmb.out',
-        args   => '-vvv -e',
-    },
-
-# bad packets from Junjie Wang
-    {
-        config_set   => 'ENABLE_SMB',
-        name => 'smb_print_trans-oobr1',
-        input => 'smb_print_trans-oobr1.pcap',
-        output => 'smb_print_trans-oobr1.out',
-        args   => '-vv',
-    },
-
-    {
-        config_unset   => 'ENABLE_SMB',
-        name => 'smb_print_trans-oobr1-nosmb',
-        input => 'smb_print_trans-oobr1.pcap',
-        output => 'smb_print_trans-oobr1-nosmb.out',
-        args   => '-vv',
-    },
-
-# bad packets from Philippe Antoine
-    {
-        config_set   => 'ENABLE_SMB',
-        name => 'smb_print_trans-oobr2',
-        input => 'smb_print_trans-oobr2.pcap',
-        output => 'smb_print_trans-oobr2.out',
-        args   => '-vv',
-    },
-
-    {
-        config_unset   => 'ENABLE_SMB',
-        name => 'smb_print_trans-oobr2-nosmb',
-        input => 'smb_print_trans-oobr2.pcap',
-        output => 'smb_print_trans-oobr2-nosmb.out',
-        args   => '-vv',
-    },
-
-# bad packets from Luis Rocha
-    {
-        config_set   => 'ENABLE_SMB',
-        name => 'smb_data_print-oobr',
-        input => 'smb_data_print-oobr.pcapng',
-        output => 'smb_data_print-oobr.out',
-        args   => '-vv',
-    },
-
-    {
-        config_unset   => 'ENABLE_SMB',
-        name => 'smb_data_print-oobr-nosmb',
-        input => 'smb_data_print-oobr.pcapng',
-        output => 'smb_data_print-oobr-nosmb.out',
-        args   => '-vv',
-    },
-
-    {
-        config_set   => 'ENABLE_SMB',
-        name => 'smb_data_print-segv',
-        input => 'smb_data_print-segv.pcap',
-        output => 'smb_data_print-segv.out',
-        args   => '-vv',
-    },
-
-    {
-        config_unset   => 'ENABLE_SMB',
-        name => 'smb_data_print-segv-nosmb',
-        input => 'smb_data_print-segv.pcap',
-        output => 'smb_data_print-segv-nosmb.out',
-        args   => '-vv',
-    },
-
-# WCCP redirect over GRE
-    {
-        config_set   => 'ENABLE_SMB',
-        name => 'wccp_redirect_gre',
-        input => 'wccp_redirect_gre.pcap',
-        output => 'wccp_redirect_gre.out',
-        args   => '-v',
-    },
-
-    {
-        config_unset   => 'ENABLE_SMB',
-        name => 'wccp_redirect_gre-nosmb',
-        input => 'wccp_redirect_gre.pcap',
-        output => 'wccp_redirect_gre-nosmb.out',
-        args   => '-v',
-    },
-
-];
-
-1;
diff --git a/tests/time.tests b/tests/time.tests
deleted file mode 100644 (file)
index d819063..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- perl -*-
-
-# The packet time when > 2038-01-19T03:14:07Z cannot be correctly printed
-# if time_t size is 32 bits (overflow).
-# Some tests are run only if HAVE_TIME_T_64 is set. it depends on the
-# output of "./tcpdump --time-t-size" (32 or 64).
-
-# A 32-bit unsigned time_t goes until 2106-02-07T06:28:15Z.
-# All values above require a pcapng file.
-
-$testlist = [
-    {
-        name => 'time_2038',
-        input => 'time_2038.pcap',
-        output => 'time_2038.out',
-        args   => '-q'
-    },
-    {
-        name => 'time_2038_max',
-        input => 'time_2038_max.pcap',
-        output => 'time_2038_max.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2038_overflow',
-        input => 'time_2038_overflow.pcap',
-        output => 'time_2038_overflow.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2039',
-        input => 'time_2039.pcap',
-        output => 'time_2039.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2106',
-        input => 'time_2106.pcap',
-        output => 'time_2106.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2106_max',
-        input => 'time_2106_max.pcap',
-        output => 'time_2106_max.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2106_overflow',
-        input => 'time_2106_overflow.pcapng',
-        output => 'time_2106_overflow.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2107',
-        input => 'time_2107.pcapng',
-        output => 'time_2107.out',
-        args   => '-q'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2106_overflow-tt',
-        input => 'time_2106_overflow.pcapng',
-        output => 'time_2106_overflow-tt.out',
-        args   => '-tt -q SPECIAL_t'
-    },
-    {
-        config_set => 'HAVE_TIME_T_64',
-        name => 'time_2107-tt',
-        input => 'time_2107.pcapng',
-        output => 'time_2107-tt.out',
-        args   => '-tt -q SPECIAL_t'
-    },
-];
-
-1;