#!/usr/bin/perl

# Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of the License "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description:
#

use strict;
use Test::Harness;
use Getopt::Long qw(:config auto_version auto_help);
use File::Spec::Functions;
use Cwd;

$Test::Harness::Verbose = 1;

# Version of the script - just use the date
$main::VERSION = '17-Oct-08';

# a list of all the tests.
my @all = ( 
'../bldtest/test.pl',
'../symuser/test.pl',
'../symfile/test.pl'
);

my ( $verbose, $ignore, $coverage );
GetOptions("verbose" => \$verbose, "ignore" => \$ignore, "coverage" => \$coverage) or pod2usage(2);

# Get OS version
my $win32 = 1 if $^O =~ /MSWin32/;
print "Running on Win32\n" if $win32 && $verbose;
print "Running on Linux\n" if !$win32 && $verbose;

# Clear coverage stats and rebuild the code with coverage enabled
if ($coverage)
	{
	clearCoverageStats();
	setCoverage(1);
	}

# Run all the tests
my $fail;
eval { runtests(@all); };
$fail = $@ if $@;

# Show coverage stats and rebuild the code with coverage disabled
if ($coverage)
	{
	showCoverageStats();
	setCoverage(0);
	clearCoverageStats();
	}
die $fail if $fail;

# Show coverage stats
sub showCoverageStats
	{
	my %hits;

	my $loc = cwd();
	print "Calculating converage stats...\n";

	# Find all the GCDA files
	my @dirs = "$ENV{EPOCROOT}epoc32/build";
	foreach my $dir ( @dirs )
		{
		opendir DIR, $dir or die "Failed on $dir: $!";
		foreach my $child ( readdir DIR )
			{
			next if $child =~ /^\./;
			
		 	push @{ $hits{$dir} }, "$child" if $child =~ /\.gcda$/;
			push @dirs, "$dir/$child" if -d "$dir/$child";
			}
		closedir DIR;
		}

	# Collect the stats
	my %result;
	foreach my $dir ( keys %hits )
		{
		chdir($dir) or die "Failed: $!";
		my $cmd = $win32 ? "$ENV{EPOCROOT}epoc32/gcc_mingw/bin/gcov.exe @{ $hits{$dir} }" : "gcov @{ $hits{$dir} }";
		print "Executing: $cmd\n";
		open CMD, "$cmd|" or die "Failed: $!";
		while(my $line = <CMD>)
			{
			if ($line =~ /Lines executed:(\d+.\d+)% of (\d+)/)
				{
				my ($total, $coverage) = ( $2, int(($2 / 100) * $1));
				my $oldline = $line;
				$line = <CMD>;

				# Filter by filename symport/<component>
				if ($line =~ m[symport/([^/]+)/])
					{
					print "\t$oldline";
					my $comp = $1;
	
					$result{$comp}{total} = $result{$comp}{total} ? $result{$comp}{total} + $total : $total;
					$result{$comp}{coverage} = $result{$comp}{coverage} ? $result{$comp}{coverage} + $coverage : $coverage;
					}
				else
					{
					print STDERR "Unknown: Line $. - $line" if $verbose;
					}
				}
			}
		close CMD;
		}

	# Print a summary of the stats
	print "\nTEST COVERAGE RESULTS\n";
	foreach ( keys %result )
		{
		my $percent = ($result{$_}{coverage}/$result{$_}{total})*100;
		print "$_: $result{$_}{coverage}/$result{$_}{total} (${percent}%)\n";
		}
	chdir($loc);
	}

# Make sure all GCDA files are deleted
sub clearCoverageStats
	{
	print "Clearing converage stats...\n" if $verbose;

	my @dirs = "$ENV{EPOCROOT}epoc32/build";
	foreach my $dir ( @dirs )
		{
		opendir DIR, $dir or die "Failed on $dir: $!";
		foreach my $child ( readdir DIR )
			{
			next if $child =~ /^\./;
			
			if ($child =~ /\.gcda$/)
				{
				print "Deleting: $dir/$child\n" if $verbose;
			 	unlink "$dir/$child";
				}
			push @dirs, "$dir/$child" if -d "$dir/$child";
			}
		closedir DIR;
		}
	}

# Enables/Disables code coverage
sub setCoverage
	{
	my $enable = shift;
	
	if ($verbose) { print $enable ? "Enabling code coverage...\n" : "Disabling code coverage...\n"; }
	my $makefile = catfile($ENV{EPOCROOT}, 'epoc32', 'tools', 'makefile_templates', 'tools', 'x86tool.mk');
	die "Can't find makefile $makefile" if !-e $makefile;
	
	# Read the makefile
	my @lines;
	open IN, $makefile or die "Failed to open $makefile: $!";
	while(<IN>)
		{
		if (/CODE_COVERAGE:=/)
			{
			push @lines, $enable ? "CODE_COVERAGE:=1\n" : "CODE_COVERAGE:=\n";
			next;
			}
		push @lines, $_;
		}
	close IN;

	# Write out the makefile with the change
	open OUT, ">$makefile" or die "Failed to open $makefile for writing: $!";
	print OUT @lines;
	close OUT;

	# Now do the same for the new build system
	my $xml = catfile($ENV{SBS_HOME}, 'lib', 'flm', 'x86tool.xml');
	die "Can't find xml $xml" if !-e $xml;
	
	# Read the makefile
	@lines = ();
	open IN, $xml or die "Failed to open $xml: $!";
	while(<IN>)
		{
		if (/(\s*<param name=\"CODE_COVERAGE\" default=\")\d?(\" \/>)/)
			{
			push @lines, sprintf("$1%s$2\n", $enable ? '1' : '');
			next;
			}
		push @lines, $_;
		}
	close IN;

	# Write out the makefile with the change
	open OUT, ">$xml" or die "Failed to open $xml for writing: $!";
	print OUT @lines;
	close OUT;

	doClean();
	doBuild();
	}

# ***
# Get the version of the build system
# *
sub getBuildVersion
	{
	# First of all see if SBSv2 is installed
	my $sbs_ver = 1;
	open SBS, 'sbs -v 2>&1|' or die "Failed to execute command: $!";
	while(<SBS>)
		{
		if (/^sbs version/)
			{
			$sbs_ver = 2;
			last;
			}
		}
	close SBS;
	
	# Override the result using environment variable
	$sbs_ver = 1 if $ENV{SBS_VERSION} && $ENV{SBS_VERSION} == 1;
	return $sbs_ver;
	}

# ***
# Cleans the code
# *
sub doClean
	{
	print "Cleaning code...\n" if $verbose;
	my $sbs_ver = getBuildVersion();
	my $redir = $verbose?'':' >nul 2>&1';

	if ($sbs_ver == 1)
		{
		# Use the old build system
		system("bldmake bldfiles$redir");
		system("abld makefile$redir");
		system("abld clean$redir");
		}
	else
		{
		# Use the new build system
		system("sbs -c tools2 CLEAN$redir");
		system("sbs -c winscw CLEAN$redir");
		}
	}

# ***
# Builds the code
# *
sub doBuild
	{
	print "Building code...\n" if $verbose;
	my $sbs_ver = getBuildVersion();
	my $redir = $verbose?'':' >nul 2>&1';

	# Now build the test code - assumes current working directory is correct!
	print "Using SBSv$sbs_ver\n" if $verbose;
	if ($sbs_ver == 1)
		{

		# Use the old build system
		system("bldmake bldfiles$redir");
		system("abld build$redir");
		}
	else
		{
		# Use the new build system
		system("sbs -c tools2$redir");
		system("sbs -c winscw$redir");
		}
	}

=head1 NAME

test.pl - A script for running other tests

=head1 SYNOPSIS

test.pl [-help] [-version] [-verbose] [-coverage]

 Options:
   -help      brief help message
   -version   version of the script
   -verbose   print what the scripts does
   -coverage  gather code coverage stats (rebuilds everything twice)

=cut
