File Coverage

blib/lib/TAPx/Parser/Aggregator.pm
Criterion Covered Total %
statement 60 62 96.7
branch 14 16 87.5
condition 1 3 33.3
subroutine 13 14 92.8
pod 6 6 100.0
total 94 101 93.0


line stmt bran cond sub pod time code
1             package TAPx::Parser::Aggregator;
2              
3 3     3   6240 use strict;
  3         6  
  3         114  
4 3     3   16 use vars qw($VERSION);
  3         6  
  3         366  
5              
6             =head1 NAME
7              
8             TAPx::Parser::Aggregator - Aggregate TAPx::Parser results.
9              
10             =head1 VERSION
11              
12             Version 0.50_07
13              
14             =cut
15              
16             $VERSION = '0.50_07';
17              
18             =head1 SYNOPSIS
19              
20             use TAPx::Parser::Aggregator;
21              
22             my $aggregate = TAPx::Parser::Aggregator->new;
23             $aggregate->add( 't/00-load.t', $load_parser );
24             $aggregate->add( 't/10-lex.t', $lex_parser );
25            
26             my $summary = <<'END_SUMMARY';
27             Passed: %s
28             Failed: %s
29             Unexpectedly succeeded: %s
30             END_SUMMARY
31             printf $summary,
32             scalar $aggregate->passed,
33             scalar $aggregate->failed,
34             scalar $aggregate->todo_passed;
35              
36             =head1 DESCRIPTION
37              
38             C is a simple class which takes parser objects and
39             allows reporting of aggregate results.
40              
41             =head1 METHODS
42              
43             =head2 Class methods
44              
45             =head3 C
46              
47             my $aggregate = TAPx::Parser::Aggregator->new;
48              
49             Returns a new C object.
50              
51             =cut
52              
53             my %SUMMARY_METHOD_FOR;
54              
55             BEGIN {
56 3     3   8 %SUMMARY_METHOD_FOR = map { $_ => $_ } qw(
  27         61  
57             failed
58             parse_errors
59             passed
60             skipped
61             todo
62             todo_passed
63             total
64             wait
65             exit
66             );
67 3         16 $SUMMARY_METHOD_FOR{total} = 'tests_run';
68              
69 3         14 foreach my $method ( keys %SUMMARY_METHOD_FOR ) {
70 27 100       63 next if 'total' eq $method;
71 3     3   16 no strict 'refs';
  3         15  
  3         265  
72             *$method = sub {
73 79     79   118 my $self = shift;
74             return wantarray
75 79 100       706 ? @{ $self->{"descriptions_for_$method"} }
  6         46  
76             : $self->{$method};
77 24         2055 };
78             }
79             }
80              
81             sub new {
82 10     10 1 634 my ($class) = @_;
83 10         36 my $self = bless {}, $class;
84 10         41 $self->_initialize;
85 10         30 return $self;
86             }
87              
88             sub _initialize {
89 10     10   22 my ($self) = @_;
90 10         43 $self->{parser_for} = {};
91 10         33 $self->{parse_order} = [];
92 10         64 foreach my $summary ( keys %SUMMARY_METHOD_FOR ) {
93 90         180 $self->{$summary} = 0;
94 90 100       191 next if 'total' eq $summary;
95 80         241 $self->{"descriptions_for_$summary"} = [];
96             }
97 10         34 return $self;
98             }
99              
100             ##############################################################################
101              
102             =head2 Instance methods
103              
104             =head3 C
105              
106             $aggregate->add( $description, $parser );
107              
108             Takes two arguments, the description of the TAP source (usually a test file
109             name, but it doesn't have to be) and a C object.
110              
111             Trying to reuse a description is a fatal error.
112              
113             =cut
114              
115             sub add {
116 13     13 1 32 my ( $self, $description, $parser ) = @_;
117 13 100       50 if ( exists $self->{parser_for}{$description} ) {
118 1         6 $self->_croak("You already have a parser for ($description)");
119             }
120 12         30 push @{ $self->{parse_order} } => $description;
  12         37  
121 12         4131 $self->{parser_for}{$description} = $parser;
122              
123 12         149 while ( my ( $summary, $method ) = each %SUMMARY_METHOD_FOR ) {
124 108 100       326 if ( my $count = $parser->$method ) {
125 37         84 $self->{$summary} += $count;
126 37         35 push @{ $self->{"descriptions_for_$summary"} } => $description;
  37         302  
127             }
128             }
129              
130 12         108 return $self;
131             }
132              
133             ##############################################################################
134              
135             =head3 C
136              
137             my $count = $aggregate->parsers;
138             my @parsers = $aggregate->parsers;
139             my @parsers = $aggregate->parsers(@descriptions);
140              
141             In scalar context without arguments, this method returns the number of parsers
142             aggregated. In list context without arguments, returns the parsers in the
143             order they were added.
144              
145             If arguments are used, these should be a list of descriptions used with the
146             C method. Returns an array in list context or an array reference in
147             scalar context. The array contents will the requested parsers in the order
148             they were listed in the argument list.
149              
150             Passing in an unknown description is a fatal error.
151              
152             =cut
153              
154             sub parsers {
155 9     9 1 981 my $self = shift;
156 9 100       49 return $self->_get_parsers(@_) if @_;
157 2         4 my $descriptions = $self->{parse_order};
158 2         3 my @parsers = @{ $self->{parser_for} }{@$descriptions};
  2         7  
159              
160             # Note: Because of the way context works, we must assign the parsers to
161             # the @parsers array or else this method does not work as documented.
162 2         11 return @parsers;
163             }
164              
165             sub _get_parsers {
166 7     7   20 my ( $self, @descriptions ) = @_;
167 7         11 my @parsers;
168 7         32 foreach my $description (@descriptions) {
169 8 50       314 $self->_croak("A parser for ($description) could not be found")
170             unless exists $self->{parser_for}{$description};
171 8         43 push @parsers => $self->{parser_for}{$description};
172             }
173 7 50       45 return wantarray ? @parsers : \@parsers;
174             }
175              
176             ##############################################################################
177              
178             =head2 Summary methods
179              
180             Each of the following methods will return the total number of corresponding
181             tests if called in scalar context. If called in list context, returns the
182             descriptions of the parsers which contain the corresponding tests (see C
183             for an explanation of description.
184              
185             =over 4
186              
187             =item * failed
188              
189             =item * parse_errors
190              
191             =item * passed
192              
193             =item * skipped
194              
195             =item * todo
196              
197             =item * todo_passed
198              
199             =item * wait
200              
201             =item * exit
202              
203             =back
204              
205             For example, to find out how many tests unexpectedly succeeded (TODO tests
206             which passed when they shouldn't):
207              
208             my $count = $aggregate->todo_passed;
209             my @descriptions = $aggregate->todo_passed;
210              
211             Note that C and C are the totals of the wait and exit
212             statuses of each of the tests. These values are totalled only to provide
213             a true value if any of them are non-zero.
214              
215             =cut
216              
217             ##############################################################################
218              
219             =head3 C
220              
221             my $tests_run = $aggregate->total;
222              
223             Returns the total number of tests run.
224              
225             =cut
226              
227 10     10 1 46 sub total { shift->{total} }
228              
229             ##############################################################################
230              
231             =head3 C
232              
233             if ( $parser->has_problems ) {
234             ...
235             }
236              
237             This is a 'catch-all' method which returns true if any tests have currently
238             failed, any TODO tests unexpectedly succeeded, or any parse errors.
239              
240             =cut
241              
242             sub has_problems {
243 11     11 1 22 my $self = shift;
244 11   33     33 return $self->failed
245             || $self->todo_passed
246             || $self->parse_errors
247             || $self->exit
248             || $self->wait;
249             }
250              
251             ##############################################################################
252              
253             =head3 C
254              
255             # deprecated in favor of 'todo_passed'. This method was horribly misnamed.
256              
257             This was a badly misnamed method. It indicates which TODO tests unexpectedly
258             succeeded. Will now issue a warning and call C.
259              
260             =cut
261              
262             sub todo_failed {
263 0     0 1 0 warn
264             '"todo_failed" is deprecated. Please use "todo_passed". See the docs.';
265 0         0 goto &todo_passed;
266             }
267              
268             sub _croak {
269 1     1   3 my $proto = shift;
270 1         12 require Carp;
271 1         164 Carp::croak(@_);
272             }
273              
274             1;