File Coverage

Tester.pm
Criterion Covered Total %
statement 3 151 1.9
branch 0 80 0.0
condition 0 3 0.0
subroutine 1 3 33.3
pod 0 2 0.0
total 4 239 1.6


line stmt bran cond sub pod time code
1             # Tester.pm module
2              
3             # $Id$
4             #
5             # This package is designed to run tests on modules which
6             # perform interactively.
7              
8             package Tester;
9              
10             @ISA = qw( Exporter );
11             @EXPORT = qw( run_test_with_input run_class_test );
12              
13             # run_test_with_input $class, $testno, $input,
14             # \&testsub, $testargsref, $condition.
15              
16             sub run_test_with_input {
17 0     0 0   my $class = shift;
18 0           my $test = shift;
19 0           my $inputstring = shift;
20 0           my $testsub = shift;
21 0           my $testargs = shift;
22 0           my $condition = shift;
23              
24 0 0 0       if (!ref($testsub) and $testsub !~ /::/) {
25 0           my $pkg = (caller)[0];
26 0           my $i;
27 0           for ($i = 1; $pkg = (caller)[0]; $i++) {
28 0 0         last unless $pkg eq 'Tester';
29             }
30 0           $testsub =~ s/^/$pkg::/; # qualify the sub
31             }
32              
33 0           select(STDOUT); $| = 1;
  0            
34 0           printf STDOUT "%d.......", $test;
35              
36 0           $SIG{'PIPE'} = 'IGNORE'; # don't let pipe errors hurt us
37 0           pipe(TESTREAD, CHILDWRITE);
38 0           pipe(CHILDREAD, TESTWRITE);
39 0 0         if (!fork) {
40 0           open(STDIN, "<&CHILDREAD");
41 0           open(STDOUT, ">&CHILDWRITE"); select(STDOUT); $| = 1;
  0            
  0            
42 0           open(STDERR, ">&STDOUT"); select(STDERR); $| = 1;
  0            
  0            
43 0           close CHILDREAD;
44 0           close CHILDWRITE;
45 0           select(STDOUT); $| = 1;
  0            
46              
47             # Finally, after all that -- run the actual test subroutine
48 0           my $sub = eval 'sub { package main; &{$_[0]}(@{$_[1]}); }';
49 0           $_ = &$sub($testsub, $testargs);
50              
51             # The condition must be evaluated here, in the child
52             # process -- since it may involve variables which have
53             # been set in the child (but not the parent)
54 0 0         if ($condition) {
55 0           my $sub = eval
56             'sub { package main;
57             ref($_[0]) eq "CODE" ? &{$_[0]} : eval $_[0]; }';
58 0 0         &$sub($condition) or print "Condition failed\n";
59             }
60 0           close STDOUT;
61 0           close STDIN;
62 0           exit;
63             }
64 0           close CHILDREAD;
65 0           close CHILDWRITE;
66              
67             # Generate the output
68 0           print TESTWRITE $inputstring."\n";
69 0           close TESTWRITE; # will cause an EOF
70            
71 0           my @output;
72 0           while () { # Now get the results
73 0           push(@output, $_);
74 0 0         print if $Details > 1;
75             }
76 0           close TESTREAD;
77 0           $SIG{'PIPE'} = 'DEFAULT'; # normal pipe stuff
78              
79             # If reference output doesn't exist, generate it from our
80             # current input
81 0 0         my $testdir = -d "t" ? "t" :
    0          
    0          
82             -d "../t" ? "../t" :
83             -d "../../t" ? "../../t" :
84             die "Can't find 't'!\n";
85 0           my $testref = "$testdir/$class.$test.ref";
86 0           my $testout = "$testdir/$class.$test.out";
87 0           my @Details = ();
88              
89 0 0         if (! -f $testref) {
90 0 0         push(@Details,"Generated reference output.") if $Details > 1;
91 0           open(NEWREF,">$testref");
92 0           print NEWREF @output;
93 0           close NEWREF;
94             }
95              
96 0 0         if (open(OUT,">$testout")) {
97 0           print OUT @output;
98 0           close OUT;
99             } else {
100 0           die "Cannot open output file: $testout: $!\n";
101             }
102              
103 0 0         open(REF,$testref) or die "Can't open '$testref': $!\n";
104              
105 0           my $notok = '';
106 0           my $refout;
107              
108 0           for ($i = 0; $i <= $#output; $i++) {
109 0 0         length($refout = ) || last;
110 0 0         $notok++ if $output[$i] =~ /condition failed/i;
111 0 0         next if $output[$i] eq $refout;
112 0           $notok++;
113 0 0         if ($Details) {
114 0           push(@Details, sprintf("line %d: \"%s\"", $i, $output[$i]));
115 0           push(@Details, sprintf("should be: \"%s\"", $refout));
116             }
117 0           last;
118             }
119 0 0         if ( $i <= $#output) {
    0          
120 0           $notok++;
121 0 0         push(@Details, "reference output has less lines.") if $Details;
122             } elsif ( !eof(REF) ) {
123 0           $notok++;
124 0 0         push(@Details, "reference output has more lines.") if $Details;
125             }
126 0           close REF;
127 0 0         if ($notok) {
128 0           print "not ok\n";
129             } else {
130 0           print "ok\n";
131 0           unlink $testout;
132             }
133 0 0         print "\t".join("\n\t", @Details)."\n" if @Details;
134 0           undef @Details;
135             }
136              
137             # Run a class of tests
138             # Just like the Perl tests
139              
140             # run_test_class class_name;
141             #
142             # * The file testdir/$class.pl must exist
143             # * The subroutine &$class_Tests will be invoked.
144              
145             sub run_class_test {
146 0     0 0   my $class = shift;
147 0 0         my $testdir = -d "t" ? "t" :
    0          
    0          
148             -d "../t" ? "../t" :
149             -d "../../t" ? "../../t" :
150             die "Can't find 't'!\n";
151 0           my $testmodule = "$testdir/$class.pl";
152 0           my $failed;
153              
154 0 0         if ( ! -f $testmodule ) {
155 0           print STDERR "No such test for class: $class.\n";
156 0           return;
157             }
158              
159 0           select(STDOUT); $| = 1;
  0            
160 0           print substr($class.('.' x 15),0,15);
161 0 0         if (!(open(STDIN,"-|"))) {
162 0           open(STDIN,"/dev/null");
163 0           open(STDERR,">&STDOUT");
164 0           select(STDERR); $| = 1;
  0            
165 0           select(STDOUT); $| = 1;
  0            
166              
167 0           do $testmodule; # execute the test code
168              
169 0           exit;
170             }
171              
172 0           my( $range, $begin, $end );
173 0           my( $test, $status );
174              
175 0           $range = ; # get the test range
176 0 0         if ($range =~ /^(\d+)\.\.(\d+)/) {
177 0           ($begin, $end) = ($1, $2);
178             } else {
179             # Non-standard test output -- print it, and exit.
180 0           do { print "! $_\n"; } while ($_ = );
  0            
181 0           return;
182             }
183 0           @Test{$begin .. $end} = ($begin .. $end);
184 0           while () {
185 0           chomp;
186 0 0         if (s/^(\d+)\.+((?:not )?ok)\s*//) {
    0          
187 0           ($test, $status) = ($1, $2);
188 0           $Test{$test} = $status;
189 0 0         if ($status eq 'not ok') {
190 0 0         $Test{$test} .= ": ".$_ if length;
191 0           $failed++;
192             }
193             } elsif ($test) {
194 0           $Test{$test} .= "\n".$_;
195             } else {
196 0           print "! $_\n";
197             }
198             }
199 0           close STDIN;
200 0 0         if ($failed) {
201 0           my @failed = grep($Test{$_} =~ /not/, keys %Test);
202 0           my @msgs = @Test{@failed};
203 1 0   1   3443 if ($#failed == $[) {
  1         520  
  1         348  
  0            
204 0           printf "Test %s failed %s", $failed[0], $Test{$failed[0]};
205             } else {
206 0           my $last = pop @failed;
207 0           printf "Tests %s and %s failed", join(", ", @failed), $last;
208 0           push(@failed, $last);
209             }
210 0           foreach (@msgs) { s/not ok[:,\s;]*//; }
  0            
211 0           @msgs = grep(/./,@msgs);
212 0 0         if (@msgs) {
213 0 0         printf ":\n\t".join("\n\t", @msgs)."\n" if @msgs;
214             } else {
215 0           print ".\n";
216             }
217 0           foreach $test (@failed) {
218 0           $testout = "$testdir/$class.$test.out";
219 0 0         next unless -f $testout;
220 0 0         open(OUT,$testout) or next;
221 0           print "Test $test results:\n";
222 0           while () { print "\t".$_; }
  0            
223 0           close OUT;
224             }
225 0 0         exit unless $KeepGoing;
226             } else {
227 0           print "ok\n";
228             }
229             }
230              
231             1;