#!/usr/bin/perl
#****************************************************************************#
# Copyright (c) International Business Machines  Corp., 2001                 #
#                                                                            #
# This program is free software;  you can redistribute it an#or modify       #
# it under the terms of the GNU General Public License as published by       #
# the Free Software Foundation; either version 2 of the License, or          #
# (at your option) any later version.                                        #
#                                                                            #
# This program is distributed in the hope that it will be useful,            #
# but WITHOUT ANY WARRANTY;  without even the implied warranty of            #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  #
# the GNU General Public License for more details.                           #
#                                                                            #
# You should have received a copy of the GNU General Public License          #
# along with this program;  if not, write to the Free Software               #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    #
#                                                                            #
#****************************************************************************#

#****************************************************************************
#
# File:        genhtml.pl
#
# Description: This is a Parser which can parse the text output generated by
#              pan and convert the same to an HTML format, with proper high-
#              lighting of test result background for easy identification of
#              pass/fail of testcases
#
# Author:      Subrata Modak: subrata@linux.vnet.ibm.com
#
# History:     May 20 2009 - Modified - Marc Gauthier <marc@alumni.uwaterloo.ca>
#               - catch test output between test_end and test_start tags
#               - look at exit value if no explicit test result reported
#               - allow reporting tests without explicit result as unresolved
#               - simplify parsing a bit
#
#****************************************************************************


#  Constants
my %result_priority = (FAIL=>6, BROK=>5, WARN=>4, RETR=>3, CONF=>2, PASS=>1, UNRESOLVED=>0);
my %colours = (	FAIL => "#ff0000",		# red
		BROK => "Yellow",
		WARN => "Fuchsia",
		RETR => "#8dc997",		# darker green
		CONF => "Aqua",
		PASS => "#66ff66",		# light green
		UNRESOLVED => "#c0c0ff" );	# light blue

#  Globals
my $test_counter = 0;
my $eof = 0;
my %total_count = (FAIL=>0, BROK=>0, WARN=>0, RETR=>0, CONF=>0, PASS=>0, UNRESOLVED=>0);

#  Script arguments
my $header_file   = shift (@ARGV) || syntax();
my $start_tag     = shift (@ARGV) || syntax();
my $end_tag       = shift (@ARGV) || syntax();
my $output_tag    = shift (@ARGV) || syntax();
my $execution_tag = shift (@ARGV) || syntax();

if ($start_tag eq "" || $end_tag eq "" || $output_tag eq "" || $execution_tag eq "") {
    syntax();
}

sub syntax {
    print "syntax: genhtml header_file start_tag end_tag output_tag execution_tag file(s)\n";
    exit (1);
}

#  Get a line from <FILE>, with chomp and sticky EOF.
sub get_line {
    my ($lineref) = @_;
    $$lineref = undef;
    return undef if $eof;
    if (!defined($$lineref = <FILE>)) {
	$eof = 1;
	return undef;
    }
    chomp $$lineref;
    return 1;
}

#  Display HTML header
open (FILE, "<$header_file") || die "Cannot open file: $header_file";
my $header = "";
while ($headerline = <FILE>) {
       $header .= $headerline;
}
my $start_time = $ENV{TEST_START_TIME} || "[unknown date/time]";
$header =~ s/LTP\ Output\/Log/LTP\ Output\/Log\ (Report\ Generated\ on\ $start_time)/;
print $header;
close (FILE);


#  Parse and display test results

foreach my $file (@ARGV) {

	open (FILE, $file) || die "Cannot open file: $file\n";

	my $line = "";

	TEST: while (defined($line)) {

		my %values = ();
		my @output_lines = ();
		my $read_output = 0;

		#  Find start of test
		while ($line !~ /$start_tag/) {
			#  Capture lines present between end_tag and start_tag that apply to the subsequent test.
			push @output_lines, $line unless $test_counter == 0;
			get_line(\$line) or last TEST;
		}

		#  Read test result parameters and test output
		while ($line !~ /$end_tag/) {
			($read_output = 1, next) if $line =~ /$output_tag/;
			($read_output = 0, next) if $line =~ /$execution_tag/;
			if ($read_output) {
			    push @output_lines, $line;
			} else {
			    while ($line =~ s/^\s*(\w+)=(".*"|\S*)//) {
				$values{$1} = $2;
			    }
			}
		} continue {
			get_line(\$line) or last TEST;
		}

		#  Treat lines that follow <<<end_test>>> as output lines
		#  if they start with the same test name (tag).
		#  Otherwise they're likely part of the next test.
		while (1) {
			get_line(\$line) or last;
			last unless $line !~ /$start_tag/ and $line =~ /^\s(\w+)\s/ and $1 eq $values{tag};
			push @output_lines, $line;
		}

		#  Parse output lines for test results.
		#
		my $result = "UNRESOLVED";	# single result of test
		my %result_count = ();
		my $picked_line = "";		# one representative line picked out of the output
		foreach my $output_line (@output_lines) {
		    my $line_res = "UNRESOLVED";
		    $line_res = $1 if $output_line =~ /\ (FAIL|BROK|WARN|RETR|CONF|PASS)\ /;
		    $result_count{$line_res}++;
		    #  If a test has multiple results, only tally the "most important" one.
		    if ($result_priority{$line_res} >= $result_priority{$result}) {
			$result = $line_res;
			$picked_line = $output_line;	# pick last line of highest priority
		    }
		}

		#  If no explicit result found, look at termination status to determine result.
		#
		if ($result eq "UNRESOLVED") {
		    my $efail = "BROK"; #"FAIL"		# for now, report exit status failures as BROK
		    if ($values{termination_type} eq "signaled") {
			$result = $efail;		# termination_id is the signal number
		    } elsif ($values{termination_id}) {
			if (($values{termination_id} & 1) != 0) {
			    $result = $efail;		# bit 0 set == failure
			} elsif (($values{termination_id} & 2) != 0) {
			    $result = "BROK";		# bit 1 set == broken
			} elsif ($values{termination_id} == 4) {
			    $result = "WARN";
			} else {
			    $result = $efail;		# any other non-zero value assumed to mean failure
			}
		    } else {
			#  Exited with a zero exit code.  Do we assume PASS, or mark it UNRESOLVED?
			#  (We could grep the output for other hint keywords, but that's a bit hokey.)
			$result = "PASS" unless $ENV{SHOW_UNRESOLVED};
		    }
		}

		#  Cumulate this test's result.
		$total_count{$result}++;

		##  Previous cumulation method; tests exhibiting multiple result
		##  types are counted many times.
		#
		#foreach my $res (keys %result_count) {
		#    $total_count{$res}++ if $result_count{$res};
		#}

		#  All test data scanned.  Now output HTML (row) for this test.
		#
		my $get_proper_time = localtime ($values{stime});
		my $background_colour = $colours{$result};
		my $test_output = join("", map("$_ \n", @output_lines));
		$test_output = $picked_line if $ENV{SUMMARY_OUTPUT};
		$test_counter++;
		print	"<tr bgcolor=$background_colour><td><p><strong>$test_counter</strong></p></td>\n"
			. "<td><p><strong>$values{tag}</strong></p></td>\n"
			. "<td><p><pre><strong>$get_proper_time</strong></pre></p></td>\n"
			. "<td><p><strong> $values{cmdline} </strong></p></td>\n"
			. "<td><p><strong>$values{contacts}</strong></p></td>\n"
			. "<td><p><strong>$values{analysis}</strong></p></td>\n"
			. "<td><p><strong>$values{initiation_status}</strong></p></td>\n"
			. "<td><pre><strong>$test_output</strong></pre></td>"
			. "<td><p><strong>$values{duration}</strong></p></td>\n"
			. "<td><p><strong>$values{termination_type}<strong></p></td>\n"
			. "<td><p><strong>$values{termination_id}</strong></p></td>\n"
			. "<td><p><strong>$values{corefile}</strong></p></td>\n"
			. "<td><p><strong>$values{cutime}</strong></p></td>\n"
                        . "<td><p><strong>$values{cstime}</strong></p></td></tr>\n"
			; 
	}

	close (FILE);
}


#  Display summary

print "</tbody></table></div> \n\n<h2 id=\"_2\">Summary Report</h2>\n\n<div>\n\n<table border=\"1\" cellspacing=\"3\"><tbody>\n<tr>\n<td ";
if ($ENV{LTP_EXIT_VALUE} == 1 ) {
    print "bgcolor=\"#ff0000\"> <strong>Test Summary</strong></p></td><td bgcolor=\"#ff0000\"><strong>Pan reported some Tests FAIL</strong></p></td></tr>\n";
}
else {
    print "bgcolor=\"#66ff66\"> <strong>Test Summary</strong></p></td><td bgcolor=\"#66ff66\"><strong>Pan reported all Test Pass</strong></p></td></tr>\n";
}

print "<tr><td><strong>LTP Version</strong> </td><td><strong> $ENV{LTP_VERSION}     </strong></td></tr>\n";
print "<tr><td><strong>Start Time</strong>  </td><td><strong> $ENV{TEST_START_TIME} </strong></td></tr>\n";
print "<tr><td><strong>End Time</strong>    </td><td><strong> $ENV{TEST_END_TIME}   </strong></td></tr>\n";
print "<tr><td><strong>Log Result</strong>  </td><td><a href=\"file://$ENV{TEST_LOGS_DIRECTORY}/\">      <strong>$ENV{TEST_LOGS_DIRECTORY}</strong></a></td></tr>\n";
print "<tr><td><strong>Output/Failed Result</strong></td><td><a href=\"file://$ENV{TEST_OUTPUT_DIRECTORY}/\"> <strong>$ENV{TEST_OUTPUT_DIRECTORY}</strong></a></td></tr>\n";
print "<tr><td><strong>Total Tests</strong></td><td><strong> $test_counter </strong></td></tr>\n";
#  Previous method of counting PASS:
#$total_count{PASS} = $test_counter - $total_count{FAIL} - $total_count{BROK} - $total_count{WARN} - $total_count{RETR} - $total_count{CONF} - $total_count{UNRESOLVED};
sub show_result_summary {
    my ($restype, $what) = @_;
    printf "<tr><td><strong>$what</strong></td>"
	      ."<td><strong> $total_count{$restype} </strong></td>"
	      ."<td><strong> %8.2f%% </strong></td></tr>\n",
	($total_count{$restype}*100.0) / $test_counter;
}
show_result_summary("PASS", "Test PASS");
show_result_summary("FAIL", "Test FAIL");
show_result_summary("BROK", "Test BROK");
show_result_summary("WARN", "Test WARN");
show_result_summary("RETR", "Test RETR");
show_result_summary("CONF", "Test CONF");
show_result_summary("UNRESOLVED", "Unresolved") if $ENV{SHOW_UNRESOLVED};
print "<tr><td><strong>Kernel Version</strong></td><td><strong> $ENV{KERNEL_VERSION}  </strong></td></tr>\n";
print "<tr><td><strong>Machine Architecture</strong></td><td><strong> $ENV{MACHINE_ARCH} </strong></td></tr>\n";
$hostname = `uname -n`;             chop($hostname); 
print "<tr><td><strong>Hostname</strong>  </td> <td><strong> $hostname </strong></td></tr>\n";
print "</tbody></table></div></body></html>\n";

