File Coverage

blib/lib/Test/Group/Foreach.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Test::Group::Foreach;
2 1     1   26890 use strict;
  1         3  
  1         34  
3 1     1   9 use warnings;
  1         2  
  1         104  
4             our $VERSION = '0.03';
5              
6             =head1 NAME
7              
8             Test::Group::Foreach - repeat tests for several values
9              
10             =head1 SYNOPSIS
11              
12             use Test::More;
13             use Test::Group;
14             use Test::Group::Foreach;
15              
16             next_test_foreach my $foo, 'f', 1, 2, 3;
17             next_test_foreach my $bar, 'b', 1, 2, 3;
18              
19             test mytest => sub {
20             # These tests will be repeated for each of the 9 possible
21             # combinations of $foo in (1,2,3) and $bar in (1,2,3).
22             ok "$foo$bar" =~ /^\d+$/, "numeric";
23             ok $foo+$bar < 6, "sum less than 6";
24             };
25              
26             # This will result in a failure message like:
27             # Failed test 'sum less than 6 (f=3,b=3)'
28             # ...
29              
30              
31             # Values can be given labels to be used in the test name in
32             # place of the value, useful if you're working with values
33             # that are not short printable strings...
34              
35             next_test_foreach my $foo, 'foo', [
36             null => "\0",
37             empty => '',
38             hash => {foo => 1},
39             array => ['bar'],
40             long => 'foo' x 1000,
41             ];
42             test mytest => sub {
43             ok ref($foo) || length($foo) < 1000, "ref or short";
44             };
45              
46             # This will result in a failure message like:
47             # Failed test 'ref or short (foo=long)'
48             # ...
49              
50             =cut
51              
52 1     1   5 use Carp;
  1         13  
  1         94  
53 1     1   490 use Test::Group qw(next_test_plugin);
  0            
  0            
54             use Test::NameNote;
55              
56             our (@ISA, @EXPORT, @EXPORT_OK);
57             BEGIN {
58             require Exporter;
59             @ISA = qw(Exporter);
60             @EXPORT = qw(next_test_foreach);
61             @EXPORT_OK = qw(tgf_label);
62             }
63              
64             =head1 FUNCTIONS
65              
66             The following function is exported by default.
67              
68             =over
69              
70             =item next_test_foreach ( VARIABLE, NAME, VALUE [,VALUE...] )
71              
72             Arranges for the next test group to be repeated for one or more values
73             of a variable. A note will be appended to the name of each test run
74             within the group, specifying the value used.
75              
76             The VARIABLE parameter must be a scalar, it will be set to each of the
77             specified values in turn.
78              
79             The NAME parameter should be a short name that identifies this variable.
80             It will be used in the note added to the test name. If NAME is undef
81             then no note will be added to the test name for this variable. If NAME
82             is the empty string then the note will consist of just the value rather
83             than a C pair.
84              
85             The remaining parameters are treated as values to assign to the variable.
86             There must be at least one. It's possible to specify labels to use in
87             the test name for some or all of the values, by passing array references
88             containing label/value pairs. The following examples are all equivalent:
89              
90             =for test "equiv1" begin
91              
92             next_test_foreach( my $p, 'p', [
93             foo => 'foo',
94             bar => 'bar',
95             null => "\0",
96             long => 'foo' x 1000,
97             ]);
98              
99             =for test "equiv1" end
100              
101             =for test "equiv2" begin
102              
103             next_test_foreach( my $p, 'p',
104             [ foo => 'foo' ],
105             [ bar => 'bar' ],
106             [ null => "\0" ],
107             [ long => 'foo' x 1000 ],
108             );
109              
110             =for test "equiv2" end
111              
112             =for test "equiv3" begin
113              
114             next_test_foreach( my $p, 'p',
115             'foo',
116             'bar',
117             [ null => "\0" ],
118             [ long => 'foo' x 1000 ],
119             );
120              
121             =for test "equiv3" end
122              
123             =for test "equiv4" begin
124              
125             next_test_foreach( my $p, 'p',
126             'foo',
127             'bar',
128             [ null => "\0", long => 'foo' x 1000 ],
129             );
130              
131             =for test "equiv4" end
132              
133             =cut
134              
135             our %_value_to_label;
136              
137             sub next_test_foreach (\$$@) {
138             my $varref = shift;
139             my $name = shift;
140            
141             @_ or croak "empty value list invalid for next_test_foreach";
142             my @vals;
143             foreach my $valspec (@_) {
144             if (ref $valspec eq 'ARRAY') {
145             my @a = @$valspec;
146             @a or croak "empty arrayref passed to next_test_foreach";
147             @a % 2 and croak
148             "odd number of elts in arrayref passed to next_test_foreach";
149             while (@a) {
150             my $label = shift @a;
151             my $value = shift @a;
152             push @vals, [$label => $value];
153             }
154             } else {
155             push @vals, ["$valspec" => $valspec];
156             }
157             }
158              
159             next_test_plugin {
160             my $next = shift;
161              
162             foreach my $val (@vals) {
163             $$varref = $val->[1];
164             my $note;
165             if (defined $name) {
166             my $notetext = length $name ? "$name=$val->[0]" : $val->[0];
167             $note = Test::NameNote->new($notetext);
168             }
169             local $_value_to_label{"$varref"} = $val->[0];
170             $next->();
171             }
172             };
173             }
174              
175             =back
176              
177             The following function is not exported by default.
178              
179             =over
180              
181             =item tgf_label ( VARIABLE )
182              
183             Returns the label associated with the current value of VARIABLE. Can only be
184             called from within a test group, and VARIABLE must be a scalar that is being
185             varied by next_test_foreach().
186              
187             This is useful if you want your test to do something slightly differently
188             for some values, for example:
189              
190             use Test::Group::Foreach qw(next_test_foreach tgf_label);
191              
192             next_test_foreach my $x, 'x', [
193             foo => [{asd => 0, r => 19}, 'foo'],
194             bar => [{a => b}, ['bar'], [], {}],
195             baz => [{x => y}, {p => q}],
196             ];
197              
198             test mytest => sub {
199             if (tgf_label $x eq 'bar') {
200             # special handling for the 'bar' case ...
201             ...
202             }
203             ...
204             };
205              
206              
207             =cut
208              
209             sub tgf_label (\$) {
210             my $varref = shift;
211              
212             defined $_value_to_label{"$varref"} or croak
213             "non-foreach scalar in tgf_label";
214              
215             return $_value_to_label{"$varref"};
216             }
217              
218             =back
219              
220             =head1 AUTHOR
221              
222             Nick Cleaton, C<< >>
223              
224             =head1 COPYRIGHT & LICENSE
225              
226             Copyright 2009 Nick Cleaton, all rights reserved.
227              
228             This program is free software; you can redistribute it and/or modify it under
229             the same terms as Perl itself.
230              
231             =cut
232              
233             1;