--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecfw/tef/scriptengine/src/scriptengine.cpp Mon Mar 08 15:03:44 2010 +0800
@@ -0,0 +1,4076 @@
+/*
+* 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);
+ }
+ }