File Coverage

blib/lib/Test/TAP/Model.pm
Criterion Covered Total %
statement 110 116 94.8
branch 19 24 79.1
condition 11 20 55.0
subroutine 34 35 97.1
pod 23 25 92.0
total 197 220 89.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Test::TAP::Model;
4 5     5   118587 use base qw/Test::Harness::Straps/;
  5         14  
  5         8704  
5              
6 5     5   130990 use strict;
  5         13  
  5         182  
7 5     5   27 use warnings;
  5         15  
  5         147  
8              
9 5     5   4160 use Test::TAP::Model::File;
  5         21  
  5         175  
10              
11 5     5   38 use List::Util qw/sum/;
  5         9  
  5         10527  
12              
13             our $VERSION = "0.10";
14              
15             # callback handlers
16             sub _handle_bailout {
17 2     2   5 my($self, $line, $type, $totals) = @_;
18              
19 2 50       8 $self->log_event(
20             type => 'bailout',
21             ($self->{bailout_reason}
22             ? (reason => $self->{bailout_reason})
23             : ()
24             ),
25             );
26              
27 2         7 $self->{meat}{test_files}[-1]{results} = $totals;
28              
29 2         26 die "Bailed out"; # catch with an eval { }
30             }
31            
32             sub _handle_test {
33 37     37   69 my($self, $line, $type, $totals) = @_;
34 37   50     107 my $curr = $totals->seen || 0;
35              
36             # this is used by pugs' Test.pm, it's rather useful
37 37         239 my $pos;
38 37 100       126 if ($line =~ /^(.*?) (\r?$|\s*#.*\r?$)/){
39 3         12 $line = $1 . $3;
40 3         8 $pos = $2;
41             }
42              
43 37         49 my %details = %{ $totals->details->[-1] };
  37         110  
44              
45 37 100       705 $self->log_event(
46             type => 'test',
47             num => $curr,
48             ok => $details{ok},
49             actual_ok => $details{actual_ok},
50             str => $details{ok} # string for people
51             ? "ok $curr/" . $totals->max
52             : "NOK $curr",
53             todo => ($details{type} eq 'todo'),
54             skip => ($details{type} eq 'skip'),
55              
56             reason => $details{reason}, # if at all
57              
58             # pugs aux stuff
59             line => $line,
60             pos => $pos,
61             );
62              
63 37 50       428 if( $curr > $self->{'next'} ) {
    50          
64 0         0 $self->latest_event->{note} =
65             "Test output counter mismatch [test $curr]\n";
66             }
67             elsif( $curr < $self->{'next'} ) {
68 0   0     0 $self->latest_event->{note} = join("",
69             "Confused test output: test $curr answered after ",
70             "test ", ($self->{'next'}||0) - 1, "\n");
71             }
72             }
73              
74             sub _handle_other {
75 12     12   19 my($self, $line, $type, $totals) = @_;
76              
77 12         27 my $last_test = $self->{meat}{test_files}[-1];
78 12 100 50     12 if (@{ $last_test->{events} ||= [] } > 0) {
  12         40  
79 10   100     18 ($self->latest_event->{diag} ||= "") .= "$line\n";
80             } else {
81 2   100     16 ($last_test->{pre_diag} ||= "") .= "$line\n";
82             }
83             }
84              
85             sub new_with_tests {
86 1     1 1 1250 my $pkg = shift;
87 1         3 my @tests = @_;
88              
89 1         4 my $self = $pkg->new;
90 1         12 $self->run_tests(@tests);
91              
92 1         3 $self;
93             }
94              
95             sub new_with_struct {
96 2     2 1 292 my $pkg = shift;
97 2         3 my $meat = shift;
98              
99 2         13 my $self = $pkg->new(@_);
100 2         34 $self->{meat} = $meat; # FIXME - the whole Test::Harness::Straps model can be figured out from this
101              
102 2         9 $self;
103             }
104              
105             sub structure {
106 5     5 1 1652 my $self = shift;
107 5         26 $self->{meat};
108             }
109              
110             # just a dispatcher for the above event handlers
111             sub _init {
112 23     23   6911 my $s = shift;
113              
114             $s->{callback} = sub {
115 67     67   9438 my($self, $line, $type, $totals) = @_;
116              
117 67         119 my $meth = "_handle_$type";
118 67 100       376 $self->$meth($line, $type, $totals) if $self->can($meth);
119 23         209 };
120              
121 23         132 $s->SUPER::_init( @_ );
122             }
123              
124             sub log_time {
125 41     41 1 54 my $self = shift;
126 41 50       99 $self->{log_time} = shift if @_;
127 41         340 $self->{log_time};
128             }
129              
130             sub log_event {
131 41     41 1 263 my $self = shift;
132 41 50       94 my %event = (($self->log_time ? (time => time) : ()), @_);
133              
134 41         65 push @{ $self->{events} }, \%event;
  41         93  
135              
136 41         81 \%event;
137             }
138              
139             sub latest_event {
140 12     12 1 6936 my($self) = shift;
141 12         22 my %event = @_;
142 12 100       89 $self->{events}[-1] || $self->log_event(%event);
143             }
144              
145             sub run {
146 1     1 1 434 my $self = shift;
147 1         4 $self->run_tests($self->get_tests);
148             }
149              
150             sub get_tests {
151 2     2 1 32 die 'the method get_tests is a stub. You must implement it yourself if you want $self->run to work.';
152             }
153              
154             sub run_tests {
155 1     1 1 3 my $self = shift;
156              
157 1         5 $self->_init;
158              
159 1         17 $self->{meat}{start_time} = time;
160              
161 1         3 foreach my $file (@_) {
162 1         4 $self->run_test($file);
163             }
164              
165 1         4 $self->{meat}{end_time} = time;
166             }
167              
168             sub run_test {
169 1     1 1 1 my $self = shift;
170 1         2 my $file = shift;
171              
172 1         4 my $test_file = $self->start_file($file);
173            
174 1   33     2 my $results = eval { $self->analyze_file($file) } || Test::Harness::Results->new;
175 1         80 $test_file->{results} = $results;
176 1         6 $test_file->{results}->details(undef); # we don't need that
177              
178 1         7 $test_file;
179             }
180              
181             sub start_file {
182 20     20 1 3044 my $self = shift;
183 20         36 my $file = shift;
184              
185 20         31 push @{ $self->{meat}{test_files} }, my $test_file = {
  20         154  
186             file => $file,
187             events => ($self->{events} = []),
188             };
189              
190 20         57 $test_file;
191             }
192              
193 20     20 1 125 sub file_class { "Test::TAP::Model::File" }
194              
195             sub test_files {
196 62     62 1 264 my $self = shift;
197 62   100     76 @{$self->{_test_files_cache} ||= [ $self->get_test_files ]};
  62         330  
198             }
199              
200             sub get_test_files {
201 19     19 0 29 my $self = shift;
202 19         21 map { $self->file_class->new($_) } @{ $self->{meat}{test_files} };
  20         54  
  19         247  
203             }
204              
205 15   100 15 1 368 sub ok { $_->ok or return for $_[0]->test_files; 1 }; *passed = \&ok; *passing = \&ok;
  6         64  
206 3     3 1 72 sub nok { !$_[0]->ok }; *failing = \&nok; *failed = \&nok;
207 8 100   8 1 25 sub total_ratio { return $_ ? $_[0]->total_passed / $_ : ($_[0]->ok ? 1 : 0) for $_[0]->total_seen }; *ratio = \&total_ratio;
    100          
208 2     2 1 10 sub total_percentage { sprintf("%.2f%%", 100 * $_[0]->total_ratio) }
209 9     9 1 1006 sub total_seen { sum map { scalar $_->seen } $_[0]->test_files }
  14         1043  
210 1     1 1 769 sub total_todo { sum map { scalar $_->todo_tests } $_[0]->test_files }
  2         8  
211 1     1 1 849 sub total_skipped { sum map { scalar $_->skipped_tests } $_[0]->test_files }
  2         7  
212 6     6 1 1134 sub total_passed { sum map { scalar $_->ok_tests } $_[0]->test_files }; *total_ok = \&total_passed;
  11         42  
213 1     1 1 1098 sub total_failed { sum map { scalar $_->nok_tests } $_[0]->test_files }; *total_nok = \&total_failed;
  2         9  
214 1     1 1 837 sub total_unexpectedly_succeeded { sum map { scalar $_->unexpectedly_succeeded_tests } $_[0]->test_files }
  2         6  
215              
216             sub summary {
217 0     0 0   my $self = shift;
218 0           $self->{_summary} ||=
219             sprintf "%d test cases: %d ok, %d failed, %d todo, "
220             ."%d skipped and %d unexpectedly succeeded",
221 0   0       map { my $m = "total_$_"; $self->$m }
  0            
222             qw/seen passed failed todo skipped unexpectedly_succeeded/;
223             }
224              
225             __PACKAGE__
226              
227             __END__