File Coverage

blib/lib/Test/ManyParams.pm
Criterion Covered Total %
statement 125 125 100.0
branch 41 42 97.6
condition 2 3 66.6
subroutine 26 26 100.0
pod 7 9 77.7
total 201 205 98.0


line stmt bran cond sub pod time code
1             package Test::ManyParams;
2              
3 11     11   13614 use 5.006;
  11         37  
  11         499  
4 11     11   58 use strict;
  11         20  
  11         321  
5 11     11   51 use warnings;
  11         30  
  11         1078  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             our @EXPORT = qw/
12             all_ok
13             all_are all_arent
14             any_ok
15             any_is any_isnt
16            
17             most_ok
18            
19             set_seed
20             /;
21              
22             our $VERSION = '0.10';
23              
24 11     11   13784 use Test::Builder;
  11         164116  
  11         388  
25 11     11   10311 use Set::CrossProduct;
  11         38733  
  11         380  
26 11     11   12810 use Data::Dumper;
  11         165606  
  11         28495  
27             our $seed;
28              
29             my $Tester = Test::Builder->new();
30              
31             sub does_all {
32 1480     1480 0 3445 my ($sub, $params) = @_;
33 1480         3273 my $failed_param = undef;
34 1480 100       7012 if (ref($params->[0]) eq 'ARRAY') {
35 1346 100       4770 if (grep {ref($params->[$_]) ne 'ARRAY'} (1 .. @$params-1)) {
  1652         8596  
36 6         20 die "If the first parameter is an arrayref, all other parameters must be also. " .
37             "Called with Parameter-Ref: " . _dump_params($params);
38             }
39 129         571 $failed_param = @$params > 1
40             ? _try_all_of_xproduct($sub, Set::CrossProduct->new( $params ))
41 1340 100       8963 : _try_all_of_the_list($sub, @{$params->[0]});
42             } else {
43 134         399 $failed_param = _try_all_of_the_list($sub, @$params);
44             }
45 1474         44769 my $ok = not defined($failed_param);
46 1474 100       7540 my @diag = $ok
47             ? ()
48             : ("Tests with the parameters: " . _dump_params($params),
49             "Failed first using these parameters: " . _dump_params($failed_param));
50 1474         7877 return ($ok, @diag);
51             }
52              
53             sub does_most {
54 38     38 0 72 my ($sub, $params, $nr) = @_;
55 38         63 my $failed_param = undef;
56 38 100       263 $nr =~ /^\d+$/ or die "The number of tests that shall be done must be an integer, not '$nr'";
57 36 100       109 if (ref($params->[0]) eq 'ARRAY') {
58 28 100       83 if (grep {ref($params->[$_]) ne 'ARRAY'} (1 .. @$params-1)) {
  52         211  
59 1         4 die "If the first parameter is an arrayref, all other parameters must be also. " .
60             "Called with Parameter-Ref: " . _dump_params($params);
61             }
62 2         6 $failed_param = @$params > 1
63             ? _try_most_of_xproduct($sub,$nr, Set::CrossProduct->new( $params ))
64 27 100       140 : _try_most_of_the_list($sub,$nr, @{$params->[0]});
65             } else {
66 8         499 $failed_param = _try_most_of_the_list($sub,$nr, @$params);
67             }
68 35         207 my $ok = not defined($failed_param);
69 35 100       129 my @diag = $ok
70             ? ()
71             : ("Tests with most ($nr) of the parameters: " . _dump_params($params),
72             "Failed using these parameters: " . _dump_params($failed_param));
73 35         142 return ($ok, @diag);
74             }
75              
76              
77             sub all_ok(&$;$) {
78 245     245 1 525613 my ($sub, $params, $test_name) = @_;
79 245         879 my ($ok, @diag) = does_all(@_);
80 244 100       1683 $Tester->ok( $ok, $test_name ) or do { $Tester->diag($_) for @diag };
  230         132851  
81 244         44256 return $ok;
82             }
83              
84             sub most_ok(&$$;$) {
85 38     38 1 45421 my ($sub, $params, $nr, $test_name) = @_;
86 38         113 my ($ok, @diag) = does_most(@_);
87 35 100       134 $Tester->ok( $ok, $test_name ) or do { $Tester->diag($_) for @diag };
  20         9430  
88 35         24565 return $ok;
89             }
90              
91              
92             sub any_ok(&$;$) {
93 249     249 1 526706 my ($sub, $params, $test_name) = @_;
94            
95             # Please recognise the logic
96             # To find out if any of the tests is O.K.,
97             # I ask whether all tests fail
98             # If so there isn't any_ok, otherwise there is at least one ok
99 249     7338   1573 my ($all_arent_ok) = does_all(sub {!$sub->(@_)}, $params, $test_name);
  7338         19027  
100 248         1074 my $ok = !$all_arent_ok;
101 248         1426 $Tester->ok( $ok, $test_name );
102 248         98361 return $ok;
103             }
104              
105             sub any_is(&$$;$) {
106 250     250 1 525946 my ($sub, $expected_value, $params, $test_name) = @_;
107 7338     7338   16207 my ($all_arent_ok, @diag) =
108 250         23405 does_all(sub {!($sub->(@_) eq $expected_value)}, $params, $test_name);
109 248         1037 my $ok = !$all_arent_ok;
110             $Tester->ok( $ok, $test_name)
111 248 100       1068 or do {
112 8         4681 $Tester->diag($_) for @diag;
113 8         24 $Tester->diag("Expected: " . _dump_params($expected_value));
114 8         552 $Tester->diag("but didn't found it with at least one parameter");
115             };
116             }
117              
118             sub any_isnt(&$$;$) {
119 246     246 1 567438 my ($sub, $expected_value, $params, $test_name) = @_;
120 7336     7336   16931 my ($all_arent_ok, @diag) =
121 246         1795 does_all(sub {!($sub->(@_) ne $expected_value)}, $params, $test_name);
122 246         1745 my $ok = !$all_arent_ok;
123             $Tester->ok( $ok, $test_name)
124 246 100       1208 or do {
125 8         4472 $Tester->diag($_) for @diag;
126 8         22 $Tester->diag("Expected to find any parameter where result is different to " . _dump_params($expected_value));
127 8         731 $Tester->diag("but didn't found such parameters");
128             };
129             }
130              
131             sub all_are(&$$;$) {
132 245     245 1 588353 my ($sub, $expected, $params, $test_name) = @_;
133 245         522 my $found = undef;
134             my ($ok, @diag) =
135 245     8160   1762 does_all( sub { $found = $sub->(@_); $found eq $expected }, $params);
  8160         23329  
  8160         1905018  
136             $Tester->ok($ok, $test_name)
137 244 100       1885 or do {
138 230         135293 $Tester->diag($_) for @diag;
139 230         32546 $Tester->diag("Expected: " . _dump_params($expected));
140 230         16275 $Tester->diag("but found: " . _dump_params($found));
141             };
142             }
143              
144             sub all_arent(&$$;$) {
145 245     245 1 564639 my ($sub, $unexpected, $params, $test_name) = @_;
146 245         555 my $found = undef;
147             my ($ok, @diag) =
148 245     8160   1529 does_all( sub { $found = $sub->(@_); $found ne $unexpected }, $params);
  8160         16949  
  8160         1991603  
149             $Tester->ok($ok, $test_name)
150 244 100       1649 or do {
151 230         134077 $Tester->diag($_) for @diag;
152 230         31262 $Tester->diag("Expected not to find " . _dump_params($unexpected) . " but found it");
153             };
154             }
155              
156             sub _try_all_of_the_list {
157 263     263   1465 my ($sub, @param) = @_;
158 263         451 foreach my $p (@param) {
159 1397         220408 local $_ = $p;
160 1397 100       2858 $sub->($_) or return [$_];
161             }
162 33         160 return undef;
163             }
164              
165             sub _try_most_of_the_list {
166 10     10   8059 my ($sub,$nr,@param) = @_;
167 10         52 while ($nr-- > 0) {
168 522         3399 local $_ = $param[rand @param];
169 522 50       1178 $sub->($_) or return [$_];
170             }
171 10         1153 return undef;
172             }
173              
174              
175             sub _try_all_of_xproduct {
176 1211     1211   56251 my ($sub, $iterator) = @_;
177 1211         1702 my $tuple = undef;
178 1211         4791 while ($tuple = $iterator->get()) {
179 45095 100       9427256 $sub->(@$tuple) or last;
180             }
181 1211         176285 return $tuple;
182             }
183              
184             sub _try_most_of_xproduct {
185 25     25   1217 my ($sub, $nr, $iterator) = @_;
186 25         82 while ($nr-- > 0) {
187 132         825 my $tuple = $iterator->random;
188 132 100       2192 $sub->(@$tuple) or return $tuple;
189             }
190 5         29 return undef;
191             }
192              
193             sub _dump_params {
194 3569     3569   13775 local $_ = Dumper($_[0]);
195 3569         357209 s/\s+//gs; # remove all indents, but I didn't want to set
196             # $Data::Dumper::Indent as it could have global effects
197 3569         9142 s/^.*? = //; # remove the variable name of the dumped output
198 3569         16513 return $_;
199             }
200              
201             sub import {
202 17     17   2006762 my @import_arg;
203 17         134 my $seed_now = time ^ $$; # default value for the seed
204 17         196 while (local $_ = shift @_) {
205 21 100 66     298 /seed/ && do { $seed_now = shift();
  4         11  
206 4 100       45 $seed_now =~ /^\d+$/ or die "The seed must be an integer";
207             }
208             or "DEFAULT" && push @import_arg, $_;
209             }
210 16         49 srand($seed_now);
211             #Readonly::Scalar $seed => $seed_now;
212 16         32 $seed = $seed_now;
213 16         4109 Test::ManyParams->export_to_level(1, @import_arg);
214             }
215              
216             1;
217              
218             __END__