📄 more.pm
字号:
local $^W = 0; last TODO;}=item When do I use SKIP vs. TODO?B<If it's something the user might not be able to do>, use SKIP.This includes optional modules that aren't installed, running underan OS that doesn't have some feature (like fork() or symlinks), or maybeyou need an Internet connection and one isn't available.B<If it's something the programmer hasn't done yet>, use TODO. Thisis for any code you haven't written yet, or bugs you have yet to fix,but want to put tests in your testing script (always a good idea).=back=head2 Comparison functionsNot everything is a simple eq check or regex. There are times youneed to see if two arrays are equivalent, for instance. For theseinstances, Test::More provides a handful of useful functions.B<NOTE> I'm not quite sure what will happen with filehandles.=over 4=item B<is_deeply> is_deeply( $this, $that, $test_name );Similar to is(), except that if $this and $that are hash or arrayreferences, it does a deep comparison walking each data structure tosee if they are equivalent. If the two structures are different, itwill display the place where they start differing.Test::Differences and Test::Deep provide more in-depth functionalityalong these lines.=cutuse vars qw(@Data_Stack %Refs_Seen);my $DNE = bless [], 'Does::Not::Exist';sub is_deeply { unless( @_ == 2 or @_ == 3 ) { my $msg = <<WARNING;is_deeply() takes two or three args, you gave %d.This usually means you passed an array or hash instead of a reference to itWARNING chop $msg; # clip off newline so carp() will put in line/file _carp sprintf $msg, scalar @_; } my($this, $that, $name) = @_; my $ok; if( !ref $this xor !ref $that ) { # one's a reference, one isn't $ok = 0; } if( !ref $this and !ref $that ) { $ok = $Test->is_eq($this, $that, $name); } else { local @Data_Stack = (); local %Refs_Seen = (); if( _deep_check($this, $that) ) { $ok = $Test->ok(1, $name); } else { $ok = $Test->ok(0, $name); $ok = $Test->diag(_format_stack(@Data_Stack)); } } return $ok;}sub _format_stack { my(@Stack) = @_; my $var = '$FOO'; my $did_arrow = 0; foreach my $entry (@Stack) { my $type = $entry->{type} || ''; my $idx = $entry->{'idx'}; if( $type eq 'HASH' ) { $var .= "->" unless $did_arrow++; $var .= "{$idx}"; } elsif( $type eq 'ARRAY' ) { $var .= "->" unless $did_arrow++; $var .= "[$idx]"; } elsif( $type eq 'REF' ) { $var = "\${$var}"; } } my @vals = @{$Stack[-1]{vals}}[0,1]; my @vars = (); ($vars[0] = $var) =~ s/\$FOO/ \$got/; ($vars[1] = $var) =~ s/\$FOO/\$expected/; my $out = "Structures begin differing at:\n"; foreach my $idx (0..$#vals) { my $val = $vals[$idx]; $vals[$idx] = !defined $val ? 'undef' : $val eq $DNE ? "Does not exist" : "'$val'"; } $out .= "$vars[0] = $vals[0]\n"; $out .= "$vars[1] = $vals[1]\n"; $out =~ s/^/ /msg; return $out;}sub _type { my $thing = shift; return '' if !ref $thing; for my $type (qw(ARRAY HASH REF SCALAR GLOB Regexp)) { return $type if UNIVERSAL::isa($thing, $type); } return '';}=item B<eq_array> eq_array(\@this, \@that);Checks if two arrays are equivalent. This is a deep check, somulti-level structures are handled correctly.=cut#'#sub eq_array { local @Data_Stack; local %Refs_Seen; _eq_array(@_);}sub _eq_array { my($a1, $a2) = @_; if( grep !_type($_) eq 'ARRAY', $a1, $a2 ) { warn "eq_array passed a non-array ref"; return 0; } return 1 if $a1 eq $a2; if($Refs_Seen{$a1}) { return $Refs_Seen{$a1} eq $a2; } else { $Refs_Seen{$a1} = "$a2"; } my $ok = 1; my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2; for (0..$max) { my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_]; my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_]; push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [$e1, $e2] }; $ok = _deep_check($e1,$e2); pop @Data_Stack if $ok; last unless $ok; } return $ok;}sub _deep_check { my($e1, $e2) = @_; my $ok = 0; { # Quiet uninitialized value warnings when comparing undefs. local $^W = 0; $Test->_unoverload(\$e1, \$e2); # Either they're both references or both not. my $same_ref = !(!ref $e1 xor !ref $e2); if( defined $e1 xor defined $e2 ) { $ok = 0; } elsif ( $e1 == $DNE xor $e2 == $DNE ) { $ok = 0; } elsif ( $same_ref and ($e1 eq $e2) ) { $ok = 1; } else { my $type = _type($e1); $type = '' unless _type($e2) eq $type; if( !$type ) { push @Data_Stack, { vals => [$e1, $e2] }; $ok = 0; } elsif( $type eq 'ARRAY' ) { $ok = _eq_array($e1, $e2); } elsif( $type eq 'HASH' ) { $ok = _eq_hash($e1, $e2); } elsif( $type eq 'REF' ) { push @Data_Stack, { type => 'REF', vals => [$e1, $e2] }; $ok = _deep_check($$e1, $$e2); pop @Data_Stack if $ok; } elsif( $type eq 'SCALAR' ) { push @Data_Stack, { type => 'REF', vals => [$e1, $e2] }; $ok = _deep_check($$e1, $$e2); pop @Data_Stack if $ok; } } } return $ok;}=item B<eq_hash> eq_hash(\%this, \%that);Determines if the two hashes contain the same keys and values. Thisis a deep check.=cutsub eq_hash { local @Data_Stack; local %Refs_Seen; return _eq_hash(@_);}sub _eq_hash { my($a1, $a2) = @_; if( grep !_type($_) eq 'HASH', $a1, $a2 ) { warn "eq_hash passed a non-hash ref"; return 0; } return 1 if $a1 eq $a2; if( $Refs_Seen{$a1} ) { return $Refs_Seen{$a1} eq $a2; } else { $Refs_Seen{$a1} = "$a2"; } my $ok = 1; my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2; foreach my $k (keys %$bigger) { my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE; my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE; push @Data_Stack, { type => 'HASH', idx => $k, vals => [$e1, $e2] }; $ok = _deep_check($e1, $e2); pop @Data_Stack if $ok; last unless $ok; } return $ok;}=item B<eq_set> eq_set(\@this, \@that);Similar to eq_array(), except the order of the elements is B<not>important. This is a deep check, but the irrelevancy of order onlyapplies to the top level.B<NOTE> By historical accident, this is not a true set comparision.While the order of elements does not matter, duplicate elements do.=cutsub eq_set { my($a1, $a2) = @_; return 0 unless @$a1 == @$a2; # There's faster ways to do this, but this is easiest. local $^W = 0; # We must make sure that references are treated neutrally. It really # doesn't matter how we sort them, as long as both arrays are sorted # with the same algorithm. # Have to inline the sort routine due to a threading/sort bug. # See [rt.cpan.org 6782] return eq_array( [sort { ref $a ? -1 : ref $b ? 1 : $a cmp $b } @$a1], [sort { ref $a ? -1 : ref $b ? 1 : $a cmp $b } @$a2] );}=back=head2 Extending and Embedding Test::MoreSometimes the Test::More interface isn't quite enough. Fortunately,Test::More is built on top of Test::Builder which provides a single,unified backend for any test library to use. This means two testlibraries which both use Test::Builder B<can be used together in thesame program>.If you simply want to do a little tweaking of how the tests behave,you can access the underlying Test::Builder object like so:=over 4=item B<builder> my $test_builder = Test::More->builder;Returns the Test::Builder object underlying Test::More for you to playwith.=cutsub builder { return Test::Builder->new;}=back=head1 EXIT CODESIf all your tests passed, Test::Builder will exit with zero (which isnormal). If anything failed it will exit with how many failed. Ifyou run less (or more) tests than you planned, the missing (or extras)will be considered failures. If no tests were ever run Test::Builderwill throw a warning and exit with 255. If the test died, even afterhaving successfully completed all its tests, it will still beconsidered a failure and will exit with 255.So the exit codes are... 0 all tests successful 255 test died any other number how many failed (including missing or extras)If you fail more than 254 tests, it will be reported as 254.=head1 CAVEATS and NOTES=over 4=item Backwards compatibilityTest::More works with Perls as old as 5.004_05.=item Overloaded objectsString overloaded objects are compared B<as strings>. This preventsTest::More from piercing an object's interface allowing better blackboxtesting. So if a function starts returning overloaded objects instead ofbare strings your tests won't notice the difference. This is good.However, it does mean that functions like is_deeply() cannot be used totest the internals of string overloaded objects. In this case I wouldsuggest Test::Deep which contains more flexible testing functions forcomplex data structures.=item ThreadsTest::More will only be aware of threads if "use threads" has been doneI<before> Test::More is loaded. This is ok: use threads; use Test::More;This may cause problems: use Test::More use threads;=item Test::Harness upgradeno_plan and todo depend on new Test::Harness features and fixes. Ifyou're going to distribute tests that use no_plan or todo yourend-users will have to upgrade Test::Harness to the latest one onCPAN. If you avoid no_plan and TODO tests, the stock Test::Harnesswill work fine.Installing Test::More should also upgrade Test::Harness.=back=head1 HISTORYThis is a case of convergent evolution with Joshua Pritikin's Testmodule. I was largely unaware of its existence when I'd firstwritten my own ok() routines. This module exists because I can'tfigure out how to easily wedge test names into Test's interface (alongwith a few other problems).The goal here is to have a testing utility that's simple to learn,quick to use and difficult to trip yourself up with while stillproviding more flexibility than the existing Test.pm. As such, thenames of the most common routines are kept tiny, special cases andmagic side-effects are kept to a minimum. WYSIWYG.=head1 SEE ALSOL<Test::Simple> if all this confuses you and you just want to writesome tests. You can upgrade to Test::More later (it's forwardcompatible).L<Test> is the old testing module. Its main benefit is that it hasbeen distributed with Perl since 5.004_05.L<Test::Harness> for details on how your test results are interpretedby Perl.L<Test::Differences> for more ways to test complex data structures.And it plays well with Test::More.L<Test::Class> is like XUnit but more perlish.L<Test::Deep> gives you more powerful complex data structure testing.L<Test::Unit> is XUnit style testing.L<Test::Inline> shows the idea of embedded testing.L<Bundle::Test> installs a whole bunch of useful test modules.=head1 AUTHORSMichael G Schwern E<lt>schwern@pobox.comE<gt> with much inspirationfrom Joshua Pritikin's Test module and lots of help from BarrieSlaymaker, Tony Bowden, blackstar.co.uk, chromatic, Fergal Daly andthe perl-qa gang.=head1 BUGSSee F<http://rt.cpan.org> to report and view bugs.=head1 COPYRIGHTCopyright 2001, 2002, 2004 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.See F<http://www.perl.com/perl/misc/Artistic.html>=cut1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -