File Coverage

blib/lib/Tapper/TAP/Harness.pm
Criterion Covered Total %
statement 281 283 99.2
branch 68 78 87.1
condition 34 49 69.3
subroutine 33 33 100.0
pod 5 5 100.0
total 421 448 93.9


line stmt bran cond sub pod time code
1             package Tapper::TAP::Harness;
2             # git description: v5.0.6-1-g66ded60
3              
4             our $AUTHORITY = 'cpan:TAPPER';
5             # ABSTRACT: Tapper - Tapper specific TAP handling
6             $Tapper::TAP::Harness::VERSION = '5.0.7';
7 33     33   1620904 use 5.010;
  33         83  
8 33     33   117 use strict;
  33         37  
  33         542  
9 33     33   134 use warnings;
  33         40  
  33         709  
10              
11 33     33   17262 use TAP::Parser;
  33         1314271  
  33         939  
12 33     33   14097 use TAP::Parser::Aggregator;
  33         157434  
  33         786  
13 33     33   14351 use Directory::Scratch;
  33         1239149  
  33         190  
14 33     33   1123 use File::Temp 'tempdir', 'tempfile';
  33         41  
  33         1871  
15 33     33   16306 use YAML::Tiny;
  33         132263  
  33         1681  
16 33     33   19220 use Archive::Tar;
  33         2104870  
  33         2107  
17 33     33   15345 use IO::Scalar;
  33         93159  
  33         1220  
18 33     33   160 use IO::String;
  33         40  
  33         3427  
19              
20              
21              
22             our @SUITE_HEADER_KEYS_GENERAL = qw(suite-version
23             hardwaredb-systems-id
24             machine-name
25             machine-description
26             reportername
27             starttime-test-program
28             endtime-test-program
29             );
30              
31             our @SUITE_HEADER_KEYS_DATE = qw(starttime-test-program
32             endtime-test-program
33             );
34              
35             our @SUITE_HEADER_KEYS_REPORTGROUP = qw(reportgroup-arbitrary
36             reportgroup-testrun
37             reportgroup-primary
38             owner
39             );
40              
41             our @SUITE_HEADER_KEYS_REPORTCOMMENT = qw(reportcomment );
42              
43             our @SECTION_HEADER_KEYS_GENERAL = qw(ram cpuinfo bios lspci lsusb uname osname uptime language-description
44             flags changeset kernel description
45             xen-version xen-changeset xen-dom0-kernel xen-base-os-description
46             xen-guest-description xen-guest-test xen-guest-start xen-guest-flags xen-hvbits
47             kvm-module-version kvm-userspace-version kvm-kernel
48             kvm-base-os-description kvm-guest-description
49             kvm-guest-test kvm-guest-start kvm-guest-flags
50             simnow-svn-version
51             simnow-version
52             simnow-svn-repository
53             simnow-device-interface-version
54             simnow-bsd-file
55             simnow-image-file
56             ticket-url wiki-url planning-id moreinfo-url codereview-url
57             tags
58             );
59              
60 33     33   14535 use Moose;
  33         9823849  
  33         201  
61              
62             has tap => ( is => 'rw', isa => 'Str' );
63             has tap_is_archive => ( is => 'rw' );
64             has parsed_report => ( is => 'rw', isa => 'HashRef', default => sub {{tap_sections => []}});
65             has section_names => ( is => 'rw', isa => 'HashRef', default => sub {{}} );
66              
67             our $re_prove_section = qr/^([-_\d\w\/.]*\w)\s?\.{2,}\s*$/;
68             our $re_tapper_meta = qr/^#\s*((?:Tapper|Artemis|Test)-)([-\w]+):(.+)$/i;
69             our $re_tapper_meta_section = qr/^#\s*((?:Tapper|Artemis|Test)-Section:)\s*(\S.*)$/i;
70             our $re_explicit_section_start = qr/^#\s*((?:Tapper|Artemis|Test)-explicit-section-start:)\s*(\S*)/i;
71              
72             sub _get_prove {
73 17     17   32 my $prove1;
74             my $prove2;
75 17         188 ($prove1 = $^X) =~ s/perl([\d.]*)$/prove$1/;
76 17         110 ($prove2 = $^X) =~ s/[^\/]*$/prove/;
77 17 50       589 return $prove1 if -e $prove1;
78 0 0       0 return $prove2 if -e $prove2;
79 0         0 return; # undef/fail
80             }
81              
82             # report a uniqe section name
83             sub _unique_section_name
84             {
85 454     454   613 my ($self, $section_name) = @_;
86 454 100       811 return if not defined $section_name;
87 444         400 my $trail_number = 1;
88 444 100 66     11238 if (defined $self->section_names->{$section_name}
89             and not $section_name =~ m/\d$/)
90             {
91 42         72 $section_name .= $trail_number;
92             }
93 444         9732 while (defined $self->section_names->{$section_name}) {
94 16         23 $trail_number++;
95 16         431 $section_name =~ s/\d+$/$trail_number/;
96             }
97 444         9523 $self->section_names->{$section_name} = 1;
98 444         1042 return $section_name;
99             }
100              
101             # hot fix known TAP errors
102             sub _fix_broken_tap {
103 49     49   73 my ($tap) = @_;
104              
105             # TAP::Parser chokes on that
106 49         8951 $tap =~ s/^(\s+---)\s+$/$1/msg;
107              
108             # known wrong YAML-in-TAP in database,
109             # usually Kernbench wrapper output
110 49         2088 $tap =~ s/^(\s+)(jiffies)\s*$/$1Clocksource: $2/msg;
111 49         1759 $tap =~ s/^(\s+kvm-clock)\s*$/$1: ~/msg;
112 49         786 $tap =~ s/^(\s+acpi_pm)\s*$/$1: ~/msg;
113 49         880986 $tap =~ s/^(\s+Cannot determine clocksource)\s*$/ Cannot_determine_clocksource: ~/msg;
114 49         693785 $tap =~ s/^(\s+linetail):\s*$/$1: ~/msg;
115 49         6292 $tap =~ s/^(\s+CPU\d+):\s*$/$1: ~/msg;
116 49         6346 $tap =~ s/^(\s+)(\w{3} \w{3} +\d+ \d+:\d+:\d+ \w+ \d{4})$/$1date: $2/msg;
117 49         27842 $tap =~ s/^(\s+)(2\.6\.\d+[^\n]*)$/$1kernel: $2/msg; # kernel version
118 49         1726 $tap =~ s/^(\s+)(Average)\s*([^\n]*)$/$1average: $3/msg;
119 49         1645 $tap =~ s/^(\s+)(Elapsed Time)\s*([^\n]*)$/$1elapsed_time: $3/msg;
120 49         1749 $tap =~ s/^(\s+)(User Time)\s*([^\n]*)$/$1user_time: $3/msg;
121 49         1631 $tap =~ s/^(\s+)(System Time)\s*([^\n]*)$/$1system_time: $3/msg;
122 49         874 $tap =~ s/^(\s+)(Percent CPU)\s*([^\n]*)$/$1percent_cpu: $3/msg;
123 49         1283 $tap =~ s/^(\s+)(Context Switches)\s*([^\n]*)$/$1context_switches: $3/msg;
124 49         1331 $tap =~ s/^(\s+)(Sleeps)\s*([^\n]*)$/$1sleeps: $3/msg;
125              
126 49         132 return $tap;
127             }
128              
129             sub _parse_tap_into_sections_one_section
130             {
131 12     12   17 my ($self) = @_;
132 12         37 my @sections = $self->_get_tap_sections_from_single;
133 12         41 $self->_collect_meta_from_sections(@sections);
134             }
135              
136              
137             sub tap_single_plan
138             {
139 61     61 1 76 my ($self) = @_;
140 61 50       1337 return if $self->tap_is_archive;
141 61         1358 my @plans = ($self->tap) =~ m/(1\.\.\d+)/mg;
142 61         288 return(int(@plans) == 1);
143             }
144              
145              
146              
147             sub _parse_tap_into_sections
148             {
149 63     63   87 my ($self) = @_;
150              
151             # Order matters
152 63 100       1636 return $self->_parse_tap_into_sections_archive(@_) if $self->tap_is_archive;
153 61 100       183 return $self->_parse_tap_into_sections_one_section(@_) if $self->tap_single_plan;
154 49         174 return $self->_parse_tap_into_sections_raw(@_);
155             }
156              
157              
158 88     88 1 63 sub fix_last_ok { ${+shift} =~ s/\nok$// }
  88         309  
159              
160             # return sections
161             sub _parse_tap_into_sections_raw
162             {
163 49     49   64 my ($self) = @_;
164              
165              
166 49         1071 my $report_tap = $self->tap;
167              
168 49         89 my $TAPVERSION = "TAP Version 13";
169 49 100       2370 $report_tap = $TAPVERSION."\n".$report_tap unless $report_tap =~ /^TAP Version/msi;
170              
171 49         139 $report_tap = _fix_broken_tap($report_tap);
172 49         604 my $parser = new TAP::Parser ({ tap => $report_tap, version => 13 });
173              
174 49         28400 my $i = 0;
175 49         68 my %section;
176 49         59 my $looks_like_prove_output = 0;
177             $self->parsed_report->{report_meta} = {
178 49         1726 'suite-name' => 'unknown',
179             'suite-version' => 'unknown',
180             'suite-type' => 'unknown',
181             'reportcomment' => undef,
182             };
183 49         72 my $sections_marked_explicit = 0;
184 49         51 my $last_line_was_version = 0;
185 49         78 my $last_line_was_plan = 0;
186              
187 49         152 while ( my $line = $parser->next )
188             {
189 11476         1532443 my $raw = $line->raw;
190 11476         27544 my $is_plan = $line->is_plan;
191 11476         35076 my $is_version = $line->is_version;
192 11476         31490 my $is_unknown = $line->is_unknown;
193 11476         30193 my $is_yaml = $line->is_yaml;
194              
195             # prove section
196 11476 100 100     35938 if ( $is_unknown and $raw =~ $re_prove_section ) {
197 88   100     153 $looks_like_prove_output ||= 1;
198             }
199              
200             # ----- store previous section, start new section -----
201              
202 11476 100       35220 $sections_marked_explicit = 1 if $raw =~ $re_explicit_section_start;
203              
204              
205             # start new section
206 11476 100 100     67741 if ( $raw =~ $re_explicit_section_start and ! $last_line_was_version
      33        
      66        
      66        
207             or
208             (! $sections_marked_explicit
209             and ( $i == 0 or
210             ( ! $looks_like_prove_output
211             and
212             (
213             ( $is_plan and not $last_line_was_version ) or
214             ( $is_version and not $last_line_was_plan )
215             )
216             ) or
217             ( $looks_like_prove_output and
218             ! $last_line_was_version and
219             ! $last_line_was_plan and
220             $raw =~ $re_prove_section
221             ) ) ) )
222             {
223 450 100       767 if (keys %section) {
224             # Store a copy (ie., not \%section) so it doesn't get overwritten in next loop
225 401 100       675 fix_last_ok(\ $section{raw}) if $looks_like_prove_output;
226 401         326 push @{$self->parsed_report->{tap_sections}}, { %section };
  401         10977  
227             }
228 450         876 %section = ();
229             }
230              
231              
232             # ----- extract some meta information -----
233              
234             # a normal TAP line
235 11476 100       13962 if ( not $is_unknown ) {
236 10829         18029 $section{raw} .= "$raw\n";
237             }
238              
239             # looks like tapper meta line
240 11476 100 100     16111 if ( $line->is_comment and $raw =~ $re_tapper_meta )
241             {
242 953         8630 my $key = lc $2;
243 953         1120 my $val = $3;
244 953         1896 $val =~ s/^\s+//;
245 953         1352 $val =~ s/\s+$//;
246 953 100       3146 if ($raw =~ $re_tapper_meta_section) {
247 326   66     992 $section{section_name} ||= $self->_unique_section_name( $val );
248             }
249 953         1588 $section{section_meta}{$key} = $val; # section keys
250 953         22300 $self->parsed_report->{report_meta}{$key} = $val; # also global keys, later entries win
251             }
252              
253             # looks like filename line from "prove"
254 11476 100 100     61986 if ( $is_unknown and $raw =~ $re_prove_section )
255             {
256 88         140 my $section_name = $self->_unique_section_name( $1 );
257 88   33     278 $section{section_name} //= $section_name;
258             }
259              
260 11476         7519 $i++;
261 11476 100       12696 $last_line_was_plan = $is_plan ? 1 : 0;
262 11476 100       33728 $last_line_was_version = $is_version ? 1 : 0;
263             }
264              
265             # store last section
266 49 100       9803 fix_last_ok(\ $section{raw}) if $looks_like_prove_output;
267 49 50       158 push @{$self->parsed_report->{tap_sections}}, { %section } if keys %section;
  49         1468  
268              
269 49         216 $self->fix_section_names;
270             }
271              
272             sub _get_tap_sections_from_archive
273             {
274 2     2   3 my ($self) = @_;
275              
276             # some stacking to enable Archive::Tar read compressed in-memory string
277 2         42 my $TARSTR = IO::String->new($self->tap);
278 2         112 my $TARZ = IO::Zlib->new($TARSTR, "rb");
279 2         3992 my $tar = Archive::Tar->new($TARZ);
280              
281 2         5904 my $meta = YAML::Tiny::Load($tar->get_content("meta.yml"));
282             my @tap_sections = map {
283 8         7 my $f1 = $_; # original name as-is
284 8         7 my $f2 = $_; $f2 =~ s,^\./,,; # force no-leading-dot
  8         12  
285 8         8 my $f3 = $_; $f3 = "./$_"; # force leading-dot
  8         21  
286 8         9 local $Archive::Tar::WARN = 0;
287 8   33     15 my $tap = $tar->get_content($f1) // $tar->get_content($f2) // $tar->get_content($f3);
      33        
288 8 50       364 $tap = "# Untar Bummer!" if ! defined $tar;
289 8         44 { tap => $tap, filename => $f1 };
290 2         1437 } @{$meta->{file_order}};
  2         8  
291 2         40 return @tap_sections;
292             }
293              
294             sub _get_tap_sections_from_single
295             {
296 12     12   17 my ($self) = @_;
297 12         253 my ($section_name) = ($self->tap) =~ $re_tapper_meta_section;
298 12 50       28 return({ tap => $self->tap, filename => $section_name}) if $section_name;
299 12         253 return({ tap => $self->tap});
300             }
301              
302              
303             sub _parse_tap_into_sections_archive
304             {
305 2     2   2 my ($self) = @_;
306              
307 2         46 my @tap_sections = $self->_get_tap_sections_from_archive($self->tap);
308 2         160 $self->_collect_meta_from_sections(@tap_sections);
309             }
310              
311             sub _collect_meta_from_sections {
312 14     14   25 my ($self, @tap_sections) = @_;
313              
314 14         22 my $looks_like_prove_output = 0;
315             $self->parsed_report->{report_meta} = {
316 14         375 'suite-name' => 'unknown',
317             'suite-version' => 'unknown',
318             'suite-type' => 'unknown',
319             'reportcomment' => undef,
320             };
321              
322 14         19 my %section;
323              
324 14         43 foreach my $tap_file (@tap_sections)
325             {
326              
327 20         31 my $tap = $tap_file->{tap};
328 20         26 my $filename = $tap_file->{filename};
329              
330 20         203 my $parser = TAP::Parser->new ({ tap => $tap, version => 13 });
331              
332             # ----- store previous section, start new section -----
333              
334             # start new section
335 20 100       7718 if (keys %section)
336             {
337             # Store a copy (ie., not \%section) so it doesn't get overwritten in next loop
338 6         5 push @{$self->parsed_report->{tap_sections}}, { %section };
  6         185  
339             }
340 20         38 %section = ();
341              
342 20         57 while ( my $line = $parser->next )
343             {
344 142         22969 my $raw = $line->raw;
345 142         435 my $is_plan = $line->is_plan;
346 142         546 my $is_version = $line->is_version;
347 142         467 my $is_unknown = $line->is_unknown;
348 142         430 my $is_yaml = $line->is_yaml;
349              
350             # ----- extract some meta information -----
351              
352             # a normal TAP line and not a summary line from "prove"
353 142 100       438 if ( not $is_unknown )
354             {
355 139         231 $section{raw} .= "$raw\n";
356             }
357              
358 142         250 my $re_tapper_meta = qr/^#\s*((?:Tapper|Artemis|Test)-)([-\w]+):(.+)$/i;
359 142         192 my $re_tapper_meta_section = qr/^#\s*((?:Tapper|Artemis|Test)-Section:)\s*(.+)$/i;
360             # looks like tapper meta line
361 142 100 66     252 if ( $line->is_comment and $raw =~ m/^#\s*((?:Tapper|Artemis|Test)-)([-\w]+):(.+)$/i ) # (
362             {
363             # TODO: refactor inner part with _parse_tap_into_sections_raw()
364 55         519 my $key = lc $2;
365 55         73 my $val = $3;
366 55         119 $val =~ s/^\s+//;
367 55         84 $val =~ s/\s+$//;
368 55 100       218 if ($raw =~ $re_tapper_meta_section)
369             {
370 2         8 $section{section_name} = $self->_unique_section_name( $val );
371             }
372 55         98 $section{section_meta}{$key} = $val; # section keys
373 55         1337 $self->parsed_report->{report_meta}{$key} = $val; # also global keys, later entries win
374             }
375             }
376 20   100     3185 $section{section_name} //= $self->_unique_section_name( $filename );
377             }
378              
379             # store last section
380 14 50       43 push @{$self->parsed_report->{tap_sections}}, { %section } if keys %section;
  14         409  
381              
382 14         45 $self->fix_section_names;
383             }
384              
385              
386             sub fix_section_names
387             {
388 63     63 1 97 my ($self) = @_;
389              
390             # augment section names
391 63         150 for (my $i = 0; $i < @{$self->parsed_report->{tap_sections}}; $i++)
  533         11319  
392             {
393 470   66     9871 $self->parsed_report->{tap_sections}->[$i]->{section_name} //= sprintf("section-%03d", $i);
394             }
395              
396             # delete whitespace from section names
397 63         121 for (my $i = 0; $i < @{$self->parsed_report->{tap_sections}}; $i++)
  533         11420  
398             {
399 470         10462 $self->parsed_report->{tap_sections}->[$i]->{section_name} =~ s/\s/-/g;
400             }
401             }
402              
403             sub _aggregate_sections
404             {
405 63     63   91 my ($self) = @_;
406              
407 63         461 my $aggregator = new TAP::Parser::Aggregator;
408              
409 63         2668 my $TAPVERSION = "TAP Version 13";
410              
411 63         262 $aggregator->start;
412 63         1138 foreach my $section (@{$self->parsed_report->{tap_sections}})
  63         1669  
413             {
414 470   50     27665 my $rawtap = $section->{raw} || '';
415 470 100       5230 $rawtap = $TAPVERSION."\n".$rawtap unless $rawtap =~ /^TAP Version/msi;
416 470         1655 my $parser = new TAP::Parser ({ tap => $rawtap });
417 470         127100 $parser->run;
418 470         1559280 $aggregator->add( $section->{section_name} => $parser );
419             }
420 63         4686 $aggregator->stop;
421              
422 63         843 foreach (qw(total
423             passed
424             parse_errors
425             skipped
426             todo
427             todo_passed
428             failed
429             todo_passed
430             ))
431             {
432 33     33   231828 no strict 'refs'; ## no critic
  33         53  
  33         30185  
433 504         1260 $self->parsed_report->{stats}{$_} = $aggregator->$_;
434             }
435 63         229 $self->parsed_report->{stats}{successgrade} = $aggregator->get_status;
436 63 50       193 $self->parsed_report->{stats}{success_ratio} = sprintf("%02.2f",
437             $aggregator->total ? ($aggregator->passed / $aggregator->total * 100) : 100
438             );
439             }
440              
441             sub _process_suite_meta_information
442             {
443 63     63   190 my ($self) = @_;
444              
445             # suite meta
446              
447 63         294 foreach my $key (@SUITE_HEADER_KEYS_GENERAL)
448             {
449 441         9535 my $value = $self->parsed_report->{report_meta}{$key};
450 441         619 my $accessor = $key;
451 441         1306 $accessor =~ s/-/_/g;
452 441 100       4604 $self->parsed_report->{db_report_meta}{$accessor} = $value if defined $value;
453             }
454              
455 63         163 foreach my $key (@SUITE_HEADER_KEYS_DATE)
456             {
457 126         2746 my $value = $self->parsed_report->{report_meta}{$key};
458 126         142 my $accessor = $key;
459 126         291 $accessor =~ s/-/_/g;
460 126 100       1146 $self->parsed_report->{db_report_date_meta}{$accessor} = $value if defined $value;
461             }
462              
463 63         149 foreach my $key (@SUITE_HEADER_KEYS_REPORTGROUP)
464             {
465 252         5358 my $value = $self->parsed_report->{report_meta}{$key};
466 252         228 my $accessor = $key;
467 252         425 $accessor =~ s/-/_/g;
468 252 100       1860 $self->parsed_report->{db_report_reportgroup_meta}{$accessor} = $value if defined $value;
469             }
470              
471 63         145 foreach my $key (@SUITE_HEADER_KEYS_REPORTCOMMENT)
472             {
473 63         1361 my $value = $self->parsed_report->{report_meta}{$key};
474 63         92 my $accessor = $key;
475 63         97 $accessor =~ s/-/_/g;
476 63 100       291 $self->parsed_report->{db_report_reportcomment_meta}{$accessor} = $value if defined $value;
477             }
478             }
479              
480             sub _process_section_meta_information
481             {
482 63     63   86 my ($self) = @_;
483              
484             # section meta
485              
486 63         82 foreach my $section ( @{$self->parsed_report->{tap_sections}} ) {
  63         1359  
487 470         420 foreach my $key (@SECTION_HEADER_KEYS_GENERAL)
488             {
489 19740         12575 my $section_name = $section->{section_name};
490 19740         12856 my $value = $section->{section_meta}{$key};
491 19740         12039 my $accessor = $key;
492 19740         19378 $accessor =~ s/-/_/g;
493 19740 100       24954 $section->{db_section_meta}{$accessor} = $value if defined $value;
494             }
495             }
496             }
497              
498             sub _process_meta_information
499             {
500 63     63   108 my ($self) = @_;
501              
502 63         181 $self->_process_suite_meta_information;
503 63         166 $self->_process_section_meta_information;
504              
505             }
506              
507              
508             sub evaluate_report
509             {
510 74     74 1 31895 my ($self) = @_;
511 74 100       99 return if @{$self->parsed_report->{tap_sections}};
  74         1976  
512 63         176 $self->_parse_tap_into_sections();
513 63         209 $self->_aggregate_sections();
514 63         249 $self->_process_meta_information();
515              
516             }
517              
518             sub _fix_generated_html
519             {
520 13     13   102 my ($html) = @_;
521              
522 13         6741 $html =~ s/^.*<body>//msg; # cut start
523 13         1000 $html =~ s,<div id="footer">Generated by TAP::Formatter::HTML[^<]*</div>,,msg; # cut footer
524             # cut navigation that was meant for standalone html pages, not needed by us
525 13         996 $html =~ s,<div id="menu">[\t\n\s]*<ul>[\t\n\s]*<li>[\t\n\s]*<span id="show-all">[\t\n\s]*<a href="#" title="show all tests">show all</a>[\t\n\s]*</span>[\t\n\s]*<span id="show-failed">[\t\n\s]*<a href="#" title="show failed tests only">show failed</a>[\t\n\s]*</span>[\t\n\s]*</li>[\t\n\s]*</ul>[\t\n\s]*</div>,,msg;
526 13         1088 $html =~ s,<th class="time">Time</th>,<th class="time">&nbsp;</th>,msg; # cut "Time" header
527              
528 13         71 return $html;
529             }
530              
531              
532             sub generate_html
533             {
534 13     13 1 33527 my ($self) = @_;
535              
536 13         42 $self->evaluate_report();
537              
538 13         120 my $temp = new Directory::Scratch (TEMPLATE => 'ATH_XXXXXXXXXXXX',
539             CLEANUP => 1);
540 13         11093 my $dir = $temp->mkdir("section");
541 13         7969 my $TAPVERSION = "TAP Version 13";
542             my @files = map {
543 76 100       1817 if ($_->{section_name} =~ m'(^\.{1,2})|/') {
544 28         48 $_->{section_name} =~ s/^\.+$/_dot_/;
545 28         36 $_->{section_name} =~ s|^/||;
546             }
547 76         130 my $fname = "section/$_->{section_name}";
548 76         106 my $rawtap = $_->{raw};
549 76 100       2431 $rawtap = $TAPVERSION."\n".$rawtap unless $rawtap =~ /^TAP Version/msi;
550 76         75 my $script_content = $rawtap;
551 76         182 my $file = $temp->touch($fname, $script_content);
552              
553 76         68185 [ "$temp/$fname" => $_->{section_name} ];
554 13         21 } @{$self->parsed_report->{tap_sections}};
  13         407  
555              
556             # Currently a TAP::Formatter::* is only usable via the
557             # TAP::Harness which in turn is easiest to use externally on
558             # unix shell level
559 13 50       401 my $prove = _get_prove() or die "Can not find 'prove', searched near $^X";
560              
561 13         51 my $cmd = qq{cd $temp/section ; $^X $prove -vm --exec 'cat' --formatter=TAP::Formatter::HTML `find . -type f -print | sed -e 's,^\./,,' | sort`};
562 13         4339952 my $html = qx( $cmd );
563              
564 13         338 $html = _fix_generated_html( $html );
565              
566 13         245 $temp->cleanup; # above CLEANUP=>1 is not enough. Trust me.
567              
568 13         14273 return $html;
569             }
570              
571             1; # End of Tapper::TAP::Harness
572              
573             __END__
574              
575             =pod
576              
577             =encoding UTF-8
578              
579             =head1 NAME
580              
581             Tapper::TAP::Harness - Tapper - Tapper specific TAP handling
582              
583             =head2 tap_single_plan
584              
585             Return true when TAP contains exactly one plan
586              
587             =head2 fix_last_ok
588              
589             The C<prove> tool adds an annoying last summary line, cut that away.
590              
591             =head2 fix_section_names
592              
593             Create sensible section names that fit further processing,
594             eg. substitute whitespace by dashes, fill missing names, etc.
595              
596             =head2 evaluate_report
597              
598             Actually evaluate the content of the incoming report by parsing it,
599             aggregate the sections and extract contained meta information.
600              
601             =head2 generate_html
602              
603             Render TAP through TAP::Formatter::HTML and fix some formatting to fit
604             into Tapper.
605              
606             =head1 AUTHORS
607              
608             =over 4
609              
610             =item *
611              
612             AMD OSRC Tapper Team <tapper@amd64.org>
613              
614             =item *
615              
616             Tapper Team <tapper-ops@amazon.com>
617              
618             =back
619              
620             =head1 COPYRIGHT AND LICENSE
621              
622             This software is Copyright (c) 2016 by Advanced Micro Devices, Inc..
623              
624             This is free software, licensed under:
625              
626             The (two-clause) FreeBSD License
627              
628             =cut