]> The Tcpdump Group git mirrors - libpcap/commitdiff
Factor TESTlib.pm out. [skip appveyor] 1456/head
authorDenis Ovsienko <[email protected]>
Mon, 20 Jan 2025 19:57:04 +0000 (19:57 +0000)
committerDenis Ovsienko <[email protected]>
Thu, 6 Feb 2025 13:13:09 +0000 (13:13 +0000)
Rewrite the six skip subroutines in a generic manner (to take an
argument).  Add new subroutines to produce a test result of the required
type instead of hard-coding the hash structure and the ASCII character
in the test runner functions.  Move that and other generic reusable code
to the new file.  This way the project-specific script uses the shared
code roughly as follows:

1. Call read_config_h() if shared skip functions are required.
2. Define the test runner subroutines.
3. Produce a list of ready-to-run tests.
4. Call init_tmpdir().
5. Call test_and_report().

INSTALL.md
Makefile.in
testprogs/TESTlib.pm [new file with mode: 0644]
testprogs/TESTmt.pm
testprogs/TESTrun
testprogs/TESTst.pm

index f355f74ac51584ecdc144e1645a124c19a3beb27..fff86300a57b93228322e49d4ec00ea955e5e16f 100644 (file)
@@ -164,6 +164,7 @@ You can get around this by installing GCC.
        fmtutils.h          - error message formatting prototypes
        ftmacros.h          - feature test macros
        testprogs/TESTrun   - a script for "make check"
        fmtutils.h          - error message formatting prototypes
        ftmacros.h          - feature test macros
        testprogs/TESTrun   - a script for "make check"
+       testprogs/TESTlib.pm - TESTrun helper file
        testprogs/TESTmt.pm - TESTrun helper file
        testprogs/TESTst.pm - TESTrun helper file
        testprogs/filtertest.c      - test program for BPF compiler
        testprogs/TESTmt.pm - TESTrun helper file
        testprogs/TESTst.pm - TESTrun helper file
        testprogs/filtertest.c      - test program for BPF compiler
index 3aaaf6ea3ca7045c4122d9ed282fbc92bf42e91f..3d7ea48940ddabc8a022206289c1970795caa21a 100644 (file)
@@ -351,6 +351,7 @@ EXTRA_DIST = \
        testprogs/CMakeLists.txt \
        testprogs/Makefile.in \
        testprogs/TESTrun \
        testprogs/CMakeLists.txt \
        testprogs/Makefile.in \
        testprogs/TESTrun \
+       testprogs/TESTlib.pm \
        testprogs/TESTmt.pm \
        testprogs/TESTst.pm \
        testprogs/activatetest.c \
        testprogs/TESTmt.pm \
        testprogs/TESTst.pm \
        testprogs/activatetest.c \
diff --git a/testprogs/TESTlib.pm b/testprogs/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;
index b7152e0e399f77e1910ec9482acbbfd39fefee65..e9f72f2983edc29d2093fab92f5df80eefb75b76 100644 (file)
@@ -3,6 +3,8 @@ use strict;
 use warnings FATAL => qw(uninitialized);
 use threads;
 use Thread::Queue;
 use warnings FATAL => qw(uninitialized);
 use threads;
 use Thread::Queue;
+# TESTlib.pm
+use subs qw(get_njobs);
 
 # TESTrun helper functions (multithreaded implementation).
 
 
 # TESTrun helper functions (multithreaded implementation).
 
@@ -17,11 +19,6 @@ sub my_tmp_id {
        return $tmpid;
 }
 
        return $tmpid;
 }
 
-sub set_njobs {
-       $njobs = shift;
-       print "INFO: This Perl supports threads, using $njobs tester thread(s).\n";
-}
-
 # 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 {
 # 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 {
@@ -40,6 +37,8 @@ sub tester_thread_func {
 }
 
 sub start_tests {
 }
 
 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;
        @tests = @_;
        for (0 .. $njobs - 1) {
                $result_queues[$_] = Thread::Queue->new;
index 20920e0dcf17c0735886d9554d4f243474e77d2c..f9870ad65aab4eab1d96d0b8c2185409c770a1f6 100755 (executable)
 use sigtrap qw(die normal-signals);
 use strict;
 use warnings FATAL => qw(uninitialized);
 use sigtrap qw(die normal-signals);
 use strict;
 use warnings FATAL => qw(uninitialized);
-use File::Temp qw(tempdir);
+require $FindBin::RealBin . '/TESTlib.pm';
+# TESTlib.pm
+use subs qw(
+       file_get_contents
+       file_put_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_have_decl
+       skip_config_undef
+       skip_os
+       skip_os_not
+       string_in_file
+       test_and_report
+);
 
 BEGIN {
        require 5.8.4; # Solaris 10
 
 BEGIN {
        require 5.8.4; # Solaris 10
@@ -65,54 +86,9 @@ BEGIN {
 
 use constant SAVEFILE_DIR => $FindBin::RealBin . '/../tests/filter/';
 
 
 use constant SAVEFILE_DIR => $FindBin::RealBin . '/../tests/filter/';
 
-# When using threads, STDOUT becomes line-buffered on TTYs, which is not good
-# for interactive progress monitoring.
-STDOUT->autoflush (1) if $Config{useithreads} && -t STDOUT;
-
-# Parse config.h into a hash for later use.
-my %config = ();
-my $re_define_uint = qr/^#define ([0-9_A-Z]+) ([0-9]+)$/;
-my $re_define_str = qr/^#define ([0-9_A-Z]+) "(.+)"$/;
 my $config_h = defined $ENV{CONFIG_H} ? $ENV{CONFIG_H} : './config.h';
 my $config_h = defined $ENV{CONFIG_H} ? $ENV{CONFIG_H} : './config.h';
-open (my $fh, '<', $config_h) || die "failed opening '$config_h'";
-while (<$fh>) {
-       $config{$1} = $2 if /$re_define_uint/ || /$re_define_str/;
-}
-close ($fh) || die "failed closing '$config_h'";
-
-sub ipv6_disabled {
-       return (defined $config{INET6} && $config{INET6}) ? '' : 'IPv6 syntax disabled';
-}
-
-sub ipv6_enabled {
-       return (defined $config{INET6} && $config{INET6}) ? 'IPv6 syntax enabled' : '';
-}
-
-sub broken_igrp {
-       return $^O eq 'freebsd' ? 'running on FreeBSD' :
-               $^O eq 'darwin' ? 'running on macOS' :
-               '';
-}
-
-sub is_linux {
-       return $^O eq 'linux' ? 'running on Linux' : '';
-}
-
-sub is_not_linux {
-       return $^O eq 'linux' ? '' : 'not running on Linux';
-}
-
-sub 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" : '';
-}
+# Enable all shared skip functions to be able to declare the tests below.
+read_config_h ($config_h);
 
 # In accept_blocks the top-level keys are test block names.  Each test block
 # defines one or more tests.  When possible, a test block name should be easy
 
 # In accept_blocks the top-level keys are test block names.  Each test block
 # defines one or more tests.  When possible, a test block name should be easy
@@ -513,7 +489,7 @@ my %accept_blocks = (
                        ',
        }, # juniper_mfr_outbound
        inbound_linuxext => {
                        ',
        }, # juniper_mfr_outbound
        inbound_linuxext => {
-               skip => is_not_linux(),
+               skip => skip_os_not ('linux'),
                linuxext => 1,
                DLT => 'EN10MB',
                expr => 'inbound',
                linuxext => 1,
                DLT => 'EN10MB',
                expr => 'inbound',
@@ -525,7 +501,7 @@ my %accept_blocks = (
                        ',
        }, # inbound_linuxext
        outbound_linuxext => {
                        ',
        }, # inbound_linuxext
        outbound_linuxext => {
-               skip => is_not_linux(),
+               skip => skip_os_not ('linux'),
                linuxext => 1,
                DLT => 'EN10MB',
                expr => 'outbound',
                linuxext => 1,
                DLT => 'EN10MB',
                expr => 'outbound',
@@ -537,7 +513,7 @@ my %accept_blocks = (
                        ',
        }, # outbound_linuxext
        ifindex_linuxext => {
                        ',
        }, # outbound_linuxext
        ifindex_linuxext => {
-               skip => is_not_linux(),
+               skip => skip_os_not ('linux'),
                linuxext => 1,
                DLT => 'EN10MB',
                expr => 'ifindex 10',
                linuxext => 1,
                DLT => 'EN10MB',
                expr => 'ifindex 10',
@@ -1943,7 +1919,7 @@ my %accept_blocks = (
        }, # ether_proto_ip
        ether_proto_ip6 => {
                DLT => 'EN10MB',
        }, # ether_proto_ip
        ether_proto_ip6 => {
                DLT => 'EN10MB',
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                expr => 'ether proto \ip6',
                unopt => '
                        (000) ldh      [12]
                expr => 'ether proto \ip6',
                unopt => '
                        (000) ldh      [12]
@@ -2159,7 +2135,7 @@ my %accept_blocks = (
                        ',
        }, # vlan_netanalyzer_unary
        vlan_eth_linuxext_nullary => {
                        ',
        }, # vlan_netanalyzer_unary
        vlan_eth_linuxext_nullary => {
-               skip => (is_not_linux() or have_decl ('SKF_AD_VLAN_TAG_PRESENT', 0)),
+               skip => (skip_os_not ('linux') or skip_config_have_decl ('SKF_AD_VLAN_TAG_PRESENT', 0)),
                DLT => 'EN10MB',
                linuxext => 1,
                expr => 'vlan',
                DLT => 'EN10MB',
                linuxext => 1,
                expr => 'vlan',
@@ -2175,7 +2151,7 @@ my %accept_blocks = (
                        ',
        }, # vlan_eth_linuxext_nullary
        vlan_eth_linuxext_unary => {
                        ',
        }, # vlan_eth_linuxext_nullary
        vlan_eth_linuxext_unary => {
-               skip => (is_not_linux() or have_decl ('SKF_AD_VLAN_TAG_PRESENT', 0)),
+               skip => (skip_os_not ('linux') or skip_config_have_decl ('SKF_AD_VLAN_TAG_PRESENT', 0)),
                DLT => 'EN10MB',
                linuxext => 1,
                expr => 'vlan 10',
                DLT => 'EN10MB',
                linuxext => 1,
                expr => 'vlan 10',
@@ -2198,7 +2174,7 @@ my %accept_blocks = (
                        ',
        }, # vlan_eth_linuxext_unary
        vlan_and_vlan_eth_linuxext => {
                        ',
        }, # vlan_eth_linuxext_unary
        vlan_and_vlan_eth_linuxext => {
-               skip => (is_not_linux() or have_decl ('SKF_AD_VLAN_TAG_PRESENT', 0)),
+               skip => (skip_os_not ('linux') or skip_config_have_decl ('SKF_AD_VLAN_TAG_PRESENT', 0)),
                DLT => 'EN10MB',
                linuxext => 1,
                expr => 'vlan and vlan',
                DLT => 'EN10MB',
                linuxext => 1,
                expr => 'vlan and vlan',
@@ -4357,7 +4333,7 @@ my %accept_blocks = (
                # "igrp" uses IPPROTO_IGRP, which FreeBSD defines differently
                # from all other supported OSes.  Skip the test until it is
                # clear how to resolve this discrepancy.
                # "igrp" uses IPPROTO_IGRP, which FreeBSD defines differently
                # from all other supported OSes.  Skip the test until it is
                # clear how to resolve this discrepancy.
-               skip => broken_igrp(),
+               skip => (skip_os ('freebsd') or skip_os ('darwin')),
                DLT => 'EN10MB',
                expr => 'igrp',
                aliases => ['ip proto 9'],
                DLT => 'EN10MB',
                expr => 'igrp',
                aliases => ['ip proto 9'],
@@ -4520,7 +4496,7 @@ my %accept_blocks = (
        }, # udp
 
        ip6_host => {
        }, # udp
 
        ip6_host => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 host ::1',
                aliases => [
                DLT => 'RAW',
                expr => 'ip6 host ::1',
                aliases => [
@@ -4555,7 +4531,7 @@ my %accept_blocks = (
                        ',
        }, # ip6_host
        ip6_src_host => {
                        ',
        }, # ip6_host
        ip6_src_host => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 src host fe80::1122:33ff:fe44:5566',
                aliases => [
                DLT => 'RAW',
                expr => 'ip6 src host fe80::1122:33ff:fe44:5566',
                aliases => [
@@ -4580,7 +4556,7 @@ my %accept_blocks = (
                        ',
        }, # ip6_src_host
        ip6_dst_host => {
                        ',
        }, # ip6_src_host
        ip6_dst_host => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 dst host fe80::7788:99ff:feaa:bbcc',
                aliases => [
                DLT => 'RAW',
                expr => 'ip6 dst host fe80::7788:99ff:feaa:bbcc',
                aliases => [
@@ -4605,7 +4581,7 @@ my %accept_blocks = (
                        ',
        }, # ip6_dst_host
        ip6_net => {
                        ',
        }, # ip6_dst_host
        ip6_net => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 net fe80::/10',
                aliases => [
                DLT => 'RAW',
                expr => 'ip6 net fe80::/10',
                aliases => [
@@ -4628,7 +4604,7 @@ my %accept_blocks = (
                        ',
        }, # ip6_net
        ip6_src_net => {
                        ',
        }, # ip6_net
        ip6_src_net => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 src net 2000::/3',
                aliases => ['src net 2000::/3'],
                DLT => 'RAW',
                expr => 'ip6 src net 2000::/3',
                aliases => ['src net 2000::/3'],
@@ -4644,7 +4620,7 @@ my %accept_blocks = (
                        ',
        }, # ip6_src_net
        ip6_dst_net => {
                        ',
        }, # ip6_src_net
        ip6_dst_net => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 dst net ff00::/8',
                aliases => ['dst net ff00::/8'],
                DLT => 'RAW',
                expr => 'ip6 dst net ff00::/8',
                aliases => ['dst net ff00::/8'],
@@ -6226,7 +6202,7 @@ my %reject_tests = (
                errstr => 'invalid IPv4 address',
        },
        ip6_host_toolong => {
                errstr => 'invalid IPv4 address',
        },
        ip6_host_toolong => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 host fe80:0:0:0:0:0:0:0:0',
                errstr => 'syntax error',
                DLT => 'RAW',
                expr => 'ip6 host fe80:0:0:0:0:0:0:0:0',
                errstr => 'syntax error',
@@ -6250,25 +6226,25 @@ my %reject_tests = (
 #              errstr => 'unknown host',
 #      },
        ip6_host_disabled => {
 #              errstr => 'unknown host',
 #      },
        ip6_host_disabled => {
-               skip => ipv6_enabled(),
+               skip => skip_config_def1 ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 host fe80:0:0:0:0:0:0:0',
                errstr => 'not supported',
        },
        ip6_net_prefix => {
                DLT => 'RAW',
                expr => 'ip6 host fe80:0:0:0:0:0:0:0',
                errstr => 'not supported',
        },
        ip6_net_prefix => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 net fe80:0:0:0:0:0:0:0:0/64',
                errstr => 'syntax error',
        },
        ip6_net_masklen => {
                DLT => 'RAW',
                expr => 'ip6 net fe80:0:0:0:0:0:0:0:0/64',
                errstr => 'syntax error',
        },
        ip6_net_masklen => {
-               skip => ipv6_disabled(),
+               skip => skip_config_undef ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 net fe80:0:0:0:0:0:0:0/129',
                errstr => 'mask length must be <= 128',
        },
        ip6_net_disabled => {
                DLT => 'RAW',
                expr => 'ip6 net fe80:0:0:0:0:0:0:0/129',
                errstr => 'mask length must be <= 128',
        },
        ip6_net_disabled => {
-               skip => ipv6_enabled(),
+               skip => skip_config_def1 ('INET6'),
                DLT => 'RAW',
                expr => 'ip6 net fe80:0:0:0:0:0:0:0/64',
                errstr => 'not supported',
                DLT => 'RAW',
                expr => 'ip6 net fe80:0:0:0:0:0:0:0/64',
                errstr => 'not supported',
@@ -6344,37 +6320,37 @@ my %reject_tests = (
                errstr => 'greater than maximum',
        },
        inbound_not_supported_linux => {
                errstr => 'greater than maximum',
        },
        inbound_not_supported_linux => {
-               skip => is_not_linux(),
+               skip => skip_os_not ('linux'),
                DLT => 'EN10MB',
                expr => 'inbound',
                errstr => 'not a live capture',
        },
        outbound_not_supported_linux => {
                DLT => 'EN10MB',
                expr => 'inbound',
                errstr => 'not a live capture',
        },
        outbound_not_supported_linux => {
-               skip => is_not_linux(),
+               skip => skip_os_not ('linux'),
                DLT => 'EN10MB',
                expr => 'outbound',
                errstr => 'not a live capture',
        },
        ifindex_not_supported_linux => {
                DLT => 'EN10MB',
                expr => 'outbound',
                errstr => 'not a live capture',
        },
        ifindex_not_supported_linux => {
-               skip => is_not_linux(),
+               skip => skip_os_not ('linux'),
                DLT => 'LINUX_SLL',
                expr => 'ifindex 1',
                errstr => 'not a live capture',
        },
        inbound_not_supported_other => {
                DLT => 'LINUX_SLL',
                expr => 'ifindex 1',
                errstr => 'not a live capture',
        },
        inbound_not_supported_other => {
-               skip => is_linux(),
+               skip => skip_os ('linux'),
                DLT => 'EN10MB',
                expr => 'inbound',
                errstr => 'not supported',
        },
        outbound_not_supported_other => {
                DLT => 'EN10MB',
                expr => 'inbound',
                errstr => 'not supported',
        },
        outbound_not_supported_other => {
-               skip => is_linux(),
+               skip => skip_os ('linux'),
                DLT => 'EN10MB',
                expr => 'outbound',
                errstr => 'not supported',
        },
        ifindex_not_supported_other => {
                DLT => 'EN10MB',
                expr => 'outbound',
                errstr => 'not supported',
        },
        ifindex_not_supported_other => {
-               skip => is_linux(),
+               skip => skip_os ('linux'),
                DLT => 'EN10MB',
                expr => 'ifindex 1',
                errstr => 'not supported',
                DLT => 'EN10MB',
                expr => 'ifindex 1',
                errstr => 'not supported',
@@ -6420,24 +6396,12 @@ use constant TIMED_OUT => 124;
 # conditions.
 use constant EX_DATAERR => 65;
 
 # conditions.
 use constant EX_DATAERR => 65;
 
-# No File::Temp->newdir() in Perl 5.8.4.
-my $tmpdir = tempdir (
-       'libpcap_TESTrun_XXXXXXXX',
-       TMPDIR => 1,
-       CLEANUP => 1
-);
 my $filename_expected = 'expected.txt';
 my $filename_stdout = 'stdout.txt';
 my $filename_filter = 'filter.txt';
 my $filename_diags = 'diags.txt';
 
 my $filename_expected = 'expected.txt';
 my $filename_stdout = 'stdout.txt';
 my $filename_filter = 'filter.txt';
 my $filename_diags = 'diags.txt';
 
-sub mytmpfile {
-       return sprintf '%s/%s-%s', $tmpdir, my_tmp_id, shift;
-}
-
-my $diff_flags = defined $ENV{DIFF_FLAGS} ? $ENV{DIFF_FLAGS} :
-       $^O eq 'hpux' ? '-c' :
-       '-u';
+my $diff_flags = get_diff_flags;
 
 # Every test in this file uses an expression that under normal conditions takes
 # well under one second to process, so if a filtertest invocation is taking
 
 # Every test in this file uses an expression that under normal conditions takes
 # well under one second to process, so if a filtertest invocation is taking
@@ -6468,54 +6432,6 @@ my $filtertest = defined $ENV{FILTERTEST_BIN} ? $ENV{FILTERTEST_BIN} :
        'testprogs/filtertest';
 my $only_one = @ARGV == 1 ? $ARGV[0] : undef;
 
        'testprogs/filtertest';
 my $only_one = @ARGV == 1 ? $ARGV[0] : undef;
 
-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;
-set_njobs ($njobs);
-
-# 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;
-}
-
-# This is the same format as in tcpdump/tests/TESTrun.
-sub print_result {
-       printf "    %-40s: %s\n", @_;
-}
-
 # In this libpcap version "filtertest -h" prints to stdout and exits normally.
 if (system ("$filtertest -h >/dev/null 2>&1") >> 8) {
        # Make it easier to see what the problem is.
 # In this libpcap version "filtertest -h" prints to stdout and exits normally.
 if (system ("$filtertest -h >/dev/null 2>&1") >> 8) {
        # Make it easier to see what the problem is.
@@ -6544,41 +6460,24 @@ sub reject_test_label {
        return "reject_${name}";
 }
 
        return "reject_${name}";
 }
 
-# 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',
-};
-
 sub validate_stdout_test {
        my $r = system (join ' ', @_) >> 8;
 sub validate_stdout_test {
        my $r = system (join ' ', @_) >> 8;
-       return {
-               char => CHAR_TIMED_OUT,
-               failure => {reason => 'filtertest timeout'}
-       } if $r == TIMED_OUT;
+       return result_timed_out 'filtertest timeout' if $r == TIMED_OUT;
 
 
-       return {
-               char => CHAR_FAILED,
-               failure => {
-                       reason => 'filtertest error',
-                       details => file_get_contents mytmpfile $filename_stdout
-               }
-       } if $r;
+       return result_failed (
+               'filtertest error',
+               file_get_contents mytmpfile $filename_stdout
+       ) if $r;
 
 
-       return {
-               char => CHAR_FAILED,
-               failure => {
-                       reason => 'diff error',
-                       details => file_get_contents mytmpfile $filename_diags
-               }
-       } if system sprintf "diff $diff_flags %s %s >%s 2>&1",
+       return result_failed (
+               'diff error',
+               file_get_contents mytmpfile $filename_diags
+       ) if system sprintf "diff $diff_flags %s %s >%s 2>&1",
                mytmpfile ($filename_expected),
                mytmpfile ($filename_stdout),
                mytmpfile ($filename_diags);
 
                mytmpfile ($filename_expected),
                mytmpfile ($filename_stdout),
                mytmpfile ($filename_diags);
 
-       return {char => CHAR_PASSED};
+       return result_passed;
 }
 
 sub common_filtertest_args {
 }
 
 sub common_filtertest_args {
@@ -6642,44 +6541,24 @@ sub run_reject_test {
        );
        my $r = system (join ' ', @args) >> 8;
 
        );
        my $r = system (join ' ', @args) >> 8;
 
-       return {
-               char => CHAR_FAILED,
-               failure => {
-                       reason => 'no filtertest error',
-                       details => file_get_contents mytmpfile $filename_stdout
-               }
-       } if $r == 0;
+       return result_failed (
+               'no filtertest error',
+               file_get_contents mytmpfile $filename_stdout
+       ) if $r == 0;
 
 
-       return {
-               char => CHAR_TIMED_OUT,
-               failure => {reason => 'filtertest timeout'}
-       } if $r == TIMED_OUT;
+       return result_timed_out 'filtertest timeout' if $r == TIMED_OUT;
 
 
-       return {
-               char => CHAR_FAILED,
-               failure => {
-                       reason => "filtertest status $r",
-                       details => file_get_contents mytmpfile $filename_stdout
-               }
-       } if $r != EX_DATAERR;
+       return result_failed (
+               "filtertest status $r",
+               file_get_contents mytmpfile $filename_stdout
+       ) if $r != EX_DATAERR;
 
 
-       return {
-               char => CHAR_FAILED,
-               failure => {
-                       reason => 'error string mismatch',
-                       details => file_get_contents mytmpfile $filename_stdout
-               }
-       }       if ! string_in_file ($test->{expected}, mytmpfile $filename_stdout);
+       return result_failed (
+               'error string mismatch',
+               file_get_contents mytmpfile $filename_stdout
+       ) if ! string_in_file ($test->{expected}, mytmpfile $filename_stdout);
 
 
-       return {char => CHAR_PASSED};
-}
-
-sub run_skip_test {
-       my $test = shift;
-       return {
-               char => CHAR_SKIPPED,
-               skip => $test->{skip},
-       };
+       return result_passed;
 }
 
 # Sort all hash elements by key, otherwise the pseudo-random ordering in Perl
 }
 
 # Sort all hash elements by key, otherwise the pseudo-random ordering in Perl
@@ -6805,99 +6684,9 @@ foreach my $testname (sort keys %reject_tests) {
        }
 }
 
        }
 }
 
-my $results_to_print = scalar @ready_to_run;
-if (! $results_to_print) {
+if (! scalar @ready_to_run) {
        die "ERROR: Unknown test case '${only_one}'" if defined $only_one;
        die 'Internal error: no tests defined to run!'
 }
        die "ERROR: Unknown test case '${only_one}'" if defined $only_one;
        die 'Internal error: no tests defined to run!'
 }
-start_tests (@ready_to_run);
-
-# <-------------------------- MAXCOLS -------------------------->
-# ............................................ 0000 / 0000 (000%)
-#                          $max_result_digits >----< >----<
-# <--------- $max_results_per_line ---------->
-use constant MAXCOLS => 80;
-my $max_result_digits = 1 + int (log ($results_to_print) / log (10));
-my $max_results_per_line = MAXCOLS - 11 - 2 * $max_result_digits;
-my $results_printed = 0;
-
-# 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 $Config{useithreads} && ! -t STDOUT;
-}
-
-# 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";
-my $exit_status = 0;
-if (%skipped) {
-       print "Skipped tests:\n";
-       print_result $_, $skipped{$_} foreach (sort keys %skipped);
-       print "\n";
-}
-if (%failed) {
-       $exit_status = 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;
-       $exit_status = 2;
-}
-
-exit $exit_status;
+init_tmpdir 'libpcap_TESTrun';
+exit test_and_report @ready_to_run;
index cbf9d1d8a8c6147feb9650c127d58701936f1541..ffdcb6708cba39fc47a02911f21bb90f693a6294 100644 (file)
@@ -1,6 +1,8 @@
 require 5.8.4; # Solaris 10
 use strict;
 use warnings FATAL => qw(uninitialized);
 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).
 
 
 # TESTrun helper functions (single-threaded implementation).
 
@@ -10,13 +12,10 @@ sub my_tmp_id {
        return 'main';
 }
 
        return 'main';
 }
 
-sub set_njobs {
+sub start_tests {
        print "INFO: This Perl does not support threads.\n";
        print "INFO: This Perl does not support threads.\n";
-       my $njobs = shift;
+       my $njobs = get_njobs;
        die "ERROR: Impossible to run $njobs tester threads!" if $njobs > 1;
        die "ERROR: Impossible to run $njobs tester threads!" if $njobs > 1;
-}
-
-sub start_tests {
        @tests = @_;
 }
 
        @tests = @_;
 }