/*
* Copyright (c) 2005-2009 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:
* Design Overview:
* The diagram below shows the Script Engine classes and their parent child
* hierarchy. All classes have a CActive base, and apart from CTaskTimer, all classes
* have their own state machine. Apart from CScriptMaster, all classes have a reference
* to a Mixin/Interface completion call of its parent, which it calls when the object
* needs to notify the parent of an event.
* CScriptMaster (derived CActive)
* CScriptControl (derived CActiveBase - Can go recursive)
* CProgramControl (derived CTaskControlBase) CClientControl ( derived CTaskControlBase maps to n x test steps)
* CTaskTimer CTaskTimer (derived CTimer)
* state transition tables for CScriptMaster, CScriptControl & CClientControl
* CActiveBase:
* Derives CActive.
* Contains code for priming, triggering and completing AO's
* Implements the pure abstract MChildCompletion::ChildCompletion() method
* CTaskControlBase:
* Derives CActiveBase.
* Abstract class. Base for CClientControl and CProgramControl.
* CScriptMaster:
* Derives CActiveBase.
* Master control active object with simple state machine.
* Instantiates the top level CScriptControl object and triggers its state machine.
* CScriptContol:
* Derives CActiveBase.
* Main script interpreter state machine. Creates one or more CClientControl and/or
* CProgramControl objects.
* In CONCURRENT mode, it can create as many instances as there are RUN_TEST_STEP and/or
* RUN_PROGRAM calls.
* Creates root sessions with the xxxtest servers using the RTestServ::Connect() client call.
* In the case of non-nested scripts, the parent object is CScriptMaster.
* When scripts are nested and it goes recursive, the parent object could be another
* CScriptControl.
* Implements the MTaskCompletion pure abstract class for callbacks from
* CClientControl or CProgramControl objects
* Calls back into its parent object when the script is complete and all async commands have
* completed.
* CClientControl:
* Derives CTaskControlBase.
* Test Step Controler. Instantiated by CScriptControl when a RUN_TEST_STEP line is interpreted
* Creates and kicks off a CTaskTimer object set to the timeout value for the test step.
* Opens a test step using the RTestSession::Open() client call.
* Executes a test step using the RTestSession::RunTestStep() client call.
* This method issues the client RTestSession::AbortTestStep() call and
* the RunL() state machine handles the completion from the test server.
* Implements the MTaskTimerCompletion pure abstract class for callbacks from the
* CTaskTimer class.
* Calls back into its parent CScriptControl object when a test step completes.
* CProgramControl
* Derives CTaskControlBase
* Kicks off an executable in its own process and handles process completion asynchronously
* CTaskTimer:
* Derives CTimer.
* Calls back into its parent object if the timer expires.
* EPOC include
*
*/
/**
@file scriptengine.cpp
*/
//#include <utf.h>
#if !(defined TEF_LITE)
#include <apacmdln.h>
#include <apgtask.h>
#endif
// User include
#include <testexecuteclient.h>
#include "ScriptEngine.h"
// Fix defect 119337, initialize the integer to zero
GLDEF_D TInt CScriptControl::iNestedNumRunScriptInLoop=0;
// End defect 119337
/**
* @param aPtrC1 - Instance of TPtrC to compare
* @param aPtrC2 - Instance of TPtrC to compare
* Function to implement the comparison algo for RArray::Find to work with
*/
TBool TSelectiveTestingOptions::CompareTPtrC(const TPtrC& aPtrC1, const TPtrC& aPtrC2)
{
TInt ret =aPtrC1.CompareF(aPtrC2);
return (ret==0) ? ETrue : EFalse;
}
/**
* @param aRng1 - Instance of TRange to compare
* @param aRng2 - Instance of TRange to compare
* Function to implement the comparison algo for RArray::Find to work with.
* TRange::iStartTestCase determines the match
*/
TBool TRange::CompareTRangeStartCase(const TRange& aRng1, const TRange& aRng2)
{
TInt ret =aRng2.iStartTestCase.CompareF(aRng1.iStartTestCase);
return (ret==0) ? ETrue : EFalse;
}
/**
* @param aRng1 - Instance of TRange to compare
* @param aRng2 - Instance of TRange to compare
* Function to implement the comparison algo for RArray::Find to work with.
* TRange::iEndTestCase determines the match
*/
TBool TRange::CompareTRangeEnd(const TRange& aRng1, const TRange& aRng2)
{
TInt ret =aRng2.iEndTestCase.CompareF(aRng1.iEndTestCase);
return (ret==0) ? ETrue : EFalse;
}
/**
* @param aRng1 - Instance of TRange to compare
* @param aRng2 - Instance of TRange to compare
* Function to implement the comparison algo for RArray::Sort to work with.
* TRange::iStartTestCase is used as the sort key
*/
TInt TRange::CompareTRangeStartOrder(const TRange& aRng1, const TRange& aRng2)
{
return aRng1.iStartTestCase.CompareF( aRng2.iStartTestCase);
}
/**
* @param aPtrC1 - Instance of TPtrC to compare
* @param aPtrC2 - Instance of TPtrC to compare
* Function to implement the comparison algo for RArray::Sort to work with.
*/
TInt TSelectiveTestingOptions::CompareTPtrCOrder(const TPtrC& aPtrC1, const TPtrC& aPtrC2)
{
return aPtrC1.CompareF(aPtrC2);
}
/**
* @param aServ - Instance of the test server handle
* @param aStepName - Test step name
* Wrapper around the RTestServ class. Performs counting on test step sessions
*/
TInt RScriptTestSession::Open(RScriptTestServ& aServ, const TBool aIsTestStep, const TDesC& aStepName )
{
if(aServ.SharedData() && aServ.SessionCount())
return KErrInUse;
TInt ret = KErrNone;
if( aIsTestStep )
{
ret = RTestSession::Open(aServ, aStepName, aServ.SharedData());
}
else
{
ret = RTestSession::Open(aServ, aServ.SharedData());
}
if(ret)
return ret;
aServ.AddSession();
iServ = &aServ;
return KErrNone;
}
/**
* @param aScriptFilePath - The full path and filename of a script command file.
* @param aLogger - Reference to a logger interface object that contains HTML & XML log client sessions.
* @param aConsole - Reference to console object for printing script line during test execution
* @param aSysDrive - Default System drive letter
* @param aTestSysDrive - Default System drive letter overwritten through testexecute.ini
* Constructor
*/
CScriptMaster::CScriptMaster(const TDesC& aScriptFilePath, CTestExecuteLogger& aLogger, RConsoleLogger& aConsole, const TDriveName& aSysDrive, const TDriveName& aTestSysDrive, TSelectiveTestingOptions* aSelTestingOptions ) :
iState(EInit), iScriptFilePath(aScriptFilePath), iLogger(aLogger), iConsoleLogger(aConsole), iDefaultSysDrive(aSysDrive), iTestSysDrive(aTestSysDrive), iSelTestingOptions(aSelTestingOptions)
{
}
/**
* Destructor
*/
CScriptMaster::~CScriptMaster()
{
}
/**
* Pure virtual implementation.
* The Top level state machine Kick'd() into by MainL()
* Picks up the completion from a CScriptControl instance then exits the scheduler
*/
void CScriptMaster::RunL()
{
switch (iState)
{
case EInit :
{
// Create the master CScriptControl instance.
CScriptControl* scriptControl = new (ELeave) CScriptControl(*this,iScriptFilePath,Logger(),ConsoleLogger(),iStartLooping,iLoop,iDefaultSysDrive,iTestSysDrive,iSelTestingOptions);
iState = ERunning;
// Set our AO up ready for completion
Prime();
// Kick the CScriptControl state machine
scriptControl->Kick();
}
break;
case ERunning :
{
// All child AO's have completed and been deleted so it's safe to exit.
CActiveScheduler::Stop();
}
break;
default:
break;
}
}
/**
* @param aCompletion - Callback into the parent object.
* @param aScriptFilePath - The full path and filename of a script file
* @param aLogger - Reference to a logger instance
* @param aConsole - Reference to console object for printing script line during test execution
* @param aStartLooping - Initiate the looping
* @param aLoop - Check for nesting of loops
* @param aSysDrive - Default System drive letter
* @param aTestSysDrive - System drive letter overwritten from testexecute.ini
* Constructor
*/
CScriptControl::CScriptControl(MChildCompletion& aCompletion, const TDesC& aScriptFilePath, CTestExecuteLogger& aLogger, RConsoleLogger& aConsole, TBool aStartLooping, TBool aLoop, const TDriveName& aSysDrive, const TDriveName& aTestSysDrive, TSelectiveTestingOptions* aSelTestingOptions):
iScriptFile(aScriptFilePath),
iState(EInit),
iParent(aCompletion),
iConcurrent(EFalse),
iCanComplete(ETrue),
iBreakOnError(EFalse),
iAsyncTasksOutstanding(0),
iCurrentScriptLineNumber(0),
iLogger(aLogger),
iConsoleLogger(aConsole),
iScriptLinePrefixSet(EFalse),
iStartLooping(aStartLooping),
iLoop(aLoop),
iSharedDataNum(KTEFZeroValue),
iIsSharedData(EFalse),
iSyncControl(NULL),
iTestCaseID(KTEFTestCaseDefault),
iDefaultSysDrive(aSysDrive),
iTestSysDrive(aTestSysDrive),
iSelTestingOptions(aSelTestingOptions),
iSelectOne(EFalse),
iRangeRefCounter(0),
iTestCaseCounter(0)
{
}
/**
* Destructor
*/
CScriptControl::~CScriptControl()
{
iTimer.Cancel();
iTimer.Close();
// We read the complete script into the heap for parsing so:
delete iScriptData;
for (TInt index = 0; index < iSharedDataNum; index++)
{
delete iSharedDataArray[index];
}
// Instance has an array of pointers to RTestServer objects.
// Loop through deleting and closing
TInt i = 0;
TInt count = iServers.Count();
for(i=0;i<count;i++)
{
iServers[0]->Close();
delete iServers[0];
iServers.Remove(0);
}
iServers.Close();
if( iSyncControl )
{
delete iSyncControl;
}
}
/**
* @param aError - Integer error value returned by the active object while leaving
* @return TInt - System-wide error codes
* Error Handler for active object
*/
TInt CScriptControl::RunError(TInt aError)
{
if (aError == KErrNoMemory)
{
ERR_PRINTF1(_L("Insufficient memory available to perform further operation.\n\tPlease increase the maximum heap size from the testexecute.mmp and try running the test again. Exiting test script..."));
}
else
{
ERR_PRINTF2(_L("Test execution failed with error %d. Terminating tests.."), aError);
}
iParent.ChildCompletion(KErrNone);
delete this;
return KErrNone;
}
/**
* Implementation of pure virtual
* The main script interpreter state machine.
* Kick'd() into by CScriptMaster or, in the case of nested scripts, another CScriptControl
* instance.
* Picks up the completions from CClientControls and/or, in the case of nested scripts,
* another CScriptControl instance.
*/
void CScriptControl::RunL()
{
switch (iState)
{
case EInit :
// First state after Kick() from parent
{
// Standard log output goes to flogger
// Result log goes to a propietary file in c:\logs\testexecute
User::LeaveIfError(iTimer.CreateLocal());
TRAPD(err,CreateScriptDataFromScriptFileL());
if(err)
{
// If we can't open the script file then log the fact and gracefully exit
// the state machine.
TBuf<KMaxTestExecuteCommandLength> buf(iScriptFile);
_LIT(KScriptFileError,"Failed Script File Open %S");
ERR_PRINTF2(KScriptFileError,&buf);
iState = EClosing;
//condition used for checking failure in testexecute.cpp
commentedCommandsCount=-1;
iRunScriptFailCount++;
Kick();
break;
}
// Script file reading state next
iState = ERunning;
// Kick ourselves into the next state
Kick();
}
break;
case ERunning :
// Always in this state whilst we're reading lines from script file data member
{
TPtrC scriptLine;
if(!iStartLooping)
{
if(!GetNextScriptLine(scriptLine))
{
// End of the script file
// Check see if there are any async requests outstanding
// In concurrent mode there are very likely to be
if(iAsyncTasksOutstanding == 0)
{
// No requests outstanding so call into the parent
iParent.ChildCompletion(KErrNone);
delete this;
}
else
{
// Requests outstanding
// Next time we're completed we'll be in the closing state
iState = EClosing;
iCanComplete =ETrue;
// Prime ourselves for completion
Prime();
}
break;
}
}
//Get the script lines which are to be looped
else if(!GetLoopScriptLine(scriptLine))
{
// End of the script file
// Check see if there are any async requests outstanding
// In concurrent mode there are very likely to be
if(iAsyncTasksOutstanding == 0)
{
// No requests outstanding so call into the parent
iParent.ChildCompletion(KErrNone);
delete this;
}
else
{
// Requests outstanding
// Next time we're completed we'll be in the closing state
iState = EClosing;
iCanComplete =ETrue;
// Prime ourselves for completion
Prime();
}
break;
}
iCurrentScriptLine.Set(scriptLine);
TBool commentedCommand = CheckCommentedCommands();
if(commentedCommand)
{
iCanComplete = EFalse;
Kick();
break;
}
if (iScriptLinePrefixSet )
{
TLex lookahead(iCurrentScriptLine);
TPtrC firstCommand(lookahead.NextToken());
if (firstCommand.CompareF(KTEFRemovePrefixCommand) != 0)
{
// If we aren't the Remove_Prefix command, prefix the current line...
iPrefixedCurrentScriptLine = iScriptLinePrefix;
iPrefixedCurrentScriptLine.Append(scriptLine);
iCurrentScriptLine.Set(iPrefixedCurrentScriptLine);
}
}
TRAPD(err, MakeAbsoluteFilePathsL(iCurrentScriptLine));
PrintCurrentScriptLine();
TLex lex(iCurrentScriptLine);
TPtrC token(lex.NextToken());
if (err == KTEFErrInvalidRelPath)
{
_LIT(KTEFErrInvalidRelPathText,"Invalid relative path provided in the script file. Skipping the script line from execution..");
ERR_PRINTF1(KTEFErrInvalidRelPathText);
if (token.CompareF(KTEFRunTestStepCommand) == 0 ||
token.CompareF(KTEFRunPanicStepCommand) == 0 ||
token.CompareF(KTEFRunTestStepResultCommand) == 0 ||
token.CompareF(KTEFRunPanicStepResultCommand) == 0)
{
TExitCategoryName blankPanicString; //Not a Panic
LogResult(EIgnore, blankPanicString, iCurrentScriptLineNumber, iCurrentScriptLine);
}
iCanComplete = EFalse;
Kick();
break;
}
if(err == KErrTooBig)
{
_LIT(KTEFErrTooBigArguments, "One or more arguments for the command exceeded allowed limit for length. Skipping test..");
ERR_PRINTF1(KTEFErrTooBigArguments);
if (token.CompareF(KTEFRunTestStepCommand) == 0 ||
token.CompareF(KTEFRunPanicStepCommand) == 0 ||
token.CompareF(KTEFRunTestStepResultCommand) == 0 ||
token.CompareF(KTEFRunPanicStepResultCommand) == 0)
{
TExitCategoryName blankPanicString; //Not a Panic
LogResult(EIgnore, blankPanicString, iCurrentScriptLineNumber, iCurrentScriptLine);
}
iCanComplete = EFalse;
Kick();
break;
}
// Main parser
if(token.CompareF(KTEFLoadSuiteCommand) == 0 || token.CompareF(KTEFLoadServerCommand) == 0)
{
TRAPD(err,CreateServerFromScriptLineL());
// Create a TLogField structure array
// Size of array equals to number of fields to be displayed for the command
TExtraLogField logField[2];
// The first member of the structure stores the field name
// The second one holds the value for the particular field
_LIT(KSuiteName, "SUITE_NAME");
logField[0].iLogFieldName.Copy(KSuiteName);
logField[0].iLogFieldValue.Copy(lex.NextToken());
logField[1].iLogFieldName.Copy(KTEFResultString);
if(err != KErrNone)
{
logField[1].iLogFieldValue.Copy(KTEFResultFail);
if( KErrNotFound == err )
{
_LIT(KServerNotFound,"Failed to create server, either the server or one of its dependancies could not be found.");
ERR_PRINTF1(KServerNotFound);
}
else
{
_LIT(KServerCreateError,"Failed to Create Server Err = %d");
ERR_PRINTF2(KServerCreateError,err);
}
}
else
{
logField[1].iLogFieldValue.Copy(KTEFResultPass);
}
// Call the Logger().LogToXml routine which handles XML logging for individual commands
// Takes in the command name, number of fields and the struture array
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, token, 2, logField);
iCanComplete = EFalse;
Kick();
}
else if(token.CompareF(KTEFStartTestBlock)==0)
{
// Parse the START_TEST_BLOCK command line
TInt index = 0;
TBool taskCanComplete = ETrue;
TBool concurrent = iConcurrent;
// Make sure the server is loaded
if(!GetServerIndexFromScriptLine(index))
{
// Not loaded. Skip the line, but ensure its logged as a failure.
TExitCategoryName blankPanicString; //Not a Panic
LogResult(EIgnore, blankPanicString, iCurrentScriptLineNumber, iCurrentScriptLine);
iCanComplete = EFalse;
Kick();
break;
}
TBuf<KMaxTestExecuteCommandLength> startBlockLine = iCurrentScriptLine;
// Parse the test block of commands
TTEFItemArray* itemArray = new (ELeave) TTEFItemArray(1);
CleanupStack::PushL( itemArray );
TRAPD( err, ParseTestBlockL(*itemArray) );
if( KErrNone == err )
{
if(!iConcurrent)
{
// If we're not in concurrent mode then child objects can complete us
taskCanComplete = ETrue;
// Prime ready for completion
Prime();
}
else
{
// In concurrent mode children can't complete us as we kick() ourselves.
taskCanComplete = EFalse;
Kick();
}
// Create the test block controler object
TInt loopIndex = -1;
if (iLoop)
{
loopIndex = iLoopCounter + 1;
}
CClientControl* blockController = CClientControl::NewL( *iServers[index],
startBlockLine,
*this,
iCurrentScriptLineNumber,
Logger(),
loopIndex,
iTestCaseID,
iCurrentScriptLine,
iScriptFile,
*itemArray,
iDefaultSysDrive,
iTestSysDrive);
blockController->SetTaskComplete(taskCanComplete);
iAsyncTasksOutstanding++;
// Kick() the test step object into its state machine
blockController->Kick();
}
else
{
iCanComplete = EFalse;
Kick();
}
iConcurrent = concurrent;
CleanupStack::PopAndDestroy( itemArray );
}
else if(token.CompareF(KTEFEndTestBlock)==0)
{
// If this is called then there is a missing START_TEST_BLOCK command
TExitCategoryName blankPanicString;
LogResult(EIgnore, blankPanicString, iCurrentScriptLineNumber, iCurrentScriptLine);
iCanComplete = EFalse;
Kick();
}
else if(token.CompareF(KTEFStartRepeat)==0)
{
TPtrC iniFile(lex.NextToken());
TPtrC iniSection(lex.NextToken());
TPtrC tempRepeatParam=lex.NextToken();
CIniData* configData = NULL;
TInt err = 0;
if(iniFile.Length())
{
TRAP(err,configData = CIniData::NewL(iniFile));
}
if(err != KErrNone)
{
_LIT(KTEFIniFileNotFound,"Ini file not found.. Looping Ignored");
ERR_PRINTF1(KTEFIniFileNotFound);
Kick();
break;
}
iRepeatParam=0;
CleanupStack::PushL(configData);
if(configData)
{
//For Syntax Error continue ignoring looping
if (!configData->FindVar(iniSection, tempRepeatParam, iRepeatParam))
{
_LIT(KIniFailMessage,"The input data is not found in the ini specified");
INFO_PRINTF1(KIniFailMessage);
CleanupStack::PopAndDestroy(configData);
Kick();
break;
}
}
CleanupStack::PopAndDestroy(configData);
TExtraLogField logField[1];
_LIT(KIterations,"ITERATIONS");
logField[0].iLogFieldName.Copy(KIterations);
logField[0].iLogFieldValue.Copy(KNull);
logField[0].iLogFieldValue.AppendNum(iRepeatParam);
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, token, 1, logField);
if(tempRepeatParam.Compare(KNull)==0)
{
_LIT(KRepeatKeyNotFound,"Repeat Parameter Key Not Found");
INFO_PRINTF1(KRepeatKeyNotFound);
Kick();
break;
}
//Nesting of Control Logic is Not supported
if(iLoop)
{
_LIT(KNestingNotAllowed,"Nesting of START_REPEAT is not supported.. Looping Ignored");
WARN_PRINTF1(KNestingNotAllowed);
iLoop=EFalse;
Kick();
break;
}
//Looping is not to be started with Concurrent mode
if(iConcurrent)
{
_LIT(KConcurrentNotAllowed,"No concurrent Execution is Allowed in Looping");
INFO_PRINTF1(KConcurrentNotAllowed);
Kick();
break;
}
iLoopCounter=0;
//For Invalid Parameter continue ignoring looping
if(iRepeatParam<1)
{
_LIT(KInvalidRepeatParam,"The repeat Parameter is invalid");
INFO_PRINTF1(KInvalidRepeatParam);
Kick();
break;
}
iLoop=ETrue;
iCheckVar=EFalse;
Kick();
}
else if(token.CompareF(KTEFEndRepeat)==0)
{
if(!iLoop)
{
_LIT(KLoopNotInitiated,"The Looping is Not Initiated");
INFO_PRINTF1(KLoopNotInitiated);
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, token);
Kick();
break;
}
iLoopCounter++;
if(iLoopCounter==iRepeatParam)
{
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, token);
iStartLooping=EFalse;
iLoop=EFalse;
}
else
{
iStartLooping=ETrue;
//Looping needs to be started in CONSECUTIVE mode
if(iConcurrent)
{
iConcurrent=EFalse;
}
}
Kick();
}
else if(token.CompareF(KTEFRunTestStepCommand) == 0 ||
token.CompareF(KTEFRunPanicStepCommand) == 0 ||
token.CompareF(KTEFRunTestStepResultCommand) == 0 ||
token.CompareF(KTEFRunPanicStepResultCommand) == 0
)
{
if(!CheckValidScriptLine())
{
// Not a Valid Script Line
TExitCategoryName blankPanicString; //Not a Panic
LogResult(EIgnore, blankPanicString, iCurrentScriptLineNumber, iCurrentScriptLine);
// End of defect 037066
iCanComplete = EFalse;
Kick();
break;
}
TInt index;
TBool taskCanComplete = ETrue;
TBool concurrent = iConcurrent;
// Make sure the server is loaded
if(!GetServerIndexFromScriptLine(index))
{
// Not loaded. Skip the line, but ensure its logged as a failure.
// Start of defect 037066
TExitCategoryName blankPanicString; //Not a Panic
LogResult(EIgnore, blankPanicString, iCurrentScriptLineNumber, iCurrentScriptLine);
// End of defect 037066
iCanComplete = EFalse;
Kick();
break;
}
if(!iConcurrent)
{
// If we're not in concurrent mode then child objects can complete us
taskCanComplete = ETrue;
// Prime ready for completion
Prime();
}
else
{
// In concurrent mode children can't complete us as we kick() ourselves.
taskCanComplete = EFalse;
Kick();
}
iConcurrent = concurrent;
// Create the test step controler object
TInt loopIndex = -1;
if (iLoop)
{
loopIndex = iLoopCounter + 1;
}
CClientControl* stepController = new (ELeave) CClientControl(*iServers[index],iCurrentScriptLine,*this,iCurrentScriptLineNumber,Logger(), loopIndex, iTestCaseID, iScriptFile, iDefaultSysDrive, iTestSysDrive);
stepController->SetTaskComplete(taskCanComplete);
iAsyncTasksOutstanding++;
// Kick() the test step object into its state machine
stepController->Kick();
}
else if(token.CompareF(KTEFRunProgramCommand) == 0)
{
TBool taskCanComplete = ETrue;
if(!iConcurrent)
{
// If we're not in concurrent mode then child objects can complete us
taskCanComplete = ETrue;
// Prime ready for completion
Prime();
}
else
{
// In concurrent mode children can't complete us as we kick() ourselves.
taskCanComplete = EFalse;
Kick();
}
// Create the test step controller object
CProgramControl* programController = new (ELeave) CProgramControl(iCurrentScriptLine,*this,iCurrentScriptLineNumber,Logger());
programController->SetTaskComplete(taskCanComplete);
iAsyncTasksOutstanding++;
// Kick() the test step object into its state machine
programController->Kick();
}
else if(token.CompareF(KTEFRunWSProgramCommand) == 0)
{
TBool taskCanComplete = ETrue;
if(!iConcurrent)
{
// If we're not in concurrent mode then child objects can complete us
taskCanComplete = ETrue;
// Prime ready for completion
Prime();
}
else
{
// In concurrent mode children can't complete us as we kick() ourselves.
taskCanComplete = EFalse;
Kick();
}
// Create the test step controller object
CProgramControl* programController = new (ELeave) CProgramControl(iCurrentScriptLine,*this,iCurrentScriptLineNumber,Logger(),ETrue);
iAsyncTasksOutstanding++;
programController->SetTaskComplete(taskCanComplete);
// Kick() the test step object into its state machine
programController->Kick();
}
else if(token.CompareF(KTEFConcurrentCommand) == 0)
{
// Go into concurrent mode
// Whilst we're in concurrent mode we always kick() ourselves
// around the state engine
iConcurrent = ETrue;
// Call the Logger()'s LogToXml routine to handle XML logging
// Takes in just the command name without any field
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, KTEFConcurrentCommand);
iCanComplete = EFalse;
Kick();
}
else if(token.CompareF(KTEFConsecutiveCommand) == 0)
{
// If we go into consecutive mode we have to make sure there are no
// requests outstanding.Set the state accordingly
iConcurrent = EFalse;
// Call the Logger()'s LogToXml routine to handle XML logging
// Takes in just the command name without any field
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, KTEFConsecutiveCommand);
if(iAsyncTasksOutstanding)
{
iCanComplete = ETrue;
iState = EWaitCompletions;
Prime();
}
else
{
iCanComplete = EFalse;
iState = ERunning;
Kick();
}
}
else if(token.CompareF(KTEFRunUtilsCommand) == 0)
{
// All utils complete synchronously
TRAPD(err,RunUtilsFromScriptLineL());
// Create a TLogField structure array
// Size of array equals to number of fields to be displayed for the command
TExtraLogField logField[2];
// The first member of the structure stores the field name
// The second one holds the value for the particular field
_LIT(KCommand,"COMMAND");
logField[0].iLogFieldName.Copy(KCommand);
logField[0].iLogFieldValue.Copy(lex.NextToken());
logField[1].iLogFieldName.Copy(KTEFResultString);
if (err == KErrNone)
{
logField[1].iLogFieldValue.Copy(KTEFResultPass);
}
else
{
logField[1].iLogFieldValue.Copy(KTEFResultFail);
}
// Call the Logger().LogToXml routine which handles XML logging for individual commands
// Takes in the command name, number of fields and the struture array
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, KTEFRunUtilsCommand, 2, logField);
if(err != KErrNone)
{
_LIT(KRunUtilsError,"RUN_UTILS ret = %d");
INFO_PRINTF2(KRunUtilsError,err);
}
iCanComplete = EFalse;
Kick();
}
else if(token.CompareF(KTEFPrintCommand) == 0)
{
PrintFromScriptLine();
iCanComplete = EFalse;
Kick();
}
else if (token.CompareF(KTEFPrefixCommand) == 0)
{
if(iAsyncTasksOutstanding)
// Don't run Prefix until all outstanding requests have completed
{
iState = EPrefixPending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to run PREFIX - Kick the stated machine so it's run next time in the RunL()
iState = ERunPrefix;
iCanComplete = EFalse;
Kick();
}
}
else if (token.CompareF(KTEFRemovePrefixCommand) == 0)
{
iScriptLinePrefixSet = EFalse;
iCanComplete = EFalse;
Kick();
}
else if (token.CompareF(KTEFStartTestCaseCommand) == 0)
{
if(ProceedTestCase())
{
LogTestCaseMarkerL();
iCanComplete = EFalse;
Kick();
}
else
{
iState = ETestCaseIgnore;
iCanComplete = EFalse;
Kick();
}
}
else if (token.CompareF(KTEFEndTestCaseCommand) == 0)
{
ProcessEndCase();
if(iAsyncTasksOutstanding)
// Don't run END_TESTCASE until all outstanding requests have completed
{
iState = EEndTestCasePending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to run END_TESTCASE - Kick the stated machine so it's run next time in the RunL()
iState = ERunEndTestCase;
iCanComplete = EFalse;
Kick();
}
}
else if (token.CompareF(KTEFStartSyncTestCaseCommand) == 0)
{
if(ProceedTestCase())
{
// Start Synchronised Test Case
// Check to see if the Sync Data has been created
// If not then create it
if( iSyncControl == NULL )
{
iSyncControl = CSyncControl::NewL();
}
LogTestCaseMarkerL();
iState = ERunStartSyncTestCase;
iCanComplete = EFalse;
Kick();
}
else
{
//go into some sleep state until you
//encounter an end test case for this...
iState = ETestCaseIgnore;
iCanComplete = EFalse;
Kick();
}
}
else if (token.CompareF(KTEFEndSyncTestCaseCommand) == 0)
{
ProcessEndCase();
// End Synchronised Test Case
if(iAsyncTasksOutstanding)
// Don't run END_SYNCHRONISED_TESTCASE until all outstanding requests have completed
{
iState = EEndTestCasePending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to run END_SYNCHRONISED_TESTCASE - Kick the stated machine so it's run next time in the RunL()
iState = ERunEndTestCase;
iCanComplete = EFalse;
Kick();
}
}
else if(token.CompareF(KTEFRunScriptCommand) == 0)
{
// Create a TLogField structure array
// Size of array equals to number of fields to be displayed for the command
TExtraLogField logField[1];
// The first member of the structure stores the field name
// The second one holds the value for the particular field
_LIT(KScriptName,"SCRIPT_NAME");
logField[0].iLogFieldName.Copy(KScriptName);
logField[0].iLogFieldValue.Copy(lex.NextToken());
// Call the Logger().LogToXml routine which handles XML logging for individual commands
// Takes in the command name, number of fields and the struture array
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrHigh, KTEFRunScriptCommand, 1, logField);
if(iAsyncTasksOutstanding)
{
// Don't recursively process a new script until this one's async
// requests are completed
iState = ERunScriptPending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to process the script recursively
iState = ERunScript;
iCanComplete = EFalse;
Kick();
}
}
else if(token.CompareF(KTEFCedCommand) == 0)
// Run the CED comms database editor
{
if(iAsyncTasksOutstanding)
// Don't run CED until all outstanding requests have completed
{
iState = ERunCedPending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to run CED - Kick the stated machine so it's run next time in the RunL()
iState = ERunCed;
iCanComplete = EFalse;
Kick();
}
}
else if(token.CompareF(KTEFDelayCommand) == 0)
// Delay n milliseconds
{
if(iAsyncTasksOutstanding)
// Don't delay until all outstanding requests have completed
{
iState = EDelayPending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to delay
iState = EDelay;
iCanComplete = EFalse;
Kick();
}
}
// Script can exit on error
// Flag is checked on async task completion
else if(token.CompareF(KTEFBreakErrorOnCommand) == 0)
{
// Set the flag and process next line
iCanComplete = EFalse;
iBreakOnError = ETrue;
// Call the Logger()'s LogToXml routine to handle XML logging
// Takes in just the command name without any field
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, KTEFBreakErrorOnCommand);
Kick();
}
else if(token.CompareF(KTEFBreakErrorOffCommand) == 0)
{
// Reset the flag and process next line
iCanComplete = EFalse;
iBreakOnError = EFalse;
// Call the Logger()'s LogToXml routine to handle XML logging
// Takes in just the command name without any field
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrMedium, KTEFBreakErrorOffCommand);
Kick();
}
// We only implement the pause command if JustInTime debugging is switched on
else if(token.CompareF(KTEFPauseCommand) == 0 && User::JustInTime())
{
// Create a TLogField structure array
// Size of array equals to number of fields to be displayed for the command
TExtraLogField logField[1];
// The first member of the structure stores the field name
// The second one holds the value for the particular field
_LIT(KDelay,"DELAY");
logField[0].iLogFieldName.Copy(KDelay);
logField[0].iLogFieldValue.Copy(lex.NextToken());
// Call the Logger().LogToXml routine which handles XML logging for individual commands
// Takes in the command name, number of fields and the struture array
Logger().LogToXml(((TText8*)__FILE__), __LINE__, RFileFlogger::ESevrLow, KTEFPauseCommand, 1, logField);
if(iAsyncTasksOutstanding)
// Don't pause until all outstanding requests have completed
{
iState = EPausePending;
iCanComplete = ETrue;
Prime();
}
else
{
// Ok to Pause
iState = EPause;
iCanComplete = EFalse;
Kick();
}
}
// Handles the shared comand and also creates the shared object
// on reading user inputs from ini file
else if(token.CompareF(KTEFSharedDataCommand) == 0)
{
if (iIsSharedData)
{
WARN_PRINTF1(KTEFSharedDataCommandRepeated);
}
else
{
TRAPD(err,CreateSharedObjectsFromScriptLineL());
if (err != KErrNone)
{
ERR_PRINTF1(KTEFErrInCreatingSharedObjects);
}
}
iCanComplete = EFalse;
Kick();
}
else
{
// Command not implemented or a comment line
// Code implemented for defect 047340
TBuf<KMaxTestExecuteCommandLength> bufWarning;
if(token.Length())
{
TInt firstChar = iCurrentScriptLine[0];
if(firstChar != '\r' && firstChar != '\n' && firstChar != '#' && firstChar != '/' && token.CompareF(KTEFPauseCommand) != 0)
{
_LIT(KUnrecognised,"Unrecognised Command - %S");
if(token.Length() < bufWarning.MaxLength())
{
bufWarning.Copy(token);
WARN_PRINTF2(KUnrecognised,&bufWarning);
}
else
{
_LIT(KLineTooLong,"Command line too long");
bufWarning.Copy(KLineTooLong);
WARN_PRINTF2(KUnrecognised,&bufWarning);
}
}
}
iCanComplete = EFalse;
Kick();
}
}
break;
case EClosing :
// Script has been processed
// Pick up the completions
{
if(iAsyncTasksOutstanding == 0)
{
// Script finished
// Call into the parent
iParent.ChildCompletion(KErrNone);
delete this;
}
else
{
// More requests to complete
iCanComplete = ETrue;
Prime();
}
}
break;
case ERunScriptPending :
case EWaitCompletions :
case ERunCedPending :
case EDelayPending :
case EPausePending :
case EEndTestCasePending :
case EPrefixPending:
// We go into this state if we're waiting for RUN_TEST_STEP's
// to complete before we execute another command
{
if(iAsyncTasksOutstanding == 0)
{
// All steps complete
// Set up the next state and kick() the state machine
if(iState == ERunScriptPending)
iState = ERunScript;
else if(iState == EWaitCompletions)
iState = ERunning;
else if(iState == ERunCedPending)
iState = ERunCed;
else if(iState == EDelayPending)
iState = EDelay;
else if(iState == EPausePending)
iState = EPause;
else if(iState == EEndTestCasePending)
iState = ERunEndTestCase;
else if(iState == EPrefixPending)
iState = ERunPrefix;
// Safe to Kick() the state machine again
iCanComplete = EFalse;
Kick();
}
else
{
// More requests outstanding
iCanComplete = ETrue;
Prime();
}
}
break;
case ERunScript :
// Recursively instantiate the CScriptControl class
{
GetScriptFileFromScriptLine();
CScriptControl* scriptControl = new (ELeave) CScriptControl(*this,iChildScriptFile,Logger(),ConsoleLogger(),iStartLooping,iLoop,iDefaultSysDrive,iTestSysDrive,iSelTestingOptions);
// Kick the nested CScriptControl state machine
scriptControl->Kick();
// Put our instance in the idling state, Prime()'d ready for clild-parent
// completion by the nested one.
iState = EIdling;
iCanComplete = ETrue;
Prime();
}
break;
case ERunCed :
// Slightly tricky one
// WIN32 & Non-secure means we execute CED synchronously
{
SetActive();
TRAPD(err,RunCedFromScriptLineL());
if(!err)
// Expect completion asynchronously
// We're set for completion so just set the state
iState = EIdling;
else
{
_LIT(KCedError,"CED Error = %d");
ERR_PRINTF2(KCedError,err);
// A CED error so kick the state machine
iState = ERunning;
Kick();
}
}
break;
case EDelay :
{
// Kick the timer and wait for completion
SetActive();
StartTimerFromScriptLine();
iState = EIdling;
}
break;
case ERunEndTestCase :
{
LogTestCaseMarkerL();
iState = ERunning;
iCanComplete = EFalse;
Kick();
}
break;
case ERunStartSyncTestCase :
{
// Check to see if the test case is ready to continue
SetActive();
iTimer.After( iStatus, KTEFStatusDelay*1000 );
TBool syncContinue = iSyncControl->TestCaseContinueL();
if( syncContinue )
{
iState = EIdling;
}
}
break;
case ERunPrefix :
{
SetPrefix();
iState = ERunning;
iCanComplete = EFalse;
Kick();
}
break;
case EIdling :
{
// Woken up due to either:
// A child CScriptControl instance completing OR
// the delay timer has completed.
iState = ERunning;
iCanComplete = EFalse;
Kick();
}
break;
case EPause :
{
_LIT(KPaused,"PAUSED - Hit Any Key to Continue\n");
ConsoleLogger().Console().Printf(KPaused);
ConsoleLogger().Console().Getch();
iState = ERunning;
iCanComplete = EFalse;
Kick();
}
//Start of defect 115942
break;
//End of defect 115942
case ETestCaseIgnore:
{
TPtrC scriptLine;
//do we want to while till we come to end of test case?
while(GetNextScriptLine(scriptLine))
{
TLex lex(scriptLine);
TPtrC token(lex.NextToken());
if((token.CompareF(KTEFEndTestCaseCommand) == 0)
|| (token.CompareF(KTEFEndSyncTestCaseCommand) == 0)) //we found an end test case one
{
TPtrC testCID(lex.NextToken());
//to support nested test cases
if(iTestCaseIDToIgnore.CompareF(testCID) == 0)
{
//in any case...go back to running and re-evaluate our position at
iState = ERunning;
iTestCaseIDToIgnore.Set(KTEFNull);
iCanComplete = EFalse;
iCurrentScriptLine.Set(scriptLine);
//before going back to running re-evaluate the
//state of selective testing
ProcessEndCase() ;
Kick();
break;
}
}
}
break;
}
default:
break;
}
}
/**
* Implement the PRINT command
* Print the string(s) following the PRINT command to the log file
*/
void CScriptControl::PrintFromScriptLine() const
{
TLex lex(iCurrentScriptLine);
lex.NextToken();
TBuf<KMaxTestExecuteCommandLength> buf;
buf.Copy(lex.Remainder());
_LIT(KCommentString, " //");
TInt offset = buf.Find(KCommentString);
if (offset != KErrNotFound)
{
buf.SetLength(offset);
}
_LIT(KS,"%S");
INFO_PRINTF2(KS,&buf);
}
/**
* Implement the PREFIX command
* Stores the prefix for command line prefixing
*/
void CScriptControl::SetPrefix()
{
TLex lex(iCurrentScriptLine);
// Bypass the PREFIX command
lex.NextToken();
// Get rid of any leading spaces
while(!lex.Eos())
{
TChar peek = lex.Peek();
if(peek == ' ')
{
lex.Inc();
}
else
break;
}
// Chop off the carriage return and insert a space
// If there is a preceding comment line, get rid of that.
iScriptLinePrefix.Copy(lex.Remainder());
_LIT(KCarriageReturn, "\r\n");
_LIT(KCommentString, " //");
TInt offset = iScriptLinePrefix.Find(KCommentString);
if (offset != KErrNotFound)
{
iScriptLinePrefix.SetLength(offset);
}
else
{
offset = iScriptLinePrefix.Find(KCarriageReturn);
if (offset != KErrNotFound)
{
iScriptLinePrefix.SetLength(offset);
}
}
_LIT(KTEFSpace, " ");
iScriptLinePrefix.Append(KTEFSpace);
iScriptLinePrefixSet = ETrue;
}
/**
* Function to evaluate the situation of selective testing
* Returns whether the testcase on the current script line
* should be run.
*/
TBool CScriptControl::ProceedTestCase()
{
//if selective testing is not on, dont bother
if(iSelTestingOptions == NULL)
return ETrue;
iTestCaseCounter++;
if(iTestCaseCounter > 1) //if this is nested, let it run unconditionally
return ETrue;
// the remaining continues only if selective testing is on
// AND we have a non-null, and hopefully valid instance of
// iSelTestingOptions
TLex lex(iCurrentScriptLine);
TPtrC token(lex.NextToken());
TPtrC testCaseID(lex.NextToken());
//evaluating class state variables...
//check range
TIdentityRelation<TPtrC> crackID(TSelectiveTestingOptions::CompareTPtrC);
TIdentityRelation<TRange> rangeComprtr(TRange::CompareTRangeStartCase);
TRange dummy(testCaseID,testCaseID);
for ( TInt index=0; index<iSelTestingOptions->iSelectiveCaseRange.Count(); ++index )
{
if ( testCaseID.CompareF(iSelTestingOptions->iSelectiveCaseRange[index].iStartTestCase) == 0 )
{
iSelTestingOptions->iSelectiveCaseRange[index].iState=TRange::EStateInUse;
++iRangeRefCounter;//number of ranges now in operation
}
}
TBool runCase = ETrue ; //run everything by def
if( iSelTestingOptions->iSelectiveTestingType == iInclusive )
{
//so selective testing is on and also its inclusive...
runCase = (iRangeRefCounter>0) || iSelectOne ;
}
else if(iSelTestingOptions->iSelectiveTestingType == iExclusive)
{
//so selective testing is on and also its exclusive...
runCase = (iRangeRefCounter<=0) && !iSelectOne ;
}
if(!runCase)//if the test case is to be selectively skipped, log it...
{
//use this one to log unexecuted cases...
Logger().LogTestCaseResult(iScriptFile, iCurrentScriptLineNumber, RFileFlogger::ESevrInfo, token, testCaseID,ESkippedSelectively);
}
if(runCase == EFalse)
{
iTestCaseIDToIgnore.Set(testCaseID) ;
}
return runCase ;
}
/**
* Function to evaluate the state variables
* at the end of test case
*/
void CScriptControl::ProcessEndCase()
{
if(iSelTestingOptions==NULL) //selective testing is not on
return; // dont bother
iTestCaseCounter--;
if(iTestCaseCounter<0) //in case we encountered unmatched end cases
iTestCaseCounter=0;
TLex lex(iCurrentScriptLine);
TPtrC token(lex.NextToken());
TPtrC testCaseID(lex.NextToken());
//check if this is ending a range
TRange dummy(testCaseID,testCaseID);
TIdentityRelation<TRange> crackIDRangeend(TRange::CompareTRangeEnd);
for ( TInt index=0; index<iSelTestingOptions->iSelectiveCaseRange.Count(); ++index )
{
if ( testCaseID.CompareF(iSelTestingOptions->iSelectiveCaseRange[index].iEndTestCase) == 0 )
{
if ( iSelTestingOptions->iSelectiveCaseRange[index].iState == TRange::EStateInUse )
{
iSelTestingOptions->iSelectiveCaseRange[index].iState=TRange::EStateUsed;
--iRangeRefCounter;
}
else
{
// Error condition. An end test case has been matched to a range that has not processed the start test case
// Either the start test case does not exist or the start test case comes after the end test case in the script
//or maybe do nothing
}
}
}
//always reset the onetime test case thing
iSelectOne = EFalse;
}
/**
* Implement START_TESTCASE/ END_TESTCASE commands
* Write a testcase marker to the logfile
*/
void CScriptControl::LogTestCaseMarkerL()
{
TLex lex(iCurrentScriptLine);
TPtrC token(lex.NextToken());
TVerdict TestCaseResult(EFail);
TPtrC TestCaseMarker(lex.NextToken());
if (token.CompareF(KTEFStartTestCaseCommand) == 0 || token.CompareF(KTEFStartSyncTestCaseCommand) == 0)
{
// Call the interface routine for logging in HTML & XML format
Logger().LogTestCaseResult(iScriptFile, iCurrentScriptLineNumber, RFileFlogger::ESevrHigh, token, TestCaseMarker);
iTestCaseID.Copy(TestCaseMarker);
}
else
{
// Its an END_TESTCASE.
// Need to identify whether all preceding test steps in the file
// passed (back to a *matching* START_TESTCASE).
TestCaseResult = HasTestCasePassedL(TestCaseMarker);
// Special case for KTEFEndSyncTestCaseCommand where the result in
// the shared data area needs to be updated so STAT can retrieve it later.
if( token.CompareF(KTEFEndSyncTestCaseCommand) == 0 )
{
// Check to see if the Sync Data has been created
if( iSyncControl != NULL )
{
// Update the TEFResult shared data value
iSyncControl->SetResultL( TestCaseResult );
}
else
{
User::Leave( KErrNotReady );
}
}
// Call the interface routine for logging in HTML & XML format
Logger().LogTestCaseResult(iScriptFile, iCurrentScriptLineNumber, RFileFlogger::ESevrHigh, token, TestCaseMarker, TestCaseResult);
iTestCaseID.Copy(KTEFTestCaseDefault);
}
}
/**
*
* Implement TestCase pass checking
*/
TVerdict CScriptControl::HasTestCasePassedL(TPtrC aTestCaseMarker)
{
// Looks from the top of the file for the equivalent Start_TestCase
// when it finds it it checks that all the steps to the bottom of
// the file (the current position)
// Create a Cinidata object to parse through the testexecute.ini
// To retrieve the path where the log is to be placed
CTestExecuteIniData* parseTestExecuteIni = NULL;
TBuf<KMaxTestExecuteNameLength> resultFilePath;
TRAPD(err,parseTestExecuteIni = CTestExecuteIniData::NewL(iDefaultSysDrive));
if (err == KErrNone)
{
CleanupStack::PushL(parseTestExecuteIni);
parseTestExecuteIni->ExtractValuesFromIni();
parseTestExecuteIni->GetKeyValueFromIni(KTEFHtmlKey, resultFilePath);
}
else
{
resultFilePath.Copy(KTestExecuteLogPath);
resultFilePath.Replace(0, 2, iDefaultSysDrive);
}
TBuf<KMaxTestExecuteNameLength> resultFileName(resultFilePath);
// loading the simplified test result in case of out-of-memory
resultFileName.Append(KTEFTestExecuteResultSimplifiedSummaryFile);
if (parseTestExecuteIni != NULL)
{
CleanupStack::PopAndDestroy(parseTestExecuteIni);
}
// Open the result summary file
RFs fS;
User::LeaveIfError(fS.Connect());
CleanupClosePushL(fS);
RFile logFile;
User::LeaveIfError(logFile.Open(fS,resultFileName, EFileWrite | EFileRead | EFileShareAny));
CleanupClosePushL(logFile);
TInt fileSize;
// Read the complete result summary file onto the heap
// It wont be that large
User::LeaveIfError(logFile.Size(fileSize));
HBufC* resultData = HBufC::NewLC(fileSize);
HBufC8* resultData8 = HBufC8::NewLC(fileSize);
TPtr8 ptrData8(resultData8->Des());
User::LeaveIfError(logFile.Read(ptrData8));
TPtr ptrData(resultData->Des());
ptrData.Copy(ptrData8);
CleanupStack::PopAndDestroy(resultData8);
TBool foundMarker(EFalse);
TBool foundNonPassResult(EFalse);
TInt duplicatesCounter(0);
TLex lex(ptrData);
while (!lex.Eos())
{
// Find the ***Result keywords
TPtrC commandName( lex.NextToken() );
if( commandName.CompareF(KTEFStartTestCaseCommand) == 0 ||
commandName.CompareF(KTEFStartSyncTestCaseCommand) == 0 )
{
if (lex.NextToken() == aTestCaseMarker)
{
// Increment the counter to identify that the test case id is duplicated
duplicatesCounter++;
if (duplicatesCounter == 2)
{
// If the test case id is duplicated for more than once,
// issue a warning in the log file, mentioning duplicate of test case id
_LIT(KWarnDuplicateTCID, "Test Case ID : %S re-used");
WARN_PRINTF2(KWarnDuplicateTCID, &aTestCaseMarker);
}
// When a matching test case id is found, the found marker is set to ETrue
foundMarker = ETrue;
// Initialise the foundNonPassResult to EFalse, on entry into each test case result in the log
foundNonPassResult = EFalse;
continue;
}
continue;
}
else if (foundMarker && commandName == KTEFResultTag)
{
// If the START_TESTCASE is found and a RESULT tag is found in the test result file,
// Extract the result value set for every test step called within
// and check to see if there are any non-pas results
_LIT(KTEFEquals,"=");
if (lex.NextToken() != KTEFEquals)
continue;
TPtrC result(lex.NextToken());
if(result != KTEFResultPass)
{
// Set the foundNonPassResult to ETrue indicating the test case to fail
foundNonPassResult = ETrue;
}
}
}
CleanupStack::PopAndDestroy(resultData);
CleanupStack::Pop(&logFile);
logFile.Close();
CleanupStack::Pop(&fS);
fS.Close();
if (foundMarker)
{
if (foundNonPassResult)
{
return EFail;
}
else
{
return EPass;
}
}
else
{
return EInconclusive;
}
}
/**
* Implement the DELAY command
*/
void CScriptControl::StartTimerFromScriptLine()
{
TLex lex(iCurrentScriptLine);
lex.NextToken();
TLex delayLex(lex.NextToken());
TInt delay;
// Read the delay in milliseconds
TInt err = delayLex.Val(delay);
if(err)
// Set the default
delay = KDefaultDelayMilliseconds;
iTimer.After(iStatus,delay*1000);
}
/**
* Secure - same for Target and Wins
*/
void CScriptControl::RunCedFromScriptLineL()
{
TLex lex(iCurrentScriptLine);
// Skip CED
lex.NextToken();
TPtrC cedCommandLine(lex.Remainder());
iCurrentScriptLine.Set(cedCommandLine);
RProcess process;
User::LeaveIfError(process.Create(_L("ced.exe"),iCurrentScriptLine));
process.Rendezvous(iStatus);
// Run CED asynchronously
process.Resume();
process.Close();
}
/**
* Set up the path of a script file for a child CScriptControl object
*/
void CScriptControl::GetScriptFileFromScriptLine()
{
TLex lex(iCurrentScriptLine);
lex.NextToken();
iChildScriptFile.Set(lex.NextToken());
}
/**
* @param aUtilsCommand - Command string for the utilities command
* Implement basic commands:
* NB: Always requires the full path
* Logic borrowed from Scheduletest
* Always complete synchronously
*
* CopyFile
* MKDir
* MakeReadWrite
* Delete
* DeleteDirectory
*/
void CScriptControl::RunUtilsFromScriptLineL() const
{
_LIT(KDefault, "?:\\default");
_LIT(KCDrive, "?:\\");
_LIT(KTEFBackslash, "\\" );
TBuf<10> defaultPath(KDefault);
defaultPath.Replace(0, 2, iTestSysDrive);
TBuf<3> cDrive(KCDrive);
cDrive.Replace(0, 2, iTestSysDrive);
RFs fS;
User::LeaveIfError(fS.Connect() );
CleanupClosePushL(fS);
TLex lex(iCurrentScriptLine);
lex.NextToken();
TPtrC token(lex.NextToken());
if(token.CompareF(KTEFRunUtilsCopyFile) == 0)
{
TPtrC file1=lex.NextToken();
TPtrC file2=lex.NextToken();
TParse source, dest;
CFileMan* fMan = CFileMan::NewL(fS);
CleanupStack::PushL(fMan);
User::LeaveIfError(source.Set(file1, &defaultPath, NULL) );
User::LeaveIfError(dest.Set(file2, &defaultPath, NULL) );
User::LeaveIfError(fMan->Copy(source.FullName(), dest.FullName(), CFileMan::EOverWrite) );
CleanupStack::PopAndDestroy(fMan);
}
else if(token.CompareF(KTEFRunUtilsMkDir) == 0)
{
token.Set(lex.NextToken());
TParse fileName;
if (!token.Length())
User::Leave(KErrPathNotFound);
TPtrC lastChar(token.Mid(token.Length() - 1));
if ( lastChar.CompareF(KTEFBackslash) != 0 )
{
TBuf<64> tempToken(token);
tempToken.Append(KTEFBackslash);
token.Set(tempToken);
}
User::LeaveIfError( fileName.Set(token, &cDrive, NULL) );
User::LeaveIfError( fS.MkDir( fileName.DriveAndPath() ) );
}
else if(token.CompareF(KTEFRunUtilsDeleteFile) == 0 ||
token.CompareF(KTEFRunUtilsDelete) == 0)
{
token.Set(lex.NextToken());
// defect047128 - Code change for handling wildcard deletes
CFileMan* fMan = CFileMan::NewL(fS);
CleanupStack::PushL(fMan);
User::LeaveIfError(fMan->Delete(token) );
CleanupStack::PopAndDestroy(fMan);
}
else if(token.CompareF(KTEFRunUtilsMakeReadWrite) == 0)
{
token.Set(lex.NextToken());
TParse fileName;
User::LeaveIfError(fileName.Set(token, &defaultPath, NULL) );
TInt err = fS.SetAtt(fileName.FullName(),0, KEntryAttReadOnly);
if (err != KErrNone && err != KErrNotFound)
User::Leave(err);
}
//It deletes the specified directory
else if(token.CompareF(KTEFDeleteDirectory) == 0)
{
token.Set(lex.NextToken());
TParse fileName;
if (!token.Length())
User::Leave(KErrPathNotFound);
TPtrC lastChar(token.Mid(token.Length() - 1));
if ( lastChar.CompareF(KTEFBackslash) != 0 )
{
TBuf<64> tempToken(token);
tempToken.Append(KTEFBackslash);
token.Set(tempToken);
}
CFileMan* fMan = CFileMan::NewL(fS);
CleanupStack::PushL(fMan);
User::LeaveIfError(fileName.Set(token, &cDrive, NULL) );
User::LeaveIfError( fMan->RmDir( fileName.DriveAndPath() ) );
CleanupStack::PopAndDestroy(fMan);
}
fS.Close();
CleanupStack::Pop(&fS);
}
/**
* Read the Script File data into a heap buffer
* We could read the file line by line but that would be cumbersome, and unless there
* is a heap size problem, this is tidier.
*/
void CScriptControl::CreateScriptDataFromScriptFileL()
{
RFs fS;
User::LeaveIfError(fS.Connect());
CleanupClosePushL(fS);
RFile scriptFile;
User::LeaveIfError(scriptFile.Open(fS,iScriptFile,EFileRead | EFileShareAny));
CleanupClosePushL(scriptFile);
TInt fileSize;
User::LeaveIfError(scriptFile.Size(fileSize));
// Create a 16bit heap buffer
iScriptData = HBufC::NewL(fileSize);
HBufC8* narrowData = HBufC8::NewL(fileSize);
CleanupStack::PushL(narrowData);
TPtr8 narrowPtr=narrowData->Des();
// Read the file into an 8bit heap buffer
User::LeaveIfError(scriptFile.Read(narrowPtr));
TPtr widePtr(iScriptData->Des());
// Copy it to the 16bit buffer
widePtr.Copy(narrowData->Des());
CleanupStack::PopAndDestroy(narrowData);
CleanupStack::Pop(2);
scriptFile.Close();
fS.Close();
// Set up the instance token parser
iScriptLex = iScriptData->Des();
}
/**
* Extracts the human readable server name from the current script line then
* calls Client RTestServ Interface to make a connection to the server.
*/
void CScriptControl::CreateServerFromScriptLineL()
{
TLex lex(iCurrentScriptLine);
lex.NextToken();
TInt i=0;
TInt count = iServers.Count();
TPtrC serverName(lex.NextToken());
// We loop through to see if the server has already been created
for(i=0;i<count;i++)
{
if(iServers[i]->ServerName() == serverName)
// Server already exists in our array
break;
}
if(i == count)
{
// Create a new RTestServ pointer and add it to the list
RScriptTestServ* serv = new (ELeave) RScriptTestServ;
// Connect using the client API
TInt err;
if(lex.NextToken().CompareF(KTEFLoadSuiteSharedData) == 0)
{
err = serv->Connect(serverName,ETrue);
}
else
err = serv->Connect(serverName,EFalse);
if(err)
{
// Don't add the server to the array if we fail to connect.
delete serv;
// Caller TRAP's
User::Leave(err);
}
iServers.Append(serv);
}
}
/**
* @param aIndex - Return the index of the RTestServ instance - If found
* @return - EFalse if server not found. ETrue if server found.
*
*/
TBool CScriptControl::GetServerIndexFromScriptLine(TInt& aIndex)
{
TLex lex(iCurrentScriptLine);
TLex lexTimeout;
_LIT(KErrInvalidArgumentSet,"The arguments are not provided in proper format.\
Unable to retrieve the details of the server from the command line");
TPtrC command(lex.NextToken());
if(command.CompareF(KTEFRunTestStepResultCommand) == 0)
{
lex.NextToken();
lex.SkipSpace();
lex.Mark();
}
else if(command.CompareF(KTEFRunPanicStepResultCommand) == 0)
{
lex.NextToken();
TPtrC panicString(lex.NextToken());
// Check to see if the panic string contains open quotes and close quotes
// If the panic string token contains open quote, it is understood that the panic string contains spaces
// So, look for close quote in the subsequent tokens. If not found, return boolean false as return value
if(panicString.Left(1).Compare(KTEFOpenQuotes) == 0 && panicString.Right(1).Compare(KTEFOpenQuotes) != 0)
{
TBool validCommandLine(EFalse);
while(!lex.Eos() && !validCommandLine)
{
panicString.Set(lex.NextToken());
if(panicString.Right(1).Compare(KTEFOpenQuotes) == 0)
validCommandLine = ETrue;
}
if (!validCommandLine)
{
ERR_PRINTF1(KErrInvalidArgumentSet);
return EFalse;
}
}
lex.SkipSpace();
lex.Mark();
}
else if(command.CompareF(KTEFRunTestStepCommand) == 0 ||
command.CompareF(KTEFStartTestBlock) == 0)
{
TInt firstChar;
TPtrC commandStr;
TBool panicStringComplete(ETrue);
while(!lex.Eos())
{
lex.SkipSpace();
lex.Mark();
TPtrC token = lex.NextToken();
if( token.Length()>0 )
{
commandStr.Set( token );
firstChar = commandStr[0];
// 33 is the ascii value for "!". Used here for confirming switches
if (firstChar != KTEFAsciiExclamation && panicStringComplete)
{
break;
}
// Check to see if !PanicString TEF parameter contains panic string with spaces
// If so, see if they are enclosed within a open & close braces
if(commandStr.Length() > 14 &&
commandStr.Mid(0,14).Compare(_L("!PanicString=\"")) == 0)
panicStringComplete = EFalse;
if(!panicStringComplete && commandStr.Right(1).Compare(KTEFOpenQuotes) == 0)
panicStringComplete = ETrue;
}
}
if (!panicStringComplete)
{
ERR_PRINTF1(KErrInvalidArgumentSet);
return EFalse;
}
}
// We need to skip the timeout if it's there.
if( command.CompareF(KTEFRunTestStepCommand) == 0 ||
command.CompareF(KTEFStartTestBlock) == 0)
lexTimeout=lex.MarkedToken();
else
lexTimeout=lex.NextToken();
TInt timeout;
TPtrC serverName;
if(lexTimeout.Val(timeout) != KErrNone)
// No timeout so use the second token
serverName.Set(lex.MarkedToken());
else
// Timeout value there
serverName.Set(lex.NextToken());
TInt i=0;
// Loop through the installed servers
TInt count = iServers.Count();
for(i=0;i<count;i++)
{
if(iServers[i]->ServerName() == serverName)
// Found server installed
break;
}
// Return found or not found
if(i == count)
return EFalse;
else
{
aIndex = i;
if (iServers[i]->SharedData())
{
iConcurrent = EFalse;
}
return ETrue;
}
}
/**
* * @return - ETrue if the scriptline is valid, else retuens EFalse
*/
TBool CScriptControl::CheckValidScriptLine() const
{
TLex lex(iCurrentScriptLine);
TPtrC command(lex.NextToken());
TBool panicCodeSet(EFalse);
TBool panicStringSet(EFalse);
TBool heapValueSet(EFalse);
TBool validScript(ETrue);
TBool oomRequestSet(EFalse);
TBool setupOptionSet(EFalse);
if(command.CompareF(KTEFRunTestStepCommand) == 0)
{
TInt firstChar;
TPtrC commandStr;
while(!lex.Eos())
{
lex.SkipSpace();
commandStr.Set(lex.NextToken());
firstChar = commandStr[0];
// 33 is the ascii value for "!". Used here for confirming switches
if (firstChar == KTEFAsciiExclamation)
{
if (commandStr.Length() >= KTEFMinErrorParamLength && commandStr.Mid(0,KTEFMinErrorParamLength).CompareF(KTEFError) == 0)
{
if(command.CompareF(KTEFRunTestStepCommand) == 0)
command.Set(KTEFRunErrorStepResultCommand);
else
validScript = EFalse;
}
else if (commandStr.Length() >= KTEFMinSetupParamLength && commandStr.Mid(0,KTEFMinSetupParamLength).CompareF(KTEFSetUpParam) == 0)
{
if(command.CompareF(KTEFRunTestStepCommand) == 0 && !setupOptionSet)
setupOptionSet = ETrue;
else
validScript = EFalse;
}
else if (commandStr.Length() > KTEFMinResultParamLength && commandStr.Mid(0,KTEFMinResultParamLength).CompareF(KTEFResult) == 0 && commandStr.Mid(KTEFMinResultParamLength).Length() <= KTEFMaxVerdictLength)
{
if (command.CompareF(KTEFRunTestStepCommand) == 0)
command.Set(KTEFRunTestStepResultCommand);
else
validScript = EFalse;
}
else if (commandStr.Length() >= KTEFMinPanicCodeParamLength && commandStr.Mid(0,KTEFMinPanicCodeParamLength).CompareF(KTEFPanicCode) == 0)
{
if ((command.CompareF(KTEFRunTestStepCommand) == 0 || command.CompareF(KTEFRunPanicStepResultCommand) == 0) && !panicCodeSet)
{
command.Set(KTEFRunPanicStepResultCommand);
panicCodeSet=ETrue;
}
else
validScript = EFalse;
}
else if (commandStr.Length() >= KTEFMinPanicStringParamLength && commandStr.Mid(0,KTEFMinPanicStringParamLength).CompareF(KTEFPanicString) == 0)
{
if ((command.CompareF(KTEFRunTestStepCommand) == 0 || command.CompareF(KTEFRunPanicStepResultCommand) == 0) && !panicStringSet)
{
command.Set(KTEFRunPanicStepResultCommand);
panicStringSet = ETrue;
}
else
validScript = EFalse;
}
else
{
if (commandStr.Length() >= KTEFMinHeapParamLength && commandStr.Mid(0,KTEFMinHeapParamLength).CompareF(KTEFHeap) == 0 && !heapValueSet)
heapValueSet = ETrue;
else if (commandStr.Length() >= KTEFMinOomParamLength && commandStr.Mid(0,KTEFMinOomParamLength).CompareF(KTEFOom) == 0 && !oomRequestSet)
oomRequestSet = ETrue;
else
validScript = EFalse;
}
}
else
break;
}
}
return validScript;
}
/**
* Return the next line in the script file
* @param aScriptLine - return line in the script file minus CRLF
* @return - True if line found, false for end of file.
*/
TBool CScriptControl::GetNextScriptLine(TPtrC& aScriptLine)
{
if(iScriptLex.Eos())
{
// Fix defect 1193337, check the value is zero or not. If zero, this should be no nested run script
if((0 == iNestedNumRunScriptInLoop) && iLoop)
// End defect 119337
{
_LIT(KEndRepeatNotFound,"The END_REPEAT command is not found");
INFO_PRINTF1(KEndRepeatNotFound);
}
// Fix defect 119337, check if this is still in loop and this run script command is nested
// decrease one shows that the nested number is decreased
else if (iNestedNumRunScriptInLoop > 0 && iLoop)
{
--iNestedNumRunScriptInLoop;
}
// End defect 119337
return EFalse;
}
// Mark the current script line to return
iScriptLex.Mark();
if(iLoop && !iCheckVar)
{
iStoreLoop.Assign(iScriptLex.RemainderFromMark());
iTempStoreLoop.Assign(iScriptLex.RemainderFromMark());
iCheckVar=ETrue;
}
// Place the lex marker for the next read
while(!iScriptLex.Eos())
{
TChar peek = iScriptLex.Peek();
if(peek == '\n')
{
iScriptLex.Inc();
iCurrentScriptLineNumber++;
break;
}
else
iScriptLex.Inc();
}
aScriptLine.Set(iScriptLex.MarkedToken());
if(aScriptLine.FindF(KTEFRunScriptCommand)!=KErrNotFound && iLoop)
{
// Fix defect 119337, add this integer shows a nested run script added.
++iNestedNumRunScriptInLoop;
// End Fix defect 119337
}
if(aScriptLine.Length() || !iScriptLex.Eos())
return ETrue;
else
return EFalse;
}
/**
* Return the next line from script file which is to be looped
* @param aScriptLine - return line in the script file which is under loop minus CRLF
* @return -True if line is found else return false
*
* If RUN_SCRIPT command has been encountered return the line from GetNextScriptLine Function
*/
TBool CScriptControl::GetLoopScriptLine(TPtrC& aScriptLine)
{
// Fix defect 119337, check if the run script is nested
if (0 != iNestedNumRunScriptInLoop)
// End defect 119337
return(GetNextScriptLine(aScriptLine));
if(iStoreLoop.Eos())
return EFalse;
iStoreLoop.Mark();
while(!iStoreLoop.Eos())
{
TChar peek = iStoreLoop.Peek();
if(peek == '\n')
{
iStoreLoop.Inc();
break;
}
else
iStoreLoop.Inc();
}
aScriptLine.Set(iStoreLoop.MarkedToken());
if(aScriptLine.Find(KTEFEndRepeat)!=KErrNotFound)
{
iStoreLoop.Assign(iTempStoreLoop);
}
if(aScriptLine.FindF(KTEFRunScriptCommand)!=KErrNotFound)
{
// Fix defect 119337, add this integer shows a nested run script added.
++iNestedNumRunScriptInLoop;
// End defect 119337
}
if(aScriptLine.Length() || !iStoreLoop.Eos())
return ETrue;
else
return EFalse;
}
/**
* @param aErr - The completion code
* @param aPanicString - Descriptor reference containing the panic string if a test were to panic
* @param aScriptLineNumber - Script line number used for printing result into log file
* @param aCommand - Command name also used for printing result into log file
* Called by a CClientControl or CProgramControl child object
*/
void CScriptControl::TaskCompletion(TInt aErr, const TDesC& aPanicString, TInt aScriptLineNumber,const TDesC& aCommand,TBool aTaskCanComplete,TTEFItemArray* aItemArray)
{
if(aItemArray)
{
TVerdict err = Logger().LogBlock( aItemArray, aScriptLineNumber );
// If no error was set on the server side (ie. a panic) then set
// it here with the post processing result
if( EPass == aErr && aPanicString.Length() == 0 )
{
aErr = err;
}
}
// Log the test step result to the output file
LogResult((TVerdict)aErr, aPanicString, aScriptLineNumber, aCommand);
if(aErr != KErrNone && aErr != KErrNotSupported && iBreakOnError)
// Put this instance of the script engine into the closing state as we've
// encountered the BREAK_ERROR_ON command.
// KErrNotSupported is considered a benign error
{
iState = EClosing;
}
iAsyncTasksOutstanding--;
// Check the flag first then trigger our own RunL()
if(aTaskCanComplete || iCanComplete)
Complete(aErr);
}
/**
* Print the current script line to the console
*/
void CScriptControl::PrintCurrentScriptLine() const
{
// Check we don't overflow
TBuf<KMaxTestExecuteLogLineLength> output;
if((iCurrentScriptLine.Length() + iScriptFile.Length() + 4 ) > output.MaxLength())
{
output.Copy(iAlteredScriptLine);
Logger().PrintCurrentScriptLine(output);
return;
}
// Copy the script filename. Handy for recursion
output.Copy(iScriptFile);
output.Append(KTEFSpace);
// Append the script file line
output.Append(iCurrentScriptLine);
// Write to console
ConsoleLogger().Console().Printf(KTEFStringFormat,&output);
Logger().PrintCurrentScriptLine(output);
}
/**
* Checks for commented commands and increments a counter for logging
*/
TBool CScriptControl::CheckCommentedCommands() const
{
if(!iCurrentScriptLine.Length())
return ETrue;
TLex lex(iCurrentScriptLine);
TPtrC token(lex.NextToken());
if (!token.Length())
return ETrue;
TInt firstChar = iCurrentScriptLine[0];
if(firstChar == '/')
{
TInt findRunTestStep;
TInt findRunPanicStep;
TInt findRunScript;
TInt findRunProgram;
TInt findRunWSProgram;
TInt findStartTestBlock;
findRunTestStep=iCurrentScriptLine.Find(KTEFRunTestStepCommand);
findRunScript=iCurrentScriptLine.Find(KTEFRunScriptCommand);
findRunPanicStep=iCurrentScriptLine.Find(KTEFRunPanicStepCommand);
findRunProgram=iCurrentScriptLine.Find(KTEFRunProgramCommand);
findRunWSProgram=iCurrentScriptLine.Find(KTEFRunWSProgramCommand);
findStartTestBlock=iCurrentScriptLine.Find(KTEFStartTestBlock);
if(findRunTestStep>0 || findRunScript>0 || findRunPanicStep>0 || findRunProgram>0 || findRunWSProgram>0 || findStartTestBlock>0 && !iStartLooping)
{
commentedCommandsCount++;
}
}
if(firstChar == '\r' || firstChar == '\n' || firstChar == '#' || firstChar == '/')
return ETrue;
return EFalse;
}
/**
* @param aResult - Test Step result
* @param aPanicString - Descriptor containing the panic string if test were to panic
* @param aScriptLineNumber - The line in the script file
* @param aCommand - Command name whose result is set for logging
* Log a RUN_TEST_STEP, RUN_PANIC_STEP or RUN_PROGRAM result to file
*/
void CScriptControl::LogResult(TVerdict aResult, const TDesC& aPanicString, TInt aScriptLineNumber,const TDesC& aCommand)
{
// Call the Logger()'s LogResult() routine to manipulate results of RUN_TEST_STEP command/variants
// Also controls the fields for logging both HTML & XML logging
Logger().LogResult(aResult, aPanicString, aScriptLineNumber, aCommand, iScriptFile, RFileFlogger::ESevrHigh);
}
/**
* Constructor
* @param RTestServ - Reference to a root RTestServer instance
* @param aCommand - Reference to a RUN_TEST_STEP script line
* @param MTaskCompletion - Reference to the parent completion interface
* @param aScriptLineNumber - The line in script file
* @param aLogger - Reference to the Logger class
* @param aLoopIndex - TInt reference that provides the loop index for the test. The value is 0 if not in loop.
* @param aTestCaseID - Descriptor containing the test case id, if test run is within a test case
* @param aScriptFilePath - The path of the script file being executed
* @param aSysDrive - Default system drive letter
* @param aTestSysDrive - System drive letter overwritten from testexecute.ini
*/
CClientControl::CClientControl(RScriptTestServ& aServ,const TDesC& aCommand, MTaskCompletion& aCompletion, TInt aScriptLineNumber, CTestExecuteLogger& aLogger, TInt aLoopIndex, const TDesC& aTestCaseID, TPtrC& aScriptFilePath, const TDriveName& aSysDrive, const TDriveName& aTestSysDrive)
: CTaskControlBase(aCommand,aCompletion,aScriptLineNumber,aLogger)
, iServ(aServ)
, iRetryCount(0)
, iLoopIndex(aLoopIndex)
, iTestCaseID(aTestCaseID)
, iBlockArrayPkg(NULL)
, iBlockArrayPtr(STATIC_CAST(TUint8*,NULL), 0)
, iScriptFilePath(aScriptFilePath)
, iDefaultSysDrive(aSysDrive)
, iTestSysDrive(aTestSysDrive)
{
// Extract the parameters to the test step and store them in the class
GetStepParamsFromStepCommand();
}
CClientControl* CClientControl::NewL( RScriptTestServ& aTestServ,
const TDesC& aCommand,
MTaskCompletion& aCompletion,
TInt aScriptLineNumber,
CTestExecuteLogger& aLogger,
TInt aLoopIndex,
const TDesC& aTestCaseID,
const TDesC& aEndBlockCommand,
TPtrC& aScriptFilePath,
const TTEFItemArray& aBlockArray,
const TDriveName& aSysDrive,
const TDriveName& aTestSysDrive)
{
CClientControl* self = new (ELeave) CClientControl( aTestServ,
aCommand,
aCompletion,
aScriptLineNumber,
aLogger,
aLoopIndex,
aTestCaseID,
aScriptFilePath,
aSysDrive,
aTestSysDrive);
CleanupStack::PushL(self);
self->ConstructL(aEndBlockCommand, aBlockArray);
CleanupStack::Pop();
return self;
}
void CClientControl::ConstructL( const TDesC& aEndBlockCommand, const TTEFItemArray& aBlockArray )
{
iEndBlockCommand.Set( aEndBlockCommand );
TTEFItemPkgBuf itemPckgBuf;
TInt count = aBlockArray.Count();
iBlockArrayPkg = HBufC8::NewL( count * itemPckgBuf.Size() );
iBlockArrayPtr.Set( iBlockArrayPkg->Des() );
for( TInt i=0; i<count; i++ )
{
itemPckgBuf = aBlockArray.At(i);
iBlockArrayPtr.Append( itemPckgBuf );
}
}
TTEFItemArray* CClientControl::CreateBlockArrayLC()
{
TTEFItemPkgBuf itemPckgBuf;
TPtr8 blockArrayPtr(iBlockArrayPkg->Des());
TInt count = blockArrayPtr.Size()/itemPckgBuf.Size();
TTEFItemArray* itemArray = new (ELeave) TTEFItemArray( count );
CleanupStack::PushL( itemArray );
TInt pos = 0;
for( TInt i=0; i<count; i++ )
{
itemPckgBuf.Copy(blockArrayPtr.Mid(pos, itemPckgBuf.Size()));
pos += itemPckgBuf.Size();
itemArray->AppendL( itemPckgBuf() );
}
return itemArray;
}
/**
* Destructor
*/
CClientControl::~CClientControl()
{
iTimer.Cancel();
iTimer.Close();
if( iBlockArrayPkg )
{
delete iBlockArrayPkg;
iBlockArrayPkg = NULL;
}
}
const TInt KDisableTimer = -1;
/**
* Test step has done. log the test result.
*/
void CClientControl::TestStepComplete()
{
iSession.Close();
if(iBlockArrayPkg)
{
TTEFItemArray *itemArray = CreateBlockArrayLC();
iParent.TaskCompletion(iStatus.Int(), iTaskExitCategory, iScriptLineNumber, iEndBlockCommand, iTaskCanComplete, itemArray);
CleanupStack::PopAndDestroy(itemArray);
}
else
{
iParent.TaskCompletion(iStatus.Int(), iTaskExitCategory, iScriptLineNumber, iCommandLine, iTaskCanComplete);
}
}
/**
* Pure virtual
* Test step handling state machine
* Kick'd() into by the parent CScriptControl object. Constructed in the EInit state
*/
void CClientControl::RunL()
{
switch(iState)
{
case EInit :
User::LeaveIfError(iTimer.CreateLocal());
if(iBlockArrayPkg)
{
User::LeaveIfError(iSession.Open(iServ, EFalse));
}
else
{
User::LeaveIfError(iSession.Open(iServ, ETrue, iStepName));
}
// Whilst testing concurrent mode, the OS occasionally completes with
// KErrServerBusy or KErrInUse.
// clean up retry counter. case ERetry will using.
iRetryCount = 0;
case EServerRetry :
{
SetActive();
// Set the heap size for creating the thread heap size
iTaskExitCategory.Copy(iTaskHeapSize);
TBuf<5> checkOOMArgsBuf;
// Check if the step args has the OOM arguments already
// A minimum 5 chars expected to check this : "OOM=0" or "OOM=1"
if (iStepArgs.Length() >=5)
{
// Extract the first 5 chars from the start of step args string
checkOOMArgsBuf.Copy(iStepArgs.Mid(0,5));
}
_LIT(KOOMOne,"OOM=1");
_LIT(KOOMZero,"OOM=0");
// Set the OOM argument after checking for existence of OOM param already
if ((checkOOMArgsBuf.CompareF(KOOMOne) != KErrNone) && (checkOOMArgsBuf.CompareF(KOOMZero) != KErrNone))
{
// Insert the OOM arguments to the start of iStepArgs string
if (iOOMRequestSet) // Set OOM=1 if !OOM is used in the RUN_TEST_STEP command
iStepArgs.Insert(0,_L("OOM=1 "));
else
iStepArgs.Insert(0,_L("OOM=0 "));
}
TBuf<KMaxTestExecuteCommandLength> checkSetUpArgsBuf;
// Check if the step args has the Setup arguments already
// A min of 13 chars expected to check this : "OOM=0 !Setup=" or "OOM=1 !Setup="
if (iStepArgs.Length() >=13)
{
// Extract 7 chars after skipping the OOM arguments "OOM=0 " or "OOM=1 "
checkSetUpArgsBuf.Copy(iStepArgs.Mid(6,7));
}
// Set the !Setup argument after checking for existence !Setup param already
if (checkSetUpArgsBuf.CompareF(KTEFSetUpParam) != KErrNone)
{
// Retain the !Setup value from RUN_TEST_STEP command, if available
if (iSetUpParamValue.Length() == KTEFZeroValue)
{
// If !Setup is not used in RUN_TEST_STEP, set the !Setup to TTestSetupState::ESetupNone (0)
iSetUpParamValue.Copy(KTEFSetUpParam);
iSetUpParamValue.AppendNum(TTestSetupState(ESetupNone));
}
// Append a space and also include the loop index
iSetUpParamValue.Append(KTEFSpace);
// The loop index is 0 if the test is not in loop; loop index, otherwise
iSetUpParamValue.AppendNum(iLoopIndex);
iSetUpParamValue.Append(KTEFSpace);
// Append the TestCaseID along with the Setup params
iSetUpParamValue.Append(iTestCaseID);
iSetUpParamValue.Append(KTEFSpace);
// Insert the !Setup arguments after the OOM arguments within the iStepArgs
iStepArgs.Insert(6, iSetUpParamValue);
}
// Call the async client API to run the test step
if(iBlockArrayPkg)
{
iSession.RunTestBlock(iStepArgs,iTaskExitCategory,iBlockArrayPtr,iStatus);
}
else
{
iSession.RunTestStep(iStepArgs,iTaskExitCategory,iStatus);
}
// Start a timer and provide it with our callback MTaskCompletion
iState = ERunning;
// Only start the timer if the disable value is not set
if(iTaskTimeout != KDisableTimer)
{
iTaskTimer = CTaskTimer::NewL(*this);
iTaskTimer->Timeout(iTaskTimeout);
}
}
break;
case ERunning :
{
// We have been completed but we need to find out the source
// If the timer expires it Aborts the server test step which results in
// the RunTestStep call completing with KErrAbort.
// When the timer expires it calls us back and we delete it then NULL it.
if(iTaskTimer)
{
// The timer did not expire
iTaskTimer->Cancel();
delete iTaskTimer;
iTaskTimer = NULL;
}
const TInt KRetry10Microseconds = 100000;
const TInt KMaxRetryCount = 20;
if(iStatus.Int() == KErrInUse && iRetryCount < KMaxRetryCount)
{
// OS (not the server) has rejected the call.
// Timed retry
// Noticed this one after panic's in shared data mode
iState = EServerRetry;
// Keep increasing the timeout
iRetryCount++;
SetActive();
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrInfo,
_L("Error Message :: The Task Is Retrying "));
iTimer.After(iStatus,KRetry10Microseconds * iRetryCount);
}
else if(iStatus.Int() == KErrServerBusy)
{
// tempt to do test again when test server return busy.
iState = EServerRetry;
iRetryCount++;
if(iRetryCount < KMaxRetryCount)
{
iState = EServerRetry;
SetActive();
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrInfo,
_L("Error Message : Server return -16 = KErrServerBusy : Retrying %d"),iRetryCount);
iTimer.After(iStatus,KRetry10Microseconds );
}
else//server alwayse busy. stop test.
{
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrErr,
_L("Error Message : Server Busy Retrying %d times. Test Teminated!"),iRetryCount);
iParent.TaskCompletion(iStatus.Int(),iTaskExitCategory,iScriptLineNumber,iCommandLine,iTaskCanComplete);
iSession.Close();
delete this;
}
}
else
{
// see testserverbase.cpp::void SytemWideErrToTefErr(TInt &aErr). converting thi value.
//Check the status, if the status is KErrTestExecuteInUse
//then log the information and change it back to
if(iStatus.Int() == KErrTestExecuteInUse)
{
//Convert the status back to KErrInUse
iStatus=KErrInUse;
}
else if(iStatus.Int() == KErrTestExecuteServerBusy)
{
//this is not server really busy! we should change the server side iStatus back to -16
//Convert the status back to KErrServerBusy
iStatus = KErrServerBusy;
}
// Step completion
TestStepComplete();
delete this;
}
}
break;
default:
break;
}
}
/**
* @param aError - TInt value representing error returned due to processing request from RunL()
* Handles the leave from RunL() and cleans up the allocated objects
* Also returns KErrNone upon sucessful handling of leave
*/
TInt CClientControl::RunError(TInt aError)
{
if(iBlockArrayPkg)
{
TTEFItemArray* itemArray = CreateBlockArrayLC();
iParent.TaskCompletion(aError,iTaskExitCategory,iScriptLineNumber,iEndBlockCommand,iTaskCanComplete,itemArray);
CleanupStack::PopAndDestroy( itemArray );
}
else
{
iParent.TaskCompletion(aError,iTaskExitCategory,iScriptLineNumber,iCommandLine,iTaskCanComplete);
}
delete this;
return KErrNone;
}
/**
* Extract and save the timeout, step name and test step arguments
*/
void CClientControl::GetStepParamsFromStepCommand()
{
TLex scriptLineLex(iCommandLine);
TPtrC command(scriptLineLex.NextToken());
if(command.CompareF(KTEFRunTestStepResultCommand) == 0)
scriptLineLex.NextToken();
else if(command.CompareF(KTEFRunPanicStepResultCommand) == 0)
{
scriptLineLex.NextToken();
TPtrC panicString(scriptLineLex.NextToken());
if(panicString.Left(1).Compare(KTEFOpenQuotes) == 0 && panicString.Right(1).Compare(KTEFOpenQuotes) != 0)
{
TBool validCommandLine(EFalse);
while(!scriptLineLex.Eos() && !validCommandLine)
{
panicString.Set(scriptLineLex.NextToken());
if(panicString.Right(1).Compare(KTEFOpenQuotes) == 0)
validCommandLine = ETrue;
}
}
}
else if(command.CompareF(KTEFRunTestStepCommand) == 0 ||
command.CompareF(KTEFStartTestBlock) == 0 )
{
TInt firstChar;
TPtrC commandStr;
TBool panicStringComplete(ETrue);
while(!scriptLineLex.Eos())
{
scriptLineLex.SkipSpace();
scriptLineLex.Mark();
TPtrC token = scriptLineLex.NextToken();
if( token.Length()>0 )
{
commandStr.Set( token );
firstChar = commandStr[0];
// 33 is the ascii value for "!". Used here for confirming switches
if (firstChar != KTEFAsciiExclamation && panicStringComplete)
{
break;
}
if(commandStr.Length() > 14 &&
commandStr.Mid(0,14).Compare(_L("!PanicString=\"")) == 0)
panicStringComplete = EFalse;
if(!panicStringComplete && commandStr.Right(1).Compare(KTEFOpenQuotes) == 0)
panicStringComplete = ETrue;
if (commandStr.Length() >= KTEFMinHeapParamLength && commandStr.Mid(0,KTEFMinHeapParamLength).CompareF(KTEFHeap) == 0)
iTaskHeapSize.Set(commandStr.Mid(KTEFMinHeapParamLength));
else if (commandStr.Length() >= KTEFMinSetupParamLength && commandStr.Mid(0,KTEFMinSetupParamLength).CompareF(KTEFSetUpParam) == 0)
iSetUpParamValue.Copy(commandStr);
else if (commandStr.Length() >= KTEFMinOomParamLength && commandStr.Mid(0,KTEFMinOomParamLength).CompareF(KTEFOom) == 0)
{
// Out of memory cannot be supported for UREL builds due to UHEAP macros
// not being supported in UREL builds
#if defined(_DEBUG)
iOOMRequestSet = ETrue;
#else
iOOMRequestSet = EFalse;
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrWarn,
_L("Out of Memory Testing is not supported for UREL builds"));
#endif
}
}
}
}
TLex timeoutLex;
if( command.CompareF(KTEFRunTestStepCommand) == 0 ||
command.CompareF(KTEFStartTestBlock) == 0)
timeoutLex = scriptLineLex.MarkedToken();
else
timeoutLex = scriptLineLex.NextToken();
TInt err = timeoutLex.Val(iTaskTimeout);
if(err)
{
// No timeout specified
iTaskTimeout = KDefaultTimeoutSeconds;
iStepName.Set(scriptLineLex.NextToken());
}
else
{
scriptLineLex.NextToken();
if( command.CompareF(KTEFRunTestStepCommand) == 0 ||
command.CompareF(KTEFRunTestStepResultCommand) == 0 ||
command.CompareF(KTEFRunPanicStepResultCommand) == 0 ||
command.CompareF(KTEFRunPanicStepCommand) == 0||
command.CompareF(KTEFRunErrorStepResultCommand) == 0)
{
// Save the step name
iStepName.Set(scriptLineLex.NextToken());
}
}
// The rest is sent to the server
scriptLineLex.SkipSpace();
iStepArgs.Copy(iScriptFilePath.Mid(0,2));
iStepArgs.Append(KTEFSpace);
iStepArgs.Append(iDefaultSysDrive);
iStepArgs.Append(KTEFSpace);
iStepArgs.Append(iTestSysDrive);
iStepArgs.Append(KTEFSpace);
iStepArgs.Append(scriptLineLex.Remainder());
}
/**
* Callback from a CTaskTimer object
* Abort the test step, NULL the timer so we know that a timeout has caused test step completion
*/
void CClientControl::TaskTimerCompletion()
{
delete iTaskTimer;
iTaskTimer = NULL;
iSession.AbortTestStep();
}
/**
* Constructor
* @param aCompletion - Reference to a callback method in the CClientControl parent object
*/
CTaskTimer::CTaskTimer(MTaskTimerCompletion& aCompletion) : CTimer(EPriorityUserInput), iParent(aCompletion)
{
CActiveScheduler::Add(this);
}
/**
* Iterate till the timer has expired and callback into the parent
*/
void CTaskTimer::RunL()
{
if (iTimesAfter > 0 || iSecondsRemaining > 0)
{
RunTimeout(); // Function call implementing the After() routines
}
else
{
iParent.TaskTimerCompletion(); // Call the completion routine for the timeout
}
}
/**
* Implements a timeout based using CTimer::After()
* Modified for handling huge timeout values
* @param aSeconds - Timeout value in seconds
*/
void CTaskTimer::Timeout(TInt aSeconds)
{
iTimesAfter = aSeconds/60; // Convert the aSeconds to equivalent minutes
iSecondsRemaining = (aSeconds - (iTimesAfter*60)); // Remainder of seconds after converting to equivalent minutes
RunTimeout();
}
/**
* Implements the After() routines for the timeout value specified
* The call is initiated from Timeout() & is iterated from the RunL()
*/
void CTaskTimer::RunTimeout()
{
if (iTimesAfter > 0)
{
After(60*1000000); // Call After() for every minute until iTimesAfter is >0
iTimesAfter--;
}
else if (iSecondsRemaining > 0)
{
After(iSecondsRemaining*1000000); // Call After() for remainder of microsec
iSecondsRemaining = 0;
}
}
/**
* Destructor
*/
CTaskTimer::~CTaskTimer()
{
}
/*
* @param aCompletion - Reference to a callback method in a CTaskControlBase parent object
* Two phase contruction
*/
CTaskTimer* CTaskTimer::NewL(MTaskTimerCompletion& aCompletion)
{
CTaskTimer* taskTimer = new(ELeave) CTaskTimer(aCompletion);
CleanupStack::PushL(taskTimer);
// We have to call the base class second phase constructor
taskTimer->ConstructL();
CleanupStack::Pop(taskTimer);
return taskTimer;
}
/**
* @param aCommand - Command for the derived class
* @param aCompletion - Reference to the parent class callback method
* @param aScriptLineNumber - The script file line number of this command
* @param aLogger - Reference to a Flogger derived session
* Constructor - Just initialise the abstract class data
*/
CTaskControlBase::CTaskControlBase(const TDesC& aCommand, MTaskCompletion& aCompletion,TInt aScriptLineNumber, CTestExecuteLogger& aLogger) :
iCommandLine(aCommand),
iParent(aCompletion),
iScriptLineNumber(aScriptLineNumber),
iLogger(aLogger),
iTaskTimer(NULL)
{
}
/**
* Destructor
*/
CTaskControlBase::~CTaskControlBase()
{
}
/**
* @param aCommand - Command line for the program (Store in base class)
* @param aCompletion - Reference to the parent class callback method (Store in base class)
* @param aScriptLineNumber - The script file line number of this command (Store in base class)
* @param aLogger - Reference to a Flogger derived session (Store in base class)
* @param aWSProgRun - Boolean value used for identifying window server programs
*/
CProgramControl::CProgramControl(const TDesC& aCommand,MTaskCompletion& aCompletion,TInt aScriptLineNumber, CTestExecuteLogger& aLogger, TBool aWSProgRun) : CTaskControlBase(aCommand,aCompletion,aScriptLineNumber,aLogger),
iState(EInit)
{
// Extract the program arguments from the command line
GetProgramArgsFromCommand();
// Try to connect to the window server (if available)
iWSProgRun = aWSProgRun;
#if !defined TEF_LITE
if( iWSProgRun )
{
iWs.Connect();
}
#else
// Always set to false if TEF_LITE is set
//iWSProgRun = EFalse;
#endif
}
/**
* Destructor
*/
CProgramControl::~CProgramControl()
{
#if !defined TEF_LITE
if( iWSProgRun )
{
iWs.Close();
}
#endif
}
/**
* Simple State machine.
* Kick()'d into by parent object.
* Runs an executable in its own process.
*/
void CProgramControl::RunL()
{
switch(iState)
{
case EInit :
{
TRAPD(err,RunProgramL());
if(err != KErrNone)
{
// Special case where the executable has already completed
if( err == KErrCompletion )
{
// Reset the error code
err = KErrNone;
}
// Failed so complete immediately
iParent.TaskCompletion(err,iTaskExitCategory,iScriptLineNumber,iCommandLine,iTaskCanComplete);
delete this;
}
else
{
SetActive();
iState = ERunning;
// Only start the timer if the disable value is not set
if(iTaskTimeout != KDisableTimer)
{
iTaskTimer = CTaskTimer::NewL(*this);
iTaskTimer->Timeout(iTaskTimeout);
}
if (iProgRenamed == 1)
{
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrInfo,
_L(".EXE not found - .APP run instead"));
}
}
}
break;
case ERunning :
{
if(iTaskTimer)
{
// The timer did not expire
iTaskTimer->Cancel();
delete iTaskTimer;
iTaskTimer = NULL;
}
// Set up the panic string if the program panicked
if( !iWSProgRun )
{
if(iProgram.ExitType() == EExitPanic)
{
iTaskExitCategory.Copy(KPanicEquals);
iTaskExitCategory.Append(iProgram.ExitCategory());
}
else if (iProgram.ExitType() == EExitPending)
{
iProgram.Kill(KErrAbort);
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrWarn,
_L("Program has been killed as the timeout is achieved."));
}
iProgram.Close();
}
#if !defined TEF_LITE
else
{
if(iProgramWS.ExitType() == EExitPanic)
{
iTaskExitCategory.Copy(KPanicEquals);
iTaskExitCategory.Append(iProgramWS.ExitCategory());
}
// Close the application
TInt prev = 0;
TInt winGid = iWs.FindWindowGroupIdentifier(prev, iProgramWS.Id());
TApaTask task(iWs);
task.SetWgId(winGid);
if( task.Exists() )
{
task.KillTask();
}
iProgramWS.Close();
}
#endif
// Complete to the parent object.
iParent.TaskCompletion(iStatus.Int(),iTaskExitCategory,iScriptLineNumber,iCommandLine,iTaskCanComplete);
delete this;
}
break;
default:
break;
}
}
/**
* Retrieve the program arguments from the script line.
*/
void CProgramControl::GetProgramArgsFromCommand()
{
TLex scriptLineLex(iCommandLine);
// Skip the RUN_PROGRAM command
scriptLineLex.NextToken();
TLex lex(scriptLineLex);
// Get the timer if it's been included
TLex timeoutLex(lex.NextToken());
TInt err = timeoutLex.Val(iTaskTimeout);
if(err)
// No timeout specified
iTaskTimeout = KDefaultTimeoutSeconds;
else
// Skip the timeout value
scriptLineLex.NextToken();
scriptLineLex.SkipSpace();
// Use the rest
iProgramArgs.Set(scriptLineLex.Remainder());
}
/**
* Task timer expired
*/
void CProgramControl::TaskTimerCompletion()
{
delete iTaskTimer;
iTaskTimer = NULL;
if( !iWSProgRun )
{
iProgram.RendezvousCancel(iStatus);
}
#if !defined TEF_LITE
else
{
iProgramWS.RendezvousCancel(iStatus);
}
#endif
// We ORPHAN the process
// Our RunL() gets called immediately
// Kill requires KillAnyProcess capability
// ups the stakes as regards CAPABILITY
}
/**
* Processes RUN_PROGRAM command arguments and starts the program
*/
void CProgramControl::RunProgramL()
{
TLex lex(iProgramArgs);
// Get program name.
lex.Mark();
lex.NextToken();
#if !defined TEF_LITE
// Set up the program arguments
TBuf<KMaxTestExecuteCommandLength> programArgs(lex.Remainder());
programArgs.Trim();
iProgramArgs.Set(programArgs);
if( !iWSProgRun )
{
// Create the Process
User::LeaveIfError(iProgram.Create(lex.MarkedToken(),iProgramArgs));
}
else
{
if( !IsWindowServerAvailable() )
{
User::Leave(KErrNotSupported);
}
// Launch the application using RApaLsSession
// This will only work if there is a window server available.
// It allows TechView apps to be launched
CApaCommandLine *cmd=CApaCommandLine::NewLC();
cmd->SetExecutableNameL(lex.MarkedToken());
// Set the program arguments
cmd->SetDocumentNameL( iProgramArgs );
cmd->SetCommandL(EApaCommandRun);
User::LeaveIfError( iApaLsSess.Connect() );
// startup
TThreadId thread;
User::LeaveIfError( iApaLsSess.StartApp(*cmd, thread) );
TInt ret = iProgramWS.Open(thread);
if( ret != KErrNone )
{
if( ret == KErrNotFound )
{
// If the thread can not be found then it has already completed
// Leave with a relavent error
User::Leave(KErrCompletion);
}
User::Leave(ret);
}
//cleanup
iApaLsSess.Close();
CleanupStack::PopAndDestroy();
}
#else
/**
* Kick off an exe in its own pocess
* completes asynchronously
*/
if (iWSProgRun) //TEF lite doesn't support RUN_WS_PROGRAM.
{
iLogger.LogExtra((TText8*)__FILE__,__LINE__,ESevrErr,
_L("Error Message :: TEF lite doesn't support RUN_WS_PROGRAM."));
User::Leave(EFail);
}
// Set up the program arguments
TPtrC commandLine(lex.Remainder());
iProgramArgs.Set(commandLine);
// Create the Process
User::LeaveIfError(iProgram.Create(lex.MarkedToken(),iProgramArgs));
#endif
if( !iWSProgRun )
{
iProgram.Rendezvous(iStatus);
iProgram.Resume();
}
#if !defined TEF_LITE
else
{
iProgramWS.Rendezvous(iStatus);
}
#endif
}
/**
* @param aServerName - Test server to connect to
* @param aSharedData - Flag for shared data mode session with test server
* Connect to the test server
* EKA2 version requires a just in time debug flag for the test server process
* This is read from the command line.
* Base class connect acts on this.
*/
TInt RScriptTestServ::Connect(const TDesC& aServerName,TBool aSharedData)
{
iSharedData = aSharedData;
// Parse the command line for -d
TBuf<KMaxTestExecuteCommandLength> commandLine;
if(User::CommandLineLength() > commandLine.MaxLength())
User::Leave(KErrTooBig);
User::CommandLine(commandLine);
TLex flagLex(commandLine);
// Default to false
TBool aJustInTime(EFalse);
while(!flagLex.Eos())
{
TPtrC token(flagLex.NextToken());
if(token == KTestExecuteCommandLineFlagDebugMode)
{
aJustInTime = ETrue;
break;
}
}
return RTestServ::Connect(aServerName,aJustInTime);
}
/**
* Copies the integer value read from ini file to the reference integer passed to the function
* @param aConfigData - Pointer to CIniData object used for reading data from ini file
* @param aConfigSection - Descriptor value describing the section name within an ini file for reading
* @param aSharedData - KeyName within a section where the input data is available in ini file
* @param aSharedDataNum - Reference integer variable for collecting the value at the keyname specified
* @Leave system wide errors
*/
void CScriptControl::FindValueL(CIniData* aConfigData, TPtrC aConfigSection, TPtrC aSharedData, TInt& aSharedDataNum)
{
aConfigData->FindVar(aConfigSection, aSharedData, aSharedDataNum);
if (aSharedDataNum == 0)
{
User::Leave(KErrGeneral);
}
}
/**
* Copies the descriptor value read from ini file to the reference descriptor passed to the function
* @param aConfigData - Pointer to CIniData object used for reading data from ini file
* @param aConfigSection - Descriptor value describing the section name within an ini file for reading
* @param aSharedData - KeyName within a section where the input data is available in ini file
* @param aSharedDataName - Reference descriptor variable for collecting the value at the keyname specified
* @Leave system wide errors
*/
void CScriptControl::FindValueL(CIniData* aConfigData, TPtrC aConfigSection, TPtrC aSharedData, TPtrC& aSharedDataName)
{
User::LeaveIfError(aConfigData->FindVar(aConfigSection, aSharedData, aSharedDataName));
TPtrC blankString(KNull);
if (aSharedDataName.CompareF(blankString) == 0)
{
User::Leave(KErrGeneral);
}
}
/**
* Creates one or more shared objects based on the inputs provided in ini file
* @Leave system wide errors
*/
void CScriptControl::CreateSharedObjectsFromScriptLineL()
{
CIniData* configData = NULL;
TInt err = 0;
TInt sharedDataCount = 0;
TPtrC sharedDataName;
// Sets the boolean to ETrue
// Avoids SHARED_DATA command being called more than once
iIsSharedData = ETrue;
//It copies the current line from the script to TLex object
TLex shareLex(iCurrentScriptLine);
//reads the next word
shareLex.NextToken();
TPtrC configFile(shareLex.NextToken());
TPtrC configSection(shareLex.NextToken());
if(configFile.Length())
{
// Create instance of CIniData for reading ini input
TRAP(err,configData = CIniData::NewL(configFile));
}
if(err != KErrNone)
{
ERR_PRINTF1(KTEFErrorReadingIni);
User::Leave(err);
}
if(configData)
{
CleanupStack::PushL(configData);
TPtrC sharedDataNumberKey(KTEFSharedDataNum);
// Read the ini file for number of shared objects to be created
// Store the value into variable sharedDataCount
TRAP(err,FindValueL(configData,configSection,sharedDataNumberKey,sharedDataCount));
if (err != KErrNone)
{
ERR_PRINTF1(KTEFErrNumberOfShareNotInIni);
}
else
{
// If ini input is available for number of shared data
// Run a loop to read individual shared objects name
for (TInt i=1; i<=sharedDataCount; i++)
{
TBuf<20> keyName(KTEFSharedName);
keyName.AppendNum(i);
keyName.ZeroTerminate();
TPtrC sharedDataNameKey(keyName);
sharedDataName.Set(KNull);
// Read ini file for i th object name
TRAP(err,FindValueL(configData,configSection,sharedDataNameKey,sharedDataName));
if (err != KErrNone)
{
ERR_PRINTF2(KTEFErrShareNameNotInIni,i);
}
else
{
// Number of shared data is limited to the value set in the constant KTEFMaxSharedArraySize
// The constant is defined in ScriptEngine.h which can be extended from there
if (iSharedDataNum < KTEFMaxSharedArraySize)
{
// If ini input is available for i th object name
// Creating template class object for sharing the object
CTestSharedData* sharedObject = NULL;
CTEFSharedData<CTestSharedData>* sharedData1 = NULL;
TRAP(err,sharedData1 = CTEFSharedData<CTestSharedData>::NewL(sharedObject, KTEFSharedDataSize, sharedDataName));
if (err != KErrNone)
{
User::Leave(err);
}
else
{
sharedData1->EnterCriticalSection();
sharedObject->Construct();
sharedData1->ExitCriticalSection();
// Adding the template object to an array
iSharedDataArray[iSharedDataNum] = sharedData1;
// Counting the number of objects created
// destructor can destroy the objects based on this count
iSharedDataNum++;
}
}
else
{
WARN_PRINTF1(KTEFMaxNumberOfSharedObjectsReached);
}
}
}
}
// Cleanup CInidata object
CleanupStack::PopAndDestroy(configData);
}
}
/**
* Parses the test block header
* @Return ETrue if pass ok else EFalse
*/
// Fix defect 118337, check the configuration file exists or not, and set the flag.
TBool CScriptControl::ParseTestBlockHeader()
{
TLex lex(iCurrentScriptLine);
TPtrC token = lex.NextToken();
TInt paraCount = 1;
const TInt KLeastBlockHeaderParaCount = 4;
_LIT(KLegacySysDrive, "C:");
_LIT(KDefaultIniFilePath, "\\System\\Data\\");
while (!lex.Eos())
{
token.Set(lex.NextToken());
lex.SkipSpace();
++paraCount;
}
if (paraCount < KLeastBlockHeaderParaCount)
{
_LIT(KBadError, "Bad error syntax!");
ERR_PRINTF1(KBadError);
return EFalse;
}
TFileName defaultIniFilePath(KLegacySysDrive);
defaultIniFilePath.Append(KDefaultIniFilePath);
iFS.Connect();
TFindFile fileFind(iFS);
TInt ret = fileFind.FindByDir(token, defaultIniFilePath);
iFS.Close();
if (KErrNotFound == ret)
{
_LIT(KFileNotFound, "Configuration File %S Not Found!");
ERR_PRINTF2(KFileNotFound, &token);
return EFalse;
}
return ETrue;
}
// End defect 118337
/**
* Parses the test block and populates the iBlockArray
* @Leave system wide errors
*/
void CScriptControl::ParseTestBlockL( TTEFItemArray& aItemArray )
{
// Iterate through the commands contained within the test block
// and append them to the itemArray.
TPtrC startBlockScriptLine = iCurrentScriptLine;
TInt startBlockLineNumber = iCurrentScriptLineNumber;
TBool parseResult = ParseTestBlockHeader();
FOREVER
{
TTEFBlockItem blockItem;
// Read in the next script line
TBool scriptLineRes = EFalse;
if( !iStartLooping )
{
scriptLineRes = GetNextScriptLine(iCurrentScriptLine);
}
else
{
scriptLineRes = GetLoopScriptLine(iCurrentScriptLine);
}
if( !scriptLineRes )
{
_LIT( KTEFEoF, "Unexpectedly hit the end of the file" );
ERR_PRINTF1( KTEFEoF );
TExitCategoryName blankPanicString;
LogResult(EFail, blankPanicString, startBlockLineNumber, startBlockScriptLine);
User::Leave( KErrEof );
}
// Strip off any trailling comment
TInt offset = iCurrentScriptLine.Find(KTEFComment);
if( offset != KErrNotFound )
{
iCurrentScriptLine.Set( iCurrentScriptLine.Mid(0, offset) );
}
TLex lex(iCurrentScriptLine);
TPtrC token(lex.NextToken());
// Populate the blockItem with the data required for each command
// CREATE_OBJECT <object type> <object name section>
if( 0 == token.CompareF(KTEFCreateObject) )
{
blockItem.iItemType = ETEFCreateObject;
blockItem.iObjectType = lex.NextToken().Left(KTEFMaxNameLength);
blockItem.iSection = lex.NextToken().Left(KTEFMaxNameLength);
}
// RESTORE_OBJECT <object type> <object name section>
else if( 0 == token.CompareF(KTEFRestoreObject) )
{
blockItem.iItemType = ETEFRestoreObject;
blockItem.iObjectType = lex.NextToken().Left(KTEFMaxNameLength);
blockItem.iSection = lex.NextToken().Left(KTEFMaxNameLength);
}
// COMMAND [Error TEFParameter] <object name section> <function name> [section]
else if( 0 == token.CompareF(KTEFCommand) )
{
blockItem.iItemType = ETEFCommand;
TPtrC param = lex.NextToken().Left(KTEFMaxNameLength);
if( param.Length() > 0 )
{
while( param[0] == KTEFAsciiExclamation )
{
// This is a TEF Error Parameter
// Extract the type of TEF parameter being read in
if( param.Length() >= KTEFError().Length() &&
0 == param.Mid(0,KTEFError().Length()).CompareF(KTEFError) )
{
TInt start = KTEFError().Length();
TInt length = param.Length()-start;
TLex errorCodeLex( param.Mid(start,
length ));
TInt errorCode = 0;
if( errorCodeLex.Val(errorCode) == KErrNone )
{
blockItem.iExpectedError = errorCode;
}
else
{
_LIT(KBadError,"Bad error syntax.");
ERR_PRINTF1(KBadError);
blockItem.iError = KErrNotSupported;
}
}
else if( param.Length() >= KTEFAsyncError().Length() &&
0 == param.Mid(0,KTEFAsyncError().Length()).CompareF(KTEFAsyncError))
{
TInt start = KTEFAsyncError().Length();
TInt length = param.Length()-start;
TLex errorCodeLex( param.Mid(start,
length ));
TInt errorCode = 0;
if( errorCodeLex.Val(errorCode) == KErrNone )
{
blockItem.iExpectedAsyncError = errorCode;
}
else
{
_LIT(KBadError,"Bad error syntax.");
ERR_PRINTF1(KBadError);
blockItem.iAsyncError = KErrNotSupported;
}
}
else
{
// Unknown TEFParameter
_LIT(KUnknownTEFParam,"Unknown Test Block TEFParameter.");
ERR_PRINTF1(KUnknownTEFParam);
TExitCategoryName blankPanicString;
LogResult(EFail, blankPanicString, startBlockLineNumber, startBlockScriptLine);
User::Leave(KErrNotSupported);
}
// Read the next token
param.Set( lex.NextToken().Left(KTEFMaxNameLength) );
}
}
// Read in the object section name, function name and optional data section
blockItem.iCommand.iObject = param;
blockItem.iCommand.iFunction = lex.NextToken().Left(KTEFMaxNameLength);
blockItem.iSection = lex.NextToken().Left(KTEFMaxNameLength);
}
// STORE <section>
else if( 0 == token.CompareF(KTEFStore) )
{
blockItem.iItemType = ETEFStore;
blockItem.iSection = lex.NextToken().Left(KTEFMaxNameLength);
}
// OUTSTANDING <poll interval in ms>
else if( 0 == token.CompareF(KTEFOutstanding) )
{
blockItem.iItemType = ETEFOutstanding;
TLex pollLex( lex.NextToken().Left(KTEFMaxNameLength) );
TInt poll = 0;
blockItem.iTime = (KErrNone==pollLex.Val(poll)?poll:0);
blockItem.iSection = lex.NextToken().Left(KTEFMaxNameLength);
}
// DELAY <time in ms>
else if( 0 == token.CompareF(KTEFDelay) )
{
blockItem.iItemType = ETEFDelay;
TLex delayLex( lex.NextToken().Left(KTEFMaxNameLength) );
TInt delay = 0;
blockItem.iTime = (KErrNone==delayLex.Val(delay)?delay:0);
}
// ASYNC_DELAY <time in ms>
else if( 0 == token.CompareF(KTEFAsyncDelay) )
{
blockItem.iItemType = ETEFAsyncDelay;
TLex delayLex( lex.NextToken().Left(KTEFMaxNameLength) );
TInt delay = 0;
blockItem.iTime = (KErrNone==delayLex.Val(delay)?delay:0);
}
// SHARED_ACTIVE_SCHEDULER
else if( 0 == token.CompareF(KTEFSharedActiveScheduler) )
{
blockItem.iItemType = ETEFSharedActiveScheduler;
}
// STORE_ACTIVE_SCHEDULER
else if( 0 == token.CompareF(KTEFStoreActiveScheduler) )
{
blockItem.iItemType = ETEFStoreActiveScheduler;
}
// END_TEST_BLOCK [Scheduler Cleanup]
else if( 0 == token.CompareF(KTEFEndTestBlock) )
{
TExitCategoryName blankPanicString;
if( 0 == aItemArray.Count() )
{
_LIT( KTEFEmptyBlock, "The Test Block is empty." );
ERR_PRINTF1( KTEFEmptyBlock );
LogResult(EFail, blankPanicString, startBlockLineNumber, startBlockScriptLine);
User::Leave(KErrNotFound);
}
else
{
// Hit the end of the test block and the package is ready
// Fix defect 118337, check parse result, and print corresponding message.
LogResult(parseResult?EPass:EFail, blankPanicString, startBlockLineNumber, startBlockScriptLine);
//End defect 118337
break;
}
}
else if( 0 == token.CompareF(KTEFStartTestBlock) )
{
// Error - there was no end test block command
_LIT(KMissingEnd,"Missing END_TEST_BLOCK command.");
ERR_PRINTF1(KMissingEnd);
TExitCategoryName blankPanicString;
LogResult(EFail, blankPanicString, startBlockLineNumber, startBlockScriptLine);
User::Leave(KErrNotFound);
}
else
{
if( token.Length() > 0 )
{
if( 0 != token.Left(2).Compare(KTEFComment) )
{
// The SART_TEST_BLOCK command failed
_LIT(KUnknownCmd,"Unknown Test Block command.");
ERR_PRINTF1(KUnknownCmd);
TExitCategoryName blankPanicString;
LogResult(EFail, blankPanicString, startBlockLineNumber, startBlockScriptLine);
// Special case for END_TESTCASE commands
// If one has been hit here because an END_TEST_BLOCK command was missing
// the we must log its completion.
if( token.CompareF(KTEFEndTestCaseCommand) == 0 || token.CompareF(KTEFEndSyncTestCaseCommand) == 0 )
{
LogTestCaseMarkerL();
}
User::Leave(KErrNotSupported);
}
}
}
// Append the blockItem to the package
if( ETEFNull != blockItem.iItemType )
{
aItemArray.AppendL( blockItem );
}
}
}
_LIT( KTEFSyncStatus, "TEFStatus" );
_LIT( KTEFSyncResult, "TEFResult" );
const TInt KDelay = 3000000;
const TInt KRetryCount = 10;
enum TSyncStatus
{
ETEFSyncUnknown = 0,
ETEFSyncRunning = 1,
ETEFSyncComplete = 2,
ETEFSyncWaiting = 3,
ETEFSyncContinue = 4,
ETEFRetrieveResult = 5
};
/**
* Constructor
*/
CSyncControl::CSyncControl()
: iSharedTEFStatus(NULL), iSharedTEFResult(NULL)
{
}
/**
* Destructor
*/
CSyncControl::~CSyncControl()
{
if( iSharedTEFResult && iSharedTEFStatus )
{
// Don't cleanup until the status is correct
// This will allow time for any retrieve result calls to get through before TEF exits
// Will retry for 30 seconds
CTestSharedData* tefStatus = iSharedTEFStatus->Ptr();
if( tefStatus != NULL )
{
TInt64 status = ETEFRetrieveResult;
TInt count = 0;
while( status == ETEFRetrieveResult && count < KRetryCount )
{
iSharedTEFStatus->EnterCriticalSection();
HBufC* statusBuffer = NULL;
TRAPD( err, statusBuffer = HBufC::NewL(tefStatus->TextLength()) );
if( err == KErrNone )
{
TPtr statusPtr( statusBuffer->Des() );
tefStatus->GetText( statusPtr );
TLex lex(statusPtr);
lex.Val(status);
delete statusBuffer;
}
iSharedTEFStatus->ExitCriticalSection();
// Don't deley for the first i
if( count > 0 )
{
User::After( KDelay );
}
count++;
}
}
delete iSharedTEFResult;
delete iSharedTEFStatus;
}
}
/**
* Two phase construction
*/
CSyncControl* CSyncControl::NewL()
{
CSyncControl* self = CSyncControl::NewLC();
CleanupStack::Pop();
return self;
}
/**
* Two phase construction
*/
CSyncControl* CSyncControl::NewLC()
{
CSyncControl* self = new (ELeave) CSyncControl();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
/**
* ConstructL
*/
void CSyncControl::ConstructL()
{
// Initialise the sync status shared data
CTestSharedData* tefStatus = NULL;
iSharedTEFStatus = CTEFSharedData<CTestSharedData>::NewL( tefStatus,
KMaxSharedDataLength,
KTEFSyncStatus );
iSharedTEFStatus->EnterCriticalSection();
tefStatus->Construct();
HBufC* statusBuffer = NULL;
TRAPD( err, statusBuffer = HBufC::NewL(sizeof(TInt64)) );
if( err != KErrNone )
{
iSharedTEFStatus->ExitCriticalSection();
User::Leave( err );
}
TPtr statusPtr( statusBuffer->Des() );
statusPtr.Num( ETEFSyncWaiting );
tefStatus->SetText( statusPtr );
delete statusBuffer;
iSharedTEFStatus->ExitCriticalSection();
// Initialise the sync result shared data
CTestSharedData* tefResult = NULL;
iSharedTEFResult = CTEFSharedData<CTestSharedData>::NewL( tefResult,
KMaxSharedDataLength,
KTEFSyncResult );
iSharedTEFResult->EnterCriticalSection();
tefResult->Construct();
HBufC* resBuffer = NULL;
TRAP( err, resBuffer = HBufC::NewL(sizeof(TInt64)) );
if( err != KErrNone )
{
iSharedTEFResult->ExitCriticalSection();
User::Leave( err );
}
TPtr resPtr( resBuffer->Des() );
resPtr.Num( EInconclusive );
tefResult->SetText( resPtr );
delete resBuffer;
iSharedTEFResult->ExitCriticalSection();
}
/**
* @param aError - Error value resulting from synchronised testcase for logging
* Sets the result obtained from synchronised testcase for logging
*/
void CSyncControl::SetResultL( TVerdict aError )
{
// Retrieve the status and result shared data pointers
CTestSharedData* tefResult = iSharedTEFResult->Ptr();
CTestSharedData* tefStatus = iSharedTEFStatus->Ptr();
if( tefResult != NULL && tefStatus != NULL )
{
// Update the shared sync test case result code
iSharedTEFResult->EnterCriticalSection();
HBufC* resBuffer = NULL;
TRAPD( err, resBuffer = HBufC::NewL(sizeof(TInt64)) );
if( err != KErrNone )
{
iSharedTEFResult->ExitCriticalSection();
User::Leave( err );
}
TPtr resPtr( resBuffer->Des() );
resPtr.Num( (TInt64)aError );
tefResult->SetText( resPtr );
delete resBuffer;
iSharedTEFResult->ExitCriticalSection();
// So now the test has complete and the result has been updated
// we need to update the status to reflect this
iSharedTEFStatus->EnterCriticalSection();
HBufC* statusBuffer = NULL;
TRAP( err, statusBuffer = HBufC::NewL(sizeof(TInt64)) );
if( err != KErrNone )
{
iSharedTEFStatus->ExitCriticalSection();
User::Leave( err );
}
TPtr statusPtr( statusBuffer->Des() );
statusPtr.Num( ETEFRetrieveResult );
tefStatus->SetText( statusPtr );
delete statusBuffer;
iSharedTEFStatus->ExitCriticalSection();
}
else
{
User::Leave( KErrNotFound );
}
}
/**
* Identifies state of synchronised testcases and continues with the test or completes the tests
*/
TBool CSyncControl::TestCaseContinueL()
{
TBool tefContinue = EFalse;
// Retrieve the status and result shared data pointers
CTestSharedData* tefStatus = iSharedTEFStatus->Ptr();
CTestSharedData* tefResult = iSharedTEFResult->Ptr();
if( tefStatus != NULL && tefResult != NULL )
{
iSharedTEFStatus->EnterCriticalSection();
// Retrieve the current status
HBufC* statusBuffer = NULL;
TRAPD( err, statusBuffer = HBufC::NewL(tefStatus->TextLength()) );
if( err != KErrNone )
{
iSharedTEFStatus->ExitCriticalSection();
User::Leave( err );
}
TPtr statusPtr( statusBuffer->Des() );
tefStatus->GetText( statusPtr );
TLex lex(statusPtr);
TInt64 status = ETEFSyncUnknown;
User::LeaveIfError( lex.Val(status) );
if( status == ETEFSyncContinue )
{
tefContinue = ETrue;
// Update the status to running
HBufC* buffer = NULL;
TRAP( err, buffer = HBufC::NewL(sizeof(TInt64)) );
if( err != KErrNone )
{
delete statusBuffer;
iSharedTEFStatus->ExitCriticalSection();
User::Leave( err );
}
TPtr ptr( buffer->Des() );
ptr.Num( ETEFSyncRunning );
tefStatus->SetText( ptr );
delete buffer;
}
else if( status == ETEFSyncComplete )
{
// Previous test has completed and a new sync block has been hit
// Update the status to waiting
HBufC* buffer = NULL;
TRAP( err, buffer = HBufC::NewL(sizeof(TInt64)) );
if( err != KErrNone )
{
delete statusBuffer;
iSharedTEFStatus->ExitCriticalSection();
User::Leave( err );
}
TPtr ptr( buffer->Des() );
ptr.Num( ETEFSyncWaiting );
tefStatus->SetText( ptr );
delete buffer;
}
delete statusBuffer;
iSharedTEFStatus->ExitCriticalSection();
}
else
{
User::Leave( KErrNotFound );
}
return tefContinue;
}
/**
* Takes in a script line updates any relative file paths into corresponding absolute path based on the current script file path
* @param aScriptLineString - Pointer descriptor containing a particular script line for updation
*/
void CScriptControl::MakeAbsoluteFilePathsL(TPtrC16& aScriptLineString)
{
TLex lex(aScriptLineString);
iAlteredScriptLine.Zero(); // Initialise the altered script line to zero b4 we start processing
TBuf<KMaxTestExecuteCommandLength> commandName; // To store the command name, basically first token of each script line
TBuf<KMaxTestExecuteCommandLength> commandString; // To store individual tokens of script line for processing
TBuf<KMaxTestExecuteCommandLength> prevCommandString;
const TInt KTEFMinFileExtnSizeIni = 4;
const TInt KTEFMinFileExtnSizeScript = 7;
while(!lex.Eos()) // start a loop for each token until end of the script line
{
lex.NextToken();
lex.SkipSpace();
if (lex.MarkedToken().Length() > KMaxTestExecuteCommandLength)
{
User::Leave(KErrTooBig);
}
commandString.Copy(lex.MarkedToken());
lex.Mark();
if (commandName.CompareF(KTEFRunScriptCommand) == 0 &&
commandString.CompareF(KTEFNull) != 0)
{
// if the command name is RUN_SCRIPT, then check the parameter is not not null and has valid .script extn
// We append .script extn if the length of the token is less than 7 (.script -> Length)
// Or when the token does not end with .script enxtn
if(commandString.Length() < KTEFMinFileExtnSizeScript ||
commandString.Right(KTEFMinFileExtnSizeScript).CompareF(KTEFScriptExtension) != 0)
{
commandString.Append(KTEFScriptExtension);
}
}
// Expand recognised variables into their values
// At the moment just ${SYSDRIVE} -> GetSystemDrive()
ExpandVariables(commandString);
// we consider eligible path if the token is an argument for RUN_SCRIPT
// or any INI file or an argument for RUN_UTILS command
// Check to see if the token contains a ":" as second character represeting a drive letter
if (commandString.Length() >= KTEFMinFileExtnSizeIni &&
commandString.Mid(1,1).CompareF(KTEFColon) != 0)
{
// if the ":" is not found, we process converting relative -> absolute path
// Provided the token ends with .script or .ini extns
if ((commandString.Length() >= KTEFMinFileExtnSizeScript &&
commandString.Right(KTEFMinFileExtnSizeScript).CompareF(KTEFScriptExtension) == 0) ||
(commandString.Length() >= KTEFMinFileExtnSizeIni &&
commandString.Right(KTEFMinFileExtnSizeIni).CompareF(KTEFIniExtension) == 0))
{
// token does not does not have a ':' but is a eligible path,
// so, convert relative path to absolute path
TRAPD(err, ConvertRelativeToAbsoluteL(commandString));
if(err != KErrNone)
{
// Leave here since we have got an invalid path
User::Leave(err);
}
}
else if(commandName.CompareF(KTEFRunUtilsCommand) == 0 &&
(prevCommandString.CompareF(KTEFRunUtilsCopyFile) == 0 ||
prevCommandString.CompareF(KTEFRunUtilsMkDir) == 0 ||
prevCommandString.CompareF(KTEFRunUtilsDeleteFile) == 0 ||
prevCommandString.CompareF(KTEFRunUtilsDelete) == 0 ||
prevCommandString.CompareF(KTEFRunUtilsMakeReadWrite) == 0 ||
prevCommandString.CompareF(KTEFDeleteDirectory) == 0))
{
// token does not does not have a ':' but is a eligible path,
// so, convert relative path to absolute path
TRAPD(err, ConvertRelativeToAbsoluteL(commandString));
if(err != KErrNone)
{
// Leave here since we have got an invalid path
User::Leave(err);
}
}
}
//start defect 120600
//remove the code which append an extra space.
// if (iAlteredScriptLine.Length())
//end defect 120600
if (iAlteredScriptLine.Length() == 0)
{
// While completng the processing for the first token in the script line,
// we record the token as command name, so that we can use it to identify
// eligible paths in the following loop cycles for the script line
commandName.Copy(commandString);
}
prevCommandString.Copy(commandString);
// Construct the altered script line with individual verified tokens of script line
if(iAlteredScriptLine.Length() + commandString.Length() <= iAlteredScriptLine.MaxLength() )
{
iAlteredScriptLine.Append(commandString);
}
else// this scipte too long buffer not long enought
{
User::Leave(KErrTooBig);
}
}
// At the end of the while loop, we are ready with new processed script line
// which we shall update it with the original reference taken in
aScriptLineString.Set(iAlteredScriptLine);
}
/**
* Takes in lex token and updates any relative file paths into corresponding absolute path based on the current script file path
* @param aCommandString - Pointer descriptor containing a particular token within a script line for updation
*/
void CScriptControl::ConvertRelativeToAbsoluteL(TDes& aCommandString)
{
TInt offset = 0;
TInt posOfLastSlash=iScriptFile.LocateReverse('\\') ;
TBuf<KMaxTestExecuteCommandLength> tempStore(iScriptFile.Mid(0,posOfLastSlash)); // Initial script file path
if(aCommandString.FindC(KTEFOneUp) >= 0)
{
while(aCommandString.FindC(KTEFOneUp) >= 0)
{
offset = aCommandString.FindC(KTEFOneUp);
posOfLastSlash=tempStore.LocateReverse('\\') ;
if (posOfLastSlash <= 0)
{
User::Leave(KTEFErrInvalidRelPath);
}
tempStore.Copy(iScriptFile.Mid(0,posOfLastSlash));// script file path
aCommandString.Copy(aCommandString.Mid(offset + 3)); // 3 for ..'\\'
}
tempStore.Append('\\');
}
else if (aCommandString.FindC(KTEFDotSlash) >= 0)
{
offset = aCommandString.FindC(KTEFDotSlash);
aCommandString.Copy(aCommandString.Mid(offset + 1));
}
else if(aCommandString.Locate('\\') == 0)
{
tempStore.Copy(iScriptFile.Mid(0,2)); // Example: c:
}
else
{
tempStore.Append('\\');
}
tempStore.Append(aCommandString);
aCommandString.Copy(tempStore);
}
/**
* Expand recognised variables in script file into their corresponding value
* Currently supported variable is ${SYSDRIVE} -> GetSystemDrive() / Drive letter set from testexecute.ini
* @param aCommandString - Descriptor containing a particular token within a script line for updation
*/
void CScriptControl::ExpandVariables(TDes& aCommandString)
{
TInt offset = 0;
if (aCommandString.FindC(KTEFSysDrive) >= 0)
{
// If we find ${SYSDRIVE} in the token, replace it with the drive letter to be substitued
offset = aCommandString.FindC(KTEFSysDrive);
aCommandString.Replace(offset, 11, iTestSysDrive);
}
}