File Coverage

blib/lib/Test/Toolbox.pm
Criterion Covered Total %
statement 154 221 69.6
branch 51 116 43.9
condition 15 42 35.7
subroutine 27 28 96.4
pod 15 22 68.1
total 262 429 61.0


line stmt bran cond sub pod time code
1             package Test::Toolbox;
2 1     1   432 use strict;
  1         1  
  1         22  
3             # use String::Util ':all';
4 1     1   3 use Carp 'croak';
  1         1  
  1         38  
5 1     1   381 use Test::Builder::Module;
  1         7961  
  1         4  
6 1     1   24 use Cwd 'abs_path';
  1         1  
  1         54  
7              
8             # debug tools
9             # use Debug::ShowStuff ':all';
10             # use Debug::ShowStuff::ShowVar;
11              
12             # version
13             our $VERSION = '0.2';
14              
15              
16              
17             #------------------------------------------------------------------------------
18             # opening pod
19             #
20              
21             =head1 NAME
22              
23             Test::Toolbox - tools for testing
24              
25             =head1 SYNOPSIS
26              
27             # load module
28             use Test::Toolbox;
29            
30             # plan tests
31             rtplan 43;
32            
33             # or, plan tests, but die on the first failure
34             rtplan 43, autodie=>1;
35            
36             # basic test
37             rtok 'my test name', $success;
38              
39             # test for failure if you prefer
40             rtok 'test name', $success, should=>0;
41              
42             # two values should equal each other
43             rtcomp 'test name', $val, $other_val;
44            
45             # two values should not equal each other
46             rtcomp 'test name', $val, $other_val, should=>0;
47            
48             # run some code which should succeed
49             # note that the second param is undef
50             rteval 'test name', undef, sub { mysub() };
51            
52             # run some code which should cause a specific error code
53             rteval 'test name', 'file-open-failed', sub { mysub() };
54            
55             # check that $@ has a specific error code
56             rtid 'test name', $@, 'missing-keys';
57            
58             # much more
59              
60             =head1 OVERVIEW
61              
62             Test::Toolbox provides (as you might guess) tools for automated testing.
63             Test::Toolbox is much like some other testing modules, such as Test::More
64             and Test::Simple. Test::Toolbox provides a different flavor of tests which
65             may or may not actually be to your preference.
66              
67             The tools in Test::Toolbox have a standard format. Commands start with (the
68             command (of course), followed by the test name. Then there is usually the
69             value being tested, or values being compared, then other options. So, for
70             example, this command checks compares two values:
71              
72             rtcomp 'test name', $val, $other_val;
73              
74             In some cases it's preferable to flip the logic of the test, so that, for
75             example, two values should B be the same. In that case, you can add
76             the C option:
77              
78             rtcomp 'test name', $val, $other_val, should=>0;
79              
80             All test commands require a test name as the first param.
81              
82             =head1 Meta commands
83              
84             =cut
85              
86             #
87             # opening pod
88             #------------------------------------------------------------------------------
89              
90              
91              
92             #------------------------------------------------------------------------------
93             # extend Test::Builder::Module
94             #
95 1     1   4 use base 'Test::Builder::Module';
  1         1  
  1         75  
96             #
97             # extend Test::Builder::Module
98             #------------------------------------------------------------------------------
99              
100              
101             #------------------------------------------------------------------------------
102             # export
103             # KLUDGE: I don't like automatically exporting everything from a module. By
104             # default, nothing shoujld be exported. Exports should be explicit with
105             # something like :all. However, Test::Module throws an error if Test::Toolbox
106             # tries to use %EXPORT_OK. For now, I'm just going with the flow and exporting
107             # everything, but I'll see if I can correct the situation in later releases.
108             #
109 1     1   3 use base 'Exporter';
  1         1  
  1         1809  
110             our (@EXPORT);
111              
112             # @EXPORT
113             @EXPORT = qw[
114             go_script_dir
115             rtplan
116             rtcounts
117             rtok
118             rtcomp
119             rtarr
120             rtelcount
121             rthash
122             rtisa
123             rtbool
124             rtdef
125             rtrx
126             rtfile
127             rtid
128             rteval
129             ];
130             #
131             # export
132             #------------------------------------------------------------------------------
133              
134              
135              
136             #------------------------------------------------------------------------------
137             # globals
138             #
139             our ($planned_test_count);
140             our $auto_die = 0;
141             our $verbose = 0;
142             our %counts = (success=>0, fail=>0, sofar=>0, planned=>0);
143             our $script_abs_path = abs_path($0);
144             #
145             # globals
146             #------------------------------------------------------------------------------
147              
148              
149              
150             ###############################################################################
151             # public methods
152             #
153              
154              
155             #------------------------------------------------------------------------------
156             # go_script_dir
157             #
158              
159             =head2 go_script_dir()
160              
161             C changes to the directory that the script is running in. This
162             can be handy of your test script needs to read files that are part of your
163             tests. C takes no params:
164              
165             go_script_dir();
166              
167             =cut
168              
169             sub go_script_dir {
170 1     1 1 3 my ($script_dir);
171            
172             # load basename module
173 1         5 require File::Basename;
174            
175             # get script's directory
176 1         44 $script_dir = File::Basename::dirname($script_abs_path);
177            
178             # untaint directory path
179             # KLUDGE: Normally unconditional untainting is a Very Bad Idea.
180             # In this case I don't know a good way to untaint a path using a pattern.
181             # The following code checks if the path actually exists as a directory,
182             # then untaints the path
183 1 50       17 if (-d $script_dir) {
184 1 50       3 unless ($script_dir =~ m|^(.+)$|s)
185 0         0 { die 'somehow cannot untaint directory path' }
186 1         3 $script_dir = $1;
187             }
188            
189             # go to directory
190 1         10 chdir($script_dir);
191             }
192             #
193             # go_script_dir
194             #------------------------------------------------------------------------------
195              
196              
197              
198              
199             #------------------------------------------------------------------------------
200             # rtplan
201             #
202              
203             =head2 rtplan()
204              
205             rtplan() indicates how many tests you plan on running. Like with other test
206             modules, failing to run exactly that many tests is itself considered on error.
207             So, this command plans on running exactly 43 tests.
208              
209             rtplan 43;
210              
211             You might prefer that your script dies on the first failure. In that case add
212             the C option:
213              
214             rtplan 43, autodie=>1;
215              
216             =cut
217              
218             sub rtplan {
219 1     1 1 6 my ($count, %opts) = @_;
220 1         1 my ($tb);
221            
222             # TESTING
223             # println subname(); ##i
224            
225             # set planned count
226 1         1 $planned_test_count = $count;
227 1         2 $counts{'planned'} = $count;
228            
229             # autodie
230 1 50       2 if (exists $opts{'autodie'})
231 1         1 { $auto_die = $opts{'autodie'} }
232            
233             # verbose
234             # if (exists $opts{'verbose'})
235             # { $verbose = $opts{'verbose'} }
236            
237             # plan tests
238 1         6 $tb = Test::Toolbox->builder;
239 1         11 return $tb->plan(tests=>$count);
240             }
241             #
242             # rtplan
243             #------------------------------------------------------------------------------
244              
245              
246             #------------------------------------------------------------------------------
247             # rtcounts
248             #
249              
250             =head2 rtcounts()
251              
252             rtcounts() returns a hashref of the test counts so far. The hashref has the
253             following elements:
254              
255             =over
256              
257             =item * success: number of successful tests so far.
258              
259             =item * fail: number of failed tests so far.
260              
261             =item * sofar: total number of tests so far.
262              
263             =item * planned: total number of planned tests.
264              
265             =back
266              
267             =cut
268              
269             sub rtcounts {
270 1     1 1 7 return {%counts};
271             }
272             #
273             # rtcounts
274             #------------------------------------------------------------------------------
275              
276              
277              
278             #------------------------------------------------------------------------------
279             # pod for test commands
280             #
281              
282             =head1 Test commands
283              
284             =cut
285              
286             #
287             # pod for test commands
288             #------------------------------------------------------------------------------
289              
290              
291              
292             #------------------------------------------------------------------------------
293             # rtok
294             #
295              
296             =head2 rtok()
297              
298             rtok() is the basic command of Test::Toolbox. It requires two params, the name
299             of the test, and a scalar indicating success (true) or failure (false). So,
300             this simple command indicates a successful test:
301              
302             rtok 'my test', 1;
303              
304             You might prefer to flip the logic, so that false indicates success. For that,
305             use the C option:
306              
307             rtok 'my test', $val, should=>0;
308              
309             All other test command call rtok().
310              
311             =cut
312              
313             sub rtok {
314 23     23 1 127 my ($test_name, $ok, %opts) = @_;
315 23         15 my ($indent);
316            
317             # TESTING
318             # println subname(); ##i
319            
320             # default options
321 23         37 %opts = (should=>1, %opts);
322            
323             # $test_name is required
324 23 50       30 $test_name or confess ('$test_name is required');
325            
326             # TESTING
327             # unless ($test_name =~ m|^\(rt\)|si)
328             # { croak 'during development, test name must start with (rt)' }
329            
330             # verbosify
331             # if ($verbose) {
332             # println 'test: ', $test_name;
333             # $indent = indent();
334             # }
335            
336             # reverse test if necessary
337 23         29 $ok = should_flop($ok, %opts);
338            
339             # autodie if mecessary
340 23 50       45 if ($auto_die) {
341 0 0       0 if (! $ok) {
342 0         0 croak("fail: $test_name");
343             }
344             }
345            
346             # regular ok
347 23         30 ok_private($test_name, $ok);
348            
349             # set counts
350 23 100       4008 if ($ok)
351 22         24 { $counts{'success'}++ }
352             else
353 1         2 { $counts{'fail'}++ }
354            
355             # increment sofar
356 23         52 $counts{'sofar'}++;
357             }
358             #
359             # rtok
360             #------------------------------------------------------------------------------
361              
362              
363             #------------------------------------------------------------------------------
364             # rtcomp
365             #
366              
367             =head2 rtcomp()
368              
369             rtcomp() compares the string value of two values. It sets success if they are
370             the same, failure if thet are different. Its simplest use would be like this:
371              
372             rtcomp 'my test', $first, $second;
373              
374             As with other commands, you can flip the logic of the command so that success
375             is if they are not the same:
376              
377             rtcomp 'my test', $first, $second, should=>0;
378              
379             rtcomp() interprets undef as matching undef, so the following test would would
380             be successful.
381              
382             rtcomp 'my test', undef, undef;
383              
384             rtcomp() takes several options.
385              
386             =over
387              
388             =item * collapse
389              
390             If this option is true, then the strings are collapsed before they are
391             compared. So, for example, the following test would succeed:
392              
393             rtcomp 'my test', ' Fred ', 'Fred', collapse=>1;
394              
395             =item * nospace
396              
397             nospace removes all spaces before comparing strings. So this test would
398             succeed:
399              
400             rtcomp 'my test', 'Fr ed', 'Fred', nospace=>1;
401              
402             =item * case_insensitive
403              
404             The case_insensitive option indicates to compare the values case insensitively.
405             So, the following test would be successful.
406              
407             =back
408              
409             =cut
410              
411             sub rtcomp {
412 12     12 1 18 my ($name, $got, $should, %opts) = @_;
413 12         7 my ($ok);
414            
415             # TESTING
416             # println subname(); ##i
417            
418             # should have gotten at least three params
419 12 50       36 unless ( @_ >= 3 )
420 0         0 { croak 'rtcomp requires at least 3 params' }
421            
422             # default options
423 12         17 %opts = (should=>1, %opts);
424            
425             # collapse as necessary
426 12 50       24 if ($opts{'collapse'}) {
    50          
427 0         0 $got = collapse($got);
428 0         0 $should = collapse($should);
429             }
430            
431             # nospace as necessary
432             elsif ($opts{'nospace'}) {
433 0         0 $got = nospace($got);
434 0         0 $should = nospace($should);
435             }
436            
437             # remove trailing whitespace
438             # elsif ($opts{'trim_end'} || $opts{'trim_ends'}) {
439             # $got =~ s|\s+$||s;
440             # $should =~ s|\s+$||s;
441             #}
442            
443             # case insensitive
444 12 50       15 if ($opts{'case_insensitive'}) {
445 0 0       0 if (defined $should)
446 0         0 { $should = lc($should) }
447 0 0       0 if (defined $got)
448 0         0 { $got = lc($got) }
449             }
450            
451             # compare
452 12         1086 $ok = eqq($got, $should);
453            
454             # development environment
455 12 0 33     19 if ( (! should_flop($ok, %opts)) && $auto_die) {
456 0         0 print
457             "--- rtcomp fail -------------------------------------------\n",
458             $name, "\n";
459            
460 0 0       0 if (! $opts{'should'}) {
461 0 0       0 print "should-flop: ", ($opts{'should'} ? 1 : 0), "\n";
462             }
463            
464             print
465 0         0 "got: ", rtrim(define $got), "\n",
466             "should: ", rtrim(define $should), "\n",
467             "----------------------------------------------------------\n";
468             }
469            
470             # rtok
471 12         19 return rtok($name, $ok, %opts);
472             }
473             #
474             # rtcomp
475             #------------------------------------------------------------------------------
476              
477              
478              
479             #------------------------------------------------------------------------------
480             # rtelcount
481             #
482              
483             =head2 rtelcount
484              
485             Checks if an array has the correct number of elements. The first param is an
486             integer 0 or greater. The second param is an array reference. So, the following
487             test would pass:
488              
489             rtelcount 'my test', 3, \@arr;
490              
491             =cut
492              
493             sub rtelcount {
494 1     1 1 4 my ($name, $arr, $count, %opts) = @_;
495 1         4 return rtcomp $name, scalar(@$arr), $count, %opts;
496             }
497             #
498             # rtelcount
499             #------------------------------------------------------------------------------
500              
501              
502             #------------------------------------------------------------------------------
503             # rtarr
504             #
505              
506             =head2 rtarr
507              
508             rtarr compares two arrays. In its simplest use, the test passes if they are
509             identical:
510              
511             @first = qw{Larry Curly Moe};
512             @second = qw{Larry Curly Moe};
513             rtarr 'my test', \@first, \@second;
514              
515             Like with rtcomp, two undefs are considered the same, so the following test
516             would pass.
517              
518             @first = ('Larry', 'Moe', 'Curly', undef);
519             @second = ('Larry', 'Moe', 'Curly', undef);
520             rtarr 'my test', \@first, \@second;
521              
522             rtarr takes several options.
523              
524             =over
525              
526             =item * order_insensitive
527              
528             If the order_insensitive option is true, then the arrays are considered the
529             same even if the elements are not in the same order. So the following test
530             would pass:
531              
532             @first = ('Curly', 'Larry', 'Moe');
533             @second = ('Larry', 'Moe', 'Curly');
534             rtarr 'my test', \@first, \@second, order_insensitive=>1;
535              
536             =item * case_insensitive
537              
538             If the case_insensitive option is true, then the elements are compared case
539             insensitively. So the following test would pass:
540              
541             @first = ('CURLY', 'LARRY', undef, 'MOE');
542             @second = ('Curly', 'Larry', undef, 'Moe');
543             rtarr 'my test', \@first, \@second, case_insensitive=>1;
544              
545             =back
546              
547             =cut
548              
549             sub rtarr {
550 3     3 1 4 my ($name, $got, $should, %opts) = @_;
551 3         3 my ($ok);
552            
553             # TESTING
554             # println subname(); ##i
555            
556             # default options
557 3         6 %opts = (should=>1, %opts);
558            
559             # load Array::Comp
560             # require Array::Comp;
561            
562             # default options
563 3         4 %opts = (auto_die => 1, %opts);
564            
565             # get result
566 3         6 $ok = arrs_same($got, $should, %opts);
567            
568             # test
569 3 0 33     7 if ( (! should_flop($ok, %opts)) && $auto_die ) {
570             # format for printing
571 0 0       0 $got = [map({defined($_) ? $_ : '[undef]'} @$got)];
  0         0  
572 0 0       0 $should = [map({defined($_) ? $_ : '[undef]'} @$should)];
  0         0  
573            
574             # top of section
575 0         0 print "\n=== rtarr fail =============================================\n";
576            
577             # show should
578 0 0       0 if (! $opts{'should'})
579 0         0 { print 'should: ', $opts{'should'}, "\n" }
580            
581             # show $got
582 0         0 print "--- \$got ---------------------------------------------------\n";
583 0         0 print join("\n", @$got);
584 0         0 print "\n";
585            
586             # TESTING
587             # commenting out next section for testing
588            
589             # show $should
590 0         0 print "--- \$should ------------------------------------------------\n";
591 0         0 print join("\n", @$should);
592 0         0 print "\n";
593            
594             # bottom of section
595 0         0 print "===========================================================\n\n\n";
596             }
597            
598             # rtok
599 3         5 return rtok($name, $ok, %opts);
600             }
601             #
602             # rtarr
603             #------------------------------------------------------------------------------
604              
605              
606              
607             #------------------------------------------------------------------------------
608             # rthash
609             #
610              
611             =head2 rthash
612              
613             rthash checks is two hashes contain the same keys and values. The following
614             test would pass. Keep in mind that hashes don't have the concept of order, so
615             it doesn't matter that the hashes are created with differently ordered keys.
616              
617             %first = ( Curly=>'big hair', Moe=>'flat hair', Schemp=>undef);
618             %second = ( Moe=>'flat hair', Schemp=>undef, Curly=>'big hair');
619             rthash 'my test', \%first, \%second;
620              
621             rthash doesn't currently have a case_insensitive option. That will probably
622             be added in future releases.
623              
624             =cut
625              
626             sub rthash {
627 1     1 1 2 my ($name, $have_sent, $should_sent, %opts) = @_;
628 1         1 my (%have, %should, @wrong, $ok);
629            
630             # TESTING
631             # println subname(); ##i
632            
633             # special case: if either is undef, return false
634 1 50 33     5 unless (defined($have_sent) && defined($should_sent)) {
635 0 0       0 if ($opts{'auto_die'}) {
636 0         0 print 'got: ', $have_sent, "\n";
637 0         0 print 'should: ', $should_sent, "\n";
638 0         0 croak 'at least one hash not defined';
639             }
640            
641 0         0 return 0;
642             }
643            
644             # get hashes we can play with
645 1         3 %have = %$have_sent;
646 1         2 %should = %$should_sent;
647            
648             # loop through values in %should
649 1         3 foreach my $key (keys %should) {
650             # if key doesn't exist
651 3 50       4 if (exists $have{$key}) {
652 3 50       4 if (neqq($have{$key}, $should{$key})) {
653             push @wrong,
654             'have: ' . showval($have{$key}) . "\n" .
655 0         0 'should: ' . showval($should{$key});
656             }
657            
658 3         5 delete $have{$key};
659             }
660            
661             else {
662 0         0 push @wrong, "Do not have key: $key";
663             }
664             }
665            
666             # if anything left in %keys_have
667 1         2 foreach my $key (keys %have)
668 0         0 { push @wrong, "Have unexpected key: $key" }
669            
670             # decide if anything wrong
671 1 50       2 $ok = @wrong ? 0 : 1;
672            
673             # autodie if necessary
674 1 0 33     5 if ( (! should_flop($ok, %opts)) && $auto_die ) {
675 0         0 croak 'hashes are not identical';
676             }
677            
678             # call rtok
679 1         4 rtok($name, $ok, %opts);
680             }
681             #
682             # rthash
683             #------------------------------------------------------------------------------
684              
685              
686              
687             #------------------------------------------------------------------------------
688             # rtisa
689             #
690              
691             =head2 rtisa
692              
693             rtisa tests if a given value is of the given class. For example, the following
694             test would pass.
695              
696             $val = [];
697             rtisa 'my test', $val, 'ARRAY';
698              
699             The second value can be either the name of the class or an example of the
700             class, so the following test would also pass.
701              
702             $val = [];
703             rtisa 'my test', $val, [];
704              
705             If the class is undef or an empty string, then rtisa returns true if the given
706             object is not a reference.
707              
708             $val = 'whatever';
709             rtisa 'my test', $val, '';
710              
711             =cut
712              
713             sub rtisa {
714 3     3 1 5 my ($name, $have, $should, %opts) = @_;
715 3         2 my ($ok, $not);
716            
717             # TESTING
718             # println subname(); ##i
719            
720             # if $should is an object, get the class of the object
721 3 50       6 if (ref $should)
722 0         0 { $should = ref($should) }
723            
724             # if defined $should, set $isa from UNIVERSAL::isa
725 3 100 100     9 if ( defined($should) && length($should) ) {
726 1         3 $ok = UNIVERSAL::isa($have, $should);
727             }
728            
729             # else $have should not have a ref
730             else {
731 2 50       3 $ok = ref($have) ? 0 : 1;
732             }
733            
734             # return rtok
735 3         6 return rtok($name, $ok, %opts);
736             }
737             #
738             # rtisa
739             #------------------------------------------------------------------------------
740              
741              
742             #------------------------------------------------------------------------------
743             # rtbool
744             #
745              
746             =head2 rtbool
747              
748             rtbool checks if two values have the same boolean value, that is, if they are
749             both true or both false. Booleans are checked in the perlish sense, so the
750             values don't have to be the same, they just have to have the same perlish
751             boolean values. Here are some examples.
752              
753             rtbool 'my test', 'whatever', 'dude'; # passes
754             rtbool 'my test', 'whatever', 1; # passes
755             rtbool 'my test', 'whatever', undef; # fails
756             rtbool 'my test', 0, undef; # passes
757              
758             =cut
759              
760             sub rtbool {
761 4     4 1 5 my ($name, $is, $should, %opts) = @_;
762            
763             # TESTING
764             # println subname(); ##i
765             # showvar $is;
766             # showvar $should;
767            
768             # default options
769 4         6 %opts = (auto_die=>1, %opts);
770            
771             # normalize
772 4 100       5 $is = $is ? 'true' : 'false';
773 4 100       6 $should = $should ? 'true' : 'false';
774            
775             # TESTING
776             # showvar $is;
777             # showvar $should;
778            
779             # compare
780 4         6 return rtcomp($name, $is, $should, %opts);
781             }
782             #
783             # rtbool
784             #------------------------------------------------------------------------------
785              
786              
787             #------------------------------------------------------------------------------
788             # rtdef
789             #
790              
791             =head2 rtdef
792              
793             rtdef tests if the given value is defined. The second param is the value being
794             tested, the third param is if the value should be defined or not. So, the
795             following tests would pass.
796              
797             rtdef 'my test', 'hello', 1;
798             rtdef 'my test', undef, 0;
799              
800             The third param must be defined.
801              
802             =cut
803              
804             sub rtdef {
805 2     2 1 2 my ($name, $is, $should, %opts) = @_;
806            
807             # TESTING
808             # println subname(); ##i
809             # showvar $is;
810             # showvar $should;
811            
812             # $should must be defined
813 2 50       4 if (! defined $should) {
814 0         0 croak 'rtdef-should-not-defined: "should" should be defined in rtdef';
815             }
816            
817             # compare
818 2         3 return rtbool($name, defined($is), $should, %opts);
819             }
820             #
821             # rtdef
822             #------------------------------------------------------------------------------
823              
824              
825              
826             #------------------------------------------------------------------------------
827             # rtrx
828             #
829              
830             =head2 rtrx
831              
832             rtrx tests if the given value matches the given regular expression. The
833             following test would pass.
834              
835             rtrx 'my test', 'Fred', 'red';
836              
837             If you want to get fancy with your regular expressions, use qr// to create the
838             regexes as you pass them in. The following test is an example.
839              
840             rtrx 'my test', 'Fred', qr/RED$/i;
841              
842             =cut
843              
844             sub rtrx {
845 1     1 1 2 my ($name, $got, $rx, %opts) = @_;
846 1         1 my ($ok);
847            
848             # TESTING
849             # println subname(); ##i
850            
851             # default options
852 1         2 %opts = (should=>1, %opts);
853            
854             # get result
855 1 50       3 if (defined $got) {
856 1         4 $ok = $got =~ m|$rx|s;
857             }
858             else {
859 0         0 $ok = 0;
860             }
861            
862             # test
863 1 0 33     3 if ( (! should_flop($ok, %opts)) && $auto_die ) {
864            
865             # top of section
866 0         0 print "\n=== rtrx fail ============================================\n";
867            
868             # show should
869 0 0       0 if (! $opts{'should'})
870 0         0 { print 'should: ', $opts{'should'}, "\n" }
871            
872             # show $rx
873 0         0 print "--- \$rx ----------------------------------------------------\n";
874 0         0 print $rx;
875 0         0 print "\n";
876            
877             # show $got
878 0         0 print "--- \$should ------------------------------------------------\n";
879 0         0 print $got;
880 0         0 print "\n";
881            
882             # bottom of section
883 0         0 print "===========================================================\n\n\n";
884             }
885            
886             # rtok
887 1         2 return rtok($name, $ok, %opts);
888             }
889             #
890             # rtrx
891             #------------------------------------------------------------------------------
892              
893              
894              
895             #------------------------------------------------------------------------------
896             # rtfile
897             #
898              
899             =head2 rtfile
900              
901             rtfile tests if the given file path exists. In its simplest use, rtfile takes
902             just the name of the file and the path:
903              
904             rtfile 'my test', '/tmp/log.txt';
905              
906             You can use the C option to test if the file B exist:
907              
908             rtfile 'my test', '/tmp/log.txt', should=>0;
909              
910             =cut
911              
912             sub rtfile {
913 1     1 1 5 my ($name, $path, %opts) = @_;
914 1         2 my ($ok);
915            
916             # TESTING
917             # println subname(); ##i
918            
919             # default options
920 1         3 %opts = (should=>1, %opts);
921            
922             # get existence of path
923 1         22 $ok = -e($path);
924            
925             # throw error if not as should
926 1 50 33     3 if ( (! should_flop($ok, %opts)) && $auto_die ) {
927             croak
928             'file ' . $path . ' should ' .
929 0 0       0 ($opts{'should'} ? '' : 'not ') . 'exist';
930             }
931            
932             # return rtok
933 1         4 return rtok($name, $ok, %opts);
934             }
935             #
936             # rtfile
937             #------------------------------------------------------------------------------
938              
939              
940             #------------------------------------------------------------------------------
941             # message id tests
942             #
943              
944             =head1 Message ID tests
945              
946             The following tests checking for errors that begin with an error code, followed
947             by a colon, followed by plain language. For example:
948              
949             croak 'error-opening-log-file: error opening log file';
950              
951             Note that the error ID must be followed by a colon.
952              
953             =cut
954              
955             #
956             # message id tests
957             #------------------------------------------------------------------------------
958              
959              
960             #------------------------------------------------------------------------------
961             # rtid
962             #
963              
964             =head2 rtid()
965              
966             rtid() checks if the given string starts with the given id. For example, to
967             test is $! starts with the id 'error-opening-log-file' you would use this command:
968              
969             rtid 'my test', $!, 'error-opening-log-file';
970              
971             =cut
972              
973             sub rtid {
974 6     6 1 8 my ($name, $is, $should, %opts) = @_;
975            
976             # TESTING
977             # println subname(); ##i
978             # showvar $is;
979             # showvar $should;
980            
981             # get id of $is
982 6 100       7 if (defined $is)
983 5         9 { $is =~ s|\:.*||s }
984             else
985 1         1 { $is = '' }
986            
987             # get id of $should or set it to empty string
988 6 100       6 if (defined $should)
989 4         7 { $should =~ s|\:.*||s }
990             else
991 2         2 { $should = '' }
992            
993             # TESTING
994             # showvar $is;
995             # showvar $should;
996            
997             # compare
998 6         10 return rtcomp($name, $is, $should, %opts);
999             }
1000             #
1001             # rtid
1002             #------------------------------------------------------------------------------
1003              
1004              
1005             #------------------------------------------------------------------------------
1006             # rteval
1007             #
1008              
1009             =head2 rteval()
1010              
1011             rteval() allows you to test some code then check for an error id, all in one
1012             easy command. rteval runs the given subroutine in an eval{} block, then tests
1013             Here's an (admittedly contrived) example:
1014              
1015             rteval
1016             'my test',
1017             sub { die 'error-opening-log-file: whatever' },
1018             'error-opening-log-file';
1019              
1020             If your subroutine is really long, you might prefer to put the id as the first
1021             param, then the sub. rteval() provides some forgivness in that regard: if the
1022             second param is a sub, then the first param is assumed to be the id. So the
1023             following example works the same as the above example:
1024              
1025             rteval
1026             'my test',
1027             'error-opening-log-file',
1028             sub { die 'error-opening-log-file: whatever' };
1029              
1030             If the sub is supposed to work, you can put undef for the expected code:
1031              
1032             rteval
1033             'my test',
1034             sub { my $val = 1 },
1035             undef;
1036              
1037             =cut
1038              
1039             sub rteval {
1040 3     3 1 4 my ($name, $id_should, $code, %opts) = @_;
1041 3         2 my ($result);
1042            
1043             # TESTING
1044             # println subname(); ##i
1045             # println ref($id_should);
1046            
1047             # build in a little forgiveness
1048 3 50       8 if (UNIVERSAL::isa $id_should, 'CODE')
1049 3         3 { ($id_should, $code) = ($code, $id_should) }
1050            
1051             # eval code
1052 3         4 eval { &$code() };
  3         3  
1053            
1054             # test results of eval
1055 3         13 return rtid($name, $@, $id_should, %opts);
1056             }
1057             #
1058             # rteval
1059             #------------------------------------------------------------------------------
1060              
1061              
1062             #
1063             # public methods
1064             ###############################################################################
1065              
1066              
1067              
1068              
1069             ###############################################################################
1070             # private methods
1071             #
1072              
1073              
1074             #------------------------------------------------------------------------------
1075             # showval
1076             #
1077             sub showval {
1078 0     0 0 0 my ($val) = @_;
1079            
1080             # if not defined, return [undef]
1081 0 0       0 if (! defined $val) {
1082 0         0 return '[undef]';
1083             }
1084            
1085             # else just return value
1086 0         0 return $val;
1087             }
1088             #
1089             # showval
1090             #------------------------------------------------------------------------------
1091              
1092              
1093             #------------------------------------------------------------------------------
1094             # eqq, neqq
1095             #
1096             sub eqq {
1097 15     15 0 16 my ($str1, $str2) = @_;
1098            
1099             # if both defined
1100 15 50 33     49 if ( defined($str1) && defined($str2) )
1101 15         29 { return $str1 eq $str2 }
1102            
1103             # if neither are defined
1104 0 0 0     0 if ( (! defined($str1)) && (! defined($str2)) )
1105 0         0 { return 1 }
1106            
1107             # only one is defined, so return false
1108 0         0 return 0;
1109             }
1110              
1111             sub neqq {
1112 3 50   3 0 3 return eqq(@_) ? 0 : 1;
1113             }
1114             #
1115             # eqq, neqq
1116             #------------------------------------------------------------------------------
1117              
1118              
1119             #------------------------------------------------------------------------------
1120             # ok_private
1121             # private method
1122             #
1123             sub ok_private {
1124 23     23 0 18 my($name, $bool) = @_;
1125            
1126             # my $tb = Test::More->builder;
1127 23         47 my $tb = Test::Builder::Module->builder;
1128            
1129 23         122 return $tb->ok($bool, $name);
1130             }
1131             #
1132             # ok_private
1133             #------------------------------------------------------------------------------
1134              
1135              
1136             #------------------------------------------------------------------------------
1137             # should_flop
1138             #
1139             sub should_flop {
1140 41     41 0 45 my ($ok, %opts) = @_;
1141            
1142             # TESTING
1143             # println subname; ##i
1144            
1145             # default %opts
1146 41         72 %opts = (should=>1, %opts);
1147            
1148             # reverse $ok if necessary
1149 41 100       58 if (! $opts{'should'})
1150 1         3 { $ok = ! $ok }
1151            
1152             # set ok to strict boolean
1153 41 100       85 $ok = $ok ? 1 : 0;
1154             }
1155             #
1156             # should_flop
1157             #------------------------------------------------------------------------------
1158              
1159              
1160             #------------------------------------------------------------------------------
1161             # arrs_same
1162             #
1163             sub arrs_same {
1164 3     3 0 4 my ($alpha_sent, $beta_sent, %opts) = @_;
1165 3         3 my (@alpha, @beta);
1166            
1167             # both must be array references
1168 3 50 33     15 unless (
1169             UNIVERSAL::isa($alpha_sent, 'ARRAY') &&
1170             UNIVERSAL::isa($beta_sent, 'ARRAY')
1171             )
1172 0         0 { croak 'both params must be array references' }
1173            
1174             # if they have different lengths, they're different
1175 3 50       7 if (@$alpha_sent != @$beta_sent)
1176 0         0 { return 0 }
1177            
1178             # get arrays to use for comparison
1179 3         4 @alpha = @$alpha_sent;
1180 3         3 @beta = @$beta_sent;
1181            
1182             # if case insensitive
1183 3 100       4 if ($opts{'case_insensitive'}) {
1184 1 50       1 grep {if (defined $_) {$_ = lc($_)}} @alpha;
  3         6  
  3         7  
1185 1 50       1 grep {if (defined $_) {$_ = lc($_)}} @beta;
  3         8  
  3         6  
1186             }
1187            
1188             # if order insensitive
1189 3 100       5 if ($opts{'order_insensitive'}) {
1190 1         2 @alpha = comp_sorter(@alpha);
1191 1         2 @beta = comp_sorter(@beta);
1192             }
1193            
1194             # loop through array elements
1195 3         7 for (my $i=0; $i<=$#alpha; $i++) {
1196             # if one is undef but other isn't
1197 9 50 33     38 if (
    50 33        
      33        
1198             ( ( defined $alpha[$i]) && (! defined $beta[$i]) ) ||
1199             ( (! defined $alpha[$i]) && ( defined $beta[$i]) )
1200             ) {
1201 0         0 return 0;
1202             }
1203            
1204             # if $alpha[$i] is undef then both must be, so they're the same
1205             elsif (! defined $alpha[$i]) {
1206             }
1207            
1208             # both are defined
1209             else {
1210 9 50       23 unless ($alpha[$i] eq $beta[$i])
1211 0         0 { return 0 }
1212             }
1213             }
1214            
1215             # if we get this far, they're the same
1216 3         6 return 1;
1217             }
1218             #
1219             # arrs_same
1220             #------------------------------------------------------------------------------
1221              
1222              
1223             #------------------------------------------------------------------------------
1224             # comp_sorter
1225             #
1226             sub comp_sorter {
1227             return sort {
1228             # if both undefined, return 0
1229 2 50 33 2 0 4 if ( (! defined $a) && (! defined $b) )
  5 50       19  
    50          
1230 0         0 { return 0 }
1231            
1232             # if just $a isn't defined, return -1
1233             elsif ( ! defined $a )
1234 0         0 { return -1 }
1235            
1236             # if just $b isn't defined, return 1
1237             elsif ( ! defined $b )
1238 0         0 { return 1 }
1239            
1240             # else return string comparison
1241 5         7 $a cmp $b;
1242             } @_;
1243             }
1244             #
1245             # comp_sorter
1246             #------------------------------------------------------------------------------
1247              
1248              
1249              
1250              
1251             #
1252             # private methods
1253             ###############################################################################
1254              
1255              
1256             # return true
1257             1;
1258             __END__