File Coverage

lib/TAP/Formatter/HTML/Session.pm
Criterion Covered Total %
statement 100 104 96.1
branch 44 50 88.0
condition 23 34 67.6
subroutine 13 13 100.0
pod 0 7 0.0
total 180 208 86.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             TAP::Formatter::HTML::Session - TAP Test Harness output delegate for html output
4              
5             =head1 SYNOPSIS
6              
7             # see TAP::Formatter::HTML
8              
9             =cut
10              
11             package TAP::Formatter::HTML::Session;
12              
13 14     14   81 use strict;
  14         25  
  14         616  
14 14     14   89 use warnings;
  14         25  
  14         688  
15              
16             # DEBUG:
17             #use Data::Dumper 'Dumper';
18              
19 14     14   76 use base qw( TAP::Base );
  14         23  
  14         1720  
20 14     14   13424 use accessors qw( test formatter parser results html_id meta closed );
  14         16232  
  14         88  
21              
22             our $VERSION = '0.11';
23              
24             sub _initialize {
25 38     38   4711 my ($self, $args) = @_;
26              
27 38   50     375 $args ||= {};
28 38         1584 $self->SUPER::_initialize($args);
29              
30 38         2747 $self->results([])->meta({})->closed(0);
31 38         1338 foreach my $arg (qw( test parser formatter )) {
32 114 50       1770 $self->$arg($args->{$arg}) if defined $args->{$arg};
33             }
34              
35             # make referring to it in HTML easy:
36 38         503 my $html_id = $self->test;
37 38         1199 $html_id =~ s/[^a-zA-Z\d-]/-/g;
38 38         333 $self->html_id( $html_id );
39              
40 38         572 $self->info( $self->test, ':' );
41              
42 38         535 return $self;
43             }
44              
45             # Called by TAP::Parser to create a result after a session is opened
46             # TODO: override TAP::Parser::ResultFactory and add html-aware results?
47             # OR: mixin some methods to the results.
48             # this logic is getting cumbersome. :-/
49             sub result {
50 1774     1774 0 2782433 my ($self, $result) = @_;
51             #warn ref($self) . "->result called with args: " . Dumper( $result );
52              
53 1774         4725 my $iter = $self->html_id_iterator;
54 1774 100       17961 if ($result->is_test) {
55 1206         9592 $self->log( $result->as_string );
56             # make referring to it in HTML easy:
57 1206 50       9180 $result->{html_id} = $iter ? $iter->() : $self->html_id . '-' . $result->number;
58              
59             # set test status to avoid the hassle of recalculating it in the template:
60 1206 100       3394 $result->{test_status} = $result->has_todo ? 'todo-' : '';
61 1206 100       9185 $result->{test_status} .= $result->has_skip ? 'skip-' : '';
62 1206 100       10537 $result->{test_status} .= $result->is_actual_ok ? 'ok' : 'not-ok';
63              
64             # also provide a 'short' status name to reduce size of html:
65 1206         6285 my $short;
66 1206 100       2941 if ($result->has_todo) {
    100          
    100          
67 64 100       368 if ($result->is_actual_ok) {
68 4         129 $short = 'u'; # todo-ok = "unexpected" ok
69             } else {
70 60         409 $short = 't'; # todo-not-ok
71             }
72             } elsif ($result->has_skip) {
73 30         429 $short = 's'; # skip-ok
74             } elsif ($result->is_actual_ok) {
75 999         26680 $short = 'k'; # ok
76             } else {
77 113         1528 $short = 'n'; # not-ok
78             }
79 1206         2758 $result->{short_test_status} = $short;
80              
81             # keep track of passes for percent_passed calcs:
82 1206 100       3141 if ($result->is_ok) {
83 1091         19101 $self->meta->{passed}++;
84             }
85              
86             # keep track of passes (including unplanned!) for actual_percent_passed calcs:
87 1206 100 66     8665 if ($result->is_ok || $result->is_unplanned && $result->is_actual_ok) {
      66        
88 1093         18320 $self->meta->{passed_including_unplanned}++;
89             }
90              
91             # mark passed todo tests for easy reference:
92 1206 100 100     9643 if ($result->has_todo && $result->is_actual_ok) {
93 4         118 $result->{todo_passed} = 1;
94             }
95             } else {
96 568         4910 $self->info( $result->as_string );
97             }
98              
99 1774         14571 $self->set_result_css_type( $result );
100              
101 1774         1865 push @{ $self->results }, $result;
  1774         4465  
102 1774         11447 return;
103             }
104              
105             # TODO: inheritance was created for a reason... use it
106 14         11209 use constant result_css_type_map =>
107             {
108             plan => 'pln',
109             pragma => 'prg',
110             test => 'tst',
111             comment => 'cmt',
112             bailout => 'blt',
113             version => 'ver',
114             unknown => 'unk',
115             yaml => 'yml',
116 14     14   11751 };
  14         34  
117              
118             sub set_result_css_type {
119 1774     1774 0 2848 my ($self, $result) = @_;
120 1774   50     4047 my $type = $result->type || 'unknown';
121 1774   50     14975 my $css_type = $self->result_css_type_map->{$type} || 'unk';
122 1774         3632 $result->{css_type} = $css_type;
123 1774         5279 return $self;
124             }
125              
126             # Called by TAP::?? to indicate there are no more test results coming
127             sub close_test {
128 38     38 0 180382 my ($self, @args) = @_;
129             # warn ref($self) . "->close_test called with args: " . Dumper( [@args] );
130             #print STDERR 'end of: ', $self->test, "\n\n";
131 38         1430 $self->closed(1);
132 38         248 return;
133             }
134              
135             sub as_report {
136 38     38 0 79 my ($self) = @_;
137 38         125 my $p = $self->parser;
138 38         435 my $r = {
139             test => $self->test,
140             html_id => $self->html_id,
141             results => $self->results,
142             };
143              
144             # add parser info:
145 38         591 for my $key (qw(
146             tests_planned
147             tests_run
148             start_time
149             end_time
150             skip_all
151             has_problems
152             passed
153             failed
154             todo_passed
155             actual_passed
156             actual_failed
157             wait
158             exit
159             )) {
160 494         4801 $r->{$key} = $p->$key;
161             }
162              
163 38         393 $r->{num_parse_errors} = scalar $p->parse_errors;
164 38         348 $r->{parse_errors} = [ $p->parse_errors ];
165 38         239 $r->{passed_tests} = [ $p->passed ];
166 38         1240 $r->{failed_tests} = [ $p->failed ];
167              
168             # do some other handy calcs:
169 38 100       367 $r->{test_status} = $r->{has_problems} ? 'failed' : 'passed';
170 38         130 $r->{elapsed_time} = $r->{end_time} - $r->{start_time};
171 38         88 $r->{severity} = '';
172 38 100       151 if ($r->{tests_planned}) {
    100          
173             # Calculate percentage passed as # passes *excluding* unplanned passes
174             # so we can't get > 100%. Also calc # passes _including_ unplanned
175             # in case that's useful for someone.
176 34   50     125 my $num_passed = $self->meta->{passed} || 0;
177 34   50     307 my $num_actual_passed = $self->meta->{passed_including_unplanned} || 0;
178 34         492 my $p = $r->{percent_passed} = sprintf('%.1f', $num_passed / $r->{tests_planned} * 100);
179 34         207 $r->{percent_actual_passed} = sprintf('%.1f', $num_actual_passed / $r->{tests_planned} * 100);
180 34 100       200 if ($p != 100) {
181 11         559 my $s;
182 11 50       116 if ($p < 25) { $s = 'very-high' }
  0 50       0  
    100          
    50          
183 0         0 elsif ($p < 50) { $s = 'high' }
184 9         23 elsif ($p < 75) { $s = 'med' }
185 2         5 elsif ($p < 95) { $s = 'low' }
186 0         0 else { $s = 'very-low' }
187             # classify >100% as very-low
188 11         33 $r->{severity} = $s;
189             }
190             } elsif ($r->{skip_all}) {
191             ; # do nothing
192             } else {
193 2         4 $r->{percent_passed} = 0;
194 2         6 $r->{severity} = 'very-high';
195             }
196              
197 38 100       135 if (my $num = $r->{num_parse_errors}) {
198 4 50 33     35 if ($num == 1 && ! $p->is_good_plan) {
199 4   100     54 $r->{severity} ||= 'low'; # prefer value set calculating % passed
200             } else {
201 0         0 $r->{severity} = 'very-high';
202             }
203             }
204              
205             # check for scripts that died abnormally:
206 38 100 100     273 if ($r->{exit} && $r->{exit} == 255 && $p->is_good_plan) {
      100        
207 4   50     62 $r->{severity} ||= 'very-high';
208             }
209              
210             # catch-all:
211 38 100       140 if ($r->{has_problems}) {
212 19   50     62 $r->{severity} ||= 'high';
213             }
214              
215 38         110 return $r;
216             }
217              
218             sub html_id_iterator {
219 1774     1774 0 5569 shift->formatter->html_id_iterator;
220             }
221              
222             sub log {
223 1206     1206 0 24169 my ($self, @args) = @_;
224 1206         2890 $self->formatter->log_test(@args);
225             }
226              
227             sub info {
228 606     606 0 6145 my ($self, @args) = @_;
229 606         1674 $self->formatter->log_test_info(@args);
230             }
231              
232              
233             1;
234              
235             __END__