File Coverage

blib/lib/Test/Toolbox.pm
Criterion Covered Total %
statement 154 227 67.8
branch 51 118 43.2
condition 15 42 35.7
subroutine 27 29 93.1
pod 16 23 69.5
total 263 439 59.9


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