test.pm

来自「视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.」· PM 代码 · 共 956 行 · 第 1/2 页

PM
956
字号
require 5.004;package Test;# Time-stamp: "2004-04-28 21:46:51 ADT"use strict;use Carp;use vars (qw($VERSION @ISA @EXPORT @EXPORT_OK $ntest $TestLevel), #public-ish          qw($TESTOUT $TESTERR %Program_Lines $told_about_diff             $ONFAIL %todo %history $planned @FAILDETAIL) #private-ish         );# In case a test is run in a persistent environment.sub _reset_globals {    %todo       = ();    %history    = ();    @FAILDETAIL = ();    $ntest      = 1;    $TestLevel  = 0;		# how many extra stack frames to skip    $planned    = 0;}$VERSION = '1.25';require Exporter;@ISA=('Exporter');@EXPORT    = qw(&plan &ok &skip);@EXPORT_OK = qw($ntest $TESTOUT $TESTERR);$|=1;$TESTOUT = *STDOUT{IO};$TESTERR = *STDERR{IO};# Use of this variable is strongly discouraged.  It is set mainly to# help test coverage analyzers know which test is running.$ENV{REGRESSION_TEST} = $0;=head1 NAMETest - provides a simple framework for writing test scripts=head1 SYNOPSIS  use strict;  use Test;  # use a BEGIN block so we print our plan before MyModule is loaded  BEGIN { plan tests => 14, todo => [3,4] }  # load your module...  use MyModule;  # Helpful notes.  All note-lines must start with a "#".  print "# I'm testing MyModule version $MyModule::VERSION\n";  ok(0); # failure  ok(1); # success  ok(0); # ok, expected failure (see todo list, above)  ok(1); # surprise success!  ok(0,1);             # failure: '0' ne '1'  ok('broke','fixed'); # failure: 'broke' ne 'fixed'  ok('fixed','fixed'); # success: 'fixed' eq 'fixed'  ok('fixed',qr/x/);   # success: 'fixed' =~ qr/x/  ok(sub { 1+1 }, 2);  # success: '2' eq '2'  ok(sub { 1+1 }, 3);  # failure: '2' ne '3'  my @list = (0,0);  ok @list, 3, "\@list=".join(',',@list);      #extra notes  ok 'segmentation fault', '/(?i)success/';    #regex match  skip(    $^O =~ m/MSWin/ ? "Skip if MSWin" : 0,  # whether to skip    $foo, $bar  # arguments just like for ok(...)  );  skip(    $^O =~ m/MSWin/ ? 0 : "Skip unless MSWin",  # whether to skip    $foo, $bar  # arguments just like for ok(...)  );=head1 DESCRIPTIONThis module simplifies the task of writing test files for Perl modules,such that their output is in the format thatL<Test::Harness|Test::Harness> expects to see.=head1 QUICK START GUIDETo write a test for your new (and probably not even done) module, createa new file called F<t/test.t> (in a new F<t> directory). If you havemultiple test files, to test the "foo", "bar", and "baz" feature sets,then feel free to call your files F<t/foo.t>, F<t/bar.t>, andF<t/baz.t>=head2 FunctionsThis module defines three public functions, C<plan(...)>, C<ok(...)>,and C<skip(...)>.  By default, all three are exported bythe C<use Test;> statement.=over 4=item C<plan(...)>     BEGIN { plan %theplan; }This should be the first thing you call in your test script.  Itdeclares your testing plan, how many there will be, if any of themshould be allowed to fail, and so on.Typical usage is just:     use Test;     BEGIN { plan tests => 23 }These are the things that you can put in the parameters to plan:=over=item C<tests =E<gt> I<number>>The number of tests in your script.This means all ok() and skip() calls.=item C<todo =E<gt> [I<1,5,14>]>A reference to a list of tests which are allowed to fail.See L</TODO TESTS>.=item C<onfail =E<gt> sub { ... }>=item C<onfail =E<gt> \&some_sub>A subroutine reference to be run at the end of the test script, ifany of the tests fail.  See L</ONFAIL>.=backYou must call C<plan(...)> once and only once.  You should call itin a C<BEGIN {...}> block, like so:     BEGIN { plan tests => 23 }=cutsub plan {    croak "Test::plan(%args): odd number of arguments" if @_ & 1;    croak "Test::plan(): should not be called more than once" if $planned;    local($\, $,);   # guard against -l and other things that screw with                     # print    _reset_globals();    _read_program( (caller)[1] );    my $max=0;    while (@_) {	my ($k,$v) = splice(@_, 0, 2);	if ($k =~ /^test(s)?$/) { $max = $v; }	elsif ($k eq 'todo' or	       $k eq 'failok') { for (@$v) { $todo{$_}=1; }; }	elsif ($k eq 'onfail') {	    ref $v eq 'CODE' or croak "Test::plan(onfail => $v): must be CODE";	    $ONFAIL = $v;	}	else { carp "Test::plan(): skipping unrecognized directive '$k'" }    }    my @todo = sort { $a <=> $b } keys %todo;    if (@todo) {	print $TESTOUT "1..$max todo ".join(' ', @todo).";\n";    } else {	print $TESTOUT "1..$max\n";    }    ++$planned;    print $TESTOUT "# Running under perl version $] for $^O",      (chr(65) eq 'A') ? "\n" : " in a non-ASCII world\n";    print $TESTOUT "# Win32::BuildNumber ", &Win32::BuildNumber(), "\n"      if defined(&Win32::BuildNumber) and defined &Win32::BuildNumber();    print $TESTOUT "# MacPerl version $MacPerl::Version\n"      if defined $MacPerl::Version;    printf $TESTOUT      "# Current time local: %s\n# Current time GMT:   %s\n",      scalar(localtime($^T)), scalar(gmtime($^T));    print $TESTOUT "# Using Test.pm version $VERSION\n";    # Retval never used:    return undef;}sub _read_program {  my($file) = shift;  return unless defined $file and length $file    and -e $file and -f _ and -r _;  open(SOURCEFILE, "<$file") || return;  $Program_Lines{$file} = [<SOURCEFILE>];  close(SOURCEFILE);  foreach my $x (@{$Program_Lines{$file}})   { $x =~ tr/\cm\cj\n\r//d }  unshift @{$Program_Lines{$file}}, '';  return 1;}=begin _private=item B<_to_value>  my $value = _to_value($input);Converts an C<ok> parameter to its value.  Typically this just meansrunning it, if it's a code reference.  You should run all inputtedvalues through this.=cutsub _to_value {    my ($v) = @_;    return ref $v eq 'CODE' ? $v->() : $v;}sub _quote {    my $str = $_[0];    return "<UNDEF>" unless defined $str;    $str =~ s/\\/\\\\/g;    $str =~ s/"/\\"/g;    $str =~ s/\a/\\a/g;    $str =~ s/[\b]/\\b/g;    $str =~ s/\e/\\e/g;    $str =~ s/\f/\\f/g;    $str =~ s/\n/\\n/g;    $str =~ s/\r/\\r/g;    $str =~ s/\t/\\t/g;    $str =~ s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;    $str =~ s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;    $str =~ s/([^\0-\176])/sprintf('\\x{%X}',ord($1))/eg;    #if( $_[1] ) {    #  substr( $str , 218-3 ) = "..."    #   if length($str) >= 218 and !$ENV{PERL_TEST_NO_TRUNC};    #}    return qq("$str");}=end _private=item C<ok(...)>  ok(1 + 1 == 2);  ok($have, $expect);  ok($have, $expect, $diagnostics);This function is the reason for C<Test>'s existence.  It'sthe basic function thathandles printing "C<ok>" or "C<not ok>", along with thecurrent test number.  (That's what C<Test::Harness> wants to see.)In its most basic usage, C<ok(...)> simply takes a single scalarexpression.  If its value is true, the test passes; if false,the test fails.  Examples:    # Examples of ok(scalar)    ok( 1 + 1 == 2 );           # ok if 1 + 1 == 2    ok( $foo =~ /bar/ );        # ok if $foo contains 'bar'    ok( baz($x + $y) eq 'Armondo' );    # ok if baz($x + $y) returns                                        # 'Armondo'    ok( @a == @b );             # ok if @a and @b are the same lengthThe expression is evaluated in scalar context.  So the following willwork:    ok( @stuff );                       # ok if @stuff has any elements    ok( !grep !defined $_, @stuff );    # ok if everything in @stuff is                                        # defined.A special case is if the expression is a subroutine reference (in eitherC<sub {...}> syntax or C<\&foo> syntax).  Inthat case, it is executed and its value (true or false) determines ifthe test passes or fails.  For example,    ok( sub {   # See whether sleep works at least passably      my $start_time = time;      sleep 5;      time() - $start_time  >= 4    });In its two-argument form, C<ok(I<arg1>, I<arg2>)> compares the twoscalar values to see if they match.  They match if both are undefined,or if I<arg2> is a regex that matches I<arg1>, or if they compare equalwith C<eq>.    # Example of ok(scalar, scalar)    ok( "this", "that" );               # not ok, 'this' ne 'that'    ok( "", undef );                    # not ok, "" is definedThe second argument is considered a regex if it is either a regexobject or a string that looks like a regex.  Regex objects areconstructed with the qr// operator in recent versions of perl.  Astring is considered to look like a regex if its first and lastcharacters are "/", or if the first character is "m"and its second and last characters are both thesame non-alphanumeric non-whitespace character.  These regexpRegex examples:    ok( 'JaffO', '/Jaff/' );    # ok, 'JaffO' =~ /Jaff/    ok( 'JaffO', 'm|Jaff|' );   # ok, 'JaffO' =~ m|Jaff|    ok( 'JaffO', qr/Jaff/ );    # ok, 'JaffO' =~ qr/Jaff/;    ok( 'JaffO', '/(?i)jaff/ ); # ok, 'JaffO' =~ /jaff/i;If either (or both!) is a subroutine reference, it is run and usedas the value for comparing.  For example:    ok sub {        open(OUT, ">x.dat") || die $!;        print OUT "\x{e000}";        close OUT;        my $bytecount = -s 'x.dat';        unlink 'x.dat' or warn "Can't unlink : $!";        return $bytecount;      },      4    ;The above test passes two values to C<ok(arg1, arg2)> -- the first a coderef, and the second is the number 4.  Before C<ok> compares them,it calls the coderef, and uses its return value as the real value ofthis parameter. Assuming that C<$bytecount> returns 4, C<ok> ends uptesting C<4 eq 4>.  Since that's true, this test passes.Finally, you can append an optional third argument, inC<ok(I<arg1>,I<arg2>, I<note>)>, where I<note> is a string value thatwill be printed if the test fails.  This should be some usefulinformation about the test, pertaining to why it failed, and/ora description of the test.  For example:    ok( grep($_ eq 'something unique', @stuff), 1,        "Something that should be unique isn't!\n".        '@stuff = '.join ', ', @stuff      );Unfortunately, a note cannot be used with the single argumentstyle of C<ok()>.  That is, if you try C<ok(I<arg1>, I<note>)>, thenC<Test> will interpret this as C<ok(I<arg1>, I<arg2>)>, and probablyend up testing C<I<arg1> eq I<arg2>> -- and that's not what you want!All of the above special cases can occasionally cause someproblems.  See L</BUGS and CAVEATS>.=cut# A past maintainer of this module said:# <<ok(...)'s special handling of subroutine references is an unfortunate#   "feature" that can't be removed due to compatibility.>>#sub ok ($;$$) {    croak "ok: plan before you test!" if !$planned;    local($\,$,);   # guard against -l and other things that screw with                    # print    my ($pkg,$file,$line) = caller($TestLevel);    my $repetition = ++$history{"$file:$line"};    my $context = ("$file at line $line".		   ($repetition > 1 ? " fail \#$repetition" : ''));    # Are we comparing two values?    my $compare = 0;    my $ok=0;    my $result = _to_value(shift);    my ($expected, $isregex, $regex);    if (@_ == 0) {	$ok = $result;    } else {        $compare = 1;	$expected = _to_value(shift);	if (!defined $expected) {	    $ok = !defined $result;	} elsif (!defined $result) {	    $ok = 0;	} elsif (ref($expected) eq 'Regexp') {	    $ok = $result =~ /$expected/;            $regex = $expected;	} elsif (($regex) = ($expected =~ m,^ / (.+) / $,sx) or	    (undef, $regex) = ($expected =~ m,^ m([^\w\s]) (.+) \1 $,sx)) {	    $ok = $result =~ /$regex/;	} else {	    $ok = $result eq $expected;	}    }    my $todo = $todo{$ntest};    if ($todo and $ok) {	$context .= ' TODO?!' if $todo;	print $TESTOUT "ok $ntest # ($context)\n";    } else {        # Issuing two seperate prints() causes problems on VMS.        if (!$ok) {            print $TESTOUT "not ok $ntest\n";        }	else {            print $TESTOUT "ok $ntest\n";        }        $ok or _complain($result, $expected,        {          'repetition' => $repetition, 'package' => $pkg,          'result' => $result, 'todo' => $todo,          'file' => $file, 'line' => $line,          'context' => $context, 'compare' => $compare,          @_ ? ('diagnostic' =>  _to_value(shift)) : (),        });    }    ++ $ntest;    $ok;}sub _complain {    my($result, $expected, $detail) = @_;    $$detail{expected} = $expected if defined $expected;    # Get the user's diagnostic, protecting against multi-line    # diagnostics.    my $diag = $$detail{diagnostic};    $diag =~ s/\n/\n#/g if defined $diag;    $$detail{context} .= ' *TODO*' if $$detail{todo};    if (!$$detail{compare}) {        if (!$diag) {            print $TESTERR "# Failed test $ntest in $$detail{context}\n";        } else {            print $TESTERR "# Failed test $ntest in $$detail{context}: $diag\n";        }    } else {        my $prefix = "Test $ntest";        print $TESTERR "# $prefix got: " . _quote($result) .                       " ($$detail{context})\n";        $prefix = ' ' x (length($prefix) - 5);        my $expected_quoted = (defined $$detail{regex})         ?  'qr{'.($$detail{regex}).'}'  :  _quote($expected);        print $TESTERR "# $prefix Expected: $expected_quoted",           $diag ? " ($diag)" : (), "\n";        _diff_complain( $result, $expected, $detail, $prefix )          if defined($expected) and 2 < ($expected =~ tr/\n//);    }    if(defined $Program_Lines{ $$detail{file} }[ $$detail{line} ]) {        print $TESTERR          "#  $$detail{file} line $$detail{line} is: $Program_Lines{ $$detail{file} }[ $$detail{line} ]\n"         if $Program_Lines{ $$detail{file} }[ $$detail{line} ]          =~ m/[^\s\#\(\)\{\}\[\]\;]/;  # Otherwise it's uninformative        undef $Program_Lines{ $$detail{file} }[ $$detail{line} ];         # So we won't repeat it.    }    push @FAILDETAIL, $detail;    return;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?