File Coverage

blib/lib/Test/DataDriven.pm
Criterion Covered Total %
statement 52 52 100.0
branch 24 24 100.0
condition n/a
subroutine 12 12 100.0
pod 3 4 75.0
total 91 92 98.9


line stmt bran cond sub pod time code
1             package Test::DataDriven;
2              
3             =head1 NAME
4              
5             Test::DataDriven - when Test::Base is not enough
6              
7             =head1 SYNOPSIS
8              
9             In the test module:
10              
11             # t/lib/MyTest.pm
12             package MyTest;
13              
14             use Test::DataDriven::Plugin -base;
15             __PACKAGE__->register;
16              
17             my $time;
18             my $result;
19              
20             sub check_before : Begin(add1) {
21             my( $block, $section_name, @data ) = @_;
22             $time = time();
23             }
24              
25             sub do_that : Run(add1) {
26             my( $block, $section_name, @data ) = @_;
27             $result = add_1( $data[0] );
28             }
29              
30             sub check_after : End(result) {
31             my( $block, $section_name, @data ) = @_;
32             is( $result, $data[0] );
33             ok( time() - $time < 1 ); # check side effects
34             }
35              
36             In the test file:
37              
38             use MyTest;
39             use Test::More tests => 4;
40              
41             Test::DataDriven->run;
42              
43             __END__
44              
45             === Test 1
46             --- add1 chomp
47             3
48             --- result
49             4
50              
51             === Test 1
52             --- add1 chomp
53             7
54             --- result
55             8
56              
57             =head1 DESCRIPTION
58              
59             C is great for writing data driven tests, but sometimes you
60             need to test things that cannot be easily expressed using the
61             filter-and-compare-output approach.
62              
63             C builds upon C adding the ability to
64             declare actions to be run for each section of each test block. In
65             particular, the processing of each block is divided in three phases:
66             "begin", "run" and "end". The "begin" phase can be used to assess
67             or establish the preconditions for the test. The "run" phase is used
68             to perform some actions. The "end" phase can be used to check the side
69             effects of the "run" phase.
70              
71             =cut
72              
73 8     8   937 use strict;
  8         16  
  8         392  
74 8     8   47 use warnings;
  8         19  
  8         439  
75              
76             require Test::Base; # see import() below for why require() and not use()
77 8     8   12928 use Fatal qw(open close);
  8         229503  
  8         61  
78              
79             our $VERSION = '0.03';
80              
81             my( %tags, @tags_re, $stop_run );
82              
83             # we jump through there hoops beacuse when Test::Base::import is called
84             # and no test are run, Test::Base tries to run tests in its end block
85             # this breaks when ExtUtils::MakeMaker/Module::Build require()
86             # Test::DataDriven that use()s Test::Base
87             my $first_time = 1;
88             sub _import_tb {
89 64 100   64   205 Test::Base->import( '-base', '!run' ) if $first_time;
90 64         32478 $first_time = 0;
91             }
92              
93             sub import {
94 6     6   3062 _import_tb();
95 6         27 goto &Test::Base::import;
96             }
97              
98             =head1 METHODS
99              
100             =head2 register
101              
102             Test::DataDriven->register
103             ( plugin => $plugin,
104             tag => 'section_name',
105             );
106              
107             Test::DataDriven->register
108             ( plugin => $plugin,
109             tag_re => qr/match/,
110             );
111              
112             Registers a plugin whose C, C and C methods will be
113             called for each section whose name equals the one specified with 'tag'
114             or matches the regular expression specified with 'tag_re'. At least one
115             of 'tag' or 'tag_re' must be present.
116              
117             C<$plugin> can be either a class or object reference.
118              
119             =cut
120              
121             sub register {
122 51     51 1 130 _import_tb();
123              
124 51         139 my( $class, %args ) = @_;
125 51         116 my( $plugin, $tag, $tag_re ) = @args{qw(plugin tag tag_re)};
126              
127 51 100       118 push @{$tags{$tag}}, $plugin if $tag;
  50         132  
128 51 100       333 push @tags_re, [ $tag_re, $plugin ] if $tag_re;
129             }
130              
131             =head2 run
132              
133             Test::DataDriven->run;
134              
135             Iterates over the C blocks calling the plugins that match
136             the block sections.
137              
138             =cut
139              
140             sub _plugins_for {
141 100     100   139 my( $class, $tag ) = @_;
142 88         206 my @plugins =
143 18         23 ( ( exists $tags{$tag} ? @{$tags{$tag}} : () ),
144 100 100       225 ( map { my( $re, $plugin ) = @$_;
145 18 100       84 $tag =~ /$re/ ? ( $plugin ) : () }
146             @tags_re ) );
147              
148 100         220 return @plugins;
149             }
150              
151             sub _run_plugins {
152 37     37   68 my( $self, $block, $action ) = @_;
153              
154 37         65 local $Test::Builder::Level = $Test::Builder::Level + 2;
155              
156 37         118 my $section_order = $block->_section_order;
157              
158 37         324 foreach my $section_name ( @$section_order ) {
159 100         596 my @value = $block->$section_name;
160              
161 100         973 foreach my $plugin ( $self->_plugins_for( $section_name ) ) {
162 94 100       360 next unless $plugin->can( $action );
163 90         880 $plugin->$action( $block, $section_name, @value );
164             }
165             }
166             }
167              
168             my $create;
169             my $create_fh;
170              
171             sub create {
172 2 100   2 0 150 $create = $_[1] if @_ > 1;
173 2         7 return $create;
174             }
175              
176 5     5   14 sub _create_fh { $create_fh }
177              
178             sub run {
179 7     7 1 185 _import_tb();
180              
181 7         16 my( $self ) = @_;
182              
183 7         23 local $Test::Builder::Level = $Test::Builder::Level + 1;
184              
185 7         18 $stop_run = 0;
186 7         45 filters_delay();
187              
188 7 100       621 my $end = $create ? 'endc' : 'end';
189 7 100       28 if( $create ) {
190 1         28 open $create_fh, '>', $create;
191             }
192 7         191 for my $block ( blocks() ) {
193 14 100       9070 last if $stop_run;
194              
195 13         58 $block->run_filters;
196 13         78130 foreach my $action ( qw(begin run), $end ) {
197 38 100       105 last if $stop_run;
198              
199 37         128 $self->_run_plugins( $block, $action );
200             }
201             }
202              
203 7 100       406 close $create_fh if $create_fh;
204             }
205              
206             =head2 stop_run
207              
208             Test::DataDriven->stop_run;
209              
210             Stop the tests being run.
211              
212             =cut
213              
214 1     1 1 12 sub stop_run { $stop_run = 1 }
215              
216             =head1 BUGS
217              
218             Needs more documentation and examples.
219              
220             =head1 AUTHOR
221              
222             Mattia Barbon
223              
224             =head1 LICENSE
225              
226             This program is free software; you can redistribute it and/or
227             modify it under the same terms as Perl itself.
228              
229             =cut
230              
231             1;