--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tsrc/testing/tools/testdoc.pl Mon Jan 18 20:21:12 2010 +0200
@@ -0,0 +1,5437 @@
+#
+# Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "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:
+#
+
+#-----------------------------------------------
+# Sequence
+#-----------------------------------------------
+# Reads parameters -> [if !ok params] ShowHelp
+# ReadConfigFiles
+# -> ParseCfg
+# -> ReadCase
+#
+# for all testreports:
+# ReadTestRunInfoFromStifReport
+# GetReportLogFileNames
+# ParseResultsAndLogs
+#
+# ParseResultsAndLogs
+# WriteCaseLog
+# LogLineTimeMatchesForCase
+# FormatLogLine
+# UpdateCase
+# CheckCaseEntriesInLog
+#
+# OLD:
+# -> ParseReportFile
+# -> ReadReportLogs
+# -> WriteCaseLog
+# -> LogLineTimeMatchesForCase
+# -> FormatLogLine
+# -> CheckCaseEntriesInLog
+#
+# ReportNotDocumentedCases
+# SortCases
+# CalculateStats
+# WriteOfficeXml -> XmlReadyText
+# exit()
+
+#-----------------------------------------------
+# Other functions:
+#-----------------------------------------------
+# RemoveWhiteSpaces
+# SpecialChars
+# ReplaceChar
+# GetCaseField
+# GetCase (id or name)
+# GetCaseDesc (id or name)
+# PrintCases
+# JustFormatLogFile
+
+#
+#
+#
+# STIF CFG:
+#************************************************************************************
+#[IptvETDescription]
+# Testname: <insert text here>
+#
+# Purpose: <insert text here>
+#
+# Means: <insert text here>
+#
+# Required environment settings: <insert text here>
+#
+# Verification: <insert text here>
+#
+# Note: <insert text here>
+#
+# Related requirements: <reqid> <reqid> <reqid> ..
+#
+#[EndIptvETDescription]
+#------------------------------------------------------------------------------------
+#[Test]
+# do stuff here
+#[Endtest]
+
+#------------------------------------------------------------------------------------
+# Includes
+#------------------------------------------------------------------------------------
+#use strict;
+use warnings;
+use Cwd; # for cwd
+use FindBin; # for FindBin:Bin
+use File::Path; # for mkpath
+use File::Copy;
+use Date::Calc;
+
+#------------------------------------------------------------------------------------
+# Globals
+#------------------------------------------------------------------------------------
+
+my $lastCaseLogLine = 0;
+
+my $ALT_RESULTCOUNT = 10; # maximum number of runs in alternative report
+
+my @cases; #references to case arrays
+my @gCfgFiles; # list of cfg files.
+my @caseDescs; # case description and the case itself in text
+my @notDocumentedCases; #array to hold information about the cases without documentation
+
+$regexpCaseName = '[\x3C\x3E\(\)\w.,\/:_\-&\' ]+';
+
+my $caseDefaultStatus = "NOT RUN";
+
+#
+# Case field numerations
+#
+
+my $CASE_NAME = 0;
+my $CASE_ID = 1;
+my $CASE_RUN_TIMES = 2;
+my $CASE_CRASHED = 3;
+my $CASE_FAILED = 4;
+my $CASE_PASSED = 5;
+my $CASE_STATUS = 6;
+my $CASE_PURPOSE = 7;
+my $CASE_MEANS = 8;
+my $CASE_REQUIRED_SETTINGS = 9;
+my $CASE_RELATED_REQUIREMENTS = 10;
+my $CASE_VERIFICATION = 11;
+my $CASE_NOTE = 12;
+my $CASE_REASON = 13; # where crashed or what returned the error code
+my $CASE_RESULT = 14; # error code
+my $CASE_LOG_FILE = 15; # test case specific log file.
+my $CASE_LOG_FILE_SCRIPTER = 16; # test case specific log from STIF testscripter logs.
+my $CASE_CHECK_RESULT_LOG_FILE = 17; # set if the case is in the log files, if next line is found: >>>Case start: ETxxxxx CaseName
+ # or STIF own trace: Starting testcase [ET1000 Add multiple Iaps] (usually from fasttrace or emulator log)
+my $CASE_CFG_FILE = 18;
+my $CASE_RUN_TIME_SECONDS = 19; # how many seconds it took to run the case
+my $CASE_REPORTLINE1 = 20;
+my $CASE_REPORTLINE2 = 21;
+my $CASE_REPORTLINE3 = 22;
+my $CASE_ENTRY_LOG_START = 23;
+
+my $TDTOOLRESULTFILE = ".\\text_file.txt";
+my $XML_OUTPUT_FILE = ".\\test_cases.xml";
+my $XML_BRIEF_OUTPUT_FILE = ".\\test_cases_brief.xml";
+my $NOT_DOCUMENTED_CASES_FILE = ".\\test_cases_notdocumented.txt";
+
+my @globalTempFiles;
+
+#
+# Tags inside the xml, will be replaced by case data when writing the xml file
+#
+
+my $CaseCountMul8 = "CASE_COUNT_MUL8";
+
+my $STYLE_ID_STATUS_TAG = "STYLE_ID_STATUS"; # must be in the xml data
+
+my $STYLE_ID_STATUS_FAILED = "s36";
+my $STYLE_ID_STATUS_PASSED = "s37";
+my $STYLE_ID_STATUS_CRASHED = "s38";
+my $STYLE_ID_STATUS_UNKNOWN = "s401";
+my $STYLE_ID_STATUS_NA = "s39";
+
+my $STYLE_ID_STATUS_FAILED_CENTERED = "s36centered";
+my $STYLE_ID_STATUS_PASSED_CENTERED = "s37centered";
+my $STYLE_ID_STATUS_CRASHED_CENTERED = "s38centered";
+my $STYLE_ID_STATUS_UNKNOWN_CENTERED = "s401centered";
+my $STYLE_ID_STATUS_NA_CENTERED = "s39centered";
+
+# these must be in the xml data to get the results inserted into xml
+my $xmlDataCaseName = "XML_DATA_CASE_NAME";
+my $xmlDataCaseRunTimes = "XML_DATA_CASE_RUN_TIMES";
+my $xmlDataCaseFailed = "XML_DATA_CASE_FAILED";
+my $xmlDataCaseCrashed = "XML_DATA_CASE_CRASHED";
+my $xmlDataCasePassed = "XML_DATA_CASE_PASSED";
+my $xmlDataCaseStatus = "XML_DATA_CASE_STATUS";
+my $xmlDataCasePurpose = "XML_DATA_CASE_PURPOSE";
+my $xmlDataCaseMeans = "XML_DATA_CASE_MEANS";
+my $xmlDataCaseRequiredSettings = "XML_DATA_CASE_REQUIRED_SETTINGS";
+my $xmlDataCaseRelatedRequirements = "XML_DATA_CASE_RELATED_REQUIREMENTS";
+my $xmlDataCaseVerification = "XML_DATA_CASE_VERIFICATION";
+my $xmlDataCaseNote = "XML_DATA_CASE_NOTE";
+my $xmlDataCaseReason = "XML_DATA_CASE_REASON";
+my $xmlDataCaseResult = "XML_DATA_CASE_RESULT";
+my $xmlDataCaseLink1 = "XML_DATA_CASE_LINK1";
+my $xmlDataCaseLink2 = "XML_DATA_CASE_LINK2";
+
+my $xmlDataSummaryCaseCount = "XML_DATA_SUMMARY_TOTAL_CASES";
+my $xmlDataSummaryPassed = "XML_DATA_SUMMARY_PASSED";
+my $xmlDataSummaryFailed = "XML_DATA_SUMMARY_FAILED";
+my $xmlDataSummaryCrashed = "XML_DATA_SUMMARY_CRASHED";
+my $xmlDataSummaryTimeout = "XML_DATA_SUMMARY_TIMEOUT";
+my $xmlDataSummaryPassRateTotal = "XML_DATA_SUMMARY_PASS_RATE_TOTAL";
+my $xmlDataSummaryPassRateRun = "XML_DATA_SUMMARY_PASS_RATE_RUN";
+my $xmlDataSummaryRunRate = "XML_DATA_SUMMARY_RUN_RATE";
+
+my $xmlDataAltDateX = "XML_DATA_ALTDATE";
+
+my $xmlDataAltResultX = "XML_DATA_ALTRESULT";
+
+my $xmlDataCfgFile = "XML_DATA_CFG_FILE";
+
+#
+# Statistics
+#
+
+my $summaryCaseCount = 0;
+my $summaryPassedCases = 0;
+my $summaryFailedCases = 0;
+my $summaryCrashedCases = 0;
+my $summaryTimeoutCases = 0;
+my $summaryPassRateTotal = 0;
+my $summaryPassRateRun = 0;
+my $summaryRunRate = 0;
+
+#
+# Xml data
+#
+
+my $xmlHeader;
+my $xmlHeaderTableColumns;
+my $xmlHeaderTableColumnsBrief;
+my $xmlFooter;
+my $xmlDataEmptyRow;
+my $xmlSummaryData;
+my $xmlData;
+my $xmlDataCaseStatusDisabled;
+my $xmlData2;
+my $xmlDataBriefHeader;
+my $xmlDataBrief;
+my $xmlCfgFileBrief;
+my $xmlHeaderTableColumnsAlt;
+my $xmlCfgFileAltHeader;
+my $xmlCfgFileAltData;
+
+InitXmlData();
+
+#------------------------------------------------------------------------------------
+# GLOBAL CODE
+#------------------------------------------------------------------------------------
+
+my $argcount = scalar(@ARGV);
+
+my $optionSortCases = 0;
+my $optionShowMessages = 0;
+my $optionHtml = 0;
+my $optionLogAllCases = 1;
+my $optionNoLogs = 0;
+my $optionNoSecurityTests = 0;
+my $optionNoLiveTvTests = 0;
+my $optionCaseIncludedInLog = 0;
+my $optionGoodIsBetter = 1;
+my $optionPrintCfgSummaries = 0;
+my $optionCaseRunTimes = 0;
+my $optionFinalDoc = 1;
+my $optionFixFilename = "";
+my $optionDebug = 0;
+my $optionCaseList = "";
+my $optionAltResults = 0;
+my $optionLogFileName = "fusion";
+
+while(scalar(@ARGV) >= 1)
+{
+ my $argument = shift(@ARGV);
+
+ if($argument eq "-h")
+ {
+ ShowHelp();
+ }
+
+ elsif($argument eq "-e")
+ {
+ $optionShowMessages = 1;
+ }
+
+ elsif($argument eq "-s")
+ {
+ $optionSortCases = 1;
+ }
+
+ elsif($argument eq "-html")
+ {
+ $optionHtml = 1;
+ }
+
+ elsif($argument eq "-logall")
+ {
+ $optionLogAllCases = 1;
+ }
+
+ elsif($argument eq "-nologs")
+ {
+ $optionNoLogs = 1;
+ }
+
+ elsif($argument eq "-nosecuritytests")
+ {
+ $optionNoSecurityTests = 1;
+ }
+
+ elsif($argument eq "-nolivetvtests")
+ {
+ $optionNoLiveTvTests = 1;
+ }
+
+ elsif($argument eq "-i")
+ {
+ $optionCaseIncludedInLog = 1;
+ }
+
+ elsif($argument eq "-file")
+ {
+ $file = shift(@ARGV);
+
+ JustFormatLogFile($file);
+ exit;
+ }
+ elsif($argument eq "-runtimes")
+ {
+ $optionCaseRunTimes = 1;
+ }
+
+ elsif($argument eq "-xxx")
+ {
+ $optionCaseIncludedInLog = 1;
+ $optionNoLiveTvTests = 1;
+ $optionNoSecurityTests = 1;
+ $optionHtml = 1;
+ }
+ elsif($argument eq "-good")
+ {
+ $optionGoodIsBetter = 1;
+ }
+ elsif($argument eq "-cfgsum")
+ {
+ $optionPrintCfgSummaries = 1;
+ }
+ elsif($argument eq "-finalize")
+ {
+ $optionFinalDoc = 1;
+ }
+ elsif($argument eq "-fix") {
+ $optionFixFilename = shift(@ARGV);
+ FixExcelLogPaths();
+ exit();
+ }
+ elsif($argument eq "-debug") {
+ $optionShowMessages = 1;
+ $optionDebug = 1;
+ }
+ elsif($argument eq "-caselist") {
+ $optionCaseList = shift(@ARGV);
+ }
+ elsif($argument eq "-alt") {
+ $optionAltResults = 1;
+ }
+ elsif( $argument eq "-logfile") {
+ $optionLogFileName = shift(@ARGV);
+ }
+ else
+ {
+ ShowHelp();
+ }
+}
+
+UnzipAndCopyFiles();
+
+my $totalExecutionTime = 0;
+
+my $caseLogOutDir = "testcase_logs\\testcase_logs\\";
+
+my @caseList;
+
+if($optionCaseList ne "")
+{
+ ReadCaseList(\@caseList, $optionCaseList);
+}
+
+# Find cfg files.
+FindCfgFiles( ".", \@gCfgFiles );
+
+# None found from current dir, see one dir lower.
+FindCfgFiles( "..", \@gCfgFiles ) if( scalar( @gCfgFiles ) < 1 );
+
+# Parse results
+if($optionPrintCfgSummaries)
+{
+ PrintCfgSummaries();
+}
+elsif( !$optionAltResults )
+{
+ my $res = ReadTestReports();
+
+ if( $res == 0 )
+ {
+ foreach my $file ( @globalTempFiles )
+ {
+ unlink $file if( -e $file );
+ }
+ print("No reports to read.\n");
+ exit;
+ }
+
+ #ReportNotDocumentedCases($NOT_DOCUMENTED_CASES_FILE);
+
+ if($optionSortCases)
+ {
+ @cases = sort SortCases @cases;
+ }
+
+ CalculateStats();
+
+ #WriteOfficeXml($XML_OUTPUT_FILE, 0);
+ WriteOfficeXml($XML_BRIEF_OUTPUT_FILE, 1);
+}
+else
+{
+ my @runs;
+ ReadTestReportsAlt(\@runs);
+
+ WriteOfficeXmlAlt($XML_BRIEF_OUTPUT_FILE, \@runs);
+}
+
+#print("Total run time: " . $totalExecutionTime . "\n") if( $optionCaseRunTimes );
+
+foreach my $file ( @globalTempFiles )
+{
+ unlink $file if( defined( $file ) && -e $file );
+}
+
+exit();
+
+#------------------------------------------------------------------------------------
+# UnzipAndCopyFiles
+#------------------------------------------------------------------------------------
+sub UnzipAndCopyFiles
+{
+ my @files;
+ system("rmdir ziptemp /s /q>NUL") if( -e "ziptemp" );
+
+ # Unzip zips in current directory and one level of subdirectories. -> ATS results.
+ GetAllFiles( ".", \@files, 1 );
+
+ foreach my $file ( @files )
+ {
+ if( $file =~ m/\.zip/i )
+ {
+ my $fileName = GetPathFileName( $file );
+
+ mkdir ("ziptemp");
+ my $cmd = "unzip -o \"$file\" -d ziptemp\\$fileName >NUL";
+ print("Unzipping $file\n") if( $optionShowMessages );
+ system( $cmd );
+ }
+ }
+
+ undef( @files );
+ GetAllFiles( ".", \@files, -1 );
+
+ # Copy files to current dir.
+
+ my $currDir = cwd;
+
+ foreach my $file ( @files )
+ {
+ next if( -d $file );
+
+ $file =~ s/\//\\/g;
+
+ # Do nothing for files which are in current dir.
+ my $srcDir = GetPathDir( $file );
+ my $currpath = cwd;
+ $currpath =~ s/\//\\/g;
+ next if( $srcDir eq $currpath );
+
+ my $filename = GetPathFileName( $file );
+
+ # LOOP all testreport*.txt testscripter*.txt
+ # if file is testreport.txt
+ # lastFolder = last folder from the path
+ # LOOP all fusion*.txt
+ # LOOP remove tailing text from lastFolder starting from last index of '.' until it matches with folder of fusion*.txt
+ # pair fusion*.txt with testreport
+
+
+ if( ( $filename =~ m/testreport/i || $filename =~ m/testscripter/i ) && $filename =~ m/\.txt/i )
+ #if( ( $filename =~ m/$optionLogFileName/i || $filename =~ m/testreport/i || $filename =~ m/testscripter/i ) && $filename =~ m/\.txt/i )
+ {
+ my $dst = "";
+
+ if( $filename =~ m/testreport/i )
+ {
+ # Pair testreports and logs.
+ CopyTestReportWithLog( $file, \@files );
+ }
+ else
+ {
+ print("Copying file $file\n") if( $optionDebug );
+ # For other files we just need unique filename and copy them.
+ $dst = $filename;
+
+ if( -e $filename )
+ {
+ # Separate file's name and extension.
+ my $name = "";
+ my $ext = "";
+ my $pos = index($filename, ".");
+ if( $pos != -1)
+ {
+ $ext = substr( $filename, $pos );
+ $name = substr( $filename, 0, $pos );
+
+ my $count = 0;
+ while( 1 )
+ {
+ $dst = "$name" . "_" . $count . $ext;
+ last if( ! -e "$dst" );
+ $count++;
+ if( $count > 1000 )
+ {
+ $dst = "";
+ last;
+ }
+ }
+ }
+ }
+ push @globalTempFiles, $dst;
+
+ print("Dest: $dst\n") if( $optionDebug );
+
+ copy( $file, $dst ) or die "Could not copy '$file' to '$dst'\n";
+ }
+ }
+ }
+
+ system("rmdir ziptemp /s /q>NUL") if( -e "ziptemp" );
+}
+
+sub CopyTestReportWithLog
+{
+ my ( $reportFileName, $refFiles ) = @_;
+
+ print("\nTrying to pair: $reportFileName\n") if( $optionDebug );
+
+ my $reportPath = GetPathDir( $reportFileName );
+
+ my $logFileName = "";
+
+#\ResultAndLogFiles_vod\22507.23325.1.4.25129-lab.net\TestReport.txt
+#\ResultAndLogFiles_vod\22507.23325.1.4.25130-lab.net\Fusion.txt
+# ^^^^^^^^^^^^^^^ matching part
+ # Find log file with about same path with the report.
+ while( 1 )
+ {
+ # Check the log files.
+ foreach $file ( @$refFiles )
+ {
+ $file =~ s/\//\\/g;
+ my $filename = GetPathFileName( $file );
+
+ if( $filename =~ m/$optionLogFileName/i )
+ {
+ if( index( $file, $reportPath ) == 0 )
+ {
+ $logFileName = $file;
+
+ print("PAIRED: \n") if( $optionDebug );
+ print("reportPath: $reportPath\n") if( $optionDebug );
+ print("report: $reportFileName\n") if( $optionDebug );
+ print("log : $logFileName\n") if( $optionDebug );
+
+ print("Report log pair: $logFileName\n") if( $optionShowMessages && !$optionDebug );
+ last;
+ }
+ }
+ }
+
+ last if( $logFileName ne "" );
+
+ # Remove all from last dot in the path.
+ my $pos = rindex( $reportPath, "." );
+ last if( $pos == -1 );
+ $reportPath = substr( $reportPath, 0, $pos );
+
+ # The first 4 numbers might be same with multiple reports and logs. Ignore file if match is not found before.
+ last if( rindex( $reportPath, "\\" ) == -1 );
+ my $dotstr = substr( $reportPath, rindex( $reportPath, "\\" )+1 );
+ last if( ! ( $dotstr =~ m/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ ) );
+ print( "DOT: $dotstr\n" ) if( $optionDebug );
+ }
+
+ if( $logFileName eq "" )
+ {
+ print("Could not find log file for: $reportFileName\n") if( $optionShowMessages );
+ }
+
+ my $dstReportFileName = "";
+ my $dstReportLogName = "";
+
+ # Find first available name for the report in current directory.
+ my $fileNum = 0;
+
+ my $filename = GetPathFileName( $reportFileName );
+
+ # Separate file's name and extension.
+ my $name = "";
+ my $ext = "";
+
+ my $pos = index($filename, ".");
+ return if( $pos == -1);
+
+ $ext = substr( $filename, $pos );
+ $name = substr( $filename, 0, $pos );
+
+ # Find free filename.
+ while( 1 )
+ {
+ $dstReportFileName = "$name" . "_" . $fileNum . $ext;
+ last if( ! -e "$dstReportFileName" );
+ $fileNum++;
+ if( $fileNum > 1000 )
+ {
+ die("Too many files to copy.");
+ }
+ }
+
+ if( $logFileName ne "" )
+ {
+ # Get new name for the log with same numbering.
+
+ $filename = GetPathFileName( $logFileName );
+
+ $pos = index($filename, ".");
+ return if( $pos == -1);
+
+ $ext = substr( $filename, $pos );
+ $name = substr( $filename, 0, $pos );
+
+ $dstLogFileName = "$name" . "_" . $fileNum . $ext;
+ die("Log filename already exists.") if( -e "$dstLogFileName" ); # Shouldn't happen.
+ }
+
+ # Copy the files.
+
+ push @globalTempFiles, $dstReportFileName;
+ push @globalTempFiles, $dstLogFileName;
+
+ print("Copying $reportFileName\n") if( $optionShowMessages );
+ print("Dest: $dstReportFileName\n") if( $optionShowMessages );
+
+ copy( $reportFileName, $dstReportFileName ) or die "Could not copy '$reportFileName' to '$dstReportFileName'\n";
+
+ if( $logFileName ne "" )
+ {
+ print("Copying $logFileName\n") if( $optionShowMessages );
+ print("Dest: $dstLogFileName\n") if( $optionShowMessages );
+ copy( $logFileName, $dstLogFileName ) or die "Could not copy '$logFileName' to '$dstLogFileName'\n";
+ }
+}
+
+#------------------------------------------------------------------------------------
+# ReadCaseList
+#
+#------------------------------------------------------------------------------------
+sub ReadCaseList
+{
+ my ($refList, $filename) = @_;
+
+ if( open(FILE_HANDLE, ".\\" . $filename) )
+ {
+ my @lines = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+ foreach $line (@lines)
+ {
+ my $caseId;
+
+ if($line =~ m/^case /i)
+ {
+ if($line =~ m/^case ET([0-9]+) /i)
+ {
+ $caseId = "ET" . $1;
+ }
+ else
+ {
+ $caseId = substr($line, 4);
+ }
+ RemoveWhiteSpaces(\$caseId);
+ push @$refList, $caseId;
+ }
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# IsCaseInCaseList
+#
+#------------------------------------------------------------------------------------
+sub IsCaseInCaseList
+{
+ my ($caseNameOrId) = @_;
+
+ return 1 if(scalar(@caseList) <= 0);
+
+ my $caseIdFromName = GetCaseIdFromName($caseNameOrId);
+
+ foreach $caseId (@caseList)
+ {
+ if($caseId eq $caseNameOrId)
+ {
+ return 1;
+ }
+ }
+
+ foreach $caseId (@caseList)
+ {
+ if($caseId eq $caseIdFromName)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#------------------------------------------------------------------------------------
+# FixExcelLogPaths
+#
+# Changes the paths on lines:
+#<Cell ss:StyleID="s60" ss:HRef="C:\Documents and Settings\senbom\Desktop\testcase_logs\testcase_logs\ET17099_4371843802.txt"><Data>
+# To:
+#<Cell ss:StyleID="s60" ss:HRef="testcase_logs\ET17099_4371843802.txt"><Data>
+#
+# Because the absolute path does not work in Excel.
+#
+#------------------------------------------------------------------------------------
+sub FixExcelLogPaths
+{
+ if( open(FILE_HANDLE, ".\\" . $optionFixFilename) )
+ {
+ my @lines = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ if(!open(FILE_HANDLE, ">" . $optionFixFilename) )
+ {
+ die("Could not write to file $file\n");
+ }
+
+ foreach my $line(@lines)
+ {
+ my $pos = index($line, "\\testcase_logs\\testcase_logs\\");
+ if($pos != -1)
+ {
+ my $start = rindex($line, "\"", $pos);
+ my $remstr = substr($line, $start+1, $pos-$start + length("\\testcase_logs") );
+
+ $line = substr( $line, 0, index($line, $remstr) ) .
+ substr( $line, index($line, $remstr) + length($remstr) );
+
+ }
+
+ print FILE_HANDLE ($line);
+
+ }
+ close(FILE_HANDLE);
+
+ print("Fixed paths in $optionFixFilename\n");
+ }
+ else
+ {
+ die("Coult not open file $optionFixFilename\n");
+ }
+}
+
+#------------------------------------------------------------------------------------
+# CalculateStats
+#------------------------------------------------------------------------------------
+sub CalculateStats
+{
+ $summaryCaseCount = scalar( @cases );
+ $summaryPassedCases = 0;
+ $summaryFailedCases = 0;
+ $summaryCrashedCases = 0;
+ $summaryTimeoutCases = 0;
+ $summaryPassRateTotal = 0;
+ $summaryPassRateRun = 0;
+ $summaryRunRate = 0;
+
+ foreach $case(@cases)
+ {
+ if(defined(@{$case}[$CASE_STATUS]))
+ {
+ my $status = @{$case}[$CASE_STATUS];
+
+ $summaryPassedCases++ if($status eq "PASSED");
+ $summaryFailedCases++ if($status eq "FAILED");
+ $summaryCrashedCases++ if($status eq "CRASHED");
+ }
+ }
+
+ my $runCases = $summaryPassedCases + $summaryFailedCases + $summaryCrashedCases;
+
+ $summaryPassRateTotal = $summaryPassedCases / $summaryCaseCount * 100;
+ $summaryPassRateRun = $summaryPassedCases / $runCases * 100;
+ $summaryRunRate = $runCases / $summaryCaseCount * 100;
+}
+
+#------------------------------------------------------------------------------------
+# SortCases
+#------------------------------------------------------------------------------------
+sub SortCases()
+{
+ $aprio = 0;
+ $bprio = 0;
+
+ #print @{$a}[$CASE_STATUS] . " - " . $a . " vs " . $b . " - " . @{$b}[$CASE_STATUS] . "\n";
+
+ if(@{$a}[$CASE_STATUS] eq "CRASHED") { $aprio = 5; }
+ elsif(@{$a}[$CASE_STATUS] eq "FAILED") { $aprio = 4; }
+ elsif(@{$a}[$CASE_STATUS] eq "PASSED") { $aprio = 3; }
+
+ if(@{$b}[$CASE_STATUS] eq "CRASHED") { $bprio = 5; }
+ elsif(@{$b}[$CASE_STATUS] eq "FAILED") { $bprio = 4; }
+ elsif(@{$b}[$CASE_STATUS] eq "PASSED") { $bprio = 3; }
+
+ if($aprio == $bprio)
+ {
+ return lc(@{$a}[$CASE_NAME]) cmp lc(@{$b}[$CASE_NAME]);
+ }
+
+ return $bprio cmp $aprio;
+}
+
+
+#------------------------------------------------------------------------------------
+# ShowHelp
+#------------------------------------------------------------------------------------
+sub ShowHelp {
+
+print <<USAGE_EOF;
+testdoc.pl
+
+Create folder to VaDo root folder for STIF results and copy this script and
+the results there. STIF CFG files are searched from . and .. from the script
+run folder. The STIF results can be either ATS results zips or multiple
+TestReport*.txt and fusion*.txt files as long as they have the same ending
+in the name. Script also parses the STIF testscripter logs it finds.
+
+Options:
+-i: STIF case will be included in the start of the case log
+-s: cases will be sorted by status
+-e: Shows extra information during the tool run
+-html: Case logs are generated in html format instead of text
+-logall: Logs are created for passed cases too.
+-nologs: Logs are not processed.
+-nosecuritytests: Security tests are not included in the reports.
+-nolivetvttests: Live TV tests are not included in the reports.
+-i: Test case from the CFG is included in the log file
+-file <file>: Only formats defined log file into html
+-runtimes: Result of the case will contain the case execution time in seconds.
+-good: If case has passed once it will be marked as passed no matter how many
+ times it has failed.
+-cfgsum: Prints summary info for cfgs: how many cases and how long the cfg did
+ take to execute.
+-finalize
+-fix if you save the file in Excel the log paths will come absolute and don't
+ work if moved to another directory. use this fix it.
+-caselist <file>: Only reports the cases in caselist.txt, see genrerun.pl for
+ file format.
+-logfile <file>: Sets filter for log filenames. Default is fusion.
+-slogs: Reads STIF testscripter logs instead of custom logs.
+These files will be generated:
+ test_cases.xml
+ test_cases_brief.xml
+ test_cases_notdocumented.txt
+
+Case specific log files are generated in testcase_logs directory and result
+file has links to them.
+
+USAGE_EOF
+
+ exit();
+
+};
+
+#------------------------------------------------------------------------------------
+# ReadReportLogs
+#
+# Parameters:
+# $fileName
+# $refLogLines
+#
+# Reads log file of specific TestReport.
+#
+# The function has two different behaviours:
+#
+# Filenames for test report and log must match. For example
+# if test report file is TestReport_XXX.txt then fusion_XXX.txt is read if found.
+#
+# If fileName is * then *fusion*.txt files will be read one by one and processed by function CheckCaseEntriesInLog()
+#------------------------------------------------------------------------------------
+sub ReadReportLogs
+{
+ my ($fileName, $refLogLines) = @_;
+
+ return if($optionNoLogs || $optionPrintCfgSummaries);
+
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ #default mask for logs
+ my $filemask = "^$optionLogFileName\.TXT";
+
+ #create file mask for logs if testreport.txt is in format: testreport_*.txt
+ if(index($fileName, "_") != -1)
+ {
+ my $spos = index($fileName, "_");
+ my $epos = rindex($fileName, ".");
+
+ $filemask = substr($fileName, $spos, $epos - $spos);
+ #print("filemask: $filemask\n");
+
+ #$filemask = "$optionLogFileName" . $filemask . "[a-z\-0-9_]*\.txt"; # this finds $optionLogFileName_xxx*.txt
+ $filemask = "$optionLogFileName" . $filemask . "\.txt"; # this finds only $optionLogFileName_xxx.txt
+ #print("filemask: $filemask\n");
+ #die();
+ }
+
+ my $processLogsHere = 0;
+
+ if($fileName eq "*")
+ {
+ $processLogsHere = 1;
+ $filemask = $optionLogFileName . "[a-z\-0-9_]*\.txt"
+ }
+
+ my $i;
+
+ #read the files into refLogLines array
+ foreach $file(@filelist)
+ {
+ #if($file =~ m/^$optionLogFileName[a-z0-9_]+\.TXT$/i or $file =~ m/^$optionLogFileName\.TXT$/i )
+ if($file =~ m/$filemask/i )
+ {
+ print("Reading log file: " . $file . ".");
+
+ if( open(FILE_HANDLE, ".\\" . $file) )
+ {
+ my @tempArray = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ FormatFasttraceTraces(\@tempArray);
+
+ if($processLogsHere)
+ {
+ FindAndMarkCaseEntriesInLog(\@tempArray, \@cases);
+
+ CheckCaseEntriesInLog(\@tempArray);
+ }
+ else
+ {
+ while(scalar(@tempArray) > 0)
+ {
+ push @$refLogLines, (shift(@tempArray));
+ }
+ }
+ }
+ }
+ }
+
+ FindAndMarkCaseEntriesInLog($refLogLines, \@cases);
+}
+
+#------------------------------------------------------------------------------------
+# GetReportLogFileNames
+#
+# Parameters:
+# $fileName
+# $refLogFiles
+#
+# Gets log filenames for specific testreport.
+#
+# The function has two different behaviours:
+#
+# Filenames for test report and log must match. For example
+# if test report file is TestReport_XXX.txt then $optionLogFileName_XXX.txt is read if found.
+#
+# If fileName is * then *$optionLogFileName*.txt files will be read one by one and processed by function CheckCaseEntriesInLog()
+#------------------------------------------------------------------------------------
+sub GetReportLogFileNames
+{
+ my ($fileName, $refLogFiles) = @_;
+
+ return if($optionNoLogs || $optionPrintCfgSummaries);
+
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ #default mask for logs
+ my $filemask = "^$optionLogFileName\.TXT";
+
+ #create file mask for logs if testreport.txt is in format: testreport_*.txt
+ if(index($fileName, "_") != -1)
+ {
+ my $spos = index($fileName, "_");
+ my $epos = rindex($fileName, ".");
+
+ $filemask = substr($fileName, $spos, $epos - $spos);
+ $filemask = "$optionLogFileName" . $filemask . "\.txt"; # this finds only $optionLogFileName_xxx.txt
+ }
+
+ if($fileName eq "*")
+ {
+ $filemask = $optionLogFileName . "[a-z0-9_]*\.txt"
+ }
+
+ foreach $file(@filelist)
+ {
+ if($file =~ m/$filemask/i )
+ {
+ push @$refLogFiles, $file;
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# FindAndMarkCaseEntriesInLog
+#
+# Parameters:
+# $refLogLines
+#
+# Searches for case entries in the log and if found then marks the case in @cases array
+#------------------------------------------------------------------------------------
+sub FindAndMarkCaseEntriesInLog
+{
+ my ($refLogLines, $refCases) = @_;
+
+ my $line;
+
+ print(" - Searching case start entries from log\n") if($optionShowMessages);
+
+ my $startLineIndex = 0;
+
+ # scan the log thru and mark if there's log start entries
+ for( my $i = 0; $i < scalar(@$refLogLines); $i++ )
+ {
+ my $line = @$refLogLines[$i];
+
+ my $caseStartInLog = 0;
+
+ my $caseId = "";
+
+ if($line =~ m/>>> Case start:/i)
+ {
+ $startLineIndex = $i;
+ $caseStartInLog = 1;
+ $caseId = substr($line, index($line, ">>> Case start:") + length(">>> Case start:"));
+ print("Found case start: $caseId\n") if($optionShowMessages);
+ }
+
+ if($caseStartInLog)
+ {
+ RemoveWhiteSpaces(\$caseId);
+
+ my $refCase = GetCase($caseId, $refCases);
+
+ if(defined($refCase))
+ {
+ @$refCase[$CASE_CHECK_RESULT_LOG_FILE] = 1;
+ @$refCase[$CASE_ENTRY_LOG_START] = $startLineIndex;
+ }
+ else
+ {
+ print("Case start in log found: $caseId\n") if($optionShowMessages);
+ print("ERROR! The start in log found but case is not found from report or cfg.\n");
+ }
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# FormatFasttraceTraces
+#
+# Parameters:
+# $refLogArray
+#------------------------------------------------------------------------------------
+sub FormatFasttraceTraces
+{
+ my ($refLogArray) = @_;
+
+ my $ftDebug = 0;
+
+ # strip fasttrace logging text from the start of lines
+ #[13:58:17.234] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:$optionLogFileName.TXT 09/10/2006¿1:57:08¿C$optionLogFileName::CheckIsPluginRunning
+
+ my $stripFasttrace = 0;
+ # find first occurance of Musti message, remove anything before that
+ my $i;
+
+ for($i= 0; $i<100; $i++)
+ {
+ if(defined(@$refLogArray[$i]))
+ {
+ if(@$refLogArray[$i] =~ m/MCU_ASCII_PRINTF/i)
+ {
+ $stripFasttrace = 1;
+ last;
+ }
+ }
+ }
+
+ print("fasttrace: end $i, strip: $stripFasttrace\n") if($ftDebug);
+
+ #remove the fasttrace specific lines
+ print("fasttrace: lines before: " . scalar(@$refLogArray) . "\n") if($ftDebug);
+
+ splice(@$refLogArray, 0, $i) if($stripFasttrace);
+
+ return if(!$stripFasttrace);
+
+ print("fasttrace: lines " . scalar(@$refLogArray) . "\n") if($ftDebug);
+
+ #remove the fasttrace line startings and change format of STIF messages
+
+ for($i = 0; $i<scalar(@$refLogArray); $i++)
+ {
+ #before: [14:38:40.641] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:TestCase [ET1024 Sort IapList when it has no IAPs] finished with verdict[0]
+ #after: [14:38:40.641] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:$optionLogFileName.TXT 18/10/2006¿2:37:37¿TestCase [ET1024 Sort IapList when it has no IAPs] finished with verdict[0]
+ if(@$refLogArray[$i] =~ m/TestCase \[([[a-z0-9_]+) ($regexpCaseName)\] finished with verdict\[[-]?([0-9]+)/i)
+ {
+ #die(@$refLogArray[$i]);
+
+ my $startStr = substr(@$refLogArray[$i], 0, index(@$refLogArray[$i], "TestCase"));
+ my $endStr = substr(@$refLogArray[$i], index(@$refLogArray[$i], "TestCase"));
+
+ my $timeStr = FasttraceLogFindIptvTraceTime($refLogArray, $i);
+
+ @$refLogArray[$i] = $startStr . "$optionLogFileName.TXT " . $timeStr . "\t" . $endStr;
+
+ print("fasttrace: " . @$refLogArray[$i] . "\n") if($ftDebug);
+
+ #print("\n\n" . $startStr . "'\n$optionLogFileName.TXT \n" . $timeStr . "'\n" . $endStr . "'\n" );
+ #die();
+ }
+
+ #change the lines where is STIF message saying starting testcase to "$optionLogFileName.TXT <TIME> >>> Case start: <CASEID>" format, otherwise it will be not be recognized later
+ if(@$refLogArray[$i] =~ m/Starting testcase \[([[a-z0-9_]+) ($regexpCaseName)\]/i)
+ {
+ print("debug: " . @$refLogArray[$i] . "\n");
+ @$refLogArray[$i] = substr(@$refLogArray[$i], 0, index(@$refLogArray[$i], "Starting testcase"));
+
+ my $timeStr = FasttraceLogFindIptvTraceTime($refLogArray, $i);
+
+ @$refLogArray[$i] .= "$optionLogFileName.TXT $timeStr\t>>> Case start: $1" . "\r\n";
+
+ print("fasttrace: '" . @$refLogArray[$i] . "'\n") if($ftDebug);
+
+ #@$refLogArray[$i] = "[14:38:37.953] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:$optionLogFileName.TXT 18/10/2006\t2:37:34\t>>> Case start: $1";
+ }
+
+ if(@$refLogArray[$i] =~ m/channel\:[0-9a-z]+; msg:$optionLogFileName.TXT [0-9]+\/[0-9]+\/[0-9]+/i)
+ {
+ @$refLogArray[$i] = substr(@$refLogArray[$i], index(@$refLogArray[$i], "msg:$optionLogFileName.TXT") + length("msg:$optionLogFileName.TXT") + 1);
+
+ #replace fasttrace tab chars
+ @$refLogArray[$i] =~ s/¿/\t/g;
+ #print(@$refLogArray[$i]);
+
+ }
+ else
+ {
+ # if there's no match then this is not a trace for $optionLogFileName
+ splice(@$refLogArray, $i, 1);
+ $i--;
+ }
+ }
+}
+
+
+#------------------------------------------------------------------------------------
+# FastTraceLogFindIptvTraceTime
+#
+# Parameters:
+# $refLines: reference to array of the log line
+# $startLine: line where to start looking for
+#
+# Finds next time stamp of Iptvengine from Fasttrace log
+#------------------------------------------------------------------------------------
+sub FasttraceLogFindIptvTraceTime
+{
+ my ($refLines, $startLine) = @_;
+
+ #find next trace of iptvengine and get the time and date
+ my $timeStr = "";
+ for(my $e = $startLine+1; $e < scalar(@$refLines); $e++)
+ {
+ if(@$refLines[$e] =~m/msg:$optionLogFileName.TXT/)
+ {
+ my $line = @$refLines[$e];
+ #remove the fasttrace trace from line start, we don't want it's time
+ $line = substr($line, index($line, "msg:$optionLogFileName.TXT"));
+
+ if($line =~ m/([0-9]+\/[0-9]+\/[0-9]+)/i)
+ {
+ $timeStr .= $1 . "\t";
+ }
+
+ if($line =~ m/([0-9]+:[0-9]+:[0-9]+)/i)
+ {
+ $timeStr .= $1;
+ }
+ last if($timeStr ne "");
+ }
+ }
+
+ return $timeStr;
+}
+
+#------------------------------------------------------------------------------------
+# ReportNotDocumentedCases
+#
+# Parameters:
+# $file
+#
+# Writes the @notDocumentedCases array into a file
+#------------------------------------------------------------------------------------
+sub ReportNotDocumentedCases
+{
+ my ($file) = @_;
+
+ if(scalar(@notDocumentedCases) > 0)
+ {
+ if(!open(FILE_HANDLE, ">" . $file) )
+ {
+ print("ERROR! Could not open file '" . $file . "'\n");
+ } else {
+ print FILE_HANDLE ( @notDocumentedCases );
+ close(FILE_HANDLE);
+ print("Report " . $NOT_DOCUMENTED_CASES_FILE . " written.\n");
+ }
+ } else
+ {
+ print("All cases are documented.");
+ }
+}
+
+#------------------------------------------------------------------------------------
+# ReadTestReports
+#
+# Reads TestReportXX.txt files from the current directory and updates the cases with the results.
+# Reads also logs for the report and creates case specific logs.
+#------------------------------------------------------------------------------------
+sub ReadTestReports
+{
+ # Read filelist of current directory
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ my $readSomething = 0;
+
+ my @testScripterLogLines;
+ ReadTestScripterLogs( \@testScripterLogLines );
+
+ # Read reports and logs in the current directory
+ foreach $file(@filelist)
+ {
+ next if( -d $file or $file eq "." or $file eq "..");
+
+ # Read results STIF testreport
+ if($file =~ m/^TestReport[a-z\-0-9_]+\.txt$/i or $file =~ m/^TestReport\.txt$/i )
+ {
+ if($optionShowMessages) { print("***************************\n"); };
+ print("Report file: " . $file . "\n");
+
+ my @logFiles;
+ my @caseResults;
+
+ ReadTestRunInfoFromStifReport( $file, \@caseResults, \@logFiles );
+ ParseResultsAndLogs( \@caseResults, \@logFiles, \@testScripterLogLines );
+
+ undef(@logFiles);
+ undef(@caseResults);
+
+ $readSomething++;
+ }
+ }
+
+ return if($optionPrintCfgSummaries);
+
+ # No testreports found. Read all logs and parse them.
+ if($readSomething == 0)
+ {
+ print("\nNo test reports found in the current directory. Trying to read all the logs.\n");
+
+ my @logFileLines;
+
+ ReadReportLogs("*", \@logFileLines);
+
+ if( scalar( @logFileLines ) > 0 )
+ {
+ $readSomething = 1;
+ }
+
+ undef(@logFileLines);
+ }
+
+ return $readSomething;
+}
+
+#------------------------------------------------------------------------------------
+# ReadTestReportsAlt
+#
+# Every test report is one run and those should have as much same cases as possible.
+#------------------------------------------------------------------------------------
+sub ReadTestReportsAlt
+{
+ my ($refRuns) = @_;
+
+ # Read filelist of current directory
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ my @runs;
+
+ # Read reports and logs in the current directory
+ foreach $file(@filelist)
+ {
+ if($file eq "." or $file eq "..") {next};
+
+ # Read results STIF testreport
+ if($file =~ m/^TestReport[a-z0-9_]+\.txt$/i or $file =~ m/^TestReport\.txt$/i )
+ {
+ if($optionShowMessages) { print("***************************\n"); };
+ print("Report file: " . $file . "\n");
+
+ # Store report filename, run date and then cases into array
+
+ # Read date from report
+ if( !open(FILE_HANDLE, $file) ) {
+ print("ERROR! Could not open file '" . $file . "'\n");
+ return;
+ }
+ my @array = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ #Monday 25th August 2008
+ my @pieces = split(' ', $array[1]);
+
+ $pieces[1] =~ s/st//;
+ $pieces[1] =~ s/nd//;
+ $pieces[1] =~ s/rd//;
+ $pieces[1] =~ s/th//;
+
+ undef(@array);
+
+ my @runInfo;
+ $runInfo[0] = $file;
+ $runInfo[1] = substr( $pieces[0], 0, 3 ) . " " . $pieces[1] . " " . substr( $pieces[2], 0, 3 );
+
+ my @runResults;
+ my @logFiles;
+ ReadTestRunInfoFromStifReport($file, \@runResults, \@logFiles );
+ $runInfo[2] = \@runResults;
+
+ push @$refRuns, \@runInfo;
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# ReadTestScripterLogs
+#------------------------------------------------------------------------------------
+sub ReadTestScripterLogs
+{
+ my ( $refLogLines ) = @_;
+
+ return if($optionNoLogs || $optionPrintCfgSummaries);
+
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ foreach $file(@filelist)
+ {
+ if($file =~ m/^testscripter[a-z0-9_]+.txt/i )
+ {
+ print("Reading scripter log: $file\n") if( $optionDebug );
+ if( open(FILE_HANDLE, $file) )
+ {
+ my @tempArray = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ while(scalar(@tempArray) > 0)
+ {
+ push @$refLogLines, ( shift( @tempArray ) );
+ }
+ undef(@tempArray);
+ }
+ else
+ {
+ print("ERROR: Could not open the log file: $file!\n");
+ }
+ }
+ else
+ {
+ print("Not a scripter log: $file\n") if( $optionDebug );
+ }
+ }
+}
+
+
+#------------------------------------------------------------------------------------
+# ReadTestReportDates
+#
+# Reads the date from each testreport in current directory
+#------------------------------------------------------------------------------------
+sub ReadTestReportDates
+{
+ my ($refDates) = @_;
+
+ # Read filelist of current directory
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ my @runs;
+
+ # Read reports and logs in the current directory
+ foreach $file(@filelist)
+ {
+ if($file eq "." or $file eq "..") {next};
+
+ # Read results STIF testreport
+ if($file =~ m/^TestReport[a-z0-9_]+\.txt$/i or $file =~ m/^TestReport\.txt$/i )
+ {
+ my @fileDate;
+ $fileDate[0] = $file;
+
+ if( !open(FILE_HANDLE, $file) ) {
+ print("ERROR! Could not open file '" . $file . "'\n");
+ return;
+ }
+ my @array = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ #Monday 25th August 2008
+ my @pieces = split(' ', $array[1]);
+
+ $pieces[1] =~ s/st//;
+ $pieces[1] =~ s/nd//;
+ $pieces[1] =~ s/rd//;
+ $pieces[1] =~ s/th//;
+
+ $fileDate[1] = substr( $pieces[0], 0, 3 ) . " " . $pieces[1] . " " . substr( $pieces[2], 0, 3 );
+
+ undef(@array);
+
+ push @$refDates, \@fileDate;
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# ParseTimeFromLine
+#
+#------------------------------------------------------------------------------------
+sub ParseTimeFromLine
+{
+ my ($line) = @_;
+
+ my $timestr = "";
+
+ if($line =~ m/([0-9]+)(:[0-9]+:[0-9]+\,[0-9]*)/i || $line =~ m/([0-9]+)(:[0-9]+:[0-9]+\.[0-9]*)/i)
+ {
+ $timestr = "" . $1 . $2;
+ if($1 > 12)
+ {
+ $timestr = "" . ($1-12) . $2;
+ }
+ }
+
+ return $timestr;
+}
+
+#------------------------------------------------------------------------------------
+# ReadTestRunInfoFromStifReport
+#
+# Parameters:
+# $file, the testreport
+# $refCaseResults, results for all cases of the testreport
+# $refLogFiles, filenames for the log files of the testreport
+#------------------------------------------------------------------------------------
+sub ReadTestRunInfoFromStifReport
+{
+ my ($file, $refCaseResults, $refLogFiles) = @_;
+
+ if( !open(FILE_HANDLE, $file) ) {
+ print("ERROR! Could not open file '" . $file . "'\n");
+ return;
+ }
+ my @array = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ # Get log files for the report
+ GetReportLogFileNames($file, $refLogFiles);
+
+ my $index = 0;
+ my $line = "";
+
+ for(my $i = 0; $i < scalar(@array); $i++)
+ {
+ $line = $array[$i];
+ RemoveWhiteSpaces(\$line);
+
+#[testscripter_iptvservicetest][C:\TestFramework\IptvServiceTest.cfg][10] Title:[ET9009 Set id]
+#[testscripter][c:\testframework\iptvvoddlapitest2.cfg][2] Title:[ET12100 Purchase]
+# StartTime: 8:54:23.5565 PM, EndTime: 8:54:24.3471 PM
+# Result: 0 [] ==> PASSED
+# Info: xxx
+
+ # found a start of a result
+ #[1] Title:[ET1000 Add multiple Iaps]
+ my $cfgFile = "";
+
+ if($line =~ m/([a-z_0-9.]+)\]\[[0-9]+\][ ]+Title:\[/i)
+ {
+ $cfgFile = $1;
+ if($optionShowMessages) { print(" - Cfg: $cfgFile\n"); };
+
+ for( my $e = 0; $e < scalar( @gCfgFiles ); $e++ )
+ {
+ if( $gCfgFiles[$e] =~ m/$cfgFile/i )
+ {
+ my $caseCount = ParseCfg( $gCfgFiles[$e] );
+ $gCfgFiles[$e] = ""; # We don't want to read it again.
+ }
+ }
+ }
+
+ if($line =~ m/\[[0-9]+\][ ]+Title:\[($regexpCaseName)\]$/i)
+ {
+ if($optionShowMessages) { print(" - Case: " . $1 . "\n"); };
+
+ #get the case name
+ my $caseName = $1;
+ my $caseId = GetCaseIdFromName($caseName);
+ my $caseRunTime = CountCaseRunTime($array[$i+1]);
+
+ # Save case report lines for later use
+ my $caseLine1 = $array[$i];
+ my $caseLine2 = $array[$i+1];
+ my $caseLine3 = $array[$i+2];
+
+ # Read the case result
+
+ # StartTime: 3:54:10.1670 PM, EndTime: 3:54:23.8226 PM
+ $line = $array[$i+2];
+ RemoveWhiteSpaces(\$line);
+
+ my $info = "";
+ my $result = "N/A";
+ my $status = "$caseDefaultStatus";
+ my $reason = "";
+
+ # Result: 0 [] ==> PASSED / something
+ if($line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[[\w]*\][ ]==>[ ]([\w ]+)$/i)
+ {
+ $result = $1;
+ $status = $2;
+ }
+ # Result: -2 [CTestRunner::RunError [CTestRunner::ExecuteCommandL returned error]] ==> FAILED
+ # Result: -2 [CTestRunner::ExecuteCommandL returned error] ==> FAILED
+ elsif($line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[([\w: ]+)\][ ]==>[ ]([\w]+)$/i or
+ $line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[[\w: ]+\[([\w: ]+)\]\][ ]==>[ ]([\w]+)$/i )
+ {
+ $result = $1;
+ $status = $3;
+ $reason = $2;
+ }
+
+ #CaseExecutionResult: Test case execution fails with -15
+ elsif($line =~ m/^CaseExecutionResult:[ ]Test case execution fails with ([-]*[0-9]+)$/i)
+ {
+ $result = $1;
+ $status = "FAILED";
+ $reason = "Test case execution failed.";
+ }
+
+ # CaseExecutionResult: Leave during case: with -4
+ elsif($line =~ m/^CaseExecutionResult:[ ]Leave during case: with ([-]*[0-9]+)$/i)
+ {
+ $result = $1;
+ $status = "FAILED";
+ $reason = "Leave during case";
+ }
+ #CaseExecutionResult: Crash reason:Error in test ca with 69
+ #CaseExecutionResult: Crash reason:IptvEngineServer with 13
+ elsif($line =~ m/^CaseExecutionResult:[ ]Crash reason:([\w_ \-]+)[ ]with[ ]([-]*[0-9]+)$/i)
+ {
+ $result = $2;
+ $status = "CRASHED";
+ $reason = $1;
+ }
+
+ # Result: -2 [Crash reason:KERN-EXEC] ==> FAILED
+ elsif($line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[Crash reason:([\w\-:\. ]+)\] ==> ([\w]+)/i)
+ {
+ $result = $1;
+ $status = "CRASHED";
+ $reason = $2;
+ }
+
+ # CaseExecutionResult: TestModule loading fails, cannot connect to the TestModule with -2
+ elsif($line =~ m/^CaseExecutionResult: TestModule loading fails, cannot connect to the TestModule with ([-]*[0-9]+)/i)
+ {
+ $result = $1;
+ $status = "FAILED";
+ $reason = "Test module loading failed.";
+ }
+ else
+ {
+ print("Error while parsing case result line: " . $line . "\n");
+ }
+
+ $line = $array[$i+3];
+ RemoveWhiteSpaces(\$line);
+
+ # Info: xxx
+ if($line =~ m/^Info:/i)
+ {
+ $info = substr($line, 5) . " / ";
+ RemoveWhiteSpaces(\$info);
+ $info .= " ";
+ }
+
+ my @caseResult;
+
+ $caseResult[$CASE_CFG_FILE] = $cfgFile;
+ $caseResult[$CASE_NAME] = $caseName;
+ $caseResult[$CASE_ID] = $caseId;
+ $caseResult[$CASE_RUN_TIME_SECONDS] = $caseRunTime;
+ $caseResult[$CASE_NOTE] = $info;
+ $caseResult[$CASE_RESULT] = $result;
+ $caseResult[$CASE_STATUS] = $status;
+ $caseResult[$CASE_REASON] = $reason;
+ $caseResult[$CASE_REPORTLINE1] = $caseLine1;
+ $caseResult[$CASE_REPORTLINE2] = $caseLine2;
+ $caseResult[$CASE_REPORTLINE3] = $caseLine3;
+
+ push @$refCaseResults, \@caseResult;
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# ParseResultsAndLogs
+#
+# Parameters:
+# $refCaseResults
+# $refLogFiles
+# $refTestScripterLogLines
+#------------------------------------------------------------------------------------
+sub ParseResultsAndLogs
+{
+ my ($refCaseResults, $refLogFiles, $refTestScripterLogLines) = @_;
+
+ my @logLines;
+
+ # Read log files
+ foreach $file (@$refLogFiles)
+ {
+ $file =~ s/\//\\/g;
+
+ print("Reading log file: " . $file . " .. ");
+
+ if( open(FILE_HANDLE, $file) )
+ {
+ my @tempArray = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ FormatFasttraceTraces(\@tempArray);
+ print " .. ";
+
+ while(scalar(@tempArray) > 0)
+ {
+ push @logLines, (shift(@tempArray));
+ }
+ print " done.\n";
+
+ undef(@tempArray);
+ }
+ else
+ {
+ print("ERROR: Could not open the log file: $file!\n");
+ }
+ }
+
+ FindAndMarkCaseEntriesInLog( \@logLines, $refCaseResults );
+
+ my @caseSpecificLogs;
+
+ foreach $refCaseResult (@$refCaseResults)
+ {
+ my $cfgFile = @$refCaseResult[$CASE_CFG_FILE];
+ my $caseName = @$refCaseResult[$CASE_NAME];
+ my $caseId = @$refCaseResult[$CASE_ID];
+ my $caseRunTime = @$refCaseResult[$CASE_RUN_TIME_SECONDS];
+ my $info = @$refCaseResult[$CASE_NOTE];
+ my $result = @$refCaseResult[$CASE_RESULT];
+ my $status = @$refCaseResult[$CASE_STATUS];
+ my $reason = @$refCaseResult[$CASE_REASON];
+ my $reportLine1 = @$refCaseResult[$CASE_REPORTLINE1];
+ my $reportLine2 = @$refCaseResult[$CASE_REPORTLINE2];
+ my $reportLine3 = @$refCaseResult[$CASE_REPORTLINE3];
+
+ if($optionShowMessages) { print(" - Case: " . $caseName . "\n"); };
+
+ # Create case specific log into the log directory
+ my $caseLogFile = GetCaseField($caseId, $CASE_LOG_FILE);
+ my $caseScripterLogFile = GetCaseField($caseId, $CASE_LOG_FILE_SCRIPTER);
+ my $refCaseDesc = GetCaseDesc($caseId);
+
+ $caseLogFile = GetFileNameForCaseLog( $reportLine1, $reportLine2, $reportLine3 );
+ $caseScripterLogFile = GetFileNameForCaseLog( $reportLine1, $reportLine2, $reportLine3, "_scripter" );
+
+ if( -e $caseLogFile )
+ {
+ unlink ( $caseLogFile );
+ }
+
+ if( -e $caseScripterLogFile )
+ {
+ unlink ( $caseScripterLogFile );
+ }
+
+ my @logInfo;
+ $logInfo[0] = $caseLogFile;
+ if( defined( @$refCaseResult[$CASE_CHECK_RESULT_LOG_FILE] ) )
+ {
+ # Case start entry trace was found from log.
+ $logInfo[1] = @$refCaseResult[$CASE_ENTRY_LOG_START];
+ }
+ else
+ {
+ $logInfo[1] = -1;
+ }
+ $logInfo[2] = $reportLine1;
+ $logInfo[3] = $reportLine2;
+ $logInfo[4] = $reportLine3;
+ $logInfo[5] = $refCaseDesc;
+ $logInfo[6] = $caseScripterLogFile;
+ push @caseSpecificLogs, \@logInfo;
+
+ # Update case
+ my $refCase = GetCase($caseId, \@cases);
+ if(!defined($refCase))
+ {
+ $refCase = GetCaseByNameOnly($caseName);
+ }
+
+ if(defined($refCase))
+ {
+ UpdateCase($refCase, $caseLogFile, $caseScripterLogFile, $result, $status, $info, $reason, $caseRunTime);
+ }
+ else
+ {
+ # Case doesn't exist yet, add it.
+ my @case;
+ $case[$CASE_NAME] = $caseName;
+ $case[$CASE_ID] = $caseId;
+ $case[$CASE_RUN_TIMES] = 0;
+ $case[$CASE_CRASHED] = 0;
+ $case[$CASE_FAILED] = 0;
+ $case[$CASE_PASSED] = 0;
+ $case[$CASE_STATUS] = "$caseDefaultStatus";
+ $case[$CASE_PURPOSE] = "N/A";
+ $case[$CASE_MEANS] = "N/A";
+ $case[$CASE_REQUIRED_SETTINGS] = "N/A";
+ $case[$CASE_RELATED_REQUIREMENTS] = "N/A";
+ $case[$CASE_VERIFICATION] = "N/A";
+ $case[$CASE_NOTE] = "N/A";
+ $case[$CASE_REASON] = "";
+ $case[$CASE_RESULT] = "";
+ $case[$CASE_LOG_FILE] = "";
+ $case[$CASE_LOG_FILE_SCRIPTER] = "";
+ $case[$CASE_CHECK_RESULT_LOG_FILE] = 0;
+ $case[$CASE_CFG_FILE] = $cfgFile;
+ $case[$CASE_RUN_TIME_SECONDS] = 0;
+
+ $refCase = GetCaseByNameOnly($caseName);
+
+ UpdateCase(\@case, $caseLogFile, $caseScripterLogFile, $result, $status, $info, $reason, $caseRunTime);
+
+ # Insert case after other cases from same CFG, if any.
+
+ my $indexToInsert = -1;
+
+ for( my $i = 0; $i < scalar(@cases); $i++ )
+ {
+ my $case = $cases[$i];
+
+ if( defined(@$case[$CASE_CFG_FILE]) )
+ {
+ if( @$case[$CASE_CFG_FILE] eq $cfgFile )
+ {
+ $indexToInsert = $i;
+ }
+ }
+ }
+
+ if( $indexToInsert == -1 )
+ {
+ push @cases, [ @case ];
+ }
+ else
+ {
+ splice @cases, $indexToInsert+1, 0, [ @case ];
+ }
+ }
+ }
+
+ my $caseCount = scalar( @$refCaseResults );
+
+ my @testScripterLogCaseLocations;
+ PrepareTestScripterLogs( $refTestScripterLogLines, \@testScripterLogCaseLocations );
+ WriteCaseSpecificScripterLogs( \@caseSpecificLogs, $refTestScripterLogLines, \@testScripterLogCaseLocations );
+ WriteCaseSpecificLogs( \@caseSpecificLogs, $caseCount, \@logLines );
+
+ if($caseCount >= 10 && $optionShowMessages == 0)
+ {
+ print("\n"); #line break for the progress bar
+ }
+ elsif($optionShowMessages == 0)
+ {
+ print("##########\n"); # fake it
+ }
+
+ undef(@logLines);
+}
+
+#------------------------------------------------------------------------------------
+# WriteCaseSpecificLogs
+#
+# Parameters:
+# $refCaseSpecificLogs
+# $caseCount
+# $refLogLines
+#------------------------------------------------------------------------------------
+sub WriteCaseSpecificLogs
+{
+ my ($refCaseSpecificLogs, $caseCount, $refLogLines ) = @_;
+
+ my $caseLogProgress = 0;
+
+ foreach my $refLogInfo ( @$refCaseSpecificLogs )
+ {
+ #@logInfo[1] = @$refCaseResult[$CASE_ENTRY_LOG_START];
+
+ my $caseLogFile = @$refLogInfo[0];
+ my $reportLine1 = @$refLogInfo[2];
+ my $reportLine2 = @$refLogInfo[3];
+ my $reportLine3 = @$refLogInfo[4];
+ my $refCaseDesc = @$refLogInfo[5];
+
+ my $logWritten = 0;
+ if( @$refLogInfo[1] != -1 )
+ {
+ # Case start entry trace found from log files.
+ $logWritten = WriteCaseLogFromEntry($caseLogFile, $refLogLines, @$refLogInfo[1], $reportLine1, $reportLine2, $reportLine3);
+ }
+
+ if( !$logWritten )
+ {
+ # Use case start and end times to write case specific log.
+ WriteCaseLog($caseLogFile, $refLogLines, $refCaseDesc, $reportLine1, $reportLine2, $reportLine3);
+ }
+
+ # Show simple progress bar
+ if($caseCount >= 10 && $optionShowMessages == 0)
+ {
+ $caseLogProgress++;
+ if($caseLogProgress > $caseCount/10)
+ {
+ $caseLogProgress = 0;
+ print("#");
+ }
+ }
+ }
+
+ if($caseCount >= 10 && $optionShowMessages == 0)
+ {
+ print("\n"); #line break for the progress bar
+ }
+ elsif($optionShowMessages == 0)
+ {
+ print("##########\n"); # fake it
+ }
+}
+
+#------------------------------------------------------------------------------------
+# PrepareTestScripterLogs
+#
+# Parameters:
+# $refTestScripterLogLines
+# $refTestScripterLogCaseLocations
+#------------------------------------------------------------------------------------
+sub PrepareTestScripterLogs
+{
+ my ($refTestScripterLogLines, $refTestScripterLogCaseLocations ) = @_;
+
+ for( my $i = 0; $i < scalar(@$refTestScripterLogLines); $i++ )
+ {
+ my $line = @$refTestScripterLogLines[$i];
+
+ if( $line =~ m/RunTest:/ )
+ {
+ push @$refTestScripterLogCaseLocations, ( $i );
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# WriteCaseSpecificScripterLogs
+#
+# Parameters:
+# $refLogFiles
+# $refCaseResults
+# $refTestScripterLogCaseLocations
+#------------------------------------------------------------------------------------
+sub WriteCaseSpecificScripterLogs
+{
+ my ($refCaseSpecificLogs, $refScripterLogLines, $refTestScripterLogCaseLocations ) = @_;
+
+ foreach my $refLogInfo ( @$refCaseSpecificLogs )
+ {
+ my $caseLogFile = @$refLogInfo[6];
+ my $reportLine1 = @$refLogInfo[2];
+ my $reportLine2 = @$refLogInfo[3];
+ my $reportLine3 = @$refLogInfo[4];
+ my $refCaseDesc = @$refLogInfo[5];
+
+ WriteCaseLogFromTestScripterLogs( $caseLogFile, $refScripterLogLines, $refTestScripterLogCaseLocations, $refCaseDesc, $reportLine1, $reportLine2, $reportLine3);
+ }
+}
+
+#------------------------------------------------------------------------------------
+# WriteCaseLogFromTestScripterLogs
+#
+#------------------------------------------------------------------------------------
+sub WriteCaseLogFromTestScripterLogs
+{
+ my ( $caseLogFile, $refLogLines, $refTestScripterLogCaseLocations, $refCaseDesc, $line1, $line2, $line3 ) = @_;
+
+ print("### WriteCaseLogFromTestScripterLogs") if( $optionDebug );
+
+ # Don't generate log files if we only print summary
+ if($optionPrintCfgSummaries)
+ {
+ return;
+ }
+
+ RemoveWhiteSpaces(\$line1);
+ RemoveWhiteSpaces(\$line2);
+ RemoveWhiteSpaces(\$line3);
+
+ my $lineBreak = "\n";
+ $lineBreak = "<br>\n" if($optionHtml);
+
+ my $caseName = "";
+
+ if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+$regexpCaseName)\]$/i)
+ {
+ #"' ultraedit
+ $caseName = $1;
+ print(" Writing scripter log for: $caseName.\n") if($optionShowMessages);
+ }
+ else
+ {
+ return;
+ }
+
+ # Write header for case
+
+ my @writeArray;
+
+ # split the first line
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+ push @writeArray, ( substr($line1, 0, index($line1, "Title:")) . $lineBreak );
+ push @writeArray, ( substr($line1, index($line1, "Title:")) . $lineBreak );
+ my $title = substr($line1, index($line1, "Title:"));
+
+ #($line1 . "\n");
+ push @writeArray, ($line2 . $lineBreak);
+ push @writeArray, ($line3 . $lineBreak);
+ push @writeArray, ("\n");
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+
+ # Include the script for the case in the file?
+
+ if($optionCaseIncludedInLog)
+ {
+ foreach $linexxx (@{$refCaseDesc})
+ {
+ push @writeArray, ("$linexxx");
+ push @writeArray, ($lineBreak) if($optionHtml);
+ }
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+ push @writeArray, ("\n");
+ }
+
+ # Create log directory
+
+ if ( !(-e "testcase_logs") )
+ {
+ mkdir("testcase_logs");
+ }
+
+ if ( !(-e "$caseLogOutDir") )
+ {
+ mkdir($caseLogOutDir, 0755);
+ }
+
+ # Find start and end lines for the case.
+ my $startLine = -1;
+ my $endLine = -1;
+
+ my $caseNameRegexp = $caseName;
+ $caseNameRegexp =~s/\)/\\\)/;
+ $caseNameRegexp =~s/\(/\\\(/;
+
+ # Try to find case start from cached locations.
+ foreach my $lineNum ( @$refTestScripterLogCaseLocations )
+ {
+ if( @$refLogLines[$lineNum] =~ m/RunTest: $caseNameRegexp/ )
+ {
+ print(" - found cached start: $lineNum") if( $optionDebug );
+ $startLine = $lineNum;
+ last;
+ }
+ }
+
+ for( my $i = $startLine; $i < scalar(@$refLogLines); $i++ )
+ {
+ $i++ if( $i < 0 );
+
+ my $line = @$refLogLines[$i];
+
+ next if( !defined $line );
+
+ # Case start was not found from cached locations, find it as we go thru the lines.
+ if( $startLine == -1 )
+ {
+ if( $line =~ m/RunTest: $caseNameRegexp/ )
+ {
+ print(" - found start: $line") if( $optionDebug );
+ $startLine = $i;
+ }
+ }
+ else
+ {
+ if( $line =~ m/\*\*\*Testcase [a-z]+\*\*\*/i )
+ {
+ print(" - found end: $line") if( $optionDebug );
+ $endLine = $i + 1;
+ last;
+ }
+ }
+ }
+
+ if( $startLine == -1 || $endLine == -1 )
+ {
+ return;
+ }
+
+ # Write the log file
+
+ my $fileMode = ">>";
+
+ print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);
+
+ if( open(FILE_HANDLE, $fileMode . $caseLogFile) )
+ {
+ if($optionHtml)
+ {
+ print FILE_HANDLE (
+ "<html>\n" .
+ "<head>\n" .
+ "<title>$title</title>\n" .
+ "</head>\n" .
+ "<body>\n" .
+ "<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
+ );
+ }
+
+ foreach $line(@writeArray)
+ {
+ print FILE_HANDLE ($line);
+ }
+
+ for( my $i = $startLine; $i < $endLine; $i++ )
+ {
+ my $line = @$refLogLines[$i];
+ FormatLogLine(\$line) if($optionHtml);
+
+ print FILE_HANDLE ($line);
+ }
+
+ if($optionHtml)
+ {
+ print FILE_HANDLE (
+ "</body>\n" .
+ "</html>"
+ );
+ }
+
+ print FILE_HANDLE ( $lineBreak );
+ print FILE_HANDLE ( $lineBreak );
+
+ close FILE_HANDLE;
+
+ } else
+ {
+ print("ERROR: Could not write to file: " . $caseLogFile . "\n");
+ }
+}
+
+#------------------------------------------------------------------------------------
+# CheckCaseEntriesInLog
+#
+# Parameters:
+# $refLogLines: reference to array of log lines
+#
+# Finds if there's log entries for cases that are not reported in the testreport files
+# and create case specific logs for them
+#------------------------------------------------------------------------------------
+sub CheckCaseEntriesInLog
+{
+ my ($refLogLines) = @_;
+
+ foreach $case(@cases)
+ {
+ if(@{$case}[$CASE_CHECK_RESULT_LOG_FILE] == 1)
+ {
+ @{$case}[$CASE_CHECK_RESULT_LOG_FILE] = 0;
+
+#create the next lines for WriteCaseLog function
+
+#line1: [testscripter_iptvservicemanagementapitestasync][c:\TestFramework\IptvServiceManagementApiTestAsync.cfg][2] Title:[ET08203 Add valid hardcoded service_0 ASYNC]
+#line2: StartTime: 3:06:14.2212 PM, EndTime: 3:06:18.1037 PM
+#line3: Result: 0 [] ==> PASSED
+
+ #starttime = case startline
+ #endttime = next case starttline | lastline
+
+ my $line1 = "[unknown.cfg][0] Title:[" . @{$case}[$CASE_NAME] . "]";
+ my $line2 = "";
+ my $line3 = "Result: 0 [] ==> UNKNOWN";
+
+ my $startTime = "";
+ my $endTime = "";
+ my $status = "UNKNOWN";
+ my $caseLogFile = "";
+ my $result = "0";
+ my $info = "";
+ my $reason = "";
+
+ my $caseId = "";
+ foreach $line(@$refLogLines)
+ {
+ # take the times from lines where is case start text
+
+ if($startTime eq "" && $line =~ m/>>> Case start:/i)
+ {
+ $caseId = substr($line, index($line, ">>> Case start:") + length(">>> Case start:"));
+
+ RemoveWhiteSpaces(\$caseId);
+
+ # set start time if case matches
+ #02/08/2006 12:15:42 >>> Case start: ET00000 caseId
+ if($caseId eq @{$case}[$CASE_ID])
+ {
+ #print("*** Reading case name\n\n");
+ if($line =~ m/([0-9]+):([0-9]+):([0-9]+)/)
+ {
+ #print("CASESTART: $line\n");
+ $startTime = "$1:$2:$3.0000";
+ #print("*** READ TIME $startTime\n\n");
+ next; # skip the rest of loop otherwise endtime will be same
+ }
+ }
+ }
+
+ # find endtime for case if starttime is set
+ if($startTime ne "")
+ {
+ #[14:38:40.641] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:TestCase [ET1024 Sort IapList when it has no IAPs] finished with verdict[0]
+
+ #die("$line") if($line =~m/$caseId/i);
+ #die("line: $line\n") if($line =~ m/finished with verdict/);
+
+ if($line =~ m/$caseId/i and $line =~ m/finished with verdict\[([-]*[0-9]+)\]/)
+ {
+
+ $result = $1;
+
+ if($1 eq "0")
+ {
+ $status = "PASSED";
+ $line3 = "Result: $1 [] ==> PASSED";
+ }
+ else
+ {
+ $status = "FAILED";
+ $line3 = "Result: $1 [] ==> FAILED";
+ }
+ }
+
+ #if line has time then grab it
+ if($line =~ m/([0-9]+):([0-9]+):([0-9]+)/)
+ {
+ $endTime = "$1:$2:$3.9999";
+ # stop searching when next case is starting
+ if( ($line =~ m/>>> Case start:/i || $line =~ m/>>> Case end./i) and !($line =~ m/$caseId/) )
+ {
+ #print("CASEEND: $line\n");
+ last;
+ }
+ }
+ }
+
+ }
+
+ $line2 = "StartTime: $startTime PM, EndTime: $endTime PM";
+
+ #print("l1: $line1\nl2: $line2\nl3: $line3\n\n");
+
+ my $refCaseDesc = GetCaseDesc($caseId);
+
+ $caseLogFile = GetFileNameForCaseLog( $line1, $line2, $line3 );
+
+ WriteCaseLog($caseLogFile, $refLogLines, $refCaseDesc, $line1, $line2, $line3);
+
+ my $refCase = GetCase($caseId, \@cases);
+
+ UpdateCase($refCase, $caseLogFile, "", $result, $status, $info, $reason, 0);
+ }
+ }
+}
+
+sub UpdateCase
+{
+ my ($refCase, $caseLogFile, $caseScripterLogFile, $result, $status, $info, $reason, $caseRunTimeSeconds) = @_;
+
+ if($optionShowMessages) { print(" - Case update: $result, $status, $reason, $caseRunTimeSeconds\n\n"); };
+
+ die("Result not defined. Cannot update.\n") if(!defined($result) );
+ die("Status not defined. Cannot update.\n") if(!defined($status) );
+ die("Info not defined. Cannot update.\n") if( !defined($info) );
+ die("Reason not defined. Cannot update.\n") if( !defined($reason) );
+
+ $caseRunTimeSeconds = 0 if($caseRunTimeSeconds < 0);
+
+ # we have actual result, no need for this anymore
+ @$refCase[$CASE_CHECK_RESULT_LOG_FILE] = 0;
+
+ if(!$optionFinalDoc)
+ {
+ @$refCase[$CASE_RUN_TIMES]++;
+
+ @$refCase[$CASE_RUN_TIME_SECONDS] = $caseRunTimeSeconds;
+
+ if($status eq "CRASHED") {
+ @$refCase[$CASE_CRASHED]++;
+ }
+ elsif($status eq "FAILED") {
+ @$refCase[$CASE_FAILED]++;
+ }
+ elsif($status eq "PASSED") {
+ @$refCase[$CASE_PASSED]++;
+ }
+ }
+ else
+ {
+ if($status eq "PASSED") {
+ @$refCase[$CASE_PASSED] = 1;
+ @$refCase[$CASE_CRASHED] = 0;
+ @$refCase[$CASE_FAILED] = 0;
+ }
+ elsif($status eq "CRASHED" && @$refCase[$CASE_STATUS] ne "PASSED") {
+ @$refCase[$CASE_PASSED] = 0;
+ @$refCase[$CASE_CRASHED] = 1;
+ @$refCase[$CASE_FAILED] = 0;
+ }
+ elsif($status eq "FAILED" && @$refCase[$CASE_STATUS] ne "PASSED" && @$refCase[$CASE_STATUS] ne "CRASHED") {
+ @$refCase[$CASE_PASSED] = 0;
+ @$refCase[$CASE_CRASHED] = 0;
+ @$refCase[$CASE_FAILED] = 1;
+ }
+ }
+
+ my $updateCase = 0;
+
+ if(!$optionGoodIsBetter and !$optionFinalDoc)
+ {
+ # Only update case status if it's more fatal than the current, CRASHED > FAILED > UNKNOWN > PASSED
+ if($status ne "$caseDefaultStatus")
+ {
+ if (@$refCase[$CASE_STATUS] eq "$caseDefaultStatus") {
+ $updateCase = 1;
+ }
+ elsif (@$refCase[$CASE_STATUS] eq "CRASHED" ) {
+
+ }
+ elsif (@$refCase[$CASE_STATUS] eq "FAILED") {
+ $updateCase = 1 if($status eq "CRASHED");
+ }
+ elsif(@$refCase[$CASE_STATUS] eq "PASSED") {
+ $updateCase = 1;
+ }
+ }
+ }
+ else
+ {
+ # Only update case status if it's less fatal than the current, PASSED > FAILED > CRASHED > UNKNOWN
+ if($status ne "$caseDefaultStatus")
+ {
+ if (@$refCase[$CASE_STATUS] eq "$caseDefaultStatus") {
+ $updateCase = 1;
+ }
+ elsif(@$refCase[$CASE_STATUS] eq "UNKNOWN") {
+ $updateCase = 1;
+ }
+ elsif($status eq "PASSED")
+ {
+ $updateCase = 1;
+ }
+ elsif (@$refCase[$CASE_STATUS] eq "CRASHED" ) {
+ $updateCase = 1 if($status eq "FAILED");
+ }
+ elsif (@$refCase[$CASE_STATUS] eq "FAILED") {
+
+ }
+ }
+ }
+
+ if($updateCase)
+ {
+ @$refCase[$CASE_REASON] = $info . $reason;
+ @$refCase[$CASE_RESULT] = $result;
+ @$refCase[$CASE_STATUS] = $status;
+ @$refCase[$CASE_LOG_FILE] = $caseLogFile;
+ @$refCase[$CASE_LOG_FILE_SCRIPTER] = $caseScripterLogFile;
+ }
+ else
+ {
+ # -1112 overrides other error codes because the case succeeded but verifying has failed.
+ if(@$refCase[$CASE_RESULT] ne "-1112" and $result eq "-1112")
+ {
+ @$refCase[$CASE_RESULT] = $result;
+ }
+ }
+ #print "case: " . @{$case}[$CASE_NAME] . "\n" . "run: " . @{$case}[$CASE_RUN_TIMES] . ", crash: " . @{$case}[$CASE_CRASHED] . ", fail " . @{$case}[$CASE_FAILED] . ", passed: " . @{$case}[$CASE_PASSED] . "\n";
+}
+
+sub CountCaseRunTime
+{
+ my ($line) = @_;
+ my $found = 0;
+ RemoveWhiteSpaces(\$line);
+ #StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
+ #StartTime: 12:02:49.9302 pm, EndTime: 12:03:04.5781 pm
+ if($line =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
+ {
+ $found = 1;
+ }
+ elsif($line =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
+ {
+ $found = 1;
+ }
+
+ my $caseRunTime = 0;
+
+ if($found)
+ {
+ my $startSeconds = ($1 * 60 * 60) + $2 * 60 + $3;
+ my $endSeconds = ($4 * 60 * 60) + $5 * 60 + $6;
+
+ $caseRunTime = $endSeconds - $startSeconds;
+ }
+ $caseRunTime = 0 if($caseRunTime < 0);
+
+ $totalExecutionTime += $caseRunTime;
+ return $caseRunTime;
+}
+
+sub GetFileNameForCaseLog
+{
+ my ($line1, $line2, $line3, $extra) = @_;
+
+ RemoveWhiteSpaces(\$line1);
+ RemoveWhiteSpaces(\$line2);
+ RemoveWhiteSpaces(\$line3);
+
+ my $caseId = "";
+
+ if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+)$regexpCaseName\]$/i)
+ {
+ #"' ultraedit
+ $caseId = $1;
+ }
+
+ my $caseTimeStr = "";
+
+ #StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
+ if($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
+ {
+ $found = 1;
+ }
+ elsif($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
+ {
+ $found = 1;
+ }
+
+ if( $found )
+ {
+ $caseTimeStr = $1 . $2 . $3 . $4 . $5 . $6;
+ }
+
+ my $fileext = ".txt";
+ $fileext = ".html" if($optionHtml);
+
+ my $caseLogFile;
+
+ if( !defined( $extra ) )
+ {
+ $caseLogFile = $caseLogOutDir . $caseId . "_" . $caseTimeStr . $fileext;
+ }
+ else
+ {
+ $caseLogFile = $caseLogOutDir . $caseId . "_" . $caseTimeStr . $extra . $fileext;
+ }
+
+ print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);
+ return $caseLogFile;
+}
+
+#------------------------------------------------------------------------------------
+# WriteCaseLog
+#
+# Parameters:
+# $caseLogFile: filename to write
+# $refLogLines: input where log lines are stored
+# $caseDesc: optional text description of case which will be written into the log file
+# $line1: [testscripter_iptvservicemanagementapitestasync][c:\TestFramework\IptvServiceManagementApiTestAsync.cfg][2] Title:[ET08203 Add valid hardcoded service_0 ASYNC]
+# $line2: StartTime: 3:06:14.2212 PM, EndTime: 3:06:18.1037 PM
+# $line3: Result: 0 [] ==> PASSED
+#
+# Writes case specific log file into testcase_logs/testcase_logs directory. Reads the lines from @caseLogLines array
+#------------------------------------------------------------------------------------
+sub WriteCaseLog
+{
+#[testscripter_iptvservicemanagementapitestasync][c:\TestFramework\IptvServiceManagementApiTestAsync.cfg][2] Title:[ET08203 Add valid hardcoded service_0 ASYNC]
+# StartTime: 3:06:14.2212 PM, EndTime: 3:06:18.1037 PM
+# StartTime: 12:34:41.5407, EndTime: 12:34:41.9687
+# Result: 0 [] ==> PASSED
+
+ my ($caseLogFile, $refLogLines, $refCaseDesc, $line1, $line2, $line3) = @_;
+
+ # Don't generate log files if we only print summary
+ if($optionPrintCfgSummaries)
+ {
+ return;
+ }
+
+ #print("1: $line1"); print("2: $line2"); print("3: $line3");
+
+ RemoveWhiteSpaces(\$line1);
+ RemoveWhiteSpaces(\$line2);
+ RemoveWhiteSpaces(\$line3);
+
+ my $lineBreak = "\n";
+ $lineBreak = "<br>\n" if($optionHtml);
+
+ my $caseId = "";
+
+ if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+)$regexpCaseName\]$/i)
+ {
+ #"' ultraedit
+ $caseId = $1;
+ print("Writing log for: $caseId.\n") if($optionShowMessages);
+ }
+
+ # Write header for case
+
+ my @writeArray;
+
+ # split the first line
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+ push @writeArray, ( substr($line1, 0, index($line1, "Title:")) . $lineBreak );
+ push @writeArray, ( substr($line1, index($line1, "Title:")) . $lineBreak );
+ my $title = substr($line1, index($line1, "Title:"));
+
+ #($line1 . "\n");
+ push @writeArray, ($line2 . $lineBreak);
+ push @writeArray, ($line3 . $lineBreak);
+ push @writeArray, ("\n");
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+
+ # Include the script for the case in the file?
+
+ if($optionCaseIncludedInLog)
+ {
+ foreach $linexxx (@{$refCaseDesc})
+ {
+ push @writeArray, ("$linexxx");
+ push @writeArray, ($lineBreak) if($optionHtml);
+ }
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+ push @writeArray, ("\n");
+ }
+
+ my $passed = 0;
+ $passed = 1 if($line3 =~ m/==> PASSED/);
+
+ # Get the log for the case
+
+ my $startLine = 0;
+ my $endLine = 0;
+
+ my $logLineCount = scalar(@$refLogLines);
+
+ if($logLineCount > 0 && ($optionLogAllCases || !$passed) )
+ {
+ if($lastCaseLogLine >= $logLineCount)
+ {
+ $lastCaseLogLine = 0;
+ }
+
+ # Get the start and end time for the case
+
+ my $found = 0;
+ #StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
+ if($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
+ {
+ $found = 1;
+ }
+ elsif($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
+ {
+ $found = 1;
+ }
+ else
+ {
+ print(" *ERROR* Could not parse case run time for case $caseId. Can not write case log note. Returning.\n");
+ return;
+ }
+
+ my $startSeconds = 0;
+ my $endSeconds = 0;
+
+ if($found)
+ {
+ $startSeconds = ($1 * 60 * 60) + $2 * 60 + $3;
+ $endSeconds = ($4 * 60 * 60) + $5 * 60 + $6;
+
+ my $caseRunTime = $endSeconds - $startSeconds;
+
+ if($caseRunTime < 0)
+ {
+ # It's possible to code solution but it'd slow down the script.
+ print(" *ERROR* Case $caseId has probably passed midnight/midday. Giving up writing case specific log.\n");
+ return;
+ }
+
+ #print " - start:" . $1 . ":" . $2 . ":" . $3 . " = " . $startSeconds . "\n";
+ #print " - end: " . $4 . ":" . $5 . ":" . $6 . " = " . $endSeconds . "\n";
+ }
+
+ # Find indexes for start and end lines
+
+ $startLine = -1;
+ # If the line at $lastCaseLogLine matches then find backwards the first matching line,
+ # otherwise some lines might be missed from the log note.
+ if(LogLineTimeMatchesForCase(\@$refLogLines[$lastCaseLogLine], $startSeconds, $startSeconds))
+ {
+ #print("find back\n");
+ for(my $i=$lastCaseLogLine; $i > 0; $i--)
+ {
+ if(!LogLineTimeMatchesForCase(\@$refLogLines[$i], $startSeconds, $startSeconds))
+ {
+ $startLine = $i+1;
+ last;
+ }
+ }
+ }
+ # Otherwise try to find match forward.
+ else
+ {
+ $startLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, $lastCaseLogLine, 1);
+ }
+ # If that doesn't succeed then lets go at start of the log. SLOW for huge logs.
+ if($startLine == -1)
+ {
+ $startLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, 0, 1);
+ $lastCaseLogLine = 0;
+ }
+ if($startLine == -1)
+ {
+ print(" *ERROR* startLine not found!\n");
+ return;
+ }
+
+ print(" - StartLine: $startLine\n") if($optionShowMessages);
+
+ # Find forward the last line which does not match.
+ $endLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, $startLine+1, 0);
+
+ if($endLine == -1 || $endLine < $startLine)
+ {
+ print(" - End line not found, trying alternative method.\n") if($optionShowMessages);
+ # Find first not matching line forward from the case start.
+ $endLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, scalar(@$refLogLines)-1, 0);
+ if( $endLine == -1 || $endLine < $startLine )
+ {
+ # Just take the rest of the log
+ $endLine = scalar(@$refLogLines)-1;
+ }
+ }
+
+ print(" - EndLine: $endLine\n") if($optionShowMessages);
+
+ $lastCaseLogLine = $endLine-1;
+ }
+
+ # Create log directory
+
+ if ( !(-e "testcase_logs") )
+ {
+ mkdir("testcase_logs");
+ }
+
+ if ( !(-e "$caseLogOutDir") )
+ {
+ mkdir($caseLogOutDir, 0755);
+ }
+
+ # Write the log file
+
+ my $fileMode = ">>";
+
+ print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);
+
+ if( open(FILE_HANDLE, $fileMode . $caseLogFile) )
+ {
+ if($optionHtml)
+ {
+ print FILE_HANDLE (
+ "<html>\n" .
+ "<head>\n" .
+ "<title>$title</title>\n" .
+ "</head>\n" .
+ "<body>\n" .
+ "<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
+ );
+ }
+
+ foreach $line(@writeArray)
+ {
+ print FILE_HANDLE ($line);
+ }
+
+ for(my $i=$startLine;$i<$endLine;$i++)
+ {
+ my $line = @$refLogLines[$i];
+ FormatLogLine(\$line) if($optionHtml);
+
+ print FILE_HANDLE ($line);
+ }
+
+ if($optionHtml)
+ {
+ print FILE_HANDLE (
+ "</body>\n" .
+ "</html>"
+ );
+ }
+
+ print FILE_HANDLE ( $lineBreak );
+ print FILE_HANDLE ( $lineBreak );
+
+ close FILE_HANDLE;
+
+ } else
+ {
+ print("ERROR: Could not write to file: " . $caseLogFile . "\n");
+ }
+}
+
+# There's case start entry in the log, write case log from there onwards.
+sub WriteCaseLogFromEntry
+{
+ my ($caseLogFile, $refLogLines, $caseEntryLogStartLine, $line1, $line2, $line3) = @_;
+
+ # Don't generate log files if we only print summary
+ if($optionPrintCfgSummaries)
+ {
+ return 0;
+ }
+
+ RemoveWhiteSpaces(\$line1);
+ RemoveWhiteSpaces(\$line2);
+ RemoveWhiteSpaces(\$line3);
+
+ my $lineBreak = "\n";
+ $lineBreak = "<br>\n" if($optionHtml);
+
+ my $caseId = "";
+
+ if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+)$regexpCaseName\]$/i)
+ {
+ #"' ultraedit
+ $caseId = $1;
+ }
+
+ # Write header for case
+
+ my @writeArray;
+
+ # split the first line
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+ push @writeArray, ( substr($line1, 0, index($line1, "Title:")) . $lineBreak );
+ push @writeArray, ( substr($line1, index($line1, "Title:")) . $lineBreak );
+ my $title = substr($line1, index($line1, "Title:"));
+
+ #($line1 . "\n");
+ push @writeArray, ($line2 . $lineBreak);
+ push @writeArray, ($line3 . $lineBreak);
+ push @writeArray, ("\n");
+ push @writeArray, ( "<hr>" ) if($optionHtml);
+
+ my $passed = 0;
+ $passed = 1 if($line3 =~ m/==> PASSED/);
+
+ # Get the log for the case
+
+ my $logLineCount = scalar(@$refLogLines);
+
+ if($logLineCount > 0 && ($optionLogAllCases || !$passed) )
+ {
+ # Get the start and end time for the case
+
+ my $found = 0;
+ #StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
+ if($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
+ {
+ $found = 1;
+ }
+ elsif($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
+ {
+ $found = 1;
+ }
+ else
+ {
+ print(" *ERROR* Could not parse case run time for case $caseId. Can not write case log note. Returning.\n");
+ return 0;
+ }
+
+ my $startSeconds = 0;
+ my $endSeconds = 0;
+
+ if($found)
+ {
+ $startSeconds = ($1 * 60 * 60) + $2 * 60 + $3;
+ $endSeconds = ($4 * 60 * 60) + $5 * 60 + $6;
+
+ my $caseRunTime = $endSeconds - $startSeconds;
+
+ if($caseRunTime < 0)
+ {
+ # It's possible to code solution but it'd slow down the script.
+ #print(" *ERROR* Case has probably passed midnight/midday. Giving up writing case specific log.\n");
+ #return;
+ }
+ }
+ }
+
+ # Create log directory
+
+ if ( !(-e "testcase_logs") )
+ {
+ mkdir("testcase_logs");
+ }
+
+ if ( !(-e "$caseLogOutDir") )
+ {
+ mkdir($caseLogOutDir, 0755);
+ }
+
+ # Write the log file
+
+ my $fileMode = ">>";
+
+ print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);
+
+ my $caseEntryLogEndLine = -1;
+ for(my $i=$caseEntryLogStartLine; $i<scalar(@$refLogLines); $i++ )
+ {
+ if(@$refLogLines[$i] =~ m/<<< Case end/i)
+ {
+ $caseEntryLogEndLine = $i;
+ last;
+ }
+ }
+ if( $caseEntryLogEndLine == -1 )
+ {
+ print("ERROR: $caseId is missing case end command in the script?\n");
+ return 0;
+ }
+
+ if( open(FILE_HANDLE, $fileMode . $caseLogFile) )
+ {
+ if($optionHtml)
+ {
+ print FILE_HANDLE (
+ "<html>\n" .
+ "<head>\n" .
+ "<title>$title</title>\n" .
+ "</head>\n" .
+ "<body>\n" .
+ "<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
+ );
+ }
+
+ for( my $i = $caseEntryLogStartLine; $i < $caseEntryLogEndLine; $i++ )
+ {
+ my $line = @$refLogLines[$i];
+ FormatLogLine(\$line) if($optionHtml);
+ print FILE_HANDLE ($line);
+ }
+
+ if($optionHtml)
+ {
+ print FILE_HANDLE (
+ "</body>\n" .
+ "</html>"
+ );
+ }
+ print FILE_HANDLE ( $lineBreak );
+ print FILE_HANDLE ( $lineBreak );
+
+ close FILE_HANDLE;
+
+ } else
+ {
+ print("ERROR: Could not write to file: " . $caseLogFile . "\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+#------------------------------------------------------------------------------------
+# FindLogLineMatchRecurse
+#
+# Parameters:
+# $startsSeconds the min time the log line will match
+# $endSeconds the max time the log line will match
+# $refStartLine index of line to start searching
+# $refLogLines reference to array of the log
+# $boolOp 1 = first line with match is returned, 0 = first line with no match is returned
+# $inc increment in the search loop
+# $recurse can the function call itself, if yes this will be passed to the new call too
+# $maxLine the last line to search
+#
+#------------------------------------------------------------------------------------
+sub FindLogLineMatchRecurse
+{
+ my ($startSeconds, $endSeconds, $refStartLine, $refLogLines, $boolOp, $inc, $recurse, $maxLine) = @_;
+
+ print("IN FindLogLineMatchRecurse\n") if($optionDebug);
+ my $spacer = "";
+ for(my $i = 0;$i<$recurse; $i++)
+ {
+ $spacer .= "-";
+ }
+
+ $maxLine = scalar(@$refLogLines) if(!defined($maxLine) or $maxLine > scalar(@$refLogLines));
+ print("s: $startSeconds, e: $endSeconds, sl: $$refStartLine, b: $boolOp, i: $inc, r: $recurse, ml: $maxLine\n") if($optionDebug);
+ print("$spacer ENTER: range: $$refStartLine - $maxLine, $inc\n") if($optionDebug);
+ print("$spacer rec: $recurse\n") if($optionDebug);
+ print("$spacer prev: $$refStartLine\n") if($optionDebug);
+ print("$spacer inc: $inc\n") if($optionDebug);
+
+ # First try to find the start line without recursion.
+ for(my $i = $$refStartLine; $i < $maxLine; $i += $inc)
+ {
+ if(LogLineTimeMatchesForCase(\@$refLogLines[$i], $startSeconds, $endSeconds) == $boolOp)
+ {
+ # We have exact match.
+ if($inc == 1)
+ {
+ $$refStartLine = $i;
+ }
+ # Not exatch match. Return start of previous block.
+ elsif($i >= $$refStartLine + $inc)
+ {
+ $$refStartLine = $i - $inc;
+ }
+
+ print("MATCH LINE: $i: " . @$refLogLines[$i] . "\n") if($optionDebug);
+ print("return line: " . $$refStartLine . "\n") if($optionDebug);
+ print("EXIT FindLogLineMatchRecurse. return 1\n") if($optionDebug);
+ return 1;
+ }
+ }
+
+ if($recurse && $inc > 500)
+ {
+ # Split the current search block to smaller blocks and do search to them
+ for(my $i = $$refStartLine; $i < $maxLine; $i += $inc)
+ {
+ print("$spacer $i\n") if($inc != 1 && $optionDebug);
+ print("...RECURSING!\n") if($optionDebug);
+
+ # Start search from the start of current block.
+ my $prevPos = $i;
+
+ # New last line to search
+ my $end = $i + $inc;
+ $end = scalar(@$refLogLines)-1 if($end > scalar(@$refLogLines)-1);
+
+ # New increment, twice smaller than now
+ my $newInc = int($inc / 2 + 0.5);
+ $newInc = 200 if($newInc < 200);
+
+ if(FindLogLineMatchRecurse($startSeconds, $endSeconds, \$prevPos, $refLogLines, $boolOp, $newInc, $recurse-1, $end) == 1)
+ {
+ $$refStartLine = $prevPos;
+ print("EXIT FindLogLineMatchRecurse. return 1\n") if($optionDebug);
+ return 1;
+ }
+ }
+ }
+
+ print("EXIT FindLogLineMatchRecurse. return 0\n") if($optionDebug);
+ return 0;
+}
+
+#------------------------------------------------------------------------------------
+# FindLogLineMatch
+#
+# Searches for log line with time between the startSeconds and endSeconds.
+#
+# Parameters:
+# $refLogLines reference to array of the log
+# $startsSeconds the min time the log line will match
+# $endSeconds the max time the log line will match
+# $startLine index of line to start searching
+# $boolOp 1 = first line with match is returned, 0 = first line with no match is returned
+#------------------------------------------------------------------------------------
+sub FindLogLineMatch
+{
+ my ($refLogLines, $startSeconds, $endSeconds, $startLine, $boolOp) = @_;
+ print("IN FindLogLineMatch\n") if($optionDebug);
+ my $prevPos = $startLine;
+
+ #print("\n\nSTART: $startLine, boolop: $boolOp \n");
+
+ my $match = 0;
+ $match = FindLogLineMatchRecurse($startSeconds, $endSeconds, \$prevPos, $refLogLines, $boolOp, 6000, 5);
+ $prevPos = 0 if(!$match);
+ # Refine the search to be exact line
+ $match = FindLogLineMatchRecurse($startSeconds, $endSeconds, \$prevPos, $refLogLines, $boolOp, 1, 0);
+
+ print("EXIT FindLogLineMatch\n") if($optionDebug);
+ # Not found.
+ return -1 if(!$match);
+
+ return $prevPos;
+}
+
+#------------------------------------------------------------------------------------
+# JustFormatLogFile
+#
+# Parameters:
+# $fileName
+#------------------------------------------------------------------------------------
+sub JustFormatLogFile
+{
+ my ($fileName) = @_;
+
+ if( !open(FILE_HANDLE, $fileName) )
+ {
+ die("ERROR! Could not open file '" . $fileName . "'\n");
+ }
+ my @array = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ $fileName = substr($fileName, 0, index($fileName, ".txt")) . ".html";
+
+ if( open(FILE_HANDLE, ">" . $fileName) )
+ {
+
+ print FILE_HANDLE (
+ "<html>\n" .
+ "<head>\n" .
+ "<title>$fileName</title>\n" .
+ "</head>\n" .
+ "<body>\n" .
+ "<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
+ );
+
+
+ my $i;
+ for($i = 0;$i<scalar(@array); $i++)
+ {
+ my $line = $array[$i];
+ $line =~ s/\t/ /; #remove tabs
+ FormatLogLine(\$line);
+
+ print FILE_HANDLE ($line);
+ }
+
+ print FILE_HANDLE (
+ "</body>\n" .
+ "</html>"
+ );
+
+ close FILE_HANDLE;
+ } else
+ {
+ print("ERROR: Could not write to file: " . $fileName . "\n");
+ }
+
+}
+
+#------------------------------------------------------------------------------------
+# LogLineTimeMatchesForCase
+#
+# Parameters:
+# $refLine
+# $startSeconds
+# $endSeconds
+#------------------------------------------------------------------------------------
+sub LogLineTimeMatchesForCase
+{
+ my ($refLine, $startSeconds, $endSeconds) = @_;
+
+ return 0 if(!defined($$refLine));
+
+ $$refLine =~ s/\t/ /; #remove tabs
+
+ #print($$refLine . "\n");
+ #print(" - $startSeconds, $endSeconds\n");
+
+ if(${$refLine} =~ m/[0-9\/]+ ([0-9]+):([0-9]+):([0-9]+)/i)
+ {
+# print("YES " . $1 . "\n");
+
+ my $currSeconds = $1 * 60 * 60 + $2 * 60 + $3;
+ #print(" - curr: $currSeconds\n");
+
+ #print("curr: $currSeconds, start: $startSeconds, end: $endSeconds\n");
+
+ if($currSeconds >= $startSeconds and $currSeconds <= $endSeconds)
+ {
+ #print("MATCH curr: " . $1 . ":" . $2 . ":" . $3 . " = " . $currSeconds . "\n");
+ return 1;
+ }
+ }
+ #print("NO MATCH\n");
+ return 0;
+}
+
+#------------------------------------------------------------------------------------
+# FormatLogLine
+# Parameters:
+# $line
+#------------------------------------------------------------------------------------
+sub FormatLogLine
+{
+ my ($line) = @_;
+
+#Color
+
+# sisään
+#27/06/2006 9:37:52 >>>* royalblue #2B60DE
+# pois
+#27/06/2006 9:37:52 <<<* lightblue #0000FF
+#27/06/2006 9:23:57 * exit
+# destructor
+#27/06/2006 9:23:58 ~* #FF0000
+#27/06/2006 9:23:58 >>>~*
+
+#27/06/2006 9:37:52 CIptv*Test * GREY #808080
+#27/06/2006 9:37:52 *error/fail RED #FF0000
+#27/06/2006 9:23:41 CreateServerProcess() GREEN #00FF00
+
+#!! TTestObject::~TTestObject #800080
+
+my $color = "#000000";
+
+
+if(${$line} =~ m/([0-9\/]+ [0-9]+:[0-9]+:[0-9]+)/i)
+{
+ $date = $1;
+ ${$line} = substr(${$line}, length($date));
+
+ $color = "#808080" if(${$line} =~ m/CIptvTest[a-z0-9]+Test/i);
+
+ $color = "#2B60DE" if(${$line} =~ m/^[\t ]*>>>/i);
+ $color = "#2B60DE" if(${$line} =~ m/\(\)$/i);
+ $color = "#2B60DE" if(${$line} =~ m/enter$/i);
+
+ $color = "#0000FF" if(${$line} =~ m/^[\t ]*<<<*/i);
+ $color = "#0000FF" if(${$line} =~ m/ exit$/i);
+
+ $color = "#800080" if(${$line} =~ m/^[\t ]*~/i);
+ $color = "#800080" if(${$line} =~ m/^[\t ]*>>>~/i);
+ $color = "#800080" if(${$line} =~ m/::~/i);
+
+ $color = "#FF0000" if(${$line} =~ m/error|fail/i);
+
+ $color = "#00AA00" if(${$line} =~ m/passed/i);
+ $color = "#FF0000" if(${$line} =~ m/\*\*\*Testcase[a-z ]+\*\*\*/i);
+ $color = "#00AA00" if(${$line} =~ m/\*\*\*Testcase PASSED+\*\*\*/i);
+ $color = "#0000FF" if(${$line} =~ m/Executing line/i);
+
+ my $formatStart = "", $formatEnd = "";
+
+ if(${$line} =~ m/Client created semaphore, init/i) { $formatStart = "<b>"; $formatEnd = "</b>"; }
+ if(${$line} =~ m/CIptvEngineServer:: ->Starting server shutdown/i) { $formatStart = "<b>"; $formatEnd = "</b>"; }
+
+ SpecialChars($line);
+
+ $date = "<font color=\"black\" face=\"arial\" size=\"2\">" . $date . "</font>";
+ ${$line} = $date . "$formatStart<font color=\"$color\" face=\"arial\" size=\"2\">" . ${$line} . "</font>$formatEnd<br>";
+}
+
+
+#$line = "<font color=\"$color\" face=\"arial\" size=\"2\"> . $line
+
+#$color = "#2B60DE" if($line =~ m/([0-9\/]+ [0-9]+:[0-9]+:[0-9]+) >>>/i)
+
+
+}
+
+sub PrintCfgSummaries
+{
+ my $caseCfgFileName = "";
+ my %cfgCaseCount;
+ my %cfgCaseTotalTime;
+
+ foreach $case(@cases)
+ {
+ $caseCfgFileName = @{$case}[$CASE_CFG_FILE];
+
+ if(!defined($cfgCaseCount{$caseCfgFileName}))
+ {
+ $cfgCaseCount{$caseCfgFileName} = 0;
+ $cfgCaseTotalTime{$caseCfgFileName} = 0;
+ }
+
+ if(defined(@{$case}[$CASE_RUN_TIME_SECONDS]))
+ {
+ $cfgCaseTotalTime{$caseCfgFileName} += @{$case}[$CASE_RUN_TIME_SECONDS];
+ }
+
+
+ $cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
+ }
+
+ my $totalTime = 0;
+ printf("\n%-50s %10s %10s\n", "CFG", "Case count", "Case run time");
+ foreach $caseCfgFileName (sort keys(%cfgCaseCount))
+ {
+ if($cfgCaseCount{$caseCfgFileName} > 0)
+ {
+ my $mins = ($cfgCaseTotalTime{$caseCfgFileName}/60);
+ $totalTime += $mins;
+ printf("%-50s %10d %10.1f\n", $caseCfgFileName, $cfgCaseCount{$caseCfgFileName}, $mins);
+ }
+ }
+ printf("Total time: %.2f hours\n\n", $totalTime/60 );
+
+ print("No cases run for:\n");
+ foreach $caseCfgFileName (sort keys(%cfgCaseCount))
+ {
+ if($cfgCaseCount{$caseCfgFileName} == 0)
+ {
+ print("$caseCfgFileName\n");
+ }
+ }
+}
+
+#------------------------------------------------------------------------------------
+# WriteOfficeXml
+#
+# Parameters:
+# $outputFile
+# $briefSummary
+#
+# Writes the cases into a word formatted xml file.
+#------------------------------------------------------------------------------------
+sub WriteOfficeXml
+{
+ my ($outputFile, $briefSummary) = @_;
+
+ if( !open(FILE_HANDLE, ">" . $outputFile) )
+ {
+ print("ERROR! Could not open file '" . $outputFile . "'\n");
+ return;
+ }
+
+ my $writeData = $xmlHeader;
+ my $replacement;
+
+ if($briefSummary == 0) {
+ $writeData .= $xmlHeaderTableColumns;
+ }
+ else {
+ $writeData .= $xmlHeaderTableColumnsBrief;
+ }
+
+ $excelRowCount = scalar(@cases) * 9 + 100;
+ $writeData =~ s/$CaseCountMul8/$excelRowCount/;
+
+ print FILE_HANDLE ( $writeData );
+
+ if($briefSummary) {
+ $writeData = $xmlSummaryData;
+
+ $writeData =~ s/$xmlDataSummaryCaseCount/$summaryCaseCount/;
+ $writeData =~ s/$xmlDataSummaryPassed/$summaryPassedCases/;
+ $writeData =~ s/$xmlDataSummaryFailed/$summaryFailedCases/;
+ $writeData =~ s/$xmlDataSummaryCrashed/$summaryCrashedCases/;
+ $writeData =~ s/$xmlDataSummaryTimeout/$summaryTimeoutCases/;
+ $writeData =~ s/$xmlDataSummaryRunRate/$summaryRunRate/;
+ $writeData =~ s/$xmlDataSummaryPassRateTotal/$summaryPassRateTotal/;
+ $writeData =~ s/$xmlDataSummaryPassRateRun/$summaryPassRateRun/;
+
+ print FILE_HANDLE ( $writeData );
+ }
+
+ my $caseCfgFileName = "";
+
+ my %cfgCaseCount;
+
+ # Sort the cases by the config files, cfg's which have no run cases come last
+
+ if(!$optionSortCases)
+ {
+ #print("HASH CREATE\n");
+ #create hash of cfg case counts
+ foreach $case(@cases)
+ {
+ $caseCfgFileName = @{$case}[$CASE_CFG_FILE];
+
+ if(!defined($cfgCaseCount{$caseCfgFileName}))
+ {
+ $cfgCaseCount{$caseCfgFileName} = 0;
+ }
+
+ $cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
+ }
+
+ #print("THRU CASES\n");
+
+ foreach $caseCfgFileName (keys(%cfgCaseCount))
+ {
+ # if cfg has zero cases run then it's cases are put back of the array
+ if($cfgCaseCount{$caseCfgFileName} == 0)
+ {
+ #print("ZERO CASES RUN: $caseCfgFileName\n");
+ my @moveCases;
+
+ my $i;
+ for($i=0; $i< scalar(@cases); $i++)
+ {
+ if($cases[$i][$CASE_CFG_FILE] eq $caseCfgFileName)
+ {
+ push @moveCases, splice(@cases, $i, 1);
+ $i--;
+ }
+ }
+
+ push @cases, @moveCases;
+ }
+ }
+ }
+
+ # Write the xml file
+
+ $caseCfgFileName = "";
+
+ foreach $case(@cases)
+ {
+ if($optionShowMessages || $optionDebug)
+ {
+ print(" - Case Xml : " . @{$case}[$CASE_NAME] . ", status: " . @{$case}[$CASE_STATUS] . "\n") if( $optionDebug || @{$case}[$CASE_STATUS] ne "Not planned" );
+ }
+
+ if($briefSummary == 0)
+ {
+ $writeData = $xmlData;
+ $writeData .= $xmlData2;
+ $writeData .= $xmlDataEmptyRow;
+ }
+ else
+ {
+ $writeData = "";
+
+ # Write cfg file to the brief xml if it has changed for the case
+ if($optionSortCases == 0 && $caseCfgFileName ne @{$case}[$CASE_CFG_FILE])
+ {
+ $caseCfgFileName = @{$case}[$CASE_CFG_FILE];
+
+ $writeData .= $xmlDataEmptyRow;
+ $writeData .= $xmlCfgFileBrief;
+ $writeData .= $xmlDataBriefHeader;
+
+ $replacement = @{$case}[$CASE_CFG_FILE];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCfgFile/$replacement/;
+ }
+
+ # Write log file links to xml.
+
+ my $caseHasLog = ( defined(@{$case}[$CASE_LOG_FILE]) and @{$case}[$CASE_LOG_FILE] ne "" );
+ my $caseHasScripterLog = ( defined(@{$case}[$CASE_LOG_FILE_SCRIPTER]) and @{$case}[$CASE_LOG_FILE_SCRIPTER] ne "" );
+ my $caseLogLink1 = "";
+ my $caseLogLink2 = "";
+
+ if( $caseHasLog && $caseHasScripterLog )
+ {
+ print(" - Case has both log files\n") if ($optionDebug );
+ $writeData .= $xmlDataBrief2Links;
+ $caseLogLink1 = @{$case}[$CASE_LOG_FILE];
+ $caseLogLink2 = @{$case}[$CASE_LOG_FILE_SCRIPTER];
+ }
+ elsif( $caseHasLog )
+ {
+ print(" - Case has log file\n") if ($optionDebug );
+ $writeData .= $xmlDataBrief1Link;
+ $caseLogLink1 = @{$case}[$CASE_LOG_FILE];
+ }
+ elsif( $caseHasScripterLog )
+ {
+ print(" - Case has scripter log file\n") if ($optionDebug );
+ $writeData .= $xmlDataBrief1Link;
+ $caseLogLink1 = @{$case}[$CASE_LOG_FILE_SCRIPTER];
+ }
+ else
+ {
+ print(" - Case has no log files\n") if ($optionDebug );
+ $writeData .= $xmlDataBriefNoLinks;
+ }
+
+ if( $caseLogLink1 ne "" )
+ {
+ print(" - Log file 1: $caseLogLink1\n") if ($optionDebug );
+ $replacement = $caseLogLink1;
+ XmlReadyText(\$replacement);
+
+ #print("wordxml log file 1: $replacement\n";
+
+ #print("repl: " . $replacement . "\n");
+ $replacement = substr($replacement, index($replacement, "\\") + 1);
+ #$replacement = ".\\testcase_logs\\..\\" . $replacement;
+ #print("repl: " . $replacement . "\n");
+
+ $writeData =~ s/$xmlDataCaseLink1/$replacement/;
+ }
+
+ if( $caseLogLink2 ne "" )
+ {
+ print(" - Log file 2: $caseLogLink2\n") if ($optionDebug );
+ $replacement = $caseLogLink2;
+ XmlReadyText(\$replacement);
+
+ #print("wordxml log file 2: $replacement\n";
+
+ #print("repl: " . $replacement . "\n");
+ $replacement = substr($replacement, index($replacement, "\\") + 1);
+ #$replacement = ".\\testcase_logs\\..\\" . $replacement;
+ #print("repl: " . $replacement . "\n");
+
+ $writeData =~ s/$xmlDataCaseLink2/$replacement/;
+ }
+
+ # Write case fail reason to xml.
+
+ $replacement = @{$case}[$CASE_REASON];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseReason/$replacement/;
+
+ # Write case run time or result to xml.
+
+ if(!$optionCaseRunTimes)
+ {
+ $replacement = @{$case}[$CASE_RESULT];
+ }
+ else
+ {
+ $replacement = @{$case}[$CASE_RUN_TIME_SECONDS];
+ }
+
+ # Write result to xml.
+
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseResult/$replacement/;
+ }
+
+ #$writeData = $xmlData;
+ #if($option_brief_summary == 0) { $writeData .= $xmlData2; }
+ #$writeData .= $xmlDataEmptyRow;
+
+ $replacement = @{$case}[$CASE_NAME];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseName/$replacement/;
+
+ $replacement = @{$case}[$CASE_RUN_TIMES];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseRunTimes/$replacement/;
+
+ $replacement = @{$case}[$CASE_FAILED];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseFailed/$replacement/;
+
+ $replacement = @{$case}[$CASE_CRASHED];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseCrashed/$replacement/;
+
+ $replacement = @{$case}[$CASE_PASSED];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCasePassed/$replacement/;
+
+ $replacement = @{$case}[$CASE_STATUS];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseStatus/$replacement/;
+
+ $replacement = @{$case}[$CASE_PURPOSE];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCasePurpose/$replacement/;
+
+ $replacement = @{$case}[$CASE_MEANS];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseMeans/$replacement/;
+
+ $replacement = @{$case}[$CASE_REQUIRED_SETTINGS];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseRequiredSettings/$replacement/;
+
+ $replacement = @{$case}[$CASE_RELATED_REQUIREMENTS];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseRelatedRequirements/$replacement/;
+
+ $replacement = @{$case}[$CASE_VERIFICATION];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseVerification/$replacement/;
+
+ $replacement = @{$case}[$CASE_NOTE];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseNote/$replacement/;
+
+ if(@{$case}[$CASE_STATUS] eq "UNKNOWN") {
+ $replacement = $STYLE_ID_STATUS_UNKNOWN;
+ }
+ elsif(@{$case}[$CASE_STATUS] eq "CRASHED") {
+ $replacement = $STYLE_ID_STATUS_CRASHED;
+ }
+ elsif(@{$case}[$CASE_STATUS] eq "FAILED") {
+ $replacement = $STYLE_ID_STATUS_FAILED;
+ }
+ elsif(@{$case}[$CASE_STATUS] eq "PASSED") {
+ $replacement = $STYLE_ID_STATUS_PASSED;
+ }
+ else {
+ $replacement = $STYLE_ID_STATUS_NA;
+ }
+
+ $writeData =~ s/$STYLE_ID_STATUS_TAG/$replacement/;
+
+ print FILE_HANDLE ( $writeData );
+ }
+
+ print FILE_HANDLE ( $xmlFooter );
+
+ close(FILE_HANDLE);
+
+ print("Report " . $outputFile . " written.\n");
+}
+
+#------------------------------------------------------------------------------------
+# WriteOfficeXmlAlt
+#
+# Parameters:
+# $outputFile
+#
+# Writes the cases into a word formatted xml file.
+#------------------------------------------------------------------------------------
+sub WriteOfficeXmlAlt
+{
+ my ($outputFile, $refRuns) = @_;
+
+ CalculateStats();
+
+ if( !open(FILE_HANDLE, ">" . $outputFile) )
+ {
+ print("ERROR! Could not open file '" . $outputFile . "'\n");
+ return;
+ }
+
+ my $writeData = $xmlHeader;
+ my $replacement;
+
+ $writeData .= $xmlHeaderTableColumnsAlt;
+
+ my $xRefRunInfo = @$refRuns[0];
+ my $xRefCases = @$xRefRunInfo[2];
+ my $caseCount = scalar( @$xRefCases ) + 1000;
+
+ $excelRowCount = $caseCount * 9 + 100;
+ $writeData =~ s/$CaseCountMul8/$excelRowCount/;
+
+ print FILE_HANDLE ( $writeData );
+
+ my $caseCfgFileName = "";
+
+ my %cfgCaseCount;
+
+ # Sort the cases by the config files, cfg's which have no run cases come last
+
+ if(!$optionSortCases)
+ {
+ #print("HASH CREATE\n");
+ #create hash of cfg case counts
+ foreach $case(@cases)
+ {
+ $caseCfgFileName = @{$case}[$CASE_CFG_FILE];
+
+ if(!defined($cfgCaseCount{$caseCfgFileName}))
+ {
+ $cfgCaseCount{$caseCfgFileName} = 0;
+ }
+
+ $cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
+ }
+
+ #print("THRU CASES\n");
+
+ foreach $caseCfgFileName (keys(%cfgCaseCount))
+ {
+ # if cfg has zero cases run then it's cases are put back of the array
+ if($cfgCaseCount{$caseCfgFileName} == 0)
+ {
+ #print("ZERO CASES RUN: $caseCfgFileName\n");
+ my @moveCases;
+
+ my $i;
+ for($i=0; $i< scalar(@cases); $i++)
+ {
+ if($cases[$i][$CASE_CFG_FILE] eq $caseCfgFileName)
+ {
+ push @moveCases, splice(@cases, $i, 1);
+ $i--;
+ }
+ }
+
+ push @cases, @moveCases;
+ }
+ }
+ }
+
+ my @sortedRuns;
+
+ #Monday 25th August 2008
+ while( 1 )
+ {
+ my $maxTotal = 0;
+ my $refWinner;
+ for( my $i=0; $i<scalar(@$refRuns); $i++ )
+ {
+ my $refRunInfo = @$refRuns[$i];
+ my $date = @$refRunInfo[1];
+ my @parts = split(" ", $date);
+ my $total = 0 + $parts[1];
+
+ if( $parts[2] eq "Jan" )
+ {
+ $total += 1 * 30;
+ }
+ elsif( $parts[2] eq "Feb" )
+ {
+ $total += 2 * 30;
+ }
+ elsif( $parts[2] eq "Mar" )
+ {
+ $total += 3 * 30;
+ }
+ elsif( $parts[2] eq "Apr" )
+ {
+ $total += 4 * 30;
+ }
+ elsif( $parts[2] eq "May" )
+ {
+ $total += 5 * 30;
+ }
+ elsif( $parts[2] eq "Jun" )
+ {
+ $total += 6 * 30;
+ }
+ elsif( $parts[2] eq "Jul" )
+ {
+ $total += 7 * 30;
+ }
+ elsif( $parts[2] eq "Aug" )
+ {
+ $total += 8 * 30;
+ }
+ elsif( $parts[2] eq "Sep" )
+ {
+ $total += 9 * 30;
+ }
+ elsif( $parts[2] eq "Oct" )
+ {
+ $total += 10 * 30;
+ }
+ elsif( $parts[2] eq "Nov" )
+ {
+ $total += 11 * 30;
+ }
+ elsif( $parts[2] eq "Dec" )
+ {
+ $total += 12 * 30;
+ }
+
+ if( $maxTotal < $total )
+ {
+ my $foundAlready = 0;
+ foreach my $xrun ( @sortedRuns )
+ {
+ if( $xrun == @$refRuns[$i] )
+ {
+ $foundAlready = 1;
+ }
+
+ }
+
+ if( !$foundAlready )
+ {
+ $maxTotal = $total;
+ $winner = @$refRuns[$i];
+ }
+ }
+ }
+ push @sortedRuns, $winner;
+ if( scalar(@sortedRuns) == scalar(@$refRuns) )
+ {
+ last;
+ }
+ }
+
+ foreach $run ( @sortedRuns )
+ {
+ #print("sorted: " . @$run[1] . "\n");
+ }
+ foreach $run ( @$refRuns )
+ {
+ #print("orig: " . @$run[1] . "\n");
+ }
+
+ my $refMainRunInfo = $sortedRuns[0];
+ my $refMainCases = @$refMainRunInfo[2];
+
+ $caseCfgFileName = "";
+ $replacement = "";
+
+ # This prints only cases which are in first run. Build list of cases in all runs and use that.
+ foreach $mainCase ( @$refMainCases )
+ {
+ $writeData = "";
+
+ # Status of the current case in different runs
+ my @statuses;
+ my @results;
+ for( my $i = 0; $i<100; $i++ )
+ {
+ $statuses[$i] = "UNKNOWN";
+ $results[$i] = "";
+ }
+
+ for( my $i = 0; $i<scalar( @sortedRuns ); $i++ )
+ {
+ my $refRunInfo = $sortedRuns[$i];
+
+ my $refCases = @$refRunInfo[2];
+
+ foreach $case ( @$refCases )
+ {
+ if( @$case[$CASE_ID] eq @$mainCase[$CASE_ID] )
+ {
+ $statuses[$i] = @$case[$CASE_STATUS];
+ $results[$i] = @$case[$CASE_RESULT];
+ }
+ }
+ }
+
+ # If cfg changes, write xml header for it
+ if($caseCfgFileName ne @$mainCase[$CASE_CFG_FILE])
+ {
+ $caseCfgFileName = @$mainCase[$CASE_CFG_FILE];
+
+ $writeData .= $xmlDataEmptyRow;
+ $writeData .= $xmlCfgFileBrief;
+ $writeData .= $xmlCfgFileAltHeader;
+
+ $replacement = @$mainCase[$CASE_CFG_FILE];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCfgFile/$replacement/;
+
+
+ for( $i = 0; $i<$ALT_RESULTCOUNT; $i++ )
+ {
+ $replacement = "";
+ if( defined( $sortedRuns[$i] ) )
+ {
+ $refRunInfo = $sortedRuns[$i];
+ $replacement = @$refRunInfo[1];
+ }
+ my $field = $xmlDataAltDateX . ($i+1);
+ $writeData =~ s/$field/$replacement/;
+ }
+ }
+
+ # Write xml for X cases
+
+ $writeData .= $xmlCfgFileAltData;
+
+ $replacement = @$mainCase[$CASE_NAME];
+ XmlReadyText(\$replacement);
+ $writeData =~ s/$xmlDataCaseName/$replacement/;
+
+ # Replace the X fields for runs
+ for( my $i = 0; $i<$ALT_RESULTCOUNT; $i++ )
+ {
+ $replacement = $statuses[$i];
+ $replacement = $results[$i];
+ my $field = $xmlDataAltResultX . ($i+1);
+ $writeData =~ s/$field/$replacement/;
+
+ $replacement = $STYLE_ID_STATUS_NA_CENTERED;
+ if($statuses[$i] eq "CRASHED") {
+ $replacement = $STYLE_ID_STATUS_CRASHED_CENTERED;
+ }
+ elsif($statuses[$i] eq "FAILED") {
+ $replacement = $STYLE_ID_STATUS_FAILED_CENTERED;
+ }
+ elsif($statuses[$i] eq "PASSED") {
+ $replacement = $STYLE_ID_STATUS_PASSED_CENTERED;
+ }
+ else {
+ $replacement = $STYLE_ID_STATUS_NA_CENTERED;
+ }
+
+ $writeData =~ s/$STYLE_ID_STATUS_TAG/$replacement/;
+ }
+ print FILE_HANDLE ( $writeData );
+ }
+
+ print FILE_HANDLE ( $xmlFooter );
+ close(FILE_HANDLE);
+ print("Alternative report " . $outputFile . " written.\n");
+ return;
+}
+
+#------------------------------------------------------------------------------------
+# WriteTDToolResultFile
+#
+# Parameters:
+# $outputFile
+#
+# Writes the cases into TDTool formatted file which can be exported into Quality Center
+#------------------------------------------------------------------------------------
+sub WriteTDToolResultFile
+{
+ my ($outputFile) = @_;
+
+ if( !open(FILE_HANDLE, ">" . $outputFile) )
+ {
+ print("ERROR! Could not open file '" . $outputFile . "'\n");
+ return;
+ }
+
+ my $writeData;
+ my $replacement;
+
+ my %cfgCaseCount;
+
+ # sort the cases by the config files, cfg's which have no run cases come last
+ if(!$optionSortCases)
+ {
+ foreach $case(@cases)
+ {
+ $caseCfgFileName = @{$case}[$CASE_CFG_FILE];
+
+ if(!defined($cfgCaseCount{$caseCfgFileName}))
+ {
+ $cfgCaseCount{$caseCfgFileName} = 0;
+ }
+
+ $cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
+ }
+
+ #print("THRU CASES\n");
+
+ foreach $caseCfgFileName (keys(%cfgCaseCount))
+ {
+ # if cfg has zero cases run then it's cases are put back of the array
+ if($cfgCaseCount{$caseCfgFileName} == 0)
+ {
+ #print("ZERO CASES RUN: $caseCfgFileName\n");
+ my @moveCases;
+
+ my $i;
+ for($i=0; $i< scalar(@cases); $i++)
+ {
+ if($cases[$i][$CASE_CFG_FILE] eq $caseCfgFileName)
+ {
+ push @moveCases, splice(@cases, $i, 1);
+ $i--;
+ }
+ }
+
+ push @cases, @moveCases;
+ }
+ }
+ }
+
+#test_set_name_here
+#[1]APES PTSW_WBA_TS -1.1. - Server Version - (01) - COMM_SERVER_VERSION_GET_REQ
+#Passed&Actual result: Info: 0
+
+ print FILE_HANDLE ( "IPTV_Engine test set\n" );
+
+ foreach $case(@cases)
+ {
+ $writeData = "[1]";
+
+ my $caseName = @{$case}[$CASE_NAME];
+ $writeData .= $caseName;
+
+ $writeData .= "\n";
+
+ my $result;
+
+ if(@{$case}[$CASE_STATUS] eq "UNKNOWN") {
+ $result = "N/A";
+ }
+ elsif(@{$case}[$CASE_STATUS] eq "CRASHED") {
+ $result = "Failed";
+ }
+ elsif(@{$case}[$CASE_STATUS] eq "FAILED") {
+ $result = "Failed";
+ }
+ elsif(@{$case}[$CASE_STATUS] eq "PASSED") {
+ $result = "Passed";
+ }
+ else {
+ $result = "No Run";
+ }
+
+ $writeData .= $result;
+
+
+
+ my $comments = "&Info";
+
+ #$comments = "CFG file: @{$case}[$CASE_CFG_FILE];
+
+ #$comments .= "Actual result = " . @{$case}[$CASE_RESULT] . ", Info = " . @{$case}[$CASE_REASON];
+
+ $writeData .= $comments;
+
+ $writeData .= "\n";
+
+ # Replace bad characters for QC
+ $writeData =~ s/\\/-/g;
+ $writeData =~ s/\//-/g;
+ $writeData =~ s/:/-/g;
+ $writeData =~ s/\"/-/g;
+ $writeData =~ s/\?/-/g;
+ $writeData =~ s/\'/-/g;
+ $writeData =~ s/\|/-/g;
+ $writeData =~ s/\*/-/g;
+ $writeData =~ s/\%/-/g;
+ $writeData =~ s/ä/a/g;
+ $writeData =~ s/ö/o/g;
+ $writeData =~ s/\å/a/g;
+ $writeData =~ s/</(/g;
+ $writeData =~ s/>/)/g;
+
+ if($result eq "Passed" or $result eq "Failed")
+ {
+ print FILE_HANDLE ( $writeData );
+ }
+ }
+
+ close(FILE_HANDLE);
+
+ print("Report " . $outputFile . " written.\n");
+}
+
+
+#------------------------------------------------------------------------------------
+# FindCfgFiles
+# Parameters:
+# $godir, $refFiles
+#
+# Finds cfg files from the the specified directory and it's sub directories.
+#------------------------------------------------------------------------------------
+sub FindCfgFiles
+{
+ my ($godir, $refFiles) = @_;
+
+ my $startDir = cwd;
+
+ chdir($godir) or die("Could not change dir to $godir");
+
+ opendir(DIR, ".");
+ my @files = sort(readdir(DIR));
+ closedir(DIR);
+
+ foreach $file(@files)
+ {
+ if($file eq "." or $file eq "..") {next};
+
+ if (-d $file)
+ {
+ FindCfgFiles( $file, $refFiles );
+ } else {
+ if($file =~ m/\.cfg$/i)
+ {
+ next if($file =~ m/livetv/i and $optionNoLiveTvTests);
+
+ next if(
+ ($file =~ m/IptvSecurityServicesTest/i or
+ $file =~ m/IptvRssSecurityTest/i or
+ $file =~ m/IptvLiveTvSep/i or
+ $file =~ m/IptvRssDownloadSecurityTest/i)
+
+ and $optionNoSecurityTests
+ );
+
+ next if($file =~ m/example.cfg/i);
+
+ push @$refFiles, ( cwd . "/" . $file );
+ }
+ }
+ }
+
+ chdir("$startDir") or die("Could not change dir to $startDir");
+}
+
+#------------------------------------------------------------------------------------
+# ParseCfg
+# Parameters:
+# $file
+#------------------------------------------------------------------------------------
+sub ParseCfg
+{
+ my ($file) = @_;
+
+ my $fileCaseCount = 0;
+
+ if( !open(FILE_HANDLE, $file) )
+ {
+ print("ERROR! Could not open file '" . $file . "'\n");
+ return 0;
+ }
+ my @array = <FILE_HANDLE>;
+ close(FILE_HANDLE);
+
+ my $lineCount = scalar(@array);
+ my $i;
+ my $cfgFileWritten = 0;
+ my $caseDocumentationStart = -1;
+ my $line;
+
+ my @caseDesc; # lines for case desc and case itself
+
+ for($i=0; $i<$lineCount; $i++ ) {
+ $line = $array[$i];
+
+ RemoveWhiteSpaces(\$line);
+
+ #print(" $line\n");
+
+ if($line =~ m/^\#\[IptvETDescription\]/)
+ {
+ $caseDocumentationStart = $i;
+ }
+
+ if($line =~ m/\[Test\]/)
+ {
+ if($caseDocumentationStart >= 0)
+ {
+ ReadCaseAndDescText(\@array, \@caseDesc, $caseDocumentationStart-1)
+ }
+ else
+ {
+ ReadCaseAndDescText(\@array, \@caseDesc, $i);
+ }
+
+ #print("readcase desc: " . scalar(@caseDesc) . "\n");
+ }
+ else
+ {
+ #print("NOT READ readcase desc: " . scalar(@caseDesc) . "\n");
+ }
+
+ #test case starts here
+ if($line =~ m/^title /)
+ {
+ #print("COUNT: " . scalar(@caseDesc) . "\n\n");
+
+ if($caseDocumentationStart >= 0)
+ {
+ #print(">>> Case start: " . $line . "\n");
+ #$i +=
+ ReadCase(\@array, $caseDocumentationStart, $file);
+ $caseDocumentationStart = -1;
+ }
+
+ my $caseName = substr($line, length("title "));
+ my $caseId = GetCaseIdFromName($caseName);
+
+ RemoveWhiteSpaces(\$caseName);
+ #SpecialChars(\$caseName);
+
+ my $documentationExists = GetCase($caseId, \@cases);
+
+ $caseDesc[0] = $caseName;
+ push @caseDescs, [ @caseDesc ];
+ @caseDesc = (); #new case starts
+
+ # create empty array for case
+ if(!$documentationExists)
+ {
+ if($cfgFileWritten == 0)
+ {
+ $cfgFileWritten = 1;
+ push @notDocumentedCases, ("\n\n" . $file .
+"\n************************************************************************************************\n"
+ );
+
+ }
+ push @notDocumentedCases, ($caseName . "\n");
+
+ #create dummy case
+ my @case;
+ $case[$CASE_NAME] = $caseName;
+
+ $case[$CASE_ID] = $caseId;
+
+ $case[$CASE_RUN_TIMES] = 0;
+ $case[$CASE_CRASHED] = 0;
+ $case[$CASE_FAILED] = 0;
+ $case[$CASE_PASSED] = 0;
+ $case[$CASE_STATUS] = "$caseDefaultStatus";
+ $case[$CASE_PURPOSE] = "N/A";
+ $case[$CASE_MEANS] = "N/A";
+ $case[$CASE_REQUIRED_SETTINGS] = "N/A";
+ $case[$CASE_RELATED_REQUIREMENTS] = "N/A";
+ $case[$CASE_VERIFICATION] = "N/A";
+ $case[$CASE_NOTE] = "N/A";
+ $case[$CASE_REASON] = "";
+ $case[$CASE_RESULT] = "";
+ $case[$CASE_LOG_FILE] = "";
+ $case[$CASE_LOG_FILE_SCRIPTER] = "";
+ $case[$CASE_CHECK_RESULT_LOG_FILE] = 0;
+ $case[$CASE_CFG_FILE] = lc( GetPathFileName($file) );
+ $case[$CASE_RUN_TIME_SECONDS] = 0;
+
+ if( IsCaseInCaseList( $case[$CASE_ID] ) )
+ {
+ push @cases, [ @case ];
+ }
+ }
+
+ $fileCaseCount++;
+ if($optionShowMessages) { print(" - Case: " . $caseName . "\n"); };
+ }
+ }
+
+ return $fileCaseCount;
+}
+
+
+#------------------------------------------------------------------------------------
+# ReadCaseAndDescText
+#
+# Parameters:
+# $lines
+# $caseInfo
+# $startIndex
+#------------------------------------------------------------------------------------
+sub ReadCaseAndDescText
+{
+ my ($lines, $caseInfo, $startIndex) = @_;
+ my $lineCount = @{$lines};
+
+ my $readLines = 0;
+ my $i = 0;
+
+ @{$caseInfo}[0] = "N/A";
+
+ for($i=$startIndex; $i<$lineCount; $i++)
+ {
+ my $line = @{$lines}[$i];
+
+ @{$caseInfo}[ scalar(@{$caseInfo}) ] = $line;
+
+ #print($line . "\n");
+
+ if($line =~ m/\[Endtest\]/i)
+ {
+# push @cases, [ @case ];
+
+ #foreach $xxx (@{$caseInfo}) { print("XXX: " . $xxx . ""); }
+
+ return $readLines;
+ }
+
+ $readLines++;
+ }
+
+ return $readLines;
+}
+
+#------------------------------------------------------------------------------------
+# ReadCase
+#
+# Parameters:
+# $lines
+# $startIndex
+# $file
+#------------------------------------------------------------------------------------
+sub ReadCase
+{
+ my ($lines, $startIndex, $file) = @_;
+ my $lineCount = @{$lines};
+
+ my $readLines = 0;
+ my $i = 0;
+
+ my $caseName = "";
+ my $casePurpose = "";
+ my $caseMeans = "";
+ my $caseRequiredSettings = "";
+ my $caseRelatedRequirements = "";
+ my $caseVerification = "";
+ my $caseNote = "";
+
+ #this is where text is appended if it's on a line which has no description tag
+ # -> multiline descriptions can be specified
+ my $refAppend = 0;
+
+ for($i=$startIndex; $i<$lineCount; $i++)
+ {
+ my $line = @{$lines}[$i];
+
+ #print($line . "\n");
+
+ RemoveWhiteSpaces(\$line);
+ #$line =~ s/\s+$//; #whitespaces in the end
+ #$line =~ s/^\s+//; #whitespaces at the start
+
+ if($line =~ m/^\#\[EndIptvETDescription\]/)
+ {
+ #print(" ***** End case\n");
+
+ my @case;
+
+ $case[$CASE_NAME] = $caseName;
+ $case[$CASE_ID] = GetCaseIdFromName($caseName);
+
+ $case[$CASE_RUN_TIMES] = 0;
+ $case[$CASE_CRASHED] = 0;
+ $case[$CASE_FAILED] = 0;
+ $case[$CASE_PASSED] = 0;
+ $case[$CASE_STATUS] = "$caseDefaultStatus";
+ $case[$CASE_PURPOSE] = $casePurpose;
+ $case[$CASE_MEANS] = $caseMeans;
+ $case[$CASE_REQUIRED_SETTINGS] = $caseRequiredSettings;
+ $case[$CASE_RELATED_REQUIREMENTS] = $caseRelatedRequirements;
+ $case[$CASE_VERIFICATION] = $caseVerification;
+ $case[$CASE_NOTE] = $caseNote;
+ $case[$CASE_REASON] = "";
+ $case[$CASE_RESULT] = "";
+ $case[$CASE_LOG_FILE] = "";
+ $case[$CASE_LOG_FILE_SCRIPTER] = "";
+ $case[$CASE_CHECK_RESULT_LOG_FILE] = 0;
+ $case[$CASE_CFG_FILE] = $file;
+ $case[$CASE_RUN_TIME_SECONDS] = 0;
+
+ if( IsCaseInCaseList( $case[$CASE_ID] ) )
+ {
+ push @cases, [ @case ];
+ }
+
+ return $readLines;
+ }
+
+ elsif($line =~ m/^\# Testname:/)
+ {
+ $caseName = substr($line, length("# Testname:"));
+ RemoveWhiteSpaces(\$caseName);
+ #SpecialChars(\$caseName);
+ $refAppend = \$caseName;
+ }
+
+ elsif($line =~ m/^\# Purpose:/)
+ {
+ $casePurpose = substr($line, length("# Purpose:"));
+ RemoveWhiteSpaces(\$casePurpose);
+ #SpecialChars(\$casePurpose);
+ $refAppend = \$casePurpose;
+ }
+
+ elsif($line =~ m/^\# Means:/)
+ {
+ $caseMeans = substr($line, length("# Means:"));
+ RemoveWhiteSpaces(\$caseMeans);
+ #SpecialChars(\$caseMeans);
+ $refAppend = \$caseMeans;
+ }
+
+ elsif($line =~ m/^\# Required environment settings:/)
+ {
+ $caseRequiredSettings = substr($line, length("# Required environment settings:"));
+ RemoveWhiteSpaces(\$caseRequiredSettings);
+ #SpecialChars(\$caseRequiredSettings);
+ $refAppend = \$caseRequiredSettings;
+ }
+
+ elsif($line =~ m/^\# Related requirements:/)
+ {
+ $caseRelatedRequirements = substr($line, length("# Related requirements:"));
+ RemoveWhiteSpaces(\$caseRelatedRequirements);
+ $refAppend = \$caseRelatedRequirements;
+ }
+
+ elsif($line =~ m/^\# Verification:/)
+ {
+ $caseVerification = substr($line, length("# Verification:"));
+ RemoveWhiteSpaces(\$caseVerification);
+ $refAppend = \$caseVerification;
+ }
+
+ elsif($line =~ m/^\# Note:/)
+ {
+ $caseNote = substr($line, length("# Note:"));
+ RemoveWhiteSpaces(\$caseNote);
+ $refAppend = \$caseNote;
+ }
+
+ elsif($line =~ m/^\#/)
+ {
+ my $text = substr($line, length("#"));
+ RemoveWhiteSpaces(\$text);
+ #print(" ***** JOTTAI MUuTA: " . $text. "\n");
+ ${$refAppend} .= " " . $text;
+
+ RemoveWhiteSpaces($refAppend);
+
+ }
+
+ $readLines++;
+ }
+
+ return $readLines;
+}
+
+#------------------------------------------------------------------------------------
+# GetCaseIdFromName
+#
+# Parameters:
+# $caseName
+#------------------------------------------------------------------------------------
+sub GetCaseIdFromName
+{
+ my ($caseName) = @_;
+
+ return "NOID" if(!defined($caseName) || $caseName eq "");
+
+ RemoveWhiteSpaces(\$caseName);
+ #SpecialChars(\$caseName);
+
+ if($caseName =~ m/(ET[0-9]+)[ ]+/)
+ {
+ return $1;
+ }
+
+ return $caseName;
+}
+
+#------------------------------------------------------------------------------------
+# GetCaseField
+#
+# Parameters:
+# $caseName
+# $caseField
+#------------------------------------------------------------------------------------
+sub GetCaseField
+{
+ my ($caseNameOrId, $caseField) = @_;
+
+ my $ret = "";
+
+ foreach my $case(@cases)
+ {
+ if(@{$case}[$CASE_NAME] eq $caseNameOrId or @{$case}[$CASE_ID] eq $caseNameOrId)
+ {
+ if( defined(@{$case}[$caseField]) )
+ {
+ $ret = @{$case}[$caseField];
+ }
+ }
+ }
+
+ return $ret;
+}
+
+#------------------------------------------------------------------------------------
+# GetCaseByNameOnly
+#
+# Parameters:
+# $caseName
+#
+# Removes the case IDs from case names and tries to find case from @cases array
+#------------------------------------------------------------------------------------
+sub GetCaseByNameOnly
+{
+ my ($caseName) = @_;
+
+ my $startPos = index($caseName, " ");
+ $caseName = substr($caseName, $startPos) if($startPos != -1);
+
+ RemoveWhiteSpaces(\$caseName);
+
+ for(my $i = 0; $i<scalar(@cases); $i++)
+ {
+ my $name = $cases[$i][$CASE_NAME];
+ $startPos = index($name, " ");
+ return if($startPos == -1);
+ $name = substr($name, $startPos);
+ RemoveWhiteSpaces(\$name);
+
+ return $cases[$i] if($name eq $caseName);
+ }
+ return;
+}
+
+#------------------------------------------------------------------------------------
+# GetCase
+#
+# Parameters:
+# $caseNameOrID
+#
+# Returns reference to case
+#------------------------------------------------------------------------------------
+sub GetCase
+{
+ my ($caseNameOrID, $refCases) = @_;
+
+ for(my $i = 0; $i<scalar(@$refCases); $i++)
+ {
+ $case = @$refCases[$i];
+ if(@$case[$CASE_NAME] eq $caseNameOrID or @$case[$CASE_ID] eq $caseNameOrID)
+ {
+ return $case;
+ }
+ }
+ return;
+}
+
+#------------------------------------------------------------------------------------
+# GetCaseDesc
+#
+# Parameters:
+# $caseNameOrID
+#
+# Returns reference to casedesc
+#------------------------------------------------------------------------------------
+sub GetCaseDesc
+{
+ my ($caseNameOrID) = @_;
+
+ for(my $i=0; $i<scalar(@caseDescs); $i++)
+ {
+ if($caseDescs[$i][0] eq $caseNameOrID || $caseDescs[$i][0] eq $caseNameOrID)
+ {
+ return $caseDescs[$i];
+ }
+ }
+ return;
+}
+
+#------------------------------------------------------------------------------------
+# RemoveWhiteSpaces
+#
+# Parameters:
+# $text
+#------------------------------------------------------------------------------------
+sub RemoveWhiteSpaces()
+{
+ my ($text) = @_;
+ ${$text} =~ s/\s+$//; #whitespaces in the end
+ ${$text} =~ s/^\s+//; #whitespaces at the start
+}
+
+#------------------------------------------------------------------------------------
+# XmlReadyText
+#
+# Parameters:
+# $text
+#------------------------------------------------------------------------------------
+sub XmlReadyText
+{
+ my ($text) = @_;
+
+ $txtlt = "<";
+ $txtgt = ">";
+ ${$text} =~ s/</$txtlt/g;
+ ${$text} =~ s/>/$txtgt/g;
+
+ ${$text} =~ s/Ä/Ä/g;
+ ${$text} =~ s/ä/ä/g;
+ ${$text} =~ s/Ö/Ö/g;
+ ${$text} =~ s/ö/ö/g;
+
+ #ä ä
+
+# Ö Ö
+
+# ö ö
+
+}
+
+#------------------------------------------------------------------------------------
+# SpecialChars
+#
+# Parameters:
+# $text
+#------------------------------------------------------------------------------------
+sub SpecialChars
+{
+ my ($text) = @_;
+
+
+ ReplaceChar($text, "etmerkki#39;", "'" );
+ ReplaceChar($text, "etmerkkiamp;", "&" );
+ ReplaceChar($text, "etmerkkiacute;", "´" );
+
+ ReplaceChar($text, "etmerkkilsquo;", "‘" );
+ ReplaceChar($text, "etmerkkirsquo;", "’" );
+ ReplaceChar($text, "etmerkkisbquo;", "‚" );
+ ReplaceChar($text, "etmerkkildquo;", "“" );
+ ReplaceChar($text, "etmerkkirdquo;", "”" );
+ ReplaceChar($text, "etmerkkibdquo;", "„" );
+ ReplaceChar($text, "etmerkki#34;", "\"" );
+
+ ReplaceChar($text, "etmerkki#40;", "(" );
+ ReplaceChar($text, "etmerkki#41;", ")" );
+
+ ReplaceChar($text, "etmerkkifrasl;", "/" );
+ ReplaceChar($text, "etmerkkilt;", "<" );
+ ReplaceChar($text, "etmerkkigt;", ">" );
+ ReplaceChar($text, "etmerkki#166;" , "¦" );
+
+ ReplaceChar($text, "etmerkkipara;", "¶" );
+ ReplaceChar($text, "etmerkkimiddot;", "·" );
+ ReplaceChar($text, "etmerkkifrac14;", "¼" );
+ ReplaceChar($text, "etmerkkifrac12;", "½" );
+ ReplaceChar($text, "etmerkkifrac34;" , "¾" );
+
+
+ ${$text} =~ s/etmerkki/&/g;
+
+ # print("TEXT: " . ${$text} . "\n");
+}
+
+#------------------------------------------------------------------------------------
+# ReplaceChar
+#
+# Parameters:
+# $text
+# $replacement
+# $char
+#------------------------------------------------------------------------------------
+sub ReplaceChar
+{
+ my ($text, $replacement, $char) = @_;
+
+# print("txt: " . ${$text} . "char: " . $char . ", repl: " . $replacement . "\n");
+
+ while(index(${$text}, $char) != -1)
+ {
+ my $pos = index(${$text}, $char);
+ if($pos < 0) { $pos = 0 };
+
+ $str1 = substr(${$text}, 0, $pos);
+ $str2 = substr(${$text}, $pos+1);
+
+# print "STR: '" . $str1 . "' - '" . $str2 . "'\n";
+
+# print "XXX: " . $str1 . $replacement . $str2 . "\n";
+
+ ${$text} = $str1 . $replacement . $str2;;
+ }
+}
+
+#------------------------------------------------------------------------------------
+# PrintCases
+#------------------------------------------------------------------------------------
+sub PrintCases
+{
+
+ my ($fileName) = @_;
+
+ my @buff;
+
+ push @buff, ("Name, Status, LogFile\n");
+
+ my $i;
+
+ push @buff, ("----------------------------------------\nCASES\n--------------------------------------\n");
+ foreach $case(@cases)
+ {
+
+ # my $case = $cases[$i];
+ if(0 or @{$case}[$CASE_STATUS] ne "$caseDefaultStatus")
+ {
+
+ push @buff, (@{$case}[$CASE_NAME] . " ");
+ #@{$case}[$CASE_RUN_TIMES]
+ #@{$case}[$CASE_CRASHED]
+ #@{$case}[$CASE_FAILED]
+ #@{$case}[$CASE_PASSED]
+ push @buff, (@{$case}[$CASE_STATUS] . " ");
+ #@{$case}[$CASE_PURPOSE]
+ #@{$case}[$CASE_MEANS]
+ #@{$case}[$CASE_REQUIRED_SETTINGS]
+ #@{$case}[$CASE_RELATED_REQUIREMENTS]
+ #@{$case}[$CASE_VERIFICATION]
+ #@{$case}[$CASE_NOTE]
+ #@{$case}[$CASE_REASON]
+ #@{$case}[$CASE_RESULT]
+ push @buff, ("file: " . @{$case}[$CASE_LOG_FILE] . " ");
+
+ push @buff, ("check log: " . @{$case}[$CASE_CHECK_RESULT_LOG_FILE] . " ");
+
+ push @buff, ("\n");
+
+ }
+ }
+
+ open(XXX, ">" . $fileName);
+ print XXX ( @buff );
+ close(XXX);
+
+}
+
+#------------------------------------------------------------------------------------
+# FindFiles
+# Parameters:
+# $goDir, where to start finding
+# $fileSearch, filename search
+# $searchType, 0 = fullname search, 1 = filetype search
+# $refIncfiles, reference to array which will hold found files
+#------------------------------------------------------------------------------------
+sub FindFiles
+{
+ my ($godir, $fileSearch, $searchType, $refIncfiles) = @_;
+
+ my $startDir = cwd;
+
+ chdir($godir) or die("Could not change dir to $godir");
+
+ #print("Now in: " . cwd . "\n");
+
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ foreach my $file(@filelist)
+ {
+ if($file eq "." or $file eq "..") {next};
+
+ if (-d $file)
+ {
+ FindFiles( $file, $fileSearch, $searchType, $refIncfiles);
+ } else
+ {
+ if( ($file =~ m/$fileSearch/i and $searchType == 0 ) or ($file =~ m/$fileSearch$/i and $searchType == 1 ) )
+ {
+ $file = cwd . "/" . $file;
+ push @$refIncfiles, $file;
+ #print("$file\n");
+ }
+ }
+ }
+
+ chdir ($startDir) or die("Could not change dir to $startDir");
+}
+
+
+#------------------------------------------------------------------------------------
+# GetAllFiles
+# Parameters:
+# $goDir, where to start finding
+# $refIncfiles, reference to array which will hold found files
+# $subDirLevel, how deep in the directories we go to search files. < 0 is no limit.
+#------------------------------------------------------------------------------------
+sub GetAllFiles
+{
+ my ($godir, $refIncfiles, $subDirLevel) = @_;
+
+ my $startDir = cwd;
+
+ chdir($godir) or die("Could not change dir to $godir");
+
+ #print("Now in: " . cwd . "\n");
+
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ foreach my $file(@filelist)
+ {
+ if($file eq "." or $file eq "..") {next};
+
+ if (! (-d $file) )
+ {
+ my $path = $startDir . "/" . $file;
+ push @$refIncfiles, $path;
+ } elsif( $subDirLevel > 0 || $subDirLevel < 0 )
+ {
+ my $backupDir = cwd;
+ chdir( $file ) or die("Could not change dir to $file");
+ GetAllFiles( $godir, $refIncfiles, $subDirLevel-1 );
+ chdir( $backupDir ) or die("Could not change dir to $backupDir");
+ }
+ }
+
+ chdir ($startDir) or die("Could not change dir to $startDir");
+}
+
+#------------------------------------------------------------------------------------
+# FindDirs
+# Parameters:
+# $goDir, where to start finding
+# $fileSearch, filename search
+# $refIncfiles, reference to array which will hold found files
+#------------------------------------------------------------------------------------
+sub FindDirs
+{
+ my ($godir, $fileSearch, $refIncfiles) = @_;
+
+ my $startDir = cwd;
+
+ chdir($godir) or die("Could not change dir to $godir");
+
+ #print("Now in: " . cwd . "\n");
+
+ opendir(DIR, ".");
+ my @filelist = sort(readdir(DIR));
+ closedir(DIR);
+
+ foreach my $file(@filelist)
+ {
+ if($file eq "." or $file eq "..") {next};
+
+ if (-d $file)
+ {
+ if( $file =~ m/$fileSearch/i )
+ {
+ push @$refIncfiles, (cwd . "/" . $file);
+ }
+ FindDirs( $file, $fileSearch, $refIncfiles );
+ }
+ }
+
+ chdir ($startDir) or die("Could not change dir to $startDir");
+}
+
+#------------------------------------------------------------------------------------
+# GetPathFileName
+#
+# Parameters:
+# $str
+#------------------------------------------------------------------------------------
+sub GetPathFileName
+{
+ my ($str) = @_;
+
+ my $startPos = rindex($str, "\\");
+ if($startPos == -1)
+ {
+ $startPos = rindex($str, "/");
+ return $str if($startPos == -1);
+ }
+
+ my $filename = substr($str, $startPos+1);
+
+ return $filename;
+}
+
+#------------------------------------------------------------------------------------
+# GetPathDir
+#
+# Parameters:
+# $str
+#------------------------------------------------------------------------------------
+sub GetPathDir
+{
+ my ($str) = @_;
+
+ my $startPos = rindex($str, "\\");
+ if($startPos == -1)
+ {
+ $startPos = rindex($str, "/");
+ return $str if($startPos == -1);
+ }
+
+ my $filename = substr($str, 0, $startPos);
+
+ return $filename;
+}
+
+sub InitXmlData
+{
+
+$xmlHeader =
+"<?xml version='1.0'?>" .
+"<?mso-application progid='Excel.Sheet'?>" .
+"<Workbook xmlns='urn:schemas-microsoft-com:office:spreadsheet'" .
+" xmlns:o='urn:schemas-microsoft-com:office:office'" .
+" xmlns:x='urn:schemas-microsoft-com:office:excel'" .
+" xmlns:ss='urn:schemas-microsoft-com:office:spreadsheet'" .
+" xmlns:html='http://www.w3.org/TR/REC-html40'>" .
+" <DocumentProperties xmlns='urn:schemas-microsoft-com:office:office'>" .
+" <Author>Senbom Petri</Author>" .
+" <LastAuthor>Senbom Petri</LastAuthor>" .
+" <Created>2006-06-09T11:08:05Z</Created>" .
+" <Company>Nokia Oyj</Company>" .
+" <Version>11.6568</Version>" .
+" </DocumentProperties>" .
+" <ExcelWorkbook xmlns='urn:schemas-microsoft-com:office:excel'>" .
+" <WindowHeight>12210</WindowHeight>" .
+" <WindowWidth>18780</WindowWidth>" .
+" <WindowTopX>360</WindowTopX>" .
+" <WindowTopY>255</WindowTopY>" .
+" <ProtectStructure>False</ProtectStructure>" .
+" <ProtectWindows>False</ProtectWindows>" .
+" </ExcelWorkbook>" .
+" <Styles>" .
+" <Style ss:ID='Default' ss:Name='Normal'>" .
+" <Alignment ss:Vertical='Bottom'/>" .
+" <Borders/>" .
+" <Font/>" .
+" <Interior/>" .
+" <NumberFormat/>" .
+" <Protection/>" .
+" </Style>" .
+" <Style ss:ID='m155260432'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='m155260442'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='m155266416'>" .
+" <Alignment ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Font x:Family='Swiss' ss:Bold='1'/>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='m155266426'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='m155266436'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='m155266446'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s21'>" .
+" <Alignment ss:Horizontal='Right' ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s25'>" .
+" <Alignment ss:Horizontal='Right' ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s26'>" .
+" <Borders>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s27'>" .
+" <Alignment ss:Horizontal='Center' ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s28'>" .
+" <Borders>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s29'>" .
+" <Borders>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s30'>" .
+" <Alignment ss:Horizontal='Right' ss:Vertical='Top'/>" .
+" <Borders>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s34'>" .
+" <Alignment ss:Horizontal='Right' ss:Vertical='Top'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+" <Style ss:ID='s35'>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#failed
+
+" <Style ss:ID='s36'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFF00' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#passed style
+
+" <Style ss:ID='s37'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#CCFFCC' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#crashed style
+
+" <Style ss:ID='s38'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+# UNKNOWN style
+
+" <Style ss:ID='s401'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+
+#NA style
+" <Style ss:ID='s39'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" </Style>" .
+
+
+#failed centered
+
+" <Style ss:ID='s36centered'>" .
+" <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFF00' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#passed style centered
+
+" <Style ss:ID='s37centered'>" .
+" <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#CCFFCC' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#crashed style centered
+
+" <Style ss:ID='s38centered'>" .
+" <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+# UNKNOWN style centered
+
+" <Style ss:ID='s401centered'>" .
+" <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+
+#NA style centered
+" <Style ss:ID='s39centered'>" .
+" <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" </Style>" .
+
+#summary style
+" <Style ss:ID='summary'>" .
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#summary real number style
+" <Style ss:ID='summaryreal'>" .
+" <NumberFormat ss:Format='Fixed'/> ".
+" <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#summary header
+" <Style ss:ID='summary_header'>" .
+" <Alignment ss:Horizontal='Left' ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Font x:Family='Swiss' ss:Bold='1'/>" .
+" </Style>" .
+
+#brief header
+" <Style ss:ID='brief_header'>" .
+" <Alignment ss:Horizontal='Center' ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+" <Style ss:ID='brief_heading_cfgfilename'>" .
+" <Alignment ss:Vertical='Bottom'/>" .
+" <Borders>" .
+" <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
+" </Borders>" .
+" <Font x:Family='Swiss' ss:Bold='1'/>" .
+" <Interior ss:Color='#CCFFCC' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+#link
+" <Style ss:ID='urlparent' ss:Name='Hyperlink'>" .
+" <Font ss:Color='#0000FF' ss:Underline='Single'/>" .
+" </Style>" .
+
+" <Style ss:ID='url' ss:Parent='urlparent'>" .
+" <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
+" </Style>" .
+
+" </Styles>" .
+" <Worksheet ss:Name='Sheet1'>";
+
+$xmlHeaderTableColumns =
+" <Table ss:ExpandedColumnCount='18' ss:ExpandedRowCount='CASE_COUNT_MUL8' x:FullColumns='1'" .
+" x:FullRows='1'>" .
+" <Column ss:AutoFitWidth='0' ss:Width='138.75'/>" .
+" <Column ss:Index='3' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='5' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='7' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='16' ss:AutoFitWidth='0' ss:Width='26.25'/>" .
+" <Column ss:AutoFitWidth='0' ss:Width='15'/>" .
+" <Column ss:AutoFitWidth='0' ss:Width='525.75'/>\n\n";
+
+$xmlHeaderTableColumnsBrief =
+" <Table ss:ExpandedColumnCount='25' ss:ExpandedRowCount='CASE_COUNT_MUL8' x:FullColumns='1'" .
+" x:FullRows='1'>" .
+" <Column ss:AutoFitWidth='0' ss:Width='138.75'/>" .
+" <Column ss:Index='2' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='3' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='4' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='5' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='6' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='7' ss:AutoFitWidth='0' ss:Width='65'/>" . #status
+" <Column ss:Index='8' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='9' ss:AutoFitWidth='0' ss:Width='39'/>" .
+" <Column ss:Index='12' ss:AutoFitWidth='0' ss:Width='260'/>" . # info
+" <Column ss:Index='13' ss:AutoFitWidth='0' ss:Width='26.25'/>" . # link1
+" <Column ss:Index='14' ss:AutoFitWidth='0' ss:Width='26.25'/>" . # link2
+" <Column ss:Index='16' ss:AutoFitWidth='0' ss:Width='26.25'/>" .
+" <Column ss:AutoFitWidth='0' ss:Width='15'/>" .
+" <Column ss:AutoFitWidth='0' ss:Width='525.75'/>\n\n";
+
+$xmlHeaderTableColumnsAlt =
+" <Table ss:ExpandedColumnCount='25' ss:ExpandedRowCount='CASE_COUNT_MUL8' x:FullColumns='1'" .
+" x:FullRows='1'>" .
+" <Column ss:AutoFitWidth=\"0\" ss:Width=\"138.75\"/>" .
+" <Column ss:AutoFitWidth=\"0\" ss:Width=\"30\" ss:Span=\"4\"/>" .
+" <Column ss:Index=\"7\" ss:AutoFitWidth=\"0\" ss:Width=\"60.00\" ss:Span=\"9\"/>" .
+" <Column ss:Index=\"17\" ss:AutoFitWidth=\"0\" ss:Width=\"15\"/>" .
+" <Column ss:AutoFitWidth=\"0\" ss:Width=\"525.75\"/>";
+
+$xmlFooter =
+
+" </Table>" .
+" <WorksheetOptions xmlns='urn:schemas-microsoft-com:office:excel'>" .
+
+#splitted panes
+#" <Selected/>" .
+#" <SplitHorizontal>3060</SplitHorizontal>" .
+#" <TopRowBottomPane>11</TopRowBottomPane>" .
+#" <ActivePane>2</ActivePane>" .
+#" <Panes>" .
+#" <Pane>" .
+#" <Number>3</Number>" .
+#" </Pane>" .
+#" <Pane>" .
+#" <Number>2</Number>" .
+#" <RangeSelection>R12C1:R12C8</RangeSelection>" .
+#" </Pane>" .
+#" </Panes>" .
+
+#not splitted
+" <Selected/>" .
+" <Panes>" .
+" <Pane>" .
+" <Number>3</Number>" .
+" <ActiveRow>7</ActiveRow>" .
+" <ActiveCol>2</ActiveCol>" .
+" </Pane>" .
+" </Panes>" .
+
+" <ProtectObjects>False</ProtectObjects>" .
+" <ProtectScenarios>False</ProtectScenarios>" .
+" </WorksheetOptions>" .
+" </Worksheet>" .
+" <Worksheet ss:Name='Sheet2'>" .
+" <WorksheetOptions xmlns='urn:schemas-microsoft-com:office:excel'>" .
+" <ProtectObjects>False</ProtectObjects>" .
+" <ProtectScenarios>False</ProtectScenarios>" .
+" </WorksheetOptions>" .
+" </Worksheet>" .
+" <Worksheet ss:Name='Sheet3'>" .
+" <WorksheetOptions xmlns='urn:schemas-microsoft-com:office:excel'>" .
+" <ProtectObjects>False</ProtectObjects>" .
+" <ProtectScenarios>False</ProtectScenarios>" .
+" </WorksheetOptions>" .
+" </Worksheet>" .
+"</Workbook>\n\n";
+
+$xmlDataEmptyRow =
+" <Row>" .
+" <Cell ss:StyleID='s35'><Data ss:Type='String'></Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>\n\n";
+
+$xmlSummaryData =
+
+$xmlDataEmptyRow .
+
+" <Row>" .
+" <Cell ss:StyleID='s35' ss:MergeAcross='20'>" . "<Data ss:Type='String'>INSERT TEST SOFTWARE HERE</Data></Cell>" .
+" </Row>\n\n" .
+
+" <Row>" .
+" <Cell ss:StyleID='s35' ss:MergeAcross='20'>" . "<Data ss:Type='String'>INSERT TEST DEVICE HERE</Data></Cell>" .
+" </Row>\n\n" .
+
+$xmlDataEmptyRow .
+
+" <Row>\n" .
+" <Cell ss:MergeAcross='4' ss:StyleID='summary_header'><Data ss:Type='String'>Test Execution Metrics</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Total cases:</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryCaseCount</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Passed:</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryPassed</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Failed:</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryFailed</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Crashed:</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryCrashed</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Timeout:</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryTimeout</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Pass rate % (total cases):</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summaryreal'><Data ss:Type='Number'>$xmlDataSummaryPassRateTotal</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Pass rate % (run cases):</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summaryreal'><Data ss:Type='Number'>$xmlDataSummaryPassRateRun</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+" <Row>\n" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Run rate %:</Data></Cell>" .
+" <Cell ss:MergeAcross='3' ss:StyleID='summaryreal'><Data ss:Type='Number'>$xmlDataSummaryRunRate</Data></Cell>" .
+" <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
+" </Row>\n" .
+ $xmlDataEmptyRow;
+
+$xmlData =
+" <Row>" .
+" <Cell ss:StyleID='s21'><Data ss:Type='String'>Name:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>";
+
+# not included in the case documentation report
+$xmlDataCaseStatusDisabled =
+" <Row>" .
+" <Cell ss:StyleID='s25'><Data ss:Type='String'>Run times:</Data></Cell>" .
+" <Cell ss:StyleID='s26'><Data ss:Type='Number'>XML_DATA_CASE_RUN_TIMES</Data></Cell>" .
+#
+" <Cell ss:StyleID='s27'><Data ss:Type='String'>Crashed</Data></Cell>" .
+" <Cell ss:StyleID='s28'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>" .
+
+" <Cell ss:StyleID='s27'><Data ss:Type='String'>Failed</Data></Cell>" .
+" <Cell ss:StyleID='s28'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>" .
+" <Cell ss:StyleID='s27'><Data ss:Type='String'>Passed</Data></Cell>" .
+" <Cell ss:StyleID='s28'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>" .
+" <Cell ss:StyleID='s27'><Data ss:Type='String'>Status</Data></Cell>" .
+#orig status style id s28
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>" .
+" <Cell ss:StyleID='s28'/>" .
+" <Cell ss:StyleID='s28'/>" .
+" <Cell ss:StyleID='s28'/>" .
+" <Cell ss:StyleID='s28'/>" .
+" <Cell ss:StyleID='s28'/>" .
+" <Cell ss:StyleID='s28'/>" .
+" <Cell ss:StyleID='s28'/>" .
+#" <Cell ss:StyleID='s28'/>" .
+#" <Cell ss:StyleID='s29'/>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>\n\n";
+$xmlDataCaseStatusDisabled .= "";
+
+$xmlData2 =
+" <Row ss:AutoFitHeight='0' ss:Height='30'>" .
+" <Cell ss:StyleID='s30'><Data ss:Type='String'>Purpose:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155266426'><Data ss:Type='String'>XML_DATA_CASE_PURPOSE</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>" .
+" <Row ss:AutoFitHeight='0' ss:Height='30'>" .
+" <Cell ss:StyleID='s30'><Data ss:Type='String'>Means:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155266436'><Data ss:Type='String'>XML_DATA_CASE_MEANS</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>" .
+" <Row ss:AutoFitHeight='0' ss:Height='30'>" .
+" <Cell ss:StyleID='s30'><Data ss:Type='String'>Required environment settings:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155266446'><Data ss:Type='String'>XML_DATA_CASE_REQUIRED_SETTINGS</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>" .
+" <Row ss:AutoFitHeight='0' ss:Height='30'>" .
+" <Cell ss:StyleID='s30'><Data ss:Type='String'>Related requirements:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155266446'><Data ss:Type='String'>XML_DATA_CASE_RELATED_REQUIREMENTS</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>" .
+
+" <Row ss:AutoFitHeight='0' ss:Height='30'>" .
+" <Cell ss:StyleID='s30'><Data ss:Type='String'>Verification:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155260432'><Data ss:Type='String'>XML_DATA_CASE_VERIFICATION</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>" .
+" <Row ss:AutoFitHeight='0' ss:Height='30'>" .
+" <Cell ss:StyleID='s34'><Data ss:Type='String'>Note:</Data></Cell>" .
+" <Cell ss:MergeAcross='15' ss:StyleID='m155260442'><Data ss:Type='String'>XML_DATA_CASE_NOTE</Data></Cell>" .
+" <Cell ss:StyleID='s35'/>" .
+" </Row>\n\n";
+
+
+$xmlDataBriefHeader =
+" <Row>" .
+" <Cell ss:MergeAcross='5' ss:StyleID='brief_header'><Data ss:Type='String'>Name</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Status</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Passes</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Fails</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Crashes</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Result</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Info</Data></Cell>" .
+" <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
+" </Row>\n\n";
+
+$xmlDataBriefNoLinks =
+" <Row>\n" .
+" <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_RESULT</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='String'>XML_DATA_CASE_REASON</Data></Cell>\n" .
+" <Cell ss:MergeAcross='7' ss:StyleID='s35'/>\n" .
+" </Row>\n\n";
+
+$xmlDataBrief1Link =
+" <Row>\n" .
+" <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_RESULT</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='String'>XML_DATA_CASE_REASON</Data></Cell>\n" .
+" <Cell ss:StyleID='url' ss:HRef='XML_DATA_CASE_LINK1'><Data ss:Type='String'>Link</Data></Cell>\n" .
+" <Cell ss:MergeAcross='6' ss:StyleID='s35'/>\n" .
+" </Row>\n\n";
+
+$xmlDataBrief2Links =
+" <Row>\n" .
+" <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_RESULT</Data></Cell>\n" .
+" <Cell ss:StyleID='s39'><Data ss:Type='String'>XML_DATA_CASE_REASON</Data></Cell>\n" .
+" <Cell ss:StyleID='url' ss:HRef='XML_DATA_CASE_LINK1'><Data ss:Type='String'>Link</Data></Cell>\n" .
+" <Cell ss:StyleID='url' ss:HRef='XML_DATA_CASE_LINK2'><Data ss:Type='String'>Link</Data></Cell>\n" .
+" <Cell ss:MergeAcross='5' ss:StyleID='s35'/>\n" .
+" </Row>\n\n";
+
+$xmlCfgFileBrief =
+" <Row>" .
+" <Cell ss:MergeAcross='11' ss:StyleID='brief_heading_cfgfilename'><Data ss:Type='String'>XML_DATA_CFG_FILE</Data></Cell>" .
+" <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
+" </Row>\n\n";
+
+
+$xmlCfgFileAltHeader =
+" <Row>" .
+" <Cell ss:MergeAcross='5' ss:StyleID='brief_header'><Data ss:Type='String'>Name</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE1</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE2</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE3</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE4</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE5</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE6</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE7</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE8</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE9</Data></Cell>" .
+" <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE10</Data></Cell>" .
+" <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
+" </Row>\n\n";
+
+
+$xmlCfgFileAltData =
+" <Row>" .
+" <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT1</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT2</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT3</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT4</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT5</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT6</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT7</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT8</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT9</Data></Cell>" .
+" <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT10</Data></Cell>" .
+" <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
+" </Row>\n\n";
+
+} # sub InitXml
+