#
-# t/test.pl - most of Test::More functionality without the fuss
+# t/test.pl - most of Test::More functionality without the fuss, plus
+# has mappings native_to_latin1 and latin1_to_native so that fewer tests
+# on non ASCII-ish platforms need to be skipped
# NOTE:
$planned = $n;
}
+
+# Set the plan at the end. See Test::More::done_testing.
+sub done_testing {
+ my $n = $test - 1;
+ $n = shift if @_;
+
+ _print "1..$n\n";
+ $planned = $n;
+}
+
+
END {
my $ran = $test - 1;
if (!$NO_ENDING) {
}
}
-# Use this instead of "print STDERR" when outputing failure diagnostic
-# messages
sub _diag {
return unless @_;
- my @mess = map { /^#/ ? "$_\n" : "# $_\n" }
- map { split /\n/ } @_;
+ my @mess = _comment(@_);
$TODO ? _print(@mess) : _print_stderr(@mess);
}
+# Use this instead of "print STDERR" when outputing failure diagnostic
+# messages
sub diag {
_diag(@_);
}
+# Use this instead of "print" when outputing informational messages
+sub note {
+ return unless @_;
+ _print( _comment(@_) );
+}
+
+sub _comment {
+ return map { /^#/ ? "$_\n" : "# $_\n" }
+ map { split /\n/ } @_;
+}
+
sub skip_all {
if (@_) {
_print "1..0 # Skip @_\n";
$y = $y . $backslash_escape{$c};
} else {
my $z = chr $c; # Maybe we can get away with a literal...
- $z = sprintf "\\%03o", $c if $z =~ /[[:^print:]]/;
+ if ($z =~ /[[:^print:]]/) {
+
+ # Use octal for characters traditionally expressed as
+ # such: the low controls
+ if ($c <= 037) {
+ $z = sprintf "\\%03o", $c;
+ } else {
+ $z = sprintf "\\x{%x}", $c;
+ }
+ }
$y = $y . $z;
}
}
# Arguments :
# switches => [ command-line switches ]
# nolib => 1 # don't use -I../lib (included by default)
+# non_portable => Don't warn if a one liner contains quotes
# prog => one-liner (avoid quotes)
# progs => [ multi-liner (avoid quotes) ]
# progfile => perl script
# In VMS protect with doublequotes because otherwise
# DCL will lowercase -- unless already doublequoted.
$_ = q(").$_.q(") if $is_vms && !/^\"/ && length($_) > 0;
- $$runperl = $$runperl . ' ' . $_;
+ $runperl = $runperl . ' ' . $_;
}
+ return $runperl;
}
sub _create_runperl { # Create the string to qx in runperl().
local $Level = 2;
die "test.pl:runperl(): 'switches' must be an ARRAYREF " . _where()
unless ref $args{switches} eq "ARRAY";
- _quote_args(\$runperl, $args{switches});
+ $runperl = _quote_args($runperl, $args{switches});
}
if (defined $args{prog}) {
die "test.pl:runperl(): both 'prog' and 'progs' cannot be used " . _where()
die "test.pl:runperl(): 'progs' must be an ARRAYREF " . _where()
unless ref $args{progs} eq "ARRAY";
foreach my $prog (@{$args{progs}}) {
+ if ($prog =~ tr/'"// && !$args{non_portable}) {
+ warn "quotes in prog >>$prog<< are not portable";
+ }
if ($is_mswin || $is_netware || $is_vms) {
$runperl = $runperl . qq ( -e "$prog" );
}
}
}
if (defined $args{args}) {
- _quote_args(\$runperl, $args{args});
+ $runperl = _quote_args($runperl, $args{args});
}
$runperl = $runperl . ' 2>&1' if $args{stderr};
if ($args{verbose}) {
my @keys = grep {exists $ENV{$_}} qw(CDPATH IFS ENV BASH_ENV);
local @ENV{@keys} = ();
# Untaint, plus take out . and empty string:
- local $ENV{'DCL$PATH'} = $1 if $is_vms && ($ENV{'DCL$PATH'} =~ /(.*)/s);
+ local $ENV{'DCL$PATH'} = $1 if $is_vms && exists($ENV{'DCL$PATH'}) && ($ENV{'DCL$PATH'} =~ /(.*)/s);
$ENV{PATH} =~ /(.*)/s;
local $ENV{PATH} =
join $sep, grep { $_ ne "" and $_ ne "." and -d $_ and
($is_mswin or $is_vms or !(stat && (stat _)[2]&0022)) }
split quotemeta ($sep), $1;
- $ENV{PATH} = $ENV{PATH} . "$sep/bin" if $is_cygwin; # Must have /bin under Cygwin
-
+ if ($is_cygwin) { # Must have /bin under Cygwin
+ if (length $ENV{PATH}) {
+ $ENV{PATH} = $ENV{PATH} . $sep;
+ }
+ $ENV{PATH} = $ENV{PATH} . '/bin';
+ }
$runperl =~ /(.*)/s;
$runperl = $1;
return $result;
}
-*run_perl = \&runperl; # Nice alias.
+# Nice alias
+*run_perl = *run_perl = \&runperl; # shut up "used only once" warning
sub DIE {
_print_stderr "# @_\n";
my($prog, $expected, $runperl_args, $name) = @_;
local $Level = 2;
_fresh_perl($prog,
- sub { @_ ?
- $_[0] =~ (ref $expected ? $expected : /$expected/) :
- $expected },
+ sub { @_ ? $_[0] =~ $expected : $expected },
$runperl_args, $name);
}
_ok( !@nok, _where(), $name );
}
+
+# Call $class->new( @$args ); and run the result through isa_ok.
+# See Test::More::new_ok
+sub new_ok {
+ my($class, $args, $obj_name) = @_;
+ $args ||= [];
+ $object_name = "The object" unless defined $obj_name;
+
+ local $Level = $Level + 1;
+
+ my $obj;
+ my $ok = eval { $obj = $class->new(@$args); 1 };
+ my $error = $@;
+
+ if($ok) {
+ isa_ok($obj, $class, $object_name);
+ }
+ else {
+ ok( 0, "new() died" );
+ diag("Error was: $@");
+ }
+
+ return $obj;
+
+}
+
+
sub isa_ok ($$;$) {
my($object, $class, $obj_name) = @_;
# Set a watchdog to timeout the entire test file
# NOTE: If the test file uses 'threads', then call the watchdog() function
# _AFTER_ the 'threads' module is loaded.
-sub watchdog ($)
+sub watchdog ($;$)
{
my $timeout = shift;
+ my $method = shift || "";
my $timeout_msg = 'Test process timed out - terminating';
+ # Valgrind slows perl way down so give it more time before dying.
+ $timeout *= 10 if $ENV{PERL_VALGRIND};
+
my $pid_to_kill = $$; # PID for this process
+ if ($method eq "alarm") {
+ goto WATCHDOG_VIA_ALARM;
+ }
+
+ # shut up use only once warning
+ my $threads_on = $threads::threads && $threads::threads;
+
# Don't use a watchdog process if 'threads' is loaded -
# use a watchdog thread instead
- if (! $threads::threads) {
+ if (!$threads_on) {
# On Windows and VMS, try launching a watchdog process
# using system(1, ...) (see perlport.pod)
_diag("Watchdog warning: $_[0]");
};
my $sig = $^O eq 'VMS' ? 'TERM' : 'KILL';
- $watchdog = system(1, which_perl(), '-e',
- "sleep($timeout);" .
- "warn('# $timeout_msg\n');" .
+ my $cmd = _create_runperl( prog => "sleep($timeout);" .
+ "warn qq/# $timeout_msg" . '\n/;' .
"kill($sig, $pid_to_kill);");
+ $watchdog = system(1, $cmd);
};
if ($@ || ($watchdog <= 0)) {
_diag('Failed to start watchdog');
}
# If everything above fails, then just use an alarm timeout
+WATCHDOG_VIA_ALARM:
if (eval { alarm($timeout); 1; }) {
# Load POSIX if available
eval { require POSIX; };
}
}
+my $cp_0037 = # EBCDIC code page 0037
+ '\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F' .
+ '\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x1C\x1D\x1E\x1F' .
+ '\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61' .
+ '\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F' .
+ '\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6' .
+ '\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xBA\xE0\xBB\xB0\x6D' .
+ '\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96' .
+ '\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07' .
+ '\x20\x21\x22\x23\x24\x15\x06\x17\x28\x29\x2A\x2B\x2C\x09\x0A\x1B' .
+ '\x30\x31\x1A\x33\x34\x35\x36\x08\x38\x39\x3A\x3B\x04\x14\x3E\xFF' .
+ '\x41\xAA\x4A\xB1\x9F\xB2\x6A\xB5\xBD\xB4\x9A\x8A\x5F\xCA\xAF\xBC' .
+ '\x90\x8F\xEA\xFA\xBE\xA0\xB6\xB3\x9D\xDA\x9B\x8B\xB7\xB8\xB9\xAB' .
+ '\x64\x65\x62\x66\x63\x67\x9E\x68\x74\x71\x72\x73\x78\x75\x76\x77' .
+ '\xAC\x69\xED\xEE\xEB\xEF\xEC\xBF\x80\xFD\xFE\xFB\xFC\xAD\xAE\x59' .
+ '\x44\x45\x42\x46\x43\x47\x9C\x48\x54\x51\x52\x53\x58\x55\x56\x57' .
+ '\x8C\x49\xCD\xCE\xCB\xCF\xCC\xE1\x70\xDD\xDE\xDB\xDC\x8D\x8E\xDF';
+
+my $cp_1047 = # EBCDIC code page 1047
+ '\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x15\x0B\x0C\x0D\x0E\x0F' .
+ '\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x1C\x1D\x1E\x1F' .
+ '\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61' .
+ '\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F' .
+ '\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6' .
+ '\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D' .
+ '\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96' .
+ '\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07' .
+ '\x20\x21\x22\x23\x24\x25\x06\x17\x28\x29\x2A\x2B\x2C\x09\x0A\x1B' .
+ '\x30\x31\x1A\x33\x34\x35\x36\x08\x38\x39\x3A\x3B\x04\x14\x3E\xFF' .
+ '\x41\xAA\x4A\xB1\x9F\xB2\x6A\xB5\xBB\xB4\x9A\x8A\xB0\xCA\xAF\xBC' .
+ '\x90\x8F\xEA\xFA\xBE\xA0\xB6\xB3\x9D\xDA\x9B\x8B\xB7\xB8\xB9\xAB' .
+ '\x64\x65\x62\x66\x63\x67\x9E\x68\x74\x71\x72\x73\x78\x75\x76\x77' .
+ '\xAC\x69\xED\xEE\xEB\xEF\xEC\xBF\x80\xFD\xFE\xFB\xFC\xBA\xAE\x59' .
+ '\x44\x45\x42\x46\x43\x47\x9C\x48\x54\x51\x52\x53\x58\x55\x56\x57' .
+ '\x8C\x49\xCD\xCE\xCB\xCF\xCC\xE1\x70\xDD\xDE\xDB\xDC\x8D\x8E\xDF';
+
+my $cp_bc = # EBCDIC code page POSiX-BC
+ '\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x15\x0B\x0C\x0D\x0E\x0F' .
+ '\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x1C\x1D\x1E\x1F' .
+ '\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61' .
+ '\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F' .
+ '\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6' .
+ '\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xBB\xBC\xBD\x6A\x6D' .
+ '\x4A\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96' .
+ '\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xFB\x4F\xFD\xFF\x07' .
+ '\x20\x21\x22\x23\x24\x25\x06\x17\x28\x29\x2A\x2B\x2C\x09\x0A\x1B' .
+ '\x30\x31\x1A\x33\x34\x35\x36\x08\x38\x39\x3A\x3B\x04\x14\x3E\x5F' .
+ '\x41\xAA\xB0\xB1\x9F\xB2\xD0\xB5\x79\xB4\x9A\x8A\xBA\xCA\xAF\xA1' .
+ '\x90\x8F\xEA\xFA\xBE\xA0\xB6\xB3\x9D\xDA\x9B\x8B\xB7\xB8\xB9\xAB' .
+ '\x64\x65\x62\x66\x63\x67\x9E\x68\x74\x71\x72\x73\x78\x75\x76\x77' .
+ '\xAC\x69\xED\xEE\xEB\xEF\xEC\xBF\x80\xE0\xFE\xDD\xFC\xAD\xAE\x59' .
+ '\x44\x45\x42\x46\x43\x47\x9C\x48\x54\x51\x52\x53\x58\x55\x56\x57' .
+ '\x8C\x49\xCD\xCE\xCB\xCF\xCC\xE1\x70\xC0\xDE\xDB\xDC\x8D\x8E\xDF';
+
+my $straight = # Avoid ranges
+ '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F' .
+ '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F' .
+ '\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F' .
+ '\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F' .
+ '\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F' .
+ '\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F' .
+ '\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F' .
+ '\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F' .
+ '\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F' .
+ '\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F' .
+ '\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF' .
+ '\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF' .
+ '\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF' .
+ '\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF' .
+ '\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF' .
+ '\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF';
+
+# The following 2 functions allow tests to work on both EBCDIC and
+# ASCII-ish platforms. They convert string scalars between the native
+# character set and the set of 256 characters which is usually called
+# Latin1.
+#
+# These routines don't work on UTF-EBCDIC and UTF-8.
+
+sub native_to_latin1($) {
+ my $string = shift;
+
+ return $string if ord('^') == 94; # ASCII, Latin1
+ my $cp;
+ if (ord('^') == 95) { # EBCDIC 1047
+ $cp = \$cp_1047;
+ }
+ elsif (ord('^') == 106) { # EBCDIC POSIX-BC
+ $cp = \$cp_bc;
+ }
+ elsif (ord('^') == 176) { # EBCDIC 037 */
+ $cp = \$cp_0037;
+ }
+ else {
+ die "Unknown native character set";
+ }
+
+ eval '$string =~ tr/' . $$cp . '/' . $straight . '/';
+ return $string;
+}
+
+sub latin1_to_native($) {
+ my $string = shift;
+
+ return $string if ord('^') == 94; # ASCII, Latin1
+ my $cp;
+ if (ord('^') == 95) { # EBCDIC 1047
+ $cp = \$cp_1047;
+ }
+ elsif (ord('^') == 106) { # EBCDIC POSIX-BC
+ $cp = \$cp_bc;
+ }
+ elsif (ord('^') == 176) { # EBCDIC 037 */
+ $cp = \$cp_0037;
+ }
+ else {
+ die "Unknown native character set";
+ }
+
+ eval '$string =~ tr/' . $straight . '/' . $$cp . '/';
+ return $string;
+}
+
+sub ord_latin1_to_native {
+ # given an input latin1 code point, return the platform's native
+ # equivalent value
+
+ return ord latin1_to_native(chr $_[0]);
+}
+
+sub ord_native_to_latin1 {
+ # given an input platform code point, return the latin1 equivalent value
+
+ return ord native_to_latin1(chr $_[0]);
+}
+
1;