File Coverage

blib/lib/Test/Inter.pm
Criterion Covered Total %
statement 555 760 73.0
branch 262 474 55.2
condition 61 140 43.5
subroutine 49 63 77.7
pod 24 24 100.0
total 951 1461 65.0


line stmt bran cond sub pod time code
1             package Test::Inter;
2             # Copyright (c) 2010-2019 Sullivan Beck. All rights reserved.
3             # This program is free software; you can redistribute it and/or modify it
4             # under the same terms as Perl itself.
5              
6             ###############################################################################
7              
8             require 5.004;
9              
10 10     10   5445 use warnings;
  10         71  
  10         373  
11 10     10   53 use strict;
  10         14  
  10         286  
12 10     10   59 use File::Basename;
  10         12  
  10         1345  
13 10     10   4523 use IO::File;
  10         84501  
  10         3001  
14              
15             our($VERSION);
16             $VERSION = '1.08';
17              
18             ###############################################################################
19             # BASE METHODS
20             ###############################################################################
21              
22             sub version {
23 1     1 1 6 my($self) = @_;
24              
25 1         3 return $VERSION;
26             }
27              
28             sub new {
29 10     10 1 226 my($class,@args) = @_;
30 10         25 my($name,%opts);
31              
32 10 100       53 if (@args % 2) {
33 1         4 ($name,%opts) = @args;
34             } else {
35 9         45 $name = $0;
36 9         97 $name =~ s,^\./,,;
37 9         23 %opts = @args;
38             }
39              
40             # The basic structure
41              
42 10         118 my $self = {
43             'name' => $name, # the name of the test script
44             'start' => 1, # the first test to run
45             'end' => 0, # the last test to end
46             'plan' => 0, # the number of tests planned
47             'abort' => 0, # abort on the first failed test
48             'quiet' => 0, # if 1, no output on successes
49             # (this should only be done when
50             # running as an interactive script)
51             'mode' => 'test', # mode to run script in
52             'width' => 80, # width of terminal
53             'features' => {}, # a list of available features
54             'use_lib' => 'on', # whether to run 'use lib' when loading
55             # this module
56              
57             'skipall' => '', # the reason for skipping all
58             # remaining tests
59              
60             'plandone' => 0, # 1 if a plan is done
61             'testsrun' => 0, # 1 if any tests have been run
62              
63             'libdir' => '', # a directory to load modules from
64             'testdir' => '', # the test directory
65             };
66              
67 10         31 bless $self, $class;
68 10         22 $main::TI_NUM = 0;
69              
70             # Handle options, environment variables, global variables
71              
72 10         48 my @opts = qw(start end testnum plan abort quiet mode width skip_all);
73 10         28 my %o = map { $_,1 } @opts;
  90         175  
74              
75 10     10   83 no strict 'refs';
  10         23  
  10         83078  
76 10         33 foreach my $opt (@opts) {
77 90 50       216 if (! exists $o{$opt}) {
78 0         0 $self->_die("Invalid option to new method: $opt");
79             }
80              
81 90         167 my $OPT = uc("ti_$opt");
82              
83 90 50 33     323 if (exists $opts{opt} ||
      33        
84             exists $ENV{$OPT} ||
85 90         420 defined ${ "main::$OPT" }) {
86              
87 0         0 my $val;
88 0 0       0 if (defined ${ "main::$OPT" }) {
  0 0       0  
89 0         0 $val = ${ "main::$OPT" };
  0         0  
90             } elsif (exists $ENV{$OPT}) {
91 0         0 $val = $ENV{$OPT};
92             } else {
93 0         0 $val = $opts{$opt};
94             }
95              
96 0         0 &{ "Test::Inter::$opt" }($self,$val);
  0         0  
97             }
98             }
99              
100 10 50       73 if ($$self{'mode'} ne 'test') {
101 0         0 print "\nRunning $name...\n";
102             }
103              
104             # Find the test directory
105             #
106             # Scripts will either be run:
107             # directly (look at $0)
108             # as a test suite (look for ./t and ../t)
109              
110 10         23 my($TDIR,@LIBDIR);
111 10 50       208 if (-f "$0") {
    0          
112 10         34 my $COM = $0;
113 10         725 $TDIR = dirname($COM);
114 10 50       53 $TDIR = '.' if (! $TDIR);
115             } elsif (-d 't') {
116 0         0 $TDIR = 't';
117             } else {
118 0         0 $TDIR = '.';
119             }
120              
121 10         32 @LIBDIR = ('.');
122 10 50       140 if (-d "$TDIR/lib") {
123 0         0 push(@LIBDIR,"$TDIR/lib");
124             }
125 10 50       170 if (-d "$TDIR/../lib") {
126 10         53 push(@LIBDIR,"$TDIR/../lib");
127             }
128              
129 10         30 $$self{'testdir'} = $TDIR;
130 10         36 $$self{'libdir'} = \@LIBDIR;
131              
132 10         41 $self->use_lib();
133              
134 10         1166 return $self;
135             }
136              
137             sub use_lib {
138 10     10 1 28 my($self,$val) = @_;
139 10 50       34 if (defined $val) {
140 0         0 $$self{'use_lib'} = $val;
141 0         0 return;
142             }
143              
144 10 50       73 if ($$self{'use_lib'} eq 'on') {
145 10         21 foreach my $dir (@{ $$self{'libdir'} }) {
  10         38  
146 10     10   4461 eval "use lib '$dir'";
  10     10   6866  
  10         77  
  10         66  
  10         19  
  10         37  
  20         2413  
147             }
148             }
149             }
150              
151             sub testdir {
152 0     0 1 0 my($self) = @_;
153 0         0 return $$self{'testdir'};
154             }
155              
156             sub start {
157 0     0 1 0 my($self,$val) = @_;
158 0 0       0 $val = 1 if (! defined($val));
159 0 0       0 $self->_die("start requires an integer value") if ($val !~ /^\d+$/);
160 0         0 $$self{'start'} = $val;
161             }
162              
163             sub end {
164 0     0 1 0 my($self,$val) = @_;
165 0 0       0 $val = 0 if (! $val);
166 0 0       0 $self->_die("end requires an integer value") if ($val !~ /^\d+$/);
167 0         0 $$self{'end'} = $val;
168             }
169              
170             sub testnum {
171 0     0 1 0 my($self,$val) = @_;
172 0 0       0 if (! defined($val)) {
173 0         0 $$self{'start'} = 1;
174 0         0 $$self{'end'} = 0;
175             } else {
176 0 0       0 $self->_die("testnum requires an integer value") if ($val !~ /^\d+$/);
177 0         0 $$self{'start'} = $$self{'end'} = $val;
178             }
179             }
180              
181             sub plan {
182 0     0 1 0 my($self,$val) = @_;
183              
184 0 0       0 if ($$self{'plandone'}) {
185 0         0 $self->_die('Plan/done_testing included twice');
186             }
187 0         0 $$self{'plandone'} = 1;
188              
189 0 0       0 $val = 0 if (! defined($val));
190 0 0       0 $self->_die("plan requires an integer value") if ($val !~ /^\d+$/);
191 0         0 $$self{'plan'} = $val;
192              
193 0 0       0 if ($val != 0) {
194 0         0 $self->_plan($val);
195             }
196             }
197              
198             sub done_testing {
199 9     9 1 73 my($self,$val) = @_;
200              
201 9 50       47 if ($$self{'plandone'}) {
202 0         0 $self->_die('Plan/done_testing included twice');
203             }
204 9         22 $$self{'plandone'} = 1;
205              
206 9 50       33 $val = $main::TI_NUM if (! $val);
207 9 50       59 $self->_die("done_testing requires an integer value") if ($val !~ /^\d+$/);
208 9         50 $self->_plan($val);
209              
210 9 50       0 if ($val != $main::TI_NUM) {
211 0         0 $self->_die("Ran $main::TI_NUM tests, expected $val");
212             }
213             }
214              
215             sub abort {
216 0     0 1 0 my($self,$val) = @_;
217 0 0       0 $val = 0 if (! $val);
218 0         0 $$self{'abort'} = $val;
219             }
220              
221             sub quiet {
222 0     0 1 0 my($self,$val) = @_;
223 0 0       0 $val = 0 if (! $val);
224 0         0 $$self{'quiet'} = $val;
225             }
226              
227             sub mode {
228 0     0 1 0 my($self,$val) = @_;
229 0 0       0 $val = 'test' if (! $val);
230 0         0 $$self{'mode'} = $val;
231             }
232              
233             sub width {
234 0     0 1 0 my($self,$val) = @_;
235 0 0       0 $val = 0 if (! $val);
236 0         0 $$self{'width'} = $val;
237             }
238              
239             sub skip_all {
240 1     1 1 6 my($self,$reason,@features) = @_;
241              
242 1 50       4 if (@features) {
243 0         0 my $skip = 0;
244 0         0 foreach my $feature (@features) {
245 0 0 0     0 if (! exists $$self{'features'}{$feature} ||
246             ! $$self{'features'}{$feature}) {
247 0         0 $skip = 1;
248 0 0       0 $reason = "Required feature ($feature) missing"
249             if (! $reason);
250 0         0 last;
251             }
252             }
253 0 0       0 return if (! $skip);
254             }
255              
256 1 50 33     9 if ($$self{'plandone'} ||
257             $$self{'testsrun'}) {
258 0 0       0 $reason = 'Remaining tests skipped' if (! $reason);
259 0         0 $$self{'skipall'} = $reason;
260              
261             } else {
262 1 50       4 $reason = 'Test script skipped' if (! $reason);
263 1         4 $self->_plan(0,$reason);
264 1         0 exit 0;
265             }
266             }
267              
268             sub _die {
269 0     0   0 my($self,$message) = @_;
270              
271 0         0 print "ERROR: $message\n";
272 0         0 exit 1;
273             }
274              
275             sub feature {
276 4     4 1 10 my($self,$feature,$val) = @_;
277 4         11 $$self{'features'}{$feature} = $val;
278             }
279              
280             sub diag {
281 0     0 1 0 my($self,$message) = @_;
282 0 0       0 return if ($$self{'quiet'} == 2);
283 0         0 $self->_diag($message);
284             }
285              
286             sub note {
287 0     0 1 0 my($self,$message) = @_;
288 0 0       0 return if ($$self{'quiet'});
289 0         0 $self->_diag($message);
290             }
291              
292             ###############################################################################
293             # LOAD METHODS
294             ###############################################################################
295             # The routines were originally from Test::More (though they have been
296             # changed... some to a greater extent than others).
297              
298             sub require_ok {
299 6     6 1 44 my($self,$module,$mode) = @_;
300 6 100       13 $mode = '' if (! $mode);
301 6 100       16 $main::TI_NUM++ unless ($mode eq 'feature');
302              
303 6         12 my $pack = caller;
304 6         9 my @inc = map { "unshift(\@INC,'$_');\n" } @{ $$self{'libdir'} };
  12         37  
  6         18  
305              
306 6         12 my($desc,$code);
307              
308 6 100       23 if ( $module =~ /^\d+(?:\.\d+)?$/ ) {
309             # A perl version check.
310 2         6 $desc = "require perl $module";
311 2         4 $code = <
312             require $module;
313             1;
314             REQUIRE
315             } else {
316 4 50       11 $module = qq['$module'] unless $self->_is_module_name($module);
317 4         7 $desc = "require $module";
318 4         14 $code = <
319             package $pack;
320             @inc
321             require $module;
322             1;
323             REQUIRE
324             }
325              
326 6 100       18 $desc .= ' (should not load)' if ($mode eq 'forbid');
327 6 100       12 $desc .= ' (feature)' if ($mode eq 'feature');
328              
329 6         15 my($eval_result,$eval_error) = $self->_eval($code);
330 6         16 chomp($eval_error);
331 6         16 my @eval_error = split(/\n/,$eval_error);
332 6         14 foreach my $err (@eval_error) {
333 3         17 $err =~ s/ \(\@INC contains.*//; # strip out the actual @INC values
334             }
335              
336 6         12 my $ok = 1;
337 6 100       14 if ($eval_result) {
338             # Able to load the module
339 3 50       9 if ($mode eq 'forbid') {
    100          
340 0         0 $$self{'skipall'} = 'Loaded a module not supposed to be present';
341 0         0 $self->_not_ok($desc);
342             $self->_diag('Test required that module not be loadable')
343 0 0       0 unless ($$self{'quiet'} == 2);
344 0         0 $ok = 0;
345             } elsif ($mode eq 'feature') {
346 1         6 $self->feature($module,1);
347 1 50       3 if (! $$self{'quiet'}) {
348 1         5 $self->_diag($desc);
349 1         4 $self->_diag("Feature available: $module");
350             }
351             } else {
352 2         8 $self->_ok($desc);
353             }
354              
355             } else {
356             # Unable to load the module
357 3 100       12 if ($mode eq 'forbid') {
    50          
358 2         6 $self->_ok($desc);
359             } elsif ($mode eq 'feature') {
360 1         4 $self->feature($module,0);
361 1 50       4 if (! $$self{'quiet'}) {
362 1         4 $self->_diag($desc);
363 1         4 $self->_diag("Feature unavailable: $module");
364             }
365             } else {
366 0         0 $$self{'skipall'} = 'Unable to load a required module';
367 0         0 $self->_not_ok($desc);
368 0         0 $ok = 0;
369             }
370             }
371              
372             return
373             if ( ($ok && $$self{'quiet'}) ||
374 6 50 33     36 (! $ok && $$self{'quiet'} == 2) );
      33        
      33        
375              
376 6         20 foreach my $err (@eval_error) {
377 3         9 $self->_diag($err);
378             }
379             }
380              
381             sub use_ok {
382 12     12 1 80 my($self,@args) = @_;
383              
384 12         20 my $mode = '';
385 12 100 100     64 if ($args[$#args] eq 'forbid' ||
386             $args[$#args] eq 'feature') {
387 7         16 $mode = pop(@args);
388             }
389 12 100       86 $main::TI_NUM++ unless ($mode eq 'feature');
390              
391 12         29 my $pack = caller;
392              
393 12         15 my($code,$desc,$module);
394 12 100 100     74 if ( @args == 1 and $args[0] =~ /^\d+(?:\.\d+)?$/ ) {
    50          
395             # A perl version check.
396 3         9 $desc = "require perl $args[0]";
397 3         6 $module = 'perl';
398 3         6 $code = <
399             use $args[0];
400             1;
401             USE
402              
403             } elsif (@args) {
404 9         17 $module = shift(@args);
405              
406 9 50       25 if (! $self->_is_module_name($module)) {
407 0         0 $self->_not_ok("use module: invalid module name: $module");
408 0         0 return;
409             }
410              
411 9         18 my $vers = '';
412 9 100 100     85 if ( @args and $args[0] =~ /^\d+(?:\.\d+)?$/ ) {
413 3         9 $vers = shift(@args);
414             }
415              
416 9 100       36 my $imports = (@args ? 'qw(' . join(' ',@args) . ')' : '');
417 9         28 $desc = "use $module $vers $imports";
418              
419 9         14 my @inc = map { "unshift(\@INC,'$_');\n" } @{ $$self{'libdir'} };
  18         50  
  9         24  
420              
421 9         54 $code = <
422             package $pack;
423             @inc
424             use $module $vers $imports;
425             1;
426             USE
427              
428             } else {
429 0         0 $self->_not_ok('use module: no module specified');
430 0         0 return;
431             }
432              
433 12 100       35 $desc .= ' (should not load)' if ($mode eq 'forbid');
434 12 100       26 $desc .= ' (feature)' if ($mode eq 'feature');
435              
436 12         29 my($eval_result,$eval_error) = $self->_eval($code);
437 12         25 chomp($eval_error);
438 12         40 my @eval_error = split(/\n/,$eval_error);
439 12         49 @eval_error = grep(!/^BEGIN failed--compilation aborted/,@eval_error);
440 12         23 foreach my $err (@eval_error) {
441 6         24 $err =~ s/ \(\@INC contains.*//; # strip out the actual @INC values
442             }
443              
444 12         20 my $ok = 1;
445 12 100       26 if ($eval_result) {
446             # Able to load the module
447 6 50       18 if ($mode eq 'forbid') {
    100          
448 0         0 $$self{'skipall'} = 'Loaded a module not supposed to be present';
449 0         0 $self->_not_ok($desc);
450             $self->_diag('Test required that module not be usable')
451 0 0       0 unless ($$self{'quiet'} == 2);
452 0         0 $ok = 0;
453             } elsif ($mode eq 'feature') {
454 1         4 $self->feature($module,1);
455 1 50       4 if (! $$self{'quiet'}) {
456 1         3 $self->_diag($desc);
457 1         3 $self->_diag("Feature available: $module");
458             }
459             } else {
460 5         16 $self->_ok($desc);
461             }
462              
463             } else {
464             # Unable to load the module
465 6 100       16 if ($mode eq 'forbid') {
    50          
466 5         17 $self->_ok($desc);
467             } elsif ($mode eq 'feature') {
468 1         4 $self->feature($module,0);
469 1 50       3 if (! $$self{'quiet'}) {
470 1         3 $self->_diag($desc);
471 1         3 $self->_diag("Feature unavailable: $module");
472             }
473             } else {
474 0         0 $$self{'skipall'} = 'Unable to load a required module';
475 0         0 $self->_not_ok($desc);
476 0         0 $ok = 0;
477             }
478             }
479              
480             return
481             if ( ($ok && $$self{'quiet'}) ||
482 12 50 33     83 (! $ok && $$self{'quiet'} == 2) );
      33        
      33        
483              
484 12         2346 foreach my $err (@eval_error) {
485 6         17 $self->_diag($err);
486             }
487             }
488              
489             sub _is_module_name {
490 13     13   27 my($self,$module) = @_;
491              
492             # Module names start with a letter.
493             # End with an alphanumeric.
494             # The rest is an alphanumeric or ::
495 13         41 $module =~ s/\b::\b//g;
496              
497 13 50       84 return $module =~ /^[a-zA-Z]\w*$/ ? 1 : 0;
498             }
499              
500             sub _eval {
501 18     18   30 my($self,$code) = @_;
502              
503 18         26 my( $sigdie, $eval_result, $eval_error );
504             {
505 18         30 local( $@, $!, $SIG{__DIE__} ); # isolate eval
  18         170  
506 18     3   1643 $eval_result = eval $code;
  3     3   84  
  1     3   3  
  3     1   22  
  3     1   4  
  3     1   129  
  3         2891  
  2         7598  
  1         48  
  1         7  
  1         1525  
  1         48  
  1         147  
  0         0  
  0         0  
  1         673  
  1         3169  
  1         40  
507 18         62 $eval_error = $@;
508 18   50     166 $sigdie = $SIG{__DIE__} || undef;
509             }
510             # make sure that $code got a chance to set $SIG{__DIE__}
511 18 50       48 $SIG{__DIE__} = $sigdie if defined $sigdie;
512              
513 18         58 return( $eval_result, $eval_error );
514             }
515              
516             ###############################################################################
517             # OK/IS/ISNT METHODS
518             ###############################################################################
519              
520             sub ok {
521 19     19 1 141 my($self,@args) = @_;
522 19         31 $main::TI_NUM++;
523              
524 19         38 my($op,@ret) = $self->_ok_result(@args);
525 19         31 my($name,@diag);
526 19         25 my $ok = 1;
527              
528 19 50       39 if ($op eq 'skip') {
    50          
529 0         0 my $reason = shift(@ret);
530 0         0 $self->_skip($reason);
531              
532             } elsif ($op eq 'pass') {
533 19         32 ($name,@diag) = @ret;
534 19         38 $self->_ok($name);
535              
536             } else {
537 0         0 ($name,@diag) = @ret;
538 0         0 $self->_not_ok($name);
539 0         0 $ok = 0;
540             }
541              
542             return
543             if ( ($ok && $$self{'quiet'}) ||
544 19 50 33     85 (! $ok && $$self{'quiet'} == 2) );
      33        
      33        
545              
546 19         54 foreach my $diag (@diag) {
547 18         44 $self->_diag($diag);
548             }
549             }
550              
551             sub _ok_result {
552 22     22   51 my($self,@args) = @_;
553              
554             # Test if we're skipping this test
555              
556 22         43 my($skip,$reason) = $self->_skip_test();
557 22 50       44 return ('skip',$reason) if ($skip);
558              
559             # No args == always pass
560              
561 22 100       40 if (@args == 0) {
562 1         4 return ('pass','Empty test');
563             }
564              
565             # Get the result
566              
567 21         47 my($func,$funcargs,$result) = $self->_get_result(\@args);
568              
569             # Get name/expected
570              
571 21         35 my($name,$expected);
572 21 100       52 if (@args == 1) {
    100          
    50          
573 7         14 $name = $args[0];
574             } elsif (@args == 2) {
575 11         19 ($expected,$name) = @args;
576             } elsif (@args > 2) {
577 0         0 return(0,'','Improperly formed test: too many arguments');
578             }
579              
580             # Check the result
581              
582 21         41 my($pass,@diag) = $self->_cmp_result('ok',$func,$funcargs,$result,$expected);
583 21         65 return($pass,$name,@diag);
584             }
585              
586             sub is {
587 2     2 1 17 my($self,@args) = @_;
588 2         7 $self->_is("is",@args);
589             }
590              
591             sub isnt {
592 2     2 1 17 my($self,@args) = @_;
593 2         5 $self->_is("isnt",@args);
594             }
595              
596             sub _is {
597 11     11   26 my($self,$is,@args) = @_;
598 11         18 $main::TI_NUM++;
599              
600 11         31 my($op,@ret) = $self->_is_result($is,@args);
601 11         14 my($name,@diag);
602 11         16 my $ok = 1;
603              
604 11 50       25 if ($op eq 'skip') {
    50          
605 0         0 my $reason = shift(@ret);
606 0         0 $self->_skip($reason);
607              
608             } elsif ($op eq 'pass') {
609 11         34 ($name,@diag) = @ret;
610 11         21 $self->_ok($name);
611              
612             } else {
613 0         0 ($name,@diag) = @ret;
614 0         0 $self->_not_ok($name);
615 0         0 $ok = 0;
616             }
617              
618             return
619             if ( ($ok && $$self{'quiet'}) ||
620 11 50 33     66 (! $ok && $$self{'quiet'} == 2) );
      33        
      33        
621              
622 11         53 foreach my $diag (@diag) {
623 0         0 $self->_diag($diag);
624             }
625             }
626              
627             sub _is_result {
628 24     24   50 my($self,$is,@args) = @_;
629              
630             # Test if we're skipping this test
631              
632 24         83 my($skip,$reason) = $self->_skip_test();
633 24 50       45 return ('skip',$reason) if ($skip);
634              
635             # Test args
636              
637 24 50       48 if (@args < 2) {
638 0         0 return ('fail','','Improperly formed test: too few arguments');
639             }
640              
641 24         54 my($func,$funcargs,$result) = $self->_get_result(\@args);
642              
643 24         54 my($name,$expected);
644 24 50       54 if (@args == 1) {
    50          
645 0         0 ($expected) = @args;
646             } elsif (@args == 2) {
647 24         41 ($expected,$name) = @args;
648             } else {
649 0         0 return(0,'','Improperly formed test: too many arguments');
650             }
651              
652             # Check the result
653              
654 24         53 my($pass,@diag) = $self->_cmp_result($is,$func,$funcargs,$result,$expected);
655 24         78 return($pass,$name,@diag);
656             }
657              
658             # Returns $func,$args and $results. The first two are returned only if
659             # there is a function.
660             #
661             sub _get_result {
662 45     45   75 my($self,$args) = @_;
663 45         67 my($func,@funcargs,@result,$result);
664              
665 45 100       123 if (ref($$args[0]) eq 'CODE') {
    100          
666 21         28 $func = shift(@$args);
667              
668 21 100       52 if (ref($$args[0]) eq 'ARRAY') {
669 17         23 @funcargs = @{ $$args[0] };
  17         42  
670 17         24 shift(@$args);
671             }
672              
673 21         45 @result = &$func(@funcargs);
674 21         178 return ($func,\@funcargs,\@result);
675              
676             } elsif (ref($$args[0]) eq 'ARRAY') {
677 7         11 @result = @{ $$args[0] };
  7         50  
678 7         15 shift(@$args);
679 7         24 return ('','',\@result);
680              
681             } else {
682 17         29 $result = shift(@$args);
683 17         52 return ('','',$result);
684             }
685             }
686              
687             sub _cmp_result {
688 45     45   89 my($self,$type,$func,$funcargs,$result,$expected) = @_;
689 45         61 my $pass = 0;
690 45         55 my $identical = 0;
691 45         107 my @diag;
692              
693 45 100       78 if ($type eq 'ok') {
694 21 100       60 if (ref($result) eq 'ARRAY') {
    100          
695 13         20 foreach my $ele (@$result) {
696 18 50       39 $pass = 1 if (defined($ele));
697             }
698              
699             } elsif (ref($result) eq 'HASH') {
700 2         7 foreach my $key (keys %$result) {
701 4         7 my $val = $$result{$key};
702 4 50       8 $pass = 1 if (defined($val));
703             }
704              
705             } else {
706 6 50       11 $pass = ($result ? 1 : 0);
707             }
708              
709 21 100       43 if (! defined($expected)) {
710             # If no expected result passed in, we don't test the results
711 10         15 $identical = 1;
712             } else {
713             # Results/expected must be the same structure
714 11         20 $identical = $self->_cmp_structure($result,$expected);
715             }
716              
717             } else {
718 24         98 $identical = $self->_cmp_structure($result,$expected);
719 24 100       47 if ($type eq 'is') {
720 22         40 $pass = $identical;
721             } else {
722 2         3 $pass = 1 - $identical;
723             }
724             }
725              
726 45 100 100     122 if (! $identical && $type ne 'isnt') {
727 7 100       13 if ($func) {
728 4         6 push(@diag,"Arguments: " . $self->_stringify($funcargs));
729             }
730 7         12 push(@diag, "Results : " . $self->_stringify($result));
731 7 50 33     40 push(@diag, "Expected : " . $self->_stringify($expected)) unless ($type eq 'ok' &&
732             ! defined($result));
733             }
734              
735 45 50       127 return (($pass ? 'pass' : 'fail'),@diag);
736             }
737              
738             # Turn a data structure into a string (poor-man's Data::Dumper)
739             sub _stringify {
740 18     18   32 my($self,$s) = @_;
741              
742 18         28 my($str) = $self->__stringify($s);
743 18         30 my($width) = $$self{'width'};
744 18 50       30 if ($width) {
745 18         23 $width -= 21; # The leading string
746 18 50       31 $width = 10 if ($width < 10);
747 18 50       26 $str = substr($str,0,$width) if (length($str)>$width);
748             }
749 18         50 return $str;
750             }
751              
752             sub __stringify {
753 38     38   60 my($self,$s) = @_;
754              
755 38 50       97 if (! defined($s)) {
    100          
    100          
    50          
    50          
756 0         0 return '__undef__';
757              
758             } elsif (ref($s) eq 'ARRAY') {
759 10         12 my $str = '[ ';
760 10         18 foreach my $val (@$s) {
761 12         28 $str .= $self->__stringify($val) . ' ';
762             }
763 10         15 $str .= ']';
764 10         21 return $str;
765              
766             } elsif (ref($s) eq 'HASH') {
767 2         3 my $str = '{ ';
768 2         8 foreach my $key (sort keys %$s) {
769 4         8 my $key = $self->__stringify($key);
770 4         8 my $val = $self->__stringify($$s{$key});
771 4         9 $str .= "$key=>$val ";
772             }
773 2         4 $str .= '}';
774 2         4 return $str;
775              
776             } elsif (ref($s)) {
777 0         0 return '<' . ref($s) . '>';
778              
779             } elsif ($s eq '') {
780 0         0 return "''";
781              
782             } else {
783 26 50       52 if ($s =~ /\s/) {
784 0         0 my $q = qr/\'/; # single quote
785 0         0 my $qq = qr/\"/; # double quote
786 0 0       0 if ($s !~ $q) {
787 0         0 return "'$s'";
788             }
789 0 0       0 if ($s !~ $qq) {
790 0         0 return '"' . $s . '"';
791             }
792 0         0 return "<$s>";
793              
794             } else {
795 26         62 return $s;
796             }
797             }
798             }
799              
800             sub _cmp_structure {
801 78     78   136 my($self,$s1,$s2) = @_;
802              
803 78 0 33     138 return 1 if (! defined($s1) && ! defined($s2)); # undef = undef
804 78 50 33     231 return 0 if (! defined($s1) || ! defined($s2)); # undef != def
805 78 100       145 return 0 if (ref($s1) ne ref($s2)); # must be same type
806              
807 74 100       196 if (ref($s1) eq 'ARRAY') {
    100          
    50          
808 17 50       43 return 0 if ($#$s1 != $#$s2); # two lists must be the same length
809 17         43 foreach (my $i=0; $i<=$#$s1; $i++) {
810 35 100       82 return 0 unless $self->_cmp_structure($$s1[$i],$$s2[$i]);
811             }
812 15         29 return 1;
813              
814             } elsif (ref($s1) eq 'HASH') {
815 4         12 my @k1 = keys %$s1;
816 4         9 my @k2 = keys %$s2;
817 4 50       12 return 0 if ($#k1 != $#k2); # two hashes must be the same length
818 4         6 foreach my $key (@k1) {
819 8 50       17 return 0 if (! exists $$s2{$key}); # keys must be the same
820 8 100       25 return 0 unless $self->_cmp_structure($$s1{$key},$$s2{$key});
821             }
822 2         5 return 1;
823              
824             } elsif (ref($s1)) {
825             # Two references (other than ARRAY and HASH are assumed equal.
826 0         0 return 1;
827              
828             } else {
829             # Two scalars are compared stringwise
830 53         195 return ($s1 eq $s2);
831             }
832             }
833              
834             sub _skip_test {
835 46     46   67 my($self) = @_;
836              
837 46 50 33     269 if ($$self{'skipall'}) {
    50 33        
838 0         0 return (1,$$self{'skipall'});
839             } elsif ( $main::TI_NUM < $$self{'start'} ||
840             ($$self{'end'} && $main::TI_NUM > $$self{'end'}) ) {
841 0         0 return (1,'Test not in list of tests specified to run');
842             }
843 46         108 return 0;
844             }
845              
846             ###############################################################################
847             # FILE METHOD
848             ###############################################################################
849              
850             sub file {
851 2     2 1 17 my($self,$func,$input,$outputdir,$expected,$name,@args) = @_;
852 2 50       7 $name = "" if (! $name);
853              
854 2 50       8 if (! ref($func) eq 'CODE') {
855 0         0 $self->_die("file method required a coderef");
856             }
857              
858 2         3 my @funcargs;
859 2         8 my $testdir = $$self{'testdir'};
860              
861             # Input file
862              
863 2 100       5 if ($input) {
864 1 50       36 if (-r $input) {
    50          
865             # Nothing
866              
867             } elsif (-r "$testdir/$input") {
868 1         5 $input = "$testdir/$input";
869              
870             } else {
871 0         0 $self->_die("Input file not readable: $input");
872             }
873 1         3 push(@funcargs,$input);
874             }
875              
876             # Output file and directory
877              
878 2 50       6 if (! $outputdir) {
879 2 50 33     44 if (-d $testdir &&
880             -w $testdir) {
881 2         7 $outputdir = $testdir;
882             } else {
883 0         0 $outputdir = ".";
884             }
885             }
886 2 50       5 if ($outputdir) {
887 2 50 33     39 if (! -d $outputdir ||
888             ! -w $outputdir) {
889 0         0 $self->_die("Output directory not writable: $outputdir");
890             }
891             }
892 2         6 my $output = "$outputdir/tmp_test_inter";
893 2         4 push(@funcargs,$output);
894              
895             # Expected output
896              
897 2 50       53 if (! $expected) {
    50          
    50          
898 0         0 $self->_die("Expected output file not specified");
899              
900             } elsif (-r $expected) {
901             # Nothing
902              
903             } elsif (-r "$testdir/$expected") {
904 2         7 $expected = "$testdir/$expected";
905              
906             } else {
907 0         0 $self->_die("Expected output file not readable: $expected");
908             }
909              
910             # Create the temporary output file.
911              
912 2         11 &$func(@funcargs,@args);
913 2 50       318 if (! -r "$output") {
914 0         0 $self->_die("Output file not created");
915             }
916              
917             # Test each line
918              
919 2         20 my $in = new IO::File;
920 2         92 $in->open($output);
921 2         112 my @out = <$in>;
922 2         18 $in->close();
923 2         31 chomp(@out);
924              
925 2         9 $in->open($expected);
926 2         87 my @exp = <$in>;
927 2         12 $in->close();
928 2         25 chomp(@exp);
929 2 50       108 unlink($output) if (! $ENV{'TI_NOCLEAN'});
930              
931 2         13 while (@out < @exp) {
932 0         0 push(@out,'');
933             }
934 2         7 while (@exp < @out) {
935 0         0 push(@exp,'');
936             }
937              
938 2         6 for (my $i=0; $i<@out; $i++) {
939 7         14 my $line = $i+1;
940 7 50       19 my $n = ($name ? "$name : Line $line" : "Line $line");
941 7         22 $self->_is('is',$out[$i],$exp[$i],$n);
942             }
943             }
944              
945             ###############################################################################
946             # TESTS METHOD
947             ###############################################################################
948              
949             sub tests {
950 4     4 1 29 my($self,%opts) = @_;
951              
952             #
953             # feature => [ FEATURE, FEATURE, ... ]
954             # disable => [ FEATURE, FEATURE, ... ]
955             #
956              
957 4         7 my $skip = '';
958 4 50       11 if (exists $opts{'feature'}) {
959 0         0 foreach my $feature (@{ $opts{'feature'} }) {
  0         0  
960             $skip = "Required feature unavailable: $feature", last
961 0 0       0 if (! exists $$self{'features'}{$feature});
962             }
963             }
964 4 50 33     10 if (exists $opts{'disable'} && ! $skip) {
965 0         0 foreach my $feature (@{ $opts{'disable'} }) {
  0         0  
966             $skip = "Disabled due to feature being available: $feature", last
967 0 0       0 if (exists $$self{'features'}{$feature});
968             }
969             }
970              
971             #
972             # name => NAME
973             # skip => REASON
974             # todo => 0/1
975             #
976              
977 4         6 my $name = '';
978 4 50       7 if (exists $opts{'name'}) {
979 0         0 $name = $opts{'name'};
980             }
981              
982 4 50       9 if (exists $opts{'skip'}) {
983 0         0 $skip = $opts{'skip'};
984             }
985              
986 4         4 my $todo = 0;
987 4 50       9 if (exists $opts{'todo'}) {
988 0         0 $todo = $opts{'todo'};
989             }
990              
991             #
992             # tests => STRING OR LISTREF
993             # func => CODEREF
994             # expected => STRING OR LISTREF
995             #
996              
997             # tests
998 4 50       8 if (! exists $opts{'tests'}) {
999 0         0 $self->_die("invalid test format: tests required");
1000             }
1001 4         6 my $tests = $opts{'tests'};
1002 4         9 my(%tests,$gotexpected);
1003              
1004 4         0 my($ntest,$nexp);
1005 4 50       8 if (ref($tests) eq 'ARRAY') {
1006 0         0 my @results = @$tests;
1007 0         0 $ntest = 0;
1008 0         0 foreach my $result (@results) {
1009 0         0 $ntest++;
1010 0         0 $tests{$ntest}{'err'} = 0;
1011 0 0       0 if (ref($result) eq 'ARRAY') {
1012 0         0 $tests{$ntest}{'args'} = $result;
1013             } else {
1014 0         0 $tests{$ntest}{'args'} = [$result];
1015             }
1016             }
1017 0         0 $gotexpected = 0;
1018              
1019             } else {
1020 4         9 ($ntest,$gotexpected,%tests) = $self->_parse($tests);
1021 4 100       14 $nexp = $ntest if ($gotexpected);
1022             }
1023              
1024             # expected
1025 4 100       11 if (exists $opts{'expected'}) {
1026 2 50       5 if ($gotexpected) {
1027 0         0 $self->_die("invalid test format: expected results included twice");
1028             }
1029 2         3 my $expected = $opts{'expected'};
1030              
1031 2 100       8 if (ref($expected) eq 'ARRAY') {
1032 1         3 my @exp = @$expected;
1033 1         3 $nexp = 0;
1034 1         2 foreach my $exp (@exp) {
1035 1         2 $nexp++;
1036 1 50       2 if (ref($exp) eq 'ARRAY') {
1037 1         4 $tests{$nexp}{'expected'} = $exp;
1038             } else {
1039 0         0 $tests{$nexp}{'expected'} = [$exp];
1040             }
1041             }
1042              
1043             } else {
1044 1         2 my($g,%t);
1045 1         3 ($nexp,$g,%t) = $self->_parse($expected);
1046 1 50       4 if ($g) {
1047 0         0 $self->_die("invalid test format: expected results contain '=>'");
1048             }
1049 1         4 foreach my $t (1..$nexp) {
1050 1         4 $tests{$t}{'expected'} = $t{$t}{'args'};
1051             }
1052             }
1053 2         4 $gotexpected = 1;
1054             }
1055              
1056 4 50 66     16 if ($gotexpected &&
      66        
1057             ($nexp != 1 && $nexp != $ntest)) {
1058 0         0 $self->_die("invalid test format: number expected results differs from number of tests");
1059             }
1060              
1061             # func
1062 4         5 my $func;
1063 4 100       9 if (exists $opts{'func'}) {
1064 3         4 $func = $opts{'func'};
1065 3 50       11 if (ref($func) ne 'CODE') {
1066 0         0 $self->_die("invalid test format: func must be a code reference");
1067             }
1068             }
1069              
1070             #
1071             # Compare results
1072             #
1073              
1074 4         10 foreach my $t (1..$ntest) {
1075 16         29 $main::TI_NUM++;
1076              
1077 16 50       23 if ($skip) {
1078 0         0 $self->_skip($skip,$name);
1079 0         0 next;
1080             }
1081              
1082 16 50       33 if ($tests{$t}{'err'}) {
1083 0         0 $self->_not_ok($name);
1084 0         0 $self->diag($tests{$t}{'err'});
1085 0         0 next;
1086             }
1087              
1088 16         22 my($op,@ret);
1089              
1090             # Test results
1091              
1092 16 100       31 if ($gotexpected) {
1093             # Do an 'is' test
1094              
1095 13         25 my @a = ('is');
1096 13 50       26 push(@a,$func) if ($func);
1097 13         19 push(@a,$tests{$t}{'args'});
1098             push(@a,($nexp == 1 ? $tests{'1'}{'expected'}
1099 13 100       26 : $tests{$t}{'expected'}));
1100 13         19 push(@a,$name);
1101              
1102 13         24 ($op,@ret) = $self->_is_result(@a);
1103              
1104             } else {
1105             # Do an 'ok' test
1106              
1107 3         5 my $result = $tests{$t}{'args'};
1108 3 50       6 if (@$result == 1) {
1109 0         0 $result = $$result[0];
1110             }
1111 3         25 ($op,@ret) = $self->_ok_result($result,$name);
1112             }
1113              
1114             # Print it out
1115              
1116 16         26 my($name,@diag);
1117 16         25 my $ok = 1;
1118              
1119 16 50       34 if ($op eq 'skip') {
    50          
1120 0         0 my $reason = shift(@ret);
1121 0         0 $self->_skip($reason);
1122              
1123             } elsif ($op eq 'pass') {
1124 16         23 ($name,@diag) = @ret;
1125 16         32 $self->_ok($name);
1126              
1127             } else {
1128 0         0 ($name,@diag) = @ret;
1129 0         0 $self->_not_ok($name);
1130 0         0 $ok = 0;
1131             }
1132              
1133             next
1134             if ( ($ok && $$self{'quiet'}) ||
1135 16 50 33     71 (! $ok && $$self{'quiet'} == 2) );
      33        
      33        
1136              
1137 16         57 foreach my $diag (@diag) {
1138 0         0 $self->_diag($diag);
1139             }
1140             }
1141             }
1142              
1143             ###############################################################################
1144             # TAP METHODS
1145             ###############################################################################
1146              
1147             sub _diag {
1148 35     35   60 my($self,$message) = @_;
1149 35         1336 print '#' . ' 'x10 . "$message\n";
1150             }
1151              
1152             sub _plan {
1153 10     10   33 my($self,$n,$reason) = @_;
1154 10 100       33 $reason = '' if (! $reason);
1155              
1156 10 50       43 if ($$self{'mode'} eq 'test') {
1157              
1158             # Test mode
1159              
1160 10 100       34 if (! $n) {
1161 1 50       2 $reason = '' if (! $reason);
1162 1         7 print "1..0 # Skipped $reason\n";
1163 1         2 return;
1164             }
1165              
1166 9         42 print "1..$n\n";
1167              
1168             } else {
1169              
1170 0 0       0 if (! $n) {
1171 0         0 print " All tests skipped: $reason\n";
1172             } else {
1173             print " Epected number of tests: $n\n"
1174 0 0       0 unless ($$self{'quiet'});
1175             }
1176             }
1177             }
1178              
1179             sub _ok {
1180 60     60   110 my($self,$name) = @_;
1181              
1182 60 100       152 $name = '' if (! $name);
1183 60         121 $name =~ s/\#//;
1184              
1185 60         112 $$self{'testsrun'} = 1;
1186              
1187             return if ($$self{'mode'} ne 'test' &&
1188 60 0 33     136 $$self{'quiet'});
1189              
1190 60         350 print "ok $main::TI_NUM" . ' 'x(8-length($main::TI_NUM)) . "$name\n";
1191              
1192 60 50 33     217 if ($name =~ /^\d/ && $$self{'quiet'} != 2) {
1193 0         0 $self->_diag('It is strongly recommended that the name of a test not');
1194 0         0 $self->_diag('begin with a digit so it will not be confused with the');
1195 0         0 $self->_diag('test number.');
1196             }
1197             }
1198              
1199             sub _not_ok {
1200 0     0   0 my($self,$name) = @_;
1201 0 0       0 $name = '' if (! $name);
1202 0         0 $name =~ s/\#//;
1203              
1204 0         0 $$self{'testsrun'} = 1;
1205              
1206 0         0 print "not ok $main::TI_NUM" . ' 'x(4-length($main::TI_NUM)) . "$name\n";
1207              
1208 0 0       0 if ($$self{'abort'} == 2) {
    0          
1209 0         0 exit 1;
1210             } elsif ($$self{'abort'}) {
1211 0         0 $$self{'skipall'} = 'Tests aborted due to failed test';
1212             }
1213             }
1214              
1215             sub _skip {
1216 0     0   0 my($self,$reason,$name) = @_;
1217 0 0       0 $name = '' if (! $name);
1218 0         0 $name =~ s/\#//;
1219              
1220 0         0 $$self{'testsrun'} = 1;
1221              
1222             return if ($$self{'mode'} ne 'test' &&
1223 0 0 0     0 $$self{'quiet'});
1224              
1225 0 0       0 print "ok $main::TI_NUM" . ' 'x(8-length($main::TI_NUM)) .
1226             ($name ? "$name " : "") . "# SKIPPED $reason\n";
1227             }
1228              
1229             ###############################################################################
1230             # TEST PARSING METHODS
1231             ###############################################################################
1232              
1233             {
1234             my $l; # current line number
1235             my $sp_opt = qr/\s*/; # optional whitespace
1236             my $sp = qr/\s+/; # required whitespace
1237             my $lparen = qr/\(/; # opening paren
1238             my $lbrack = qr/\[/; # opening brack
1239             my $lbrace = qr/\{/; # opening brace
1240             my $q = qr/\'/; # single quote
1241             my $qq = qr/\"/; # double quote
1242             my $token = qr/\S+/; # a token of non-whitespace characters
1243             my $min_str = qr/.*?/; # a minimum length string
1244             my $results = qr/=>/; # the string to switch to results
1245              
1246             # We'll also need to match delimiters and other special characters that
1247             # signal the end of a token. The default delimiter is just whitespace,
1248             # both other end-of-token regular expressions will include closing
1249             # parens, delimiters, etc.
1250             #
1251             # The end-of-token regexp will return a match for a special character (if
1252             # any) that terminates the token. If a token ends a whitespace or EOL,
1253             # nothing is matched.
1254             #
1255             my $eot = qr/()(?:\s+|$)/;
1256              
1257             # Allowed delimiters is anything except () [] {} alphanumeric,
1258             # underscore, and whitespace.
1259             #
1260             my $delim = qr/[^\'\"\(\)\[\]\{\}a-zA-Z0-9_ \t]/;
1261              
1262             # This takes a string which may contain a partial or complete
1263             # descritpion of any number of tests, and parses it.
1264             #
1265             # The string is multiline, and tests must be separated from each other
1266             # by one or more blank lines. Lines starting with a pound sign (#)
1267             # are comments.
1268             #
1269             # A test may include arguments (or obtained results), expected results,
1270             # or both.
1271             #
1272             # Returns
1273             # ($n,$gotboth,%tests)
1274             # where
1275             # $n is the number of tests
1276             # $gotboth is 1 if both arguments and expected results are obtained
1277             # $tests{$i} is the i'th test.
1278             #
1279             sub _parse {
1280 5     5   11 my($self,$string) = @_;
1281 5         5 my $t = 0;
1282 5         7 my $gotboth = -1;
1283 5         9 my %tests = ();
1284              
1285             # Split on newlines
1286 5         22 $string = [ split(/\n/s,$string) ];
1287              
1288 5         11 $t = 0;
1289 5         10 while (@$string) {
1290 17         36 my $test = $self->_next_test($string);
1291 17 50       32 last if (! @$test);
1292              
1293             # All tests must contain both args/results OR only one of them.
1294 17         32 my ($err,$both,$args,$results) = $self->_parse_test($test);
1295 17 100       46 if ($gotboth == -1) {
    50          
1296 5         7 $gotboth = $both;
1297             } elsif ($gotboth != $both) {
1298 0         0 $err = "Malformed test [$l]: expected results for some tests, not others";
1299             }
1300              
1301 17         27 $t++;
1302 17         50 $tests{$t}{'err'} = $err;
1303 17         37 $tests{$t}{'args'} = $args;
1304 17 100       58 $tests{$t}{'expected'} = $results if ($gotboth);
1305             }
1306              
1307 5         35 return ($t,$gotboth,%tests);
1308             }
1309              
1310             # Get all lines up to the end of lines or a blank line. Both
1311             # signal the end of a test.
1312             #
1313             sub _next_test {
1314 17     17   29 my($self,$list) = @_;
1315 17         23 my @test;
1316 17         23 my $started = 0;
1317              
1318 17         21 while (1) {
1319 34 100       61 last if (! @$list);
1320 33         49 my $line = shift(@$list);
1321              
1322 33         102 $line =~ s/^\s*//;
1323 33         115 $line =~ s/\s*$//;
1324              
1325             # If it's a blank line, add it to the test. If we've
1326             # already done test lines, then this signals the end
1327             # of the test. Otherwise, this is before the test,
1328             # so keep looking.
1329 33 100       69 if ($line eq '') {
1330 16         27 push(@test,$line);
1331 16 50       27 next if (! $started);
1332 16         26 last;
1333             }
1334              
1335             # Comments are added to the test as a blank line.
1336 17 50       36 if ($line =~ /^#/) {
1337 0         0 push(@test,'');
1338 0         0 next;
1339             }
1340              
1341 17         32 push(@test,$line);
1342 17         23 $started = 1;
1343             }
1344              
1345 17 50       26 return [] if (! $started);
1346 17         32 return \@test;
1347             }
1348              
1349             # Parse an entire test. Look for arguments, =>, and expected results.
1350             #
1351             sub _parse_test {
1352 17     17   26 my($self,$test) = @_;
1353 17         28 my($err,$both,@args,@results);
1354              
1355 17         21 my $curr = 'args';
1356              
1357 17         31 while (@$test) {
1358              
1359 68 100       144 last if (! $self->_test_line($test));
1360              
1361             # Check for '=>'
1362              
1363 51 100       101 if ($self->_parse_begin_results($test)) {
1364 7 50       18 if ($curr eq 'args') {
1365 7         9 $curr = 'results';
1366             } else {
1367 0         0 return ("Malformed test [$l]: '=>' found twice");
1368             }
1369 7         18 next;
1370             }
1371              
1372             # Get the next item(s) to add.
1373              
1374 44         108 my($err,$match,@val) = $self->_parse_token($test,$eot);
1375 44 50       91 return ($err) if ($err);
1376              
1377 44 100       72 if ($curr eq 'args') {
1378 29         84 push(@args,@val);
1379             } else {
1380 15         43 push(@results,@val);
1381             }
1382             }
1383              
1384 17 100       32 $both = ($curr eq 'results' ? 1 : 0);
1385 17         48 return ("",$both,\@args,\@results);
1386             }
1387              
1388             # Makes sure that the first line in the test contains
1389             # something. Blank lines are ignored.
1390             #
1391             sub _test_line {
1392 129     129   190 my($self,$test) = @_;
1393              
1394 129   66     516 while (@$test &&
      100        
1395             (! defined($$test[0]) ||
1396             $$test[0] eq '')) {
1397 33         43 shift(@$test);
1398 33         43 $l++;
1399 33         87 next;
1400             }
1401 129 100       321 return 1 if (@$test);
1402 17         38 return 0;
1403             }
1404              
1405             # Check for '=>'.
1406             #
1407             # Return 1 if found, 0 otherwise.
1408             #
1409             sub _parse_begin_results {
1410 51     51   82 my($self,$test) = @_;
1411              
1412 51 100       265 return 1 if ($$test[0] =~ s/^ $sp_opt $results $eot //x);
1413 44         96 return 0;
1414             }
1415              
1416             # Gets the next item to add to the current list.
1417             #
1418             # Returns ($err,$match,@val) where $match is the character that
1419             # matched the end of the current element (either a delimiter,
1420             # closing character, or nothing if the element ends on
1421             # whitespace/newline).
1422             #
1423             sub _parse_token {
1424 61     61   113 my($self,$test,$EOT) = @_;
1425              
1426 61         81 my($err,$found,$match,@val);
1427              
1428             {
1429 61 50       74 last if (! $self->_test_line($test));
  61         104  
1430              
1431             # Check for quoted
1432              
1433 61         117 ($err,$found,$match,@val) = $self->_parse_quoted($test,$EOT);
1434 61 50       110 last if ($err);
1435 61 100       100 if ($found) {
1436             # '' remains ''
1437 2         2 last;
1438             }
1439              
1440             # Check for open
1441              
1442 59         122 ($err,$found,$match,@val) = $self->_parse_open_close($test,$EOT,$lparen,')');
1443 59 50       127 last if ($err);
1444 59 100       107 if ($found) {
1445             # () is an empty list
1446 7 50 66     22 if (@val == 1 && $val[0] eq '') {
1447 0         0 @val = ();
1448             }
1449 7         9 last;
1450             }
1451              
1452 52         102 ($err,$found,$match,@val) = $self->_parse_open_close($test,$EOT,$lbrack,']');
1453 52 50       121 last if ($err);
1454 52 100       90 if ($found) {
1455             # [] is []
1456 2 50 33     10 if (@val == 1 && $val[0] eq '') {
1457 2         5 @val = ([]);
1458             } else {
1459 0         0 @val = ( [@val] );
1460             }
1461 2         3 last;
1462             }
1463              
1464 50         95 ($err,$found,$match,@val) = $self->_parse_open_close($test,$EOT,$lbrace,'}');
1465 50 50       168 last if ($err);
1466 50 100       89 if ($found) {
1467 2 50 33     11 if (@val == 1 && $val[0] eq '') {
    0 0        
    0          
1468 2         4 @val = ( {} );
1469             } elsif (@val % 2 == 0) {
1470             # Even number of elements
1471 0         0 @val = ( {@val} );
1472             } elsif (! defined $val[$#val] ||
1473             $val[$#val] eq '') {
1474             # Odd number of elements with nothing as the
1475             # last element.
1476 0         0 pop(@val);
1477 0         0 @val = ( {@val} );
1478             } else {
1479             # Odd number of elements not supported for a hash
1480 0         0 $err = "Malformed test [$l]: hash with odd number of elements";
1481             }
1482 2         4 last;
1483             }
1484              
1485             # Check for some other token
1486              
1487 48         99 ($err,$found,$match,@val) = $self->_parse_simple_token($test,$EOT);
1488 48 50       101 last if ($err);
1489              
1490 48         74 last;
1491             }
1492              
1493 61 50       93 return ($err) if ($err);
1494 61 50       102 return ("Malformed test: unable to parse") if (! $found);
1495              
1496 61         104 foreach my $v (@val) {
1497 68 50       139 $v = '' if ($v eq '__blank__');
1498 68 50       114 $v = undef if ($v eq '__undef__');
1499 68 100       156 $v =~ s/__nl__/\n/g if ($v);
1500             }
1501 61 50       224 return (0,$match,@val) if ($found);
1502 0         0 return (0,0);
1503             }
1504              
1505             ###
1506             ### The next few routines parse parts of the test. Each of them
1507             ### take as arguments:
1508             ###
1509             ### $test : the listref containing the unparsed portion of
1510             ### the test
1511             ### $EOT : the end of a token
1512             ###
1513             ### + other args as needed.
1514             ###
1515             ### They all return:
1516             ###
1517             ### $err : a string containing the error (if any)
1518             ### $found : 1 if something matched
1519             ### $match : the character which terminates the current
1520             ### token signaling the start of the next token
1521             ### (this will either be a delimiter, a closing
1522             ### character, or nothing if the string ended on
1523             ### whitespace or a newline)
1524             ### @val : the value (or values) of the token
1525             ###
1526              
1527             # Check for a quoted string
1528             # 'STRING'
1529             # "STRING"
1530             # The string must be on one line, and everything up to the
1531             # closing quote is included (the quotes themselves are
1532             # stripped).
1533             #
1534             sub _parse_quoted {
1535 61     61   97 my($self,$test,$EOT) = @_;
1536              
1537 61 100 66     1318 if ($$test[0] =~ s/^ $sp_opt $q ($min_str) $q $EOT//x ||
    50 33        
1538             $$test[0] =~ s/^ $sp_opt $qq ($min_str) $qq $EOT//x) {
1539 2         8 return (0,1,$2,$1);
1540              
1541             } elsif ($$test[0] =~ /^ $sp_opt $q/x ||
1542             $$test[0] =~ /^ $sp_opt $qq/x) {
1543 0         0 return ("Malformed test [$l]: improper quoting");
1544             }
1545 59         181 return (0,0);
1546             }
1547              
1548             # Parses an open/close section.
1549             #
1550             # ( TOKEN TOKEN ... )
1551             # (, TOKEN, TOKEN, ... )
1552             #
1553             # $open is a regular expression matching the open, $close is the
1554             # actual closing character.
1555             #
1556             # After the closing character must be an $EOT.
1557             #
1558             sub _parse_open_close {
1559 161     161   271 my($self,$test,$EOT,$open,$close) = @_;
1560              
1561             # See if there is an open
1562              
1563 161         193 my($del,$newEOT);
1564 161 100       4869 if ($$test[0] =~ s/^ $sp_opt $open ($delim) $sp_opt //x) {
    100          
1565 2         7 $del = $1;
1566 2         43 $newEOT = qr/ $sp_opt ($|\Q$del\E|\Q$close\E) /x;
1567              
1568             } elsif ($$test[0] =~ s/^ $sp_opt $open $sp_opt //x) {
1569 9         20 $del = '';
1570 9         96 $newEOT = qr/ ($sp_opt $|$sp_opt \Q$close\E|$sp) /x;
1571              
1572             } else {
1573 150         533 return (0,0);
1574             }
1575              
1576             # If there was, then we need to read tokens until either:
1577             # the string is all used up => error
1578             # $close is found
1579              
1580 11         28 my($match,@val);
1581 11         16 while (1) {
1582              
1583             # Get a token. We MUST find something valid even if it is
1584             # an empty list followed by the closing character.
1585 17         45 my($e,$m,@v) = $self->_parse_token($test,$newEOT);
1586 17 50       39 return ($e) if ($e);
1587 17         64 $m =~ s/^$sp//;
1588              
1589             # If we ended on nothing, and $del is something, then we
1590             # ended on a newline with no delimiter. The next line MUST
1591             # start with a delimiter or close character or the test is
1592             # invalid.
1593              
1594 17 50 66     46 if (! $m && $del) {
1595              
1596 0 0       0 if (! $self->_test_line($test)) {
1597 0         0 return ("Malformed test [$l]: premature end of test");
1598             }
1599              
1600 0 0       0 if ($$test[0] =~ s/^ $sp_opt $newEOT //x) {
1601 0         0 $m = $1;
1602             } else {
1603 0         0 return ("Malformed test [$l]: unexpected token (expected '$close' or '$del')");
1604             }
1605             }
1606              
1607             # Figure out what value(s) were returned
1608 17 50 66     56 if ($m eq $close && ! @v) {
1609 0         0 push(@val,'');
1610             } else {
1611 17         34 push(@val,@v);
1612             }
1613              
1614 17 100       37 last if ($m eq $close);
1615              
1616             }
1617              
1618             # Now we need to find out what character ends this token:
1619              
1620 11 100       25 if ($$test[0] eq '') {
1621             # Ended at EOL
1622 2         9 return (0,1,'',@val);
1623             }
1624 9 50       89 if ($$test[0] =~ s/^ $sp_opt $EOT //x) {
1625 9         53 return (0,1,$1,@val);
1626             } else {
1627 0         0 return ("Malformed test [$l]: unexpected token");
1628             }
1629             }
1630              
1631             # Checks for a simple token.
1632             #
1633             sub _parse_simple_token {
1634 48     48   75 my($self,$test,$EOT) = @_;
1635              
1636 48         514 $$test[0] =~ s/^ $sp_opt (.*?) $EOT//x;
1637 48         208 return (0,1,$2,$1);
1638             }
1639             }
1640              
1641             1;
1642             # Local Variables:
1643             # mode: cperl
1644             # indent-tabs-mode: nil
1645             # cperl-indent-level: 3
1646             # cperl-continued-statement-offset: 2
1647             # cperl-continued-brace-offset: 0
1648             # cperl-brace-offset: 0
1649             # cperl-brace-imaginary-offset: 0
1650             # cperl-label-offset: 0
1651             # End: