1#!/usr/bin/perl 2# HTML output for selftest 3# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org> 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3 of the License, or 8# (at your option) any later version. 9 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17package output::html; 18use Exporter; 19@ISA = qw(Exporter); 20 21use strict; 22use warnings; 23 24use FindBin qw($RealBin); 25use lib "$RealBin/.."; 26 27sub new($$$) { 28 my ($class, $dirname, $statistics) = @_; 29 my $self = { 30 dirname => $dirname, 31 active_test => undef, 32 local_statistics => {}, 33 statistics => $statistics, 34 msg => "", 35 error_summary => { 36 skip => [], 37 expected_success => [], 38 unexpected_success => [], 39 expected_failure => [], 40 unexpected_failure => [], 41 skip_testsuites => [], 42 error => [] 43 } 44 }; 45 46 link("$RealBin/output/testresults.css", "$dirname/testresults.css"); 47 48 open(INDEX, ">$dirname/index.html"); 49 50 bless($self, $class); 51 52 $self->print_html_header("Samba Testsuite Run", *INDEX); 53 54 print INDEX " <center>"; 55 print INDEX " <table>\n"; 56 print INDEX " <tr>\n"; 57 print INDEX " <td class=\"tableHead\">Test</td>\n"; 58 print INDEX " <td class=\"tableHead\">Result</td>\n"; 59 print INDEX " </tr>\n"; 60 61 return $self; 62} 63 64sub testsuite_count($$) 65{ 66} 67 68sub print_html_header($$$) 69{ 70 my ($self, $title, $fh) = @_; 71 72 print $fh "<html lang=\"en\">\n"; 73 print $fh "<head>\n"; 74 print $fh " <title>$title</title>\n"; 75 print $fh " <link rel=\"stylesheet\" type=\"text/css\" href=\"testresults.css\"/>\n"; 76 print $fh "</head>\n"; 77 print $fh "<body>\n"; 78 print $fh "<table width=\"100%\" border=\"0\" cellspacing=\"0\">\n"; 79 print $fh " <tr><td class=\"title\">$title</td></tr>\n"; 80 print $fh " <tr><td>\n"; 81} 82 83sub print_html_footer($$) 84{ 85 my ($self, $fh) = @_; 86 87 print $fh "</td></tr>\n"; 88 print $fh "</table>\n"; 89 print $fh "</body>\n"; 90 print $fh "</html>\n"; 91} 92 93sub output_msg($$); 94 95sub start_testsuite($$) 96{ 97 my ($self, $name) = @_; 98 99 $self->{START_TIME} = $self->{last_time}; 100 101 $self->{local_statistics} = { 102 success => 0, 103 skip => 0, 104 error => 0, 105 failure => 0 106 }; 107 108 $self->{NAME} = $name; 109 $self->{HTMLFILE} = "$name.html"; 110 $self->{HTMLFILE} =~ s/[:\t\n \/]/_/g; 111 112 open(TEST, ">$self->{dirname}/$self->{HTMLFILE}") or die("Unable to open $self->{HTMLFILE} for writing"); 113 114 $self->print_html_header("Test Results for $name", *TEST); 115 116 print TEST "<h2>Tests</h2>\n"; 117 118 print TEST " <table>\n"; 119} 120 121sub control_msg($$) 122{ 123 my ($self, $output) = @_; 124 125 # Perhaps the CSS should hide this by default? 126 $self->{msg} .= "<span class=\"control\">$output<br/></span>\n"; 127} 128 129sub output_msg($$) 130{ 131 my ($self, $output) = @_; 132 133 unless (defined($self->{active_test})) { 134 if (defined($self->{NAME})) { 135 print TEST "$output<br/>"; 136 } 137 } else { 138 $self->{msg} .= "$output<br/>"; 139 } 140} 141 142sub end_testsuite($$$) 143{ 144 my ($self, $name, $result, $reason) = @_; 145 146 print TEST "</table>\n"; 147 148 print TEST "<div class=\"duration\">Duration: " . ($self->{last_time} - $self->{START_TIME}) . "s</div>\n"; 149 150 $self->print_html_footer(*TEST); 151 152 close(TEST); 153 154 print INDEX "<tr>\n"; 155 print INDEX " <td class=\"testSuite\"><a href=\"$self->{HTMLFILE}\">$name</a></td>\n"; 156 my $st = $self->{local_statistics}; 157 158 if ($result eq "xfail") { 159 print INDEX " <td class=\"resultExpectedFailure\">"; 160 } elsif ($result eq "success") { 161 print INDEX " <td class=\"resultOk\">"; 162 } else { 163 print INDEX " <td class=\"resultFailure\">"; 164 } 165 166 my $l = 0; 167 if ($st->{success} > 0) { 168 print INDEX "$st->{success} ok"; 169 $l++; 170 } 171 if ($st->{skip} > 0) { 172 print INDEX ", " if ($l); 173 print INDEX "$st->{skip} skipped"; 174 $l++; 175 } 176 if ($st->{failure} > 0) { 177 print INDEX ", " if ($l); 178 print INDEX "$st->{failure} failures"; 179 $l++; 180 } 181 if ($st->{error} > 0) { 182 print INDEX ", " if ($l); 183 print INDEX "$st->{error} errors"; 184 $l++; 185 } 186 187 if ($l == 0) { 188 print INDEX uc($result); 189 } 190 191 print INDEX "</td>"; 192 193 print INDEX "</tr>\n"; 194 195 $self->{NAME} = undef; 196} 197 198sub report_time($$) 199{ 200 my ($self, $time) = @_; 201 $self->{last_time} = $time; 202} 203 204sub start_test($$) 205{ 206 my ($self, $testname) = @_; 207 208 $self->{active_test} = $testname; 209 $self->{msg} = ""; 210} 211 212sub end_test($$$$) 213{ 214 my ($self, $testname, $result, $unexpected, $reason) = @_; 215 216 print TEST "<tr>"; 217 218 $self->{local_statistics}->{$result}++; 219 220 my $track_class; 221 222 if ($result eq "skip") { 223 print TEST "<td class=\"outputSkipped\">\n"; 224 $track_class = "skip"; 225 } elsif ($unexpected) { 226 print TEST "<td class=\"outputFailure\">\n"; 227 if ($result eq "error") { 228 $track_class = "error"; 229 } else { 230 $track_class = "unexpected_$result"; 231 } 232 } else { 233 if ($result eq "failure") { 234 print TEST "<td class=\"outputExpectedFailure\">\n"; 235 } else { 236 print TEST "<td class=\"outputOk\">\n"; 237 } 238 $track_class = "expected_$result"; 239 } 240 241 push(@{$self->{error_summary}->{$track_class}}, , 242 [$self->{HTMLFILE}, $testname, $self->{NAME}, 243 $reason]); 244 245 print TEST "<a name=\"$testname\"><h3>$testname</h3></a>\n"; 246 247 print TEST $self->{msg}; 248 249 if (defined($reason)) { 250 print TEST "<div class=\"reason\">$reason</div>\n"; 251 } 252 253 print TEST "</td></tr>\n"; 254 255 $self->{active_test} = undef; 256} 257 258sub summary($) 259{ 260 my ($self) = @_; 261 262 my $st = $self->{statistics}; 263 print INDEX "<tr>\n"; 264 print INDEX " <td class=\"testSuiteTotal\">Total</td>\n"; 265 266 if ($st->{TESTS_UNEXPECTED_OK} == 0 and 267 $st->{TESTS_UNEXPECTED_FAIL} == 0 and 268 $st->{TESTS_ERROR} == 0) { 269 print INDEX " <td class=\"resultOk\">"; 270 } else { 271 print INDEX " <td class=\"resultFailure\">"; 272 } 273 print INDEX ($st->{TESTS_EXPECTED_OK} + $st->{TESTS_UNEXPECTED_OK}) . " ok"; 274 if ($st->{TESTS_UNEXPECTED_OK} > 0) { 275 print INDEX " ($st->{TESTS_UNEXPECTED_OK} unexpected)"; 276 } 277 if ($st->{TESTS_SKIP} > 0) { 278 print INDEX ", $st->{TESTS_SKIP} skipped"; 279 } 280 if (($st->{TESTS_UNEXPECTED_FAIL} + $st->{TESTS_EXPECTED_FAIL}) > 0) { 281 print INDEX ", " . ($st->{TESTS_UNEXPECTED_FAIL} + $st->{TESTS_EXPECTED_FAIL}) . " failures"; 282 if ($st->{TESTS_UNEXPECTED_FAIL} > 0) { 283 print INDEX " ($st->{TESTS_EXPECTED_FAIL} expected)"; 284 } 285 } 286 if ($st->{TESTS_ERROR} > 0) { 287 print INDEX ", $st->{TESTS_ERROR} errors"; 288 } 289 290 print INDEX "</td>"; 291 292 print INDEX "</tr>\n"; 293 294 print INDEX "</table>\n"; 295 print INDEX "<a href=\"summary.html\">Summary</a>\n"; 296 print INDEX "</center>\n"; 297 $self->print_html_footer(*INDEX); 298 close(INDEX); 299 300 my $summ = $self->{error_summary}; 301 open(SUMMARY, ">$self->{dirname}/summary.html"); 302 $self->print_html_header("Summary", *SUMMARY); 303 sub print_table($$) { 304 my ($title, $list) = @_; 305 return if ($#$list == -1); 306 print SUMMARY "<h3>$title</h3>\n"; 307 print SUMMARY "<table>\n"; 308 print SUMMARY "<tr>\n"; 309 print SUMMARY " <td class=\"tableHead\">Testsuite</td>\n"; 310 print SUMMARY " <td class=\"tableHead\">Test</td>\n"; 311 print SUMMARY " <td class=\"tableHead\">Reason</td>\n"; 312 print SUMMARY "</tr>\n"; 313 314 foreach (@$list) { 315 print SUMMARY "<tr>\n"; 316 print SUMMARY " <td><a href=\"" . $$_[0] . "\">$$_[2]</a></td>\n"; 317 print SUMMARY " <td><a href=\"" . $$_[0] . "#$$_[1]\">$$_[1]</a></td>\n"; 318 if (defined($$_[3])) { 319 print SUMMARY " <td>$$_[3]</td>\n"; 320 } else { 321 print SUMMARY " <td></td>\n"; 322 } 323 print SUMMARY "</tr>\n"; 324 } 325 326 print SUMMARY "</table>"; 327 } 328 print_table("Errors", $summ->{error}); 329 print_table("Unexpected successes", $summ->{unexpected_success}); 330 print_table("Unexpected failures", $summ->{unexpected_failure}); 331 print_table("Skipped tests", $summ->{skip}); 332 print_table("Expected failures", $summ->{expected_failure}); 333 334 print SUMMARY "<h3>Skipped testsuites</h3>\n"; 335 print SUMMARY "<table>\n"; 336 print SUMMARY "<tr>\n"; 337 print SUMMARY " <td class=\"tableHead\">Testsuite</td>\n"; 338 print SUMMARY " <td class=\"tableHead\">Reason</td>\n"; 339 print SUMMARY "</tr>\n"; 340 341 foreach (@{$summ->{skip_testsuites}}) { 342 print SUMMARY "<tr>\n"; 343 print SUMMARY " <td>$$_[0]</td>\n"; 344 if (defined($$_[1])) { 345 print SUMMARY " <td>$$_[1]</td>\n"; 346 } else { 347 print SUMMARY " <td></td>\n"; 348 } 349 print SUMMARY "</tr>\n"; 350 } 351 352 print SUMMARY "</table>"; 353 354 $self->print_html_footer(*SUMMARY); 355 close(SUMMARY); 356} 357 358sub skip_testsuite($$$$) 359{ 360 my ($self, $name, $reason) = @_; 361 362 push (@{$self->{error_summary}->{skip_testsuites}}, 363 [$name, $reason]); 364} 365 3661; 367