--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmtestenv/mmtestfw/Source/TestFramework/parseline.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,2274 @@
+// Copyright (c) 2002-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:
+// This module contains CParseLine and CSuiteDll classes
+// CParseLine contains the functions required to execute
+// a line of test script file.
+// CSuiteDll objects contains information about test suite
+// dlls that have been loaded.
+//
+//
+
+// system includes
+#include <f32file.h>
+
+// test system includes
+#include "TestFramework.h"
+#include "script.h"
+#include "parseline.h"
+#include "Filename.h"
+
+#include "parseline.inl"
+
+const TInt KTimeIncrement = 100*1000000; // max wait interval in micro-seconds (100s)
+const TUint KMaxThreadAttempts = 128; // max number of times to attempt to create a thread
+
+/**
+ *
+ * File path literals
+ *
+ * @xxxx
+ *
+ */
+_LIT(KTxtDLLpath, "c:\\;c:\\system\\libs;d:\\;d:\\system\\libs;e:\\;e:\\system\\libs;z:\\;z:\\system\\libs");
+
+/**
+ *
+ * Script parameter defaults
+ *
+ * @xxxx
+ *
+ */
+//const TInt KTestGuardTimerDefault = 1000L; // EABI warning removal
+const TInt KPanicGuardTimerDefault = 1000000L;
+const TInt KPanicExitReasonDefault = 0;
+
+/**
+ *
+ * CParseLine first-phase constructor
+ *
+ * @xxxx
+ *
+ */
+CParseLine::CParseLine(const TDesC& aMatchString)
+ :iTestVerdict(EPass), iMatchString(aMatchString)
+ {
+ }
+
+/**
+ *
+ * CParseLine second-phase constructor
+ *
+ * @param "CScript* aScript"
+ * The script to be parsed
+ *
+ * @param "CTestUtils* aTestUtils"
+ * The TestUtils object to use
+ *
+ * @param "CLog* aLog"
+ * The logger to use
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::ConstructL(CScript* aScript, CTestUtils* aTestUtils, CLog* aLog, TInt64 aGuardTimer)
+ {
+ // create a new Array to store the test steps in
+ iArrayLoadedSuiteDll = new(ELeave) CArrayPtrFlat<CSuiteDll>(1);
+
+ iScript = aScript;
+ iTestUtils = aTestUtils;
+ iLog = aLog;
+ iGuardTimer = aGuardTimer;
+ iSeverity = ESevrAll;
+ iBreakOnError = EFalse;
+ }
+
+/**
+ *
+ * CParseLine static constructor
+ *
+ * @param "CScript* aScript"
+ * The script to be parsed
+ *
+ * @param "CTestUtils* aTestUtils"
+ * The TestUtils object to use
+ *
+ * @param "CLog* aLog"
+ * The logger to use
+ *
+ * @xxxx
+ *
+ */
+CParseLine* CParseLine::NewL(CScript* aScript, CTestUtils* aTestUtils, CLog* aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
+ {
+ CParseLine* self = new(ELeave) CParseLine(aMatchString);
+ CleanupStack::PushL(self);
+ self->ConstructL(aScript, aTestUtils, aLog, aGuardTimer);
+ CleanupStack::Pop();
+ return self;
+ }
+
+/**
+ *
+ * CParseLine destructor
+ *
+ * @xxxx
+ *
+ */
+CParseLine::~CParseLine()
+ {
+
+ // unload DLLs and their records
+ if (iArrayLoadedSuiteDll)
+ {
+ // delete all objects in iArrayLoadedSuiteDll
+ // the destructors will unload any loaded DLLS
+ iArrayLoadedSuiteDll->ResetAndDestroy();
+ delete iArrayLoadedSuiteDll;
+ }
+
+ }
+
+/**
+ *
+ * Process a single line from the script file.
+ *
+ * @param "const TDesC8& aNarrowline"
+ * The script line
+ *
+ * @param "TInt8 aLineNo"
+ * The script line number
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::ProcessLineL(const TDesC8& aNarrowline, TInt aLineNo)
+ {
+ // make a local unicode buffer
+ TPtr16 lineBuf(REINTERPRET_CAST(TUint16*,User::AllocLC(KMaxLenScriptLine*2)), 0, KMaxLenScriptLine);
+ lineBuf.Fill('\0', KMaxLenScriptLine);
+
+ // convert the narrow script file to Unicode
+ // TBC find a better way to do this
+ CFileName* testnameU = CFileName::NewLC();
+ testnameU->Copy(aNarrowline);
+
+ // find the end of the line
+ TInt end = testnameU->Locate('\n');
+
+ // copy the line into lineBuf
+ if ((end != KErrNotFound) && (end < KMaxLenScriptLine))
+ lineBuf = testnameU->Left(end - 1);
+ else
+ lineBuf = testnameU->FileName();
+
+ // destroy filename
+ CleanupStack::PopAndDestroy(testnameU);
+
+ // the parser relies on spaces between tokens. Commas are
+ // allowed but are just replaced with spaces
+ TInt findComma = lineBuf.Locate(TChar(','));
+ while (findComma != KErrNotFound )
+ {
+ // found a comma so replace with space
+ lineBuf.Replace(findComma, 1, _L(" "));
+ findComma = lineBuf.Locate(TChar(','));
+ }
+
+ // for debugging display the line with a line no
+#ifdef SCRIPT_DEBUG
+ INFO_PRINTF3(_L("Line:%d %S "), aLineNo, &lineBuf);
+#endif
+
+ // if there has been a failure and the user has selected
+ // x then the next commands in the script are skipped until
+ // a test complete statement is found
+ if (iBreakOnError)
+ {
+ if (lineBuf.FindF(_L("TEST_COMPLETE")) == 0)
+ {
+ TestComplete(lineBuf);
+ // reset flag now test complete found
+ iBreakOnError = EFalse;
+ }
+
+ CleanupStack::PopAndDestroy(); // linebuf
+ // do not process the rest of the line
+ return;
+ }
+
+ // check the line for command keywords
+ if ((lineBuf.Find(_L("//")) == 0) || (lineBuf.Find(_L("#")) == 0))
+ {
+ // ignore comments
+ }
+ else if (lineBuf.FindF(_L("LOAD_SUITE")) == 0)
+ {
+ LoadSuiteL(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("RUN_SCRIPT")) == 0)
+ {
+ RunScriptL(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("RUN_TEST_STEP")) == 0)
+ {
+ RunTestStep(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("RUN_PANIC_STEP")) == 0)
+ {
+ RunPanicTestStep(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("RUN_TERMINATION_STEP")) == 0)
+ {
+ RunTerminationTestStep(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("RUN_UTILS")) == 0)
+ {
+ RunUtil(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("RUN_PROGRAM")) == 0)
+ {
+ RunProgram(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("UNLOAD")) == 0)
+ {
+ Unload();
+ }
+ else if (lineBuf.FindF(_L("HEAP_MARK")) == 0)
+ {
+ HeapMark();
+ }
+ else if (lineBuf.FindF(_L("HEAP_CHECK")) == 0)
+ {
+ HeapCheck();
+ }
+ else if (lineBuf.FindF(_L("REQUEST_MARK")) == 0)
+ {
+ RequestMark();
+ }
+ else if (lineBuf.FindF(_L("REQUEST_CHECK")) == 0)
+ {
+ RequestCheck();
+ }
+ else if (lineBuf.FindF(_L("HANDLES_MARK")) == 0)
+ {
+ HandlesMark();
+ }
+ else if (lineBuf.FindF(_L("HANDLES_CHECK")) == 0)
+ {
+ HandlesCheck();
+ }
+ else if (lineBuf.FindF(_L("PRINT")) == 0)
+ {
+ ScriptPrint(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("DELAY")) == 0)
+ {
+ Delay(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("SEVERITY")) == 0)
+ {
+ SetSeverity(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("PAUSE_AT_END")) == 0)
+ {
+ // if implemented, add iScript->iPauseAtEnd = ETrue;
+ WARN_PRINTF1(_L("Warning : PAUSE_AT_END not implemented"));
+ }
+ else if (lineBuf.FindF(_L("MULTITHREAD")) == 0)
+ {
+ WARN_PRINTF1(_L("Warning : MULTITHREAD keyword no longer required"));
+ }
+ else if (lineBuf.FindF(_L("SINGLETHREAD")) == 0)
+ {
+ ERR_PRINTF1(_L("Error : Single thread operation no longer supported"));
+ }
+ else if (lineBuf.FindF(_L("PAUSE")) == 0)
+ {
+ iScript->Pause();
+ }
+ else if (lineBuf.FindF(_L("BREAK_ON_ERROR")) == 0)
+ {
+ // if the current test verdict is not PASS
+ // give the user the chance to quit
+ if ( iTestVerdict != EPass )
+ iBreakOnError = iScript->BreakOnError();
+ }
+ else if (lineBuf.FindF(_L("TEST_COMPLETE")) == 0)
+ {
+ // use Tlex to decode the cmd line
+ TestComplete(lineBuf);
+ }
+ else if (lineBuf.FindF(_L("LOG_SETTINGS")) == 0)
+ {
+ // use Tlex to decode the cmd line
+ LogSettings(lineBuf);
+ }
+ else if (lineBuf.Length() == 0)
+ {
+ // ignore blank lines
+ }
+ else
+ {
+ // failed to decode line
+ ERR_PRINTF3(_L("Error in script line:%d - \'%S\'"), aLineNo, &lineBuf);
+ }
+
+ CleanupStack::PopAndDestroy(); // linebuf
+ }
+
+/**
+ *
+ * Implements the TEST_COMPLETE script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::TestComplete(const TDesC& aText)
+ {
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // start at the begining
+ TPtrC token = lex.NextToken();
+
+ // get suite name, if any
+ token.Set(lex.NextToken());
+
+ if (token.Length() != 0)
+ {
+ TBuf<KMaxLenTestSuiteName> currentSuiteName;
+ currentSuiteName = token;
+
+ // get step name, if any
+ token.Set(lex.NextToken());
+
+ if (token.Length() != 0)
+ {
+ iCurrentStepName = token;
+ iCurrentSuiteName = currentSuiteName;
+ }
+ else
+ {
+ // failed to decode line - require 0 or 2 parameters exactly
+ // use last suite/step name, return fail
+ ERR_PRINTF2(_L("Error in script line: \'%S\'"), &aText);
+ iTestVerdict = EFail;
+ }
+ }
+
+ if (!iSkip)
+ {
+ // add the current result to the script
+ iScript->AddResult(iTestVerdict);
+ }
+
+ // reset for next test
+ iTestVerdict = EPass;
+ }
+
+/**
+ *
+ * Implements the PRINT script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::ScriptPrint(const TDesC& aText)
+ {
+ // display the text after the PRINT and 1 space = 6
+ INFO_PRINTF2(_L("%s "), (aText.Ptr() + 6));
+ }
+
+/**
+ *
+ * Implements the DELAY script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::Delay(const TDesC& aText)
+ {
+ // if the test has already failed skip the delay
+ if (iTestVerdict != EPass)
+ {
+ WARN_PRINTF1(_L("Skipped delay as test has already failed"));
+ return;
+ }
+
+ // get the required time for the delay
+ // first get the value as a string
+ TLex timeOut(aText);
+ timeOut.NextToken();
+ TPtrC token = timeOut.NextToken();
+
+ // convert the value into a TInt
+ TLex lexTime(token);
+ TInt64 guardTimerValue;
+ if (lexTime.Val(guardTimerValue) != KErrNone )
+ {
+ ERR_PRINTF2(_L("Error in guard timer value : could not decode \'%S\' as value"),
+ &token);
+ return;
+ }
+
+ INFO_PRINTF2(_L("Delay for %ld mS"), guardTimerValue);
+
+ // wait for the required delay
+ User::After(I64INT(guardTimerValue) * 1000);
+ }
+
+/**
+ *
+ * Implements the SEVERITY script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::SetSeverity(const TDesC& aText)
+ {
+ // get the required time for the delay
+ // first get the value as a string
+ TLex severityOut(aText);
+ severityOut.NextToken();
+ TPtrC token = severityOut.NextToken();
+
+ // convert the value into a TInt
+ TLex lexSeverity(token);
+ TInt severityValue = ESevrAll;
+ if (lexSeverity.Val(severityValue) != KErrNone)
+ {
+ ERR_PRINTF2(_L("Error in severity level value : could not decode \'%S\' as value"),
+ &token);
+ return;
+ }
+
+ // check severity value to ensure that only bitmasks in use are set...
+ if(!LogSeverity::IsValid(severityValue))
+ {
+ ERR_PRINTF1(_L("Error in severity value : out of range"));
+ return;
+ }
+ else
+ {
+ iSeverity = severityValue;
+
+ TInt noOfDlls = iArrayLoadedSuiteDll->Count();
+ for ( TInt i = 0; i < noOfDlls; i++)
+ {
+ CSuiteDll* ptrSuite = iArrayLoadedSuiteDll->At(i);
+ CTestSuite* testSuite = ptrSuite->Suite();
+ testSuite->SetSeverity(iSeverity);
+ }
+ }
+
+ INFO_PRINTF2(_L("Severity is set to %d"), severityValue);
+ }
+
+/**
+ *
+ * Implements the RUN_SCRIPT script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RunScriptL(const TDesC& aText)
+ {
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // start at the begining
+ TPtrC token=lex.NextToken();
+
+ // step over the keyword
+ token.Set(lex.NextToken());
+
+ // format for printing
+ INFO_PRINTF2(_L("RUN_SCRIPT %S"), &token);
+
+ // create a new Script object (but use the current parser
+ // as it has the dll loaded record)
+ CScript* newScript=CScript::NewLC(this, iTestUtils, iLog, iGuardTimer, iMatchString);
+
+ // read in the script file
+ CFileName* scriptFileName = CFileName::NewLC();
+ *scriptFileName = token;
+
+ if (newScript->OpenScriptFile(scriptFileName))
+ {
+ // process it
+ iTestVerdict = newScript->ExecuteScriptL();
+
+ // don't bother logging verdicts for scripts - not really useful
+ // add results from the new script to the owner script
+ iScript->AddResult(newScript);
+ }
+ else
+ {
+ // failed to find script so verdict incloncusive
+ iTestVerdict = EInconclusive;
+ }
+
+ CleanupStack::PopAndDestroy(scriptFileName);
+ CleanupStack::PopAndDestroy(newScript);
+ }
+
+/**
+ *
+ * Implements the RUN_TEST_STEP script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RunTestStep(const TDesC& aText)
+ {
+ // use TLex to decode the cmd line
+ TLex lex(aText);
+
+ // step over keyword
+ lex.NextToken();
+
+ // get guard timer
+ TPtrC timeout;
+ timeout.Set(lex.NextToken());
+
+ // get the other parameters
+ TPtrC suite, step, config, name, paramSet;
+ suite.Set(lex.NextToken());
+ step.Set(lex.NextToken());
+ config.Set(lex.NextToken());
+ name.Set(lex.NextToken());
+ if (name.Length()==0)
+ {
+ // name is optional, if not given use step
+ name.Set(step);
+ }
+ paramSet.Set(lex.NextToken());
+ if (paramSet.Length()==0)
+ {
+ // paramSet is optional, if not given use name
+ paramSet.Set(name);
+ }
+
+ // save the name of the current test suite / step
+ iCurrentSuiteName = suite;
+ iCurrentStepName = name;
+
+ TVerdict currentTestVerdict;
+
+ INFO_PRINTF2(_L("<a name=\"%S\"</a>"),&name);
+
+ if (iMatchString.Length()>0 && name.Match(iMatchString)<0)
+ {
+ // we have a match string but no match - so skip
+ INFO_PRINTF2(_L("TEST_STEP:%S skipped"), &name);
+ iSkip = ETrue;
+ return;
+ }
+
+ iSkip = EFalse;
+
+ // convert the guard timer value to a TInt64
+ TLex lexTimeOut(timeout);
+ TInt64 guardTimerValue;
+ if (lexTimeOut.Val(guardTimerValue) != KErrNone)
+ {
+ ERR_PRINTF2(_L("Error in guard timer value: %S"),
+ &timeout);
+ currentTestVerdict = EInconclusive;
+ }
+
+ else
+ {
+ // override guard timer if necessary
+ if((guardTimerValue == KNoGuardTimer) && (iGuardTimer != KNoGuardTimer))
+ {
+ INFO_PRINTF3(_L("Warning : Guard timer value overridden from %ld to %ld"),
+ guardTimerValue, iGuardTimer);
+ guardTimerValue = iGuardTimer;
+ }
+
+ // log the start of a test step
+ INFO_PRINTF7(_L("RUN_TEST_STEP:%S (step:%S suite:%S timeout:%ldmS config:%S(%S))"),
+ &name, &step, &suite, guardTimerValue, &config, ¶mSet);
+
+ // NOTE. Now running multithreaded all the time.
+ currentTestVerdict = DoTestNewThread(suite, step, guardTimerValue, config, paramSet);
+ }
+
+ TPtrC verdictText = CLog::TestResultText(currentTestVerdict);
+
+ INFO_PRINTF3(_L("TEST_STEP:%S returned:%S "),
+ &name, &verdictText);
+
+ // this result is only significant if everything else has passed
+ if (iTestVerdict == EPass)
+ iTestVerdict = currentTestVerdict;
+
+ }
+
+/**
+ *
+ * Implements the RUN_PANIC_STEP script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RunPanicTestStep(const TDesC& aText)
+ {
+ // NOTE. RUN_PANIC_STEP now incorporates the panic reason and category
+
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // start at the begining
+ TPtrC timeout=lex.NextToken();
+
+ // step over the keyword
+ timeout.Set(lex.NextToken());
+
+ // get the other parameters
+ TPtrC suite, step;
+ TPtrC category, reason;
+ TPtrC config, name, paramSet;
+
+ suite.Set(lex.NextToken());
+ step.Set(lex.NextToken());
+ category.Set(lex.NextToken());
+ reason.Set(lex.NextToken());
+ config.Set(lex.NextToken());
+ name.Set(lex.NextToken());
+ if (name.Length()==0)
+ {
+ // name is optional, if not given use step
+ name.Set(step);
+ }
+ paramSet.Set(lex.NextToken());
+ if (paramSet.Length()==0)
+ {
+ // paramSet is optional, if not given use name
+ paramSet.Set(name);
+ }
+
+ if (iMatchString.Length()>0 && name.Match(iMatchString)<0)
+ {
+ // we have a match string but no match - so skip
+ INFO_PRINTF2(_L("TEST_STEP:%S skipped"), &name);
+ iSkip = ETrue;
+ return;
+ }
+
+ iSkip = EFalse;
+
+ // save the name of the current test suite / step
+ iCurrentSuiteName = suite;
+ iCurrentStepName = name;
+
+ // convert the guard timer value to a TInt
+ TLex lexTimeOut(timeout);
+ TInt64 guardTimerValue;
+ if (lexTimeOut.Val(guardTimerValue) != KErrNone)
+ {
+ ERR_PRINTF3(_L("Error in guard timer value:%S using default %dmS"),
+ &timeout, KPanicGuardTimerDefault);
+ guardTimerValue = KPanicGuardTimerDefault;
+ }
+
+ // convert the exitReason value to a TInt
+ TLex lexReason(reason);
+ TInt exitReason;
+ if (lexReason.Val(exitReason) != KErrNone)
+ {
+ ERR_PRINTF3(_L("Error in exitReason value:%S using default %d"),
+ &reason, KPanicExitReasonDefault);
+ exitReason = KPanicExitReasonDefault;
+ }
+
+ // override guard timer if necessary
+ if((guardTimerValue == KNoGuardTimer) && (iGuardTimer != KNoGuardTimer))
+ {
+ INFO_PRINTF3(_L("Warning : Guard timer value overridden from %ld to %ld"),
+ guardTimerValue, iGuardTimer);
+ guardTimerValue = iGuardTimer;
+ }
+
+ // log the start of a test step
+ INFO_PRINTF9(_L("RUN_PANIC_STEP:%S (step:%S suite:%S timeout:%ldmS category:%S reason:%d config:%S(%S))"),
+ &name, &step, &suite, guardTimerValue, &category, exitReason, &config, ¶mSet);
+
+ // run the test step
+ TVerdict currentTestVerdict;
+
+ // now running multithreaded all the time
+ currentTestVerdict = DoPanicTest(suite, step, guardTimerValue,
+ category, exitReason, config, paramSet);
+
+ TPtrC verdictText = CLog::TestResultText(currentTestVerdict);
+ INFO_PRINTF3(_L("TEST_STEP:%S returned:%S "),
+ &name, &verdictText);
+
+ // this result is only significant if every thing else has passed
+ if (iTestVerdict == EPass)
+ iTestVerdict = currentTestVerdict;
+
+ }
+
+/**
+ *
+ * Implements the RUN_TERMINATION_STEP script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RunTerminationTestStep(const TDesC& aText)
+ {
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // start at the begining
+ TPtrC timeout=lex.NextToken();
+
+ // step over the keyword
+ timeout.Set(lex.NextToken());
+
+ // get the other parameters
+ TPtrC suite, step;
+ TPtrC reason;
+ TPtrC config;
+
+ suite.Set(lex.NextToken());
+ step.Set(lex.NextToken());
+ reason.Set(lex.NextToken());
+ config.Set(lex.NextToken());
+
+ // save the name of the current test suite / step
+ iCurrentSuiteName = suite;
+ iCurrentStepName = step;
+
+ // convert the guard timer value to a TInt
+ TLex lexTimeOut(timeout);
+ TInt64 guardTimerValue;
+ if (lexTimeOut.Val(guardTimerValue) != KErrNone)
+ {
+ ERR_PRINTF3(_L("Error in guard timer value:%S using default %dmS"),
+ &timeout, KPanicGuardTimerDefault);
+ guardTimerValue = KPanicGuardTimerDefault;
+ }
+
+ // convert the exitReason value to a TInt
+ TLex lexReason(reason);
+ TInt exitReason;
+ if (lexReason.Val(exitReason) != KErrNone)
+ {
+ ERR_PRINTF3(_L("Error in exitReason value:%S using default %d"),
+ &reason, KPanicExitReasonDefault);
+ exitReason = KPanicExitReasonDefault;
+ }
+
+ // override guard timer if necessary
+ if((guardTimerValue == KNoGuardTimer) && (iGuardTimer != KNoGuardTimer))
+ {
+ INFO_PRINTF3(_L("Warning : Guard timer value overridden from %ld to %ld"),
+ guardTimerValue, iGuardTimer);
+ guardTimerValue = iGuardTimer;
+ }
+
+ // log the start of a test step
+ INFO_PRINTF6(_L("RUN_TERMINATION_STEP:%S suite:%S timeout:%ldmS reason:%d config:%S"),
+ &step, &suite, guardTimerValue, exitReason, &config);
+
+ // run the test step
+ TVerdict currentTestVerdict;
+
+ // now running multithreaded all the time
+ currentTestVerdict = DoTerminationTest(suite, step, guardTimerValue,
+ exitReason, config);
+
+ TPtrC verdictText = CLog::TestResultText(currentTestVerdict);
+ INFO_PRINTF3(_L("TEST_STEP:%S returned:%S "),
+ &step, &verdictText);
+
+ // this result is only significant if every thing else has passed
+ if (iTestVerdict == EPass)
+ iTestVerdict = currentTestVerdict;
+
+ }
+
+/**
+ *
+ * Implements the RUN_UTILS script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RunUtil(const TDesC& aText)
+ {
+ // Call the utils
+ iTestUtils->RunUtils(aText);
+ }
+
+/**
+ *
+ * Implements the REBOOT script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::Reboot()
+ {
+ WARN_PRINTF1(_L("Warning : REBOOT command not implemented"));
+ }
+
+/**
+ *
+ * Static function to call DoTestStep which is run
+ * in a separate thread
+ *
+ * @param "TAny* aPtr"
+ * The test step data
+ *
+ * @return "TInt"
+ * EPOC error code
+ *
+ * @xxxx
+ *
+ */
+TInt CParseLine::ThreadFunctionL(TAny* aPtr)
+ {
+ TInt result = KErrNone;
+
+ // get clean-up stack
+ CTrapCleanup* trapCleanup = CTrapCleanup::New();
+
+ TRAPD(err, result = ThreadTrapFunctionL(aPtr));
+
+ delete trapCleanup;
+ return((err != KErrNone) ? err : result);
+ }
+
+/**
+ *
+ * Main function to call DoTestStep, called from within
+ * a trap
+ *
+ * @param "TAny* aPtr"
+ * The test step data
+ *
+ * @return "TInt"
+ * EPOC error code
+ *
+ * @xxxx
+ *
+ */
+TInt CParseLine::ThreadTrapFunctionL(TAny* aPtr)
+ {
+ // get the data for the test
+ CStepData* data = REINTERPRET_CAST(CStepData*, aPtr);
+ CSuiteDll* suiteDll = data->SuiteDll();
+ CTestSuite* testSuite = suiteDll->Suite();
+
+ // setup local logger
+ CLog* logClient = CLog::NewLC();
+ logClient->OpenLogFileL();
+ testSuite->SetLogSystem(logClient);
+
+ // do the test step
+ TVerdict result = testSuite->DoTestStep(data->Step(), data->Config(), data->ParamSet());
+
+ // NB it is the CALLING program's responsibility to save/restore the logger.
+ // If the thread terminates prematurely, the logger is in an undefined state.
+
+ CleanupStack::PopAndDestroy(logClient);
+ testSuite->SetLogSystem(NULL);
+
+ // return the test result
+ return result;
+ }
+
+/**
+ *
+ * Do a test step in a new thread.
+ *
+ * @param "const TDesC& aSuite"
+ * The test suite
+ *
+ * @param "const TDesC& aStep"
+ * The test step
+ *
+ * @param "TInt aGuardTimerValue"
+ * The guard timer value
+ *
+ * @param "const TDesC& aConfig"
+ * The config data
+ *
+ * @return "TVerdict"
+ * The test result
+ *
+ * @xxxx
+ *
+ */
+TVerdict CParseLine::DoTestNewThread(const TDesC& aSuite, const TDesC& aStep,
+ TInt64 aGuardTimerValue, const TDesC& aConfig, const TDesC& aParamSet)
+ {
+ // get the number of suites loaded
+ TInt noOfDlls = iArrayLoadedSuiteDll->Count();
+
+ // search the list of loaded test suite DLLs for the required one
+ for (TInt i = 0; i < noOfDlls; i++)
+ {
+ CSuiteDll* ptrSuite = iArrayLoadedSuiteDll->At(i);
+ TPtrC name = ptrSuite->Name();
+
+ if (name.FindF(aSuite)!= KErrNotFound)
+ {
+ // reset step status
+ CTestSuite* testSuite = ptrSuite->Suite();
+ testSuite->SetStepStatus(EStepStatusNone);
+
+ // store old log status, for restore at thread exit
+ // NB we must do this here, as if thread times out, the log
+ // is in an undefined state
+ CLog* oldLogger = testSuite->LogSystem();
+
+ CStepData* data = NULL;
+ TRAPD(err, data = CStepData::NewL(aStep, aConfig, aParamSet, ptrSuite));
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("CStepData::NewL() left with error %d : unable to create test data!"), err);
+ return EFail;
+ }
+
+ // get step's own stack and heap sizes
+ TInt theHeapSize = KMaxTestThreadHeapSize;
+ TInt theStackSize = KTestStackSize;
+ GetHeapAndStackSize(data, &theHeapSize, &theStackSize);
+
+ TInt res = KErrAlreadyExists;
+ RThread newThread;
+
+ TPtrC threadBaseName(_L("DoTestThread"));
+ TBuf<32> threadName;
+
+ // create a unique named test thread
+ // this will leave if creation is not successful
+ TRAP (res, CreateUniqueTestThreadL( threadBaseName,
+ threadName,
+ newThread,
+ ThreadFunctionL,
+ theStackSize,
+ KMinHeapSize,
+ theHeapSize,
+ data ) );
+
+
+ if (res != KErrNone)
+ {
+ ERR_PRINTF2(_L("CreateUniqueTestThreadL() left with error %d : unable to create test thread "), res);
+ delete data;
+ data = NULL;
+ return EFail;
+ }
+
+ // start clock
+ TTime testStart, testStop;
+ testStart.HomeTime();
+
+ // start the thread and request the status
+ TRequestStatus threadStatus;
+ newThread.Logon(threadStatus);
+
+ // if there is no guard timer value, don't time at all
+ if (aGuardTimerValue == KNoGuardTimer)
+ {
+ // no guard timer
+ newThread.Resume();
+ User::WaitForRequest(threadStatus);
+ }
+ else
+ {
+ // wait for either test thread or timer to end
+ RTimer guardTimer;
+ guardTimer.CreateLocal(); // create for this thread
+ TRequestStatus timerStatus;
+ newThread.Resume();
+
+ // NB now using At() to allow 64-bit timer values
+ TInt64 guardTimerUsec = aGuardTimerValue * 1000;
+ TInt64 totalTime = 0;
+
+ for (;;)
+ {
+ if (totalTime>=guardTimerUsec) // timeout has occured
+ break;
+ TInt timeout;
+
+ if (totalTime+KTimeIncrement >= guardTimerUsec)
+ {
+ TInt64 temp = guardTimerUsec-totalTime;
+ timeout = I64INT(temp);
+ }
+ else
+ timeout = KTimeIncrement;
+ totalTime += timeout;
+ guardTimer.After(timerStatus, timeout);
+ User::WaitForRequest(threadStatus, timerStatus);
+ if (threadStatus!=KRequestPending) // normal exit
+ break;
+ }
+
+ guardTimer.Cancel();
+ guardTimer.Close();
+ }
+
+ // reset any file server error simulations
+ RFs fs;
+ TInt fsError = fs.Connect();
+ if (fsError == KErrNone)
+ {
+ fs.SetErrorCondition(KErrNone);
+ }
+ fs.Close();
+
+ // restore logger
+ testSuite->SetLogSystem(oldLogger);
+
+ // get the test result
+ TVerdict result = STATIC_CAST(TVerdict, threadStatus.Int());
+
+ // check terminated ok
+ switch(newThread.ExitType())
+ {
+ case EExitTerminate:
+ case EExitKill:
+ break;
+ case EExitPanic:
+ {
+ TExitCategoryName exitCategory = newThread.ExitCategory();
+ TInt exitReason = newThread.ExitReason();
+ ERR_PRINTF3(_L("Thread had a panic %S:%d"), &exitCategory, exitReason);
+
+ result = EFail;
+ }
+ break;
+ case EExitPending:
+ // if the thread is still pending then the guard timer must have expired
+ ERR_PRINTF1(_L("Thread timed out"));
+ // kill the test step thread
+ newThread.Kill(1);
+ // give the OS time to cleanup devices, etc.
+ // NB if the thread dies, the postamble will NOT run
+ User::After(2000000);
+ result = EFail;
+ break;
+ default:
+ break;
+ }
+
+ // done with the test thread
+ newThread.Close();
+
+ // stop clock
+ testStop.HomeTime();
+
+ TUint testDuration = I64INT(testStop.MicroSecondsFrom(testStart).Int64());
+ testDuration /= 1000; // to microseconds
+ TUint testDurationMsec = testDuration % 1000;
+ TUint testDurationSec = testDuration / 1000;
+ INFO_PRINTF3(_L("Test took %d.%03d sec"), testDurationSec, testDurationMsec);
+
+ // return the test verdict
+ delete data;
+ data = NULL;
+ return result;
+ }
+ }
+
+ // the required suite has not been found
+ ERR_PRINTF3(_L("Error in test step:%S - cannot find suite:%S" ),
+ &aStep, &aSuite);
+
+ return ETestSuiteError;
+ }
+
+/**
+ *
+ * Do a test step which is expected to panic.
+ *
+ * @param "const TDesC& aSuite"
+ * The test suite
+ *
+ * @param "const TDesC& aStep"
+ * The test step
+ *
+ * @param "TInt aGuardTimerValue"
+ * The guard timer value
+ *
+ * @param "const TExitCategoryName aExitCategory"
+ * The expected exit category
+ *
+ * @param "TInt aExitReason"
+ * The expected exit reason
+ *
+ * @param "const TDesC& aConfig"
+ * The config data
+ *
+ * @return "TVerdict"
+ * The test result
+ *
+ * @xxxx
+ *
+ */
+TVerdict CParseLine::DoPanicTest(const TDesC& aSuite, const TDesC& aStep, TInt64 aGuardTimerValue,
+ const TExitCategoryName aExitCategory, TInt aExitReason,
+ const TDesC& aConfig, const TDesC& aParamSet)
+ {
+
+ // get the number of suites loaded
+ TInt noOfDlls = iArrayLoadedSuiteDll->Count();
+
+ // search the list of loaded test suite DLLs for the required one
+ for (TInt i = 0; i < noOfDlls; i++)
+ {
+ CSuiteDll* ptrSuite = iArrayLoadedSuiteDll->At(i);
+ TPtrC name = ptrSuite->Name();
+
+ if (name.FindF(aSuite)!= KErrNotFound)
+ {
+ // reset step status
+ CTestSuite* testSuite = ptrSuite->Suite();
+ testSuite->SetStepStatus(EStepStatusNone);
+
+ // store old log status, for restore at thread exit
+ // NB we must do this here, as if thread times out, the log
+ // is in an undefined state
+ CLog* oldLogger = testSuite->LogSystem();
+
+ CStepData* data = NULL;
+ TRAPD(err, data = CStepData::NewL(aStep, aConfig, aParamSet, ptrSuite));
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("CStepData::NewL() left with error %d : unable to create test data!"), err);
+ return EFail;
+ }
+
+ // get step's own stack and heap sizes
+ TInt theHeapSize = KMaxTestThreadHeapSize;
+ TInt theStackSize = KTestStackSize;
+ GetHeapAndStackSize(data, &theHeapSize, &theStackSize);
+
+ TInt res = KErrAlreadyExists;
+ RThread newThread;
+
+ // create a unique test name by appending a counter
+ TPtrC threadBaseName(_L("DoTestThread"));
+ TBuf<32> threadName;
+
+ // create a unique named test thread
+ // this will leave if creation is not successful
+ TRAP (res, CreateUniqueTestThreadL( threadBaseName,
+ threadName,
+ newThread,
+ ThreadFunctionL,
+ theStackSize,
+ KMinHeapSize,
+ theHeapSize,
+ data ) );
+
+ if (res != KErrNone)
+ {
+ ERR_PRINTF2(_L("CreateUniqueTestThreadL() left with error %d : unable to create test thread "), res);
+ delete data;
+ data = NULL;
+ return EFail;
+ }
+
+ // start clock
+ TTime testStart, testStop;
+ testStart.HomeTime();
+
+ // start the thread and request the status
+ TRequestStatus threadStatus;
+ newThread.Logon(threadStatus);
+
+ // if there is no guard timer value, don't time at all
+ if (aGuardTimerValue == KNoGuardTimer)
+ {
+ // no guard timer
+ newThread.Resume();
+ User::WaitForRequest(threadStatus);
+ }
+ else
+ {
+ // wait for either test thread or timer to end
+ RTimer guardTimer;
+ guardTimer.CreateLocal(); // create for this thread
+ TRequestStatus timerStatus;
+ newThread.Resume();
+
+ // NB now using At() to allow 64-bit timer values
+ TInt64 guardTimerUsec = aGuardTimerValue * 1000;
+ TInt64 totalTime = 0;
+
+ for (;;)
+ {
+ if (totalTime>=guardTimerUsec) // timeout has occured
+ break;
+ TInt timeout;
+
+ if (totalTime+KTimeIncrement >= guardTimerUsec)
+ {
+ TInt64 temp = guardTimerUsec-totalTime;
+ timeout = I64INT(temp);
+ }
+ else
+ timeout = KTimeIncrement;
+ totalTime += timeout;
+ guardTimer.After(timerStatus, timeout);
+ User::WaitForRequest(threadStatus, timerStatus);
+ if (threadStatus!=KRequestPending) // normal exit
+ break;
+ }
+
+ guardTimer.Cancel();
+ guardTimer.Close();
+ }
+
+ // restore logger
+ testSuite->SetLogSystem(oldLogger);
+
+ // get the test result
+ TVerdict result = STATIC_CAST(TVerdict, threadStatus.Int());
+
+ // check terminated ok
+ switch(newThread.ExitType())
+ {
+ case EExitPanic:
+ {
+ TExitCategoryName exitCategory = newThread.ExitCategory();
+ TInt exitReason = newThread.ExitReason();
+ if((exitCategory != aExitCategory) || (exitReason != aExitReason && aExitReason != KNoPanicReason) )
+ {
+ ERR_PRINTF3(_L("Test step had an unexpected panic %S:%d and failed"),
+ &exitCategory, exitReason);
+ result = EFail;
+ }
+ else
+ {
+ // check here that the panic occurred within the test itself
+ CTestSuite* testSuite = ptrSuite->Suite();
+ TTestStepStatus status = testSuite->StepStatus();
+ switch(status)
+ {
+ case EStepStatusPreamble:
+ {
+ // thread panicked in the test itself - success
+ INFO_PRINTF3(_L("Test step had a panic %S:%d and passed"),
+ &exitCategory, exitReason);
+ result = EPass;
+ }
+ break;
+ case EStepStatusStart:
+ {
+ // thread panicked in preamble
+ ERR_PRINTF3(_L("Test step had a panic %S:%d in preamble"),
+ &exitCategory, exitReason);
+ result = EFail;
+ }
+ break;
+ case EStepStatusTest:
+ {
+ // thread panicked in postamble
+ ERR_PRINTF3(_L("Test step had a panic %S:%d in postamble"),
+ &exitCategory, exitReason);
+ result = EFail;
+ }
+ break;
+ default:
+ {
+ // thread panicked outside the test
+ ERR_PRINTF3(_L("Test step had a panic %S:%d outside the test"),
+ &exitCategory, exitReason);
+ result = EFail;
+ }
+ break;
+ } // end switch
+ }
+ }
+ break;
+ case EExitPending:
+ // if the thread is still pending then the guard timer must have expired
+ ERR_PRINTF1(_L("Thread timed out"));
+ // kill the test step thread
+ newThread.Kill(1);
+ // give the OS time to cleanup devices, etc.
+ // NB if the thread dies, the postamble will NOT run
+ User::After(2000000);
+ result = EFail;
+ break;
+ case EExitTerminate:
+ case EExitKill:
+ default:
+ ERR_PRINTF1(_L("Test did not panic, so failed"));
+ result = EFail;
+ break;
+ }
+
+ // done with the test thread
+ newThread.Close();
+
+ // stop clock
+ testStop.HomeTime();
+
+ TUint testDuration = I64INT(testStop.MicroSecondsFrom(testStart).Int64());
+ testDuration /= 1000; // to microseconds
+ TUint testDurationMsec = testDuration % 1000;
+ TUint testDurationSec = testDuration / 1000;
+ INFO_PRINTF3(_L("Test took %d.%03d sec"), testDurationSec, testDurationMsec);
+
+ // return the test verdict
+ delete data;
+ data = NULL;
+ return result;
+ }
+ }
+
+ // the required suite has not been found
+ ERR_PRINTF3(_L("Error in test step:%S - cannot find suite:%S"),
+ &aStep, &aSuite );
+
+ return ETestSuiteError;
+ }
+
+/**
+ *
+ * Do a test step which is expected to terminate.
+ *
+ * @param "const TDesC& aSuite"
+ * The test suite
+ *
+ * @param "const TDesC& aStep"
+ * The test step
+ *
+ * @param "TInt aGuardTimerValue"
+ * The guard timer value
+ *
+ * @param "TInt aExitReason"
+ * The expected exit reason
+ *
+ * @param "const TDesC& aConfig"
+ * The config data
+ *
+ * @return "TVerdict"
+ * The test result
+ *
+ * @xxxx
+ *
+ */
+TVerdict CParseLine::DoTerminationTest(const TDesC& aSuite, const TDesC& aStep, TInt64 aGuardTimerValue,
+ TInt aExitReason, const TDesC& aConfig)
+ {
+
+ // get the number of suites loaded
+ TInt noOfDlls = iArrayLoadedSuiteDll->Count();
+
+ // search the list of loaded test suite DLLs for the required one
+ for (TInt i = 0; i < noOfDlls; i++)
+ {
+ CSuiteDll* ptrSuite = iArrayLoadedSuiteDll->At(i);
+ TPtrC name = ptrSuite->Name();
+
+ if (name.FindF(aSuite)!= KErrNotFound)
+ {
+ // reset step status
+ CTestSuite* testSuite = ptrSuite->Suite();
+ testSuite->SetStepStatus(EStepStatusNone);
+
+ // store old log status, for restore at thread exit
+ // NB we must do this here, as if thread times out, the log
+ // is in an undefined state
+ CLog* oldLogger = testSuite->LogSystem();
+
+ CStepData* data = NULL;
+ TRAPD(err, data = CStepData::NewL(aStep, aConfig, ptrSuite));
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("CStepData::NewL() left with error %d : unable to create test data!"), err);
+ return EFail;
+ }
+
+ // get step's own stack and heap sizes
+ TInt theHeapSize = KMaxTestThreadHeapSize;
+ TInt theStackSize = KTestStackSize;
+ GetHeapAndStackSize(data, &theHeapSize, &theStackSize);
+
+ TInt res = KErrAlreadyExists;
+ RThread newThread;
+
+ // create a unique test name by appending a counter
+ TPtrC threadBaseName(_L("DoTestThread"));
+ TBuf<32> threadName;
+
+ // create a unique named test thread
+ // this will leave if creation is not successful
+ TRAP (res, CreateUniqueTestThreadL( threadBaseName,
+ threadName,
+ newThread,
+ ThreadFunctionL,
+ theStackSize,
+ KMinHeapSize,
+ theHeapSize,
+ data ) );
+
+ if (res != KErrNone)
+ {
+ ERR_PRINTF2(_L("CreateUniqueTestThreadL() left with error %d : unable to create test thread "), res);
+ delete data;
+ data = NULL;
+ return EFail;
+ }
+
+ // start clock
+ TTime testStart, testStop;
+ testStart.HomeTime();
+
+ // start the thread and request the status
+ TRequestStatus threadStatus;
+ newThread.Logon(threadStatus);
+
+ // if there is no guard timer value, don't time at all
+ if (aGuardTimerValue == KNoGuardTimer)
+ {
+ // no guard timer
+ newThread.Resume();
+ User::WaitForRequest(threadStatus);
+ }
+ else
+ {
+ // wait for either test thread or timer to end
+ RTimer guardTimer;
+ guardTimer.CreateLocal(); // create for this thread
+ TRequestStatus timerStatus;
+ newThread.Resume();
+
+ // NB now using At() to allow 64-bit timer values
+ TInt64 guardTimerUsec = aGuardTimerValue * 1000;
+ TInt64 totalTime = 0;
+
+ for (;;)
+ {
+ if (totalTime>=guardTimerUsec) // timeout has occured
+ break;
+ TInt timeout;
+
+ if (totalTime+KTimeIncrement >= guardTimerUsec)
+ {
+ TInt64 temp = guardTimerUsec-totalTime;
+ timeout = I64INT(temp);
+ }
+ else
+ timeout = KTimeIncrement;
+ totalTime += timeout;
+ guardTimer.After(timerStatus, timeout);
+ User::WaitForRequest(threadStatus, timerStatus);
+ if (threadStatus!=KRequestPending) // normal exit
+ break;
+ }
+
+ guardTimer.Cancel();
+ guardTimer.Close();
+ }
+
+ // restore logger
+ testSuite->SetLogSystem(oldLogger);
+
+ // get the test result
+ TVerdict result = STATIC_CAST(TVerdict, threadStatus.Int());
+
+ // check terminated ok
+ switch(newThread.ExitType())
+ {
+ case EExitTerminate:
+ case EExitKill:
+ {
+ TInt exitReason = newThread.ExitReason();
+ if(exitReason != aExitReason)
+ {
+ ERR_PRINTF2(_L("Test step had an unexpected exit reason:%d and failed"),
+ exitReason);
+ result = EFail;
+ }
+ else
+ {
+ // check here that the panic occurred within the test itself
+ CTestSuite* testSuite = ptrSuite->Suite();
+ TTestStepStatus status = testSuite->StepStatus();
+ switch(status)
+ {
+ case EStepStatusPreamble:
+ {
+ // thread terminated in the test itself - success
+ INFO_PRINTF2(_L("Test step had terminated:%d and passed"),
+ exitReason);
+ result = EPass;
+ }
+ break;
+ case EStepStatusStart:
+ {
+ // thread panicked in preamble
+ ERR_PRINTF2(_L("Test step had terminated:%d in preamble"),
+ exitReason);
+ result = EFail;
+ }
+ break;
+ case EStepStatusTest:
+ {
+ // thread panicked in postamble
+ ERR_PRINTF2(_L("Test step had terminated:%d in postamble"),
+ exitReason);
+ result = EFail;
+ }
+ break;
+ default:
+ {
+ // thread panicked outside the test
+ ERR_PRINTF2(_L("Test step had terminated:%d outside the test"),
+ exitReason);
+ result = EFail;
+ }
+ break;
+ } // end switch
+ }
+ }
+ break;
+ case EExitPending:
+ // if the thread is still pending then the guard timer must have expired
+ ERR_PRINTF1(_L("Thread timed out"));
+ // kill the test step thread
+ newThread.Kill(1);
+ // give the OS time to cleanup devices, etc.
+ // NB if the thread dies, the postamble will NOT run
+ User::After(2000000);
+ result = EFail;
+ break;
+ case EExitPanic:
+ default:
+ ERR_PRINTF1(_L("Test did not terminate, so failed"));
+ result = EFail;
+ break;
+ }
+
+ // done with the test thread
+ newThread.Close();
+
+ // stop clock
+ testStop.HomeTime();
+
+ TUint testDuration = I64INT(testStop.MicroSecondsFrom(testStart).Int64());
+ testDuration /= 1000; // to microseconds
+ TUint testDurationMsec = testDuration % 1000;
+ TUint testDurationSec = testDuration / 1000;
+ INFO_PRINTF3(_L("Test took %d.%03d sec"), testDurationSec, testDurationMsec);
+
+ // return the test verdict
+ delete data;
+ data = NULL;
+ return result;
+ }
+ }
+
+ // the required suite has not been found
+ ERR_PRINTF3(_L("Error in test step:%S - cannot find suite:%S"),
+ &aStep, &aSuite );
+
+ return ETestSuiteError;
+ }
+
+/**
+ *
+ * Gets a step's heap and stack size.
+ *
+ * @param "const CStepData& aStepData"
+ * The step data
+ * @param "TInt* aHeapSize"
+ * Returns the step's heap size
+ * @param "TInt* aStackSize"
+ * Returns the step's stack size
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::GetHeapAndStackSize(const CStepData* aStepData, TInt* aHeapSize, TInt* aStackSize)
+ {
+ CSuiteDll* suiteDll = aStepData->SuiteDll();
+ CTestSuite* testSuite = suiteDll->Suite();
+ testSuite->GetHeapAndStackSize(aStepData->Step(), aHeapSize, aStackSize);
+ }
+
+/**
+ *
+ * Implements the RUN_PROGRAM script command.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RunProgram(const TDesC& aText)
+ {
+ TPtrC param;
+
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // step over the keyword
+ lex.NextToken();
+
+ // get program name
+ TPtrC token;
+ token.Set(lex.NextToken());
+
+ // get the parameters
+ param.Set(lex.NextToken());
+
+ INFO_PRINTF1(_L("Run Program "));
+
+
+ // In the ARM build run program as a new process
+ // use the rest of the text as parameters
+ RProcess program;
+ TInt ret = program.Create(token, lex.Remainder());
+
+ if (ret != KErrNone)
+ {
+ TPtrC errortxt = CLog::EpocErrorToText(ret);
+ ERR_PRINTF2(_L("Failed to start process - error %S"), &errortxt);
+ return;
+ }
+ else
+ {
+ INFO_PRINTF1(_L("Program started"));
+
+ // start program
+ TRequestStatus threadStatus;
+ program.Logon(threadStatus);
+ program.Resume();
+
+ // wait for guard timer
+ User::WaitForRequest(threadStatus);
+
+ // check return type
+ if (program.ExitType() == EExitPanic)
+ INFO_PRINTF1(_L("Program returned EExitPanic"));
+ else if (program.ExitType() == EExitPending)
+ INFO_PRINTF1(_L("Program returned EExitPending"));
+ else
+ INFO_PRINTF1(_L("Program returned EExitTerminate"));
+ }
+ }
+
+/**
+ *
+ * Implements the LOG_SETTINGS script command.
+ * Command format is LOG_SETTINGS "put src." (1/0),
+ * "HTML format" (1/0)
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::LogSettings(const TDesC& aText)
+ {
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // start at the begining
+ TPtrC token=lex.NextToken();
+
+ // step over the keyword
+ //Get information about source
+ token.Set(lex.NextToken());
+
+ TLex srcLex(token);
+ TInt isSrc = ETrue; //Shall we put src information?
+ if (srcLex.Val(isSrc) != KErrNone)
+ {
+ ERR_PRINTF2(_L("Error in LOG_SETTINGS: could not decode >%S< as value(0/1)"),
+ &token);
+ }
+ else
+ {
+ iLog->SetPutSrcInfo(isSrc) ;
+ }
+ //Get information about format
+ token.Set(lex.NextToken());
+ TLex htmlLex(token);
+
+ if (htmlLex.Val(isSrc) != KErrNone)
+ {
+ ERR_PRINTF2(_L("Error in LOG_SETTINGS: could not decode >%S< as value(0/1)"),
+ &token);
+ }
+ else
+ {
+ iLog->SetHtmlLogMode(isSrc);
+ }
+ }
+
+
+/**
+ *
+ * Implements the LOAD_SUITE script command.
+ * This function loads a required test suite DLL
+ * It also creates a CTestSuite object as a record
+ * of the loaded DLL.
+ *
+ * @param "const TDesC& aText"
+ * The script line
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::LoadSuiteL(const TDesC& aText)
+ {
+ // use Tlex to decode the cmd line
+ TLex lex(aText);
+
+ // step over the keyword
+ lex.NextToken();
+
+ // get suite name
+ TPtrC token;
+ token.Set(lex.NextToken());
+
+ // check not already loaded
+ // by searching the list of loaded test suite DLLs for the required one
+ // start with the number of suites loaded
+ TInt noOfDlls = iArrayLoadedSuiteDll->Count();
+ for (TInt i = 0; i < noOfDlls; i++)
+ {
+ CSuiteDll* ptrSuite = iArrayLoadedSuiteDll->At(i);
+ TPtrC name = ptrSuite->Name();
+
+ // check the names
+ if (name.FindF(token) != KErrNotFound)
+ {
+ // this suite DLL is already loaded
+ WARN_PRINTF2(_L("Warning: Test suite %S already loaded - not re-loaded"), &token);
+ return;
+ }
+ }
+
+
+ // create a new CSuiteDll object to store info on loaded DLL
+ CSuiteDll* newRef = NULL;
+
+ newRef = CSuiteDll::NewL(token, iLog);
+
+ CTestSuite* testSuite = newRef->Suite();
+
+ // set default severity and logging system
+ testSuite->SetSeverity(iSeverity);
+ testSuite->SetLogSystem(iLog);
+
+ // add to data
+ iArrayLoadedSuiteDll->AppendL(newRef);
+ }
+
+
+/**
+ *
+ * Unload all the loaded DLLs
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::Unload()
+ {
+ if (iArrayLoadedSuiteDll)
+ {
+ // unload all the loaded DLLS and their records
+ iArrayLoadedSuiteDll->ResetAndDestroy();
+ }
+ }
+
+/**
+ *
+ * Mark the heap
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::HeapMark()
+ {
+ ERR_PRINTF1(_L("Warning: Command HEAP_MARK no longer supported. Heap marking/checking should be done within test code"));
+
+ // __UHEAP_MARK;
+ }
+
+
+/**
+ *
+ * Check the heap
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::HeapCheck()
+ {
+ ERR_PRINTF1(_L("Warning: Command HEAP_CHECK no longer supported. Heap marking/checking should be done within test code"));
+
+ // __UHEAP_MARKEND;
+ }
+
+/**
+ *
+ * Mark request
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RequestMark()
+ {
+ // get number of outstanding requetsts on thread before we run the test
+ iReqsAtStart = RThread().RequestCount();
+ INFO_PRINTF2(_L("Requests at the start %d "),iReqsAtStart);
+ }
+
+
+/**
+ *
+ * Check request
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::RequestCheck()
+ {
+ // check the number of outstanding requests against recorded value
+ INFO_PRINTF3(_L("Requests at the start %d now %d"),
+ iReqsAtStart, RThread().RequestCount());
+
+ if (iReqsAtStart != RThread().RequestCount())
+ {
+ ERR_PRINTF1(_L("Test failed on requests count"));
+
+ // this result is only significant if every thing else has passed
+ if (iTestVerdict == EPass)
+ iTestVerdict = EFail;
+
+ }
+ }
+
+
+/**
+ *
+ * Mark number of handles
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::HandlesMark()
+ {
+ // get number of Handles *before* we start the program
+ RThread().HandleCount(iProcessHandleCountBefore, iThreadHandleCountBefore);
+
+ INFO_PRINTF3(_L("HandlesMark : process handle count %d thread handle count %d"),
+ iProcessHandleCountBefore,
+ iThreadHandleCountBefore);
+ }
+
+/**
+ *
+ * Check number of handles
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::HandlesCheck()
+ {
+ TInt processHandleCountAfter;
+ TInt threadHandleCountAfter;
+ RThread().HandleCount(processHandleCountAfter, threadHandleCountAfter);
+
+ INFO_PRINTF3(_L("HandlesCheck : process handle count %d thread handle count %d"),
+ processHandleCountAfter,
+ threadHandleCountAfter);
+
+ // check that we are closing all the threads
+ if(iThreadHandleCountBefore != threadHandleCountAfter)
+ {
+ ERR_PRINTF1(_L("Test failed on thread handle count"));
+
+ // this result is only significant if everything else has passed
+ if (iTestVerdict == EPass)
+ iTestVerdict = EFail;
+ }
+
+ // check that we are closing all the handles
+ if(iProcessHandleCountBefore != processHandleCountAfter)
+ {
+ ERR_PRINTF1(_L("Test failed on process handle count"));
+
+ // this result is only significant if everything else has passed
+ if (iTestVerdict == EPass)
+ iTestVerdict = EFail;
+ }
+ }
+
+/**
+ *
+ * Traceable logging function for parseline.
+ * To be called only with macros
+ *
+ * @param "const TText8* aFile"
+ * Source code file name
+ *
+ * @param "TInt aLine"
+ * Source code line
+ *
+ * @param "TInt aSeverity"
+ * Severity level required to log
+ *
+ * @param "TRefByValue<const TDesC16> aFmt"
+ * Printf-style format.
+ *
+ * @param "..."
+ * Variable print parameters
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::LogExtra(const TText8* aFile, TInt aLine, TInt aSeverity,
+ TRefByValue<const TDesC16> aFmt,...)
+ {
+ VA_LIST aList;
+ VA_START(aList, aFmt);
+
+ if(LogSeverity::IsActive(aSeverity, iSeverity))
+ {
+ if(iLog)
+ {
+ iLog->LogExtra(aFile, aLine, aSeverity, aFmt, aList);
+ }
+ }
+
+ VA_END(aList);
+ }
+
+/**
+ *
+ * Get current suite name.
+ *
+ * @return "TPtrC"
+ * The suite name
+ *
+ * @xxxx
+ *
+ */
+TPtrC CParseLine::CurrentSuiteName() const
+ {
+ return iCurrentSuiteName;
+ }
+
+/**
+ *
+ * Get current step name.
+ *
+ * @return "TPtrC"
+ * The step name
+ *
+ * @xxxx
+ *
+ */
+TPtrC CParseLine::CurrentStepName() const
+ {
+ return iCurrentStepName;
+ }
+
+/**
+ *
+ * Create a thread with a unique name from a base thread name
+ * e.g. "TestThread" may become "TestThread00000002"
+ * This test will leave instantly if an error other than
+ * KErrAlreadyExists occurs.
+ *
+ *
+ * @param "TDesC& aBaseName"
+ * The base name to use. This will be modified to contain
+ * the new unique thread name if creation is successful.
+ *
+ * @param "TDes& aThreadName"
+ * The thread name to use. This will be modified to contain
+ * the new unique thread name if creation is successful. This must
+ * be non NULL.
+ *
+ * @param "RThread&"
+ * An RThread which will be created. This must not be a valid handle.
+ *
+ * @param "TThreadFunction aFunction"
+ * Thread function to use in RThread.
+ *
+ * @param "TInt aStackSize"
+ * The size of the new thread's stack.
+ *
+ * @param "TInt aHeapMinSize"
+ * The minimum size for the new thread's heap.
+ *
+ * @param "TInt aHeapMaxSize"
+ * The maximum size for the new thread's heap.
+ *
+ * @param "TAny *aPtr"
+ * Data to pass to the new thread.
+ *
+ * @leave "function will leave with an error code if a thread cannot
+ * be created after KMaxThreadAttempts tries."
+ *
+ * @xxxx
+ *
+ */
+void CParseLine::CreateUniqueTestThreadL(const TDesC& aBaseName, TDes& aThreadName, RThread& aTestThread, TThreadFunction aFunction, TInt aStackSize, TInt aHeapMinSize, TInt aHeapMaxSize, TAny *aPtr)
+ {
+ TInt res = KErrAlreadyExists;
+
+ // attempt to create a thread with the name aBaseName + counter.
+ for (TUint i = 0; i < KMaxThreadAttempts; i++)
+ {
+ // copy the base thread name
+ aThreadName.Copy(aBaseName);
+
+ // append the current counter to the threadname
+ aThreadName.AppendNumFixedWidth(i, EDecimal, 8);
+
+ // run in a new thread, with a new heap
+ res = aTestThread.Create(aThreadName,
+ aFunction,
+ aStackSize,
+ aHeapMinSize,
+ aHeapMaxSize,
+ aPtr);
+
+ // if thread created successfully then we have
+ // a unique threadname else if an error code other
+ // than KErrAlreadyExists occurs then exit immediately.
+ if ((res == KErrNone) || (res != KErrAlreadyExists))
+ break;
+ }
+
+ User::LeaveIfError(res);
+ }
+
+/**
+ *
+ * Static constructor for CSuiteDll.
+ *
+ *
+ * @return "CSuiteDll*"
+ * The constructed CSuiteDll
+ *
+ * @xxxx
+ *
+ */
+CSuiteDll* CSuiteDll::NewL(const TDesC& aName, CLog* aLog)
+ {
+ CSuiteDll* self = new(ELeave) CSuiteDll;
+ CleanupStack::PushL(self);
+ self->ConstructL(aName, aLog);
+ CleanupStack::Pop();
+ return self;
+ }
+
+/**
+ *
+ * CSuiteDLL second-phase constructor
+ * Loads a test suite dll and saves the name and test
+ * suite pointers.
+ *
+ * @param "TDesC& aName"
+ * The test suite name
+ *
+ * @param "CLog* aLog"
+ * The logger to use
+ *
+ * @xxxx
+ *
+ */
+void CSuiteDll::ConstructL(const TDesC& aName, CLog* aLog)
+ {
+ iLog = aLog;
+
+ User::Check();
+ // load DLL by name
+ TInt ret = iLibrary.Load(aName, KTxtDLLpath);
+
+ User::Check();
+
+ if (ret == KErrNotFound)
+ {
+ iLog->LogExtra(__FILE8__, __LINE__, ESevrErr, _L("Test suite %S was not found. Check any other DLLs required by %S"), &aName, &aName);
+ User::Leave(ret);
+ }
+ else if (ret != KErrNone)
+ {
+ iLog->LogExtra(__FILE8__, __LINE__, ESevrErr, _L("Test suite %S found but would not load. Check any other DLLs required by %S"), &aName, &aName);
+ User::Leave(ret);
+ }
+
+ // save the name
+ iName.Copy(aName);
+
+ // get the interface pointer at ordinal 1
+ const TInt KLibraryOrdinal = 1;
+ TLibraryFunction entryL = iLibrary.Lookup(KLibraryOrdinal);
+
+ // Call this interface pointer to create new CTestSuite
+ // If this call goes to the wrong function then the test
+ // suite does not have the correct function at ordinal 1.
+ // This is usually caused by an error in the def file.
+ iTestSuite = REINTERPRET_CAST(CTestSuite*, entryL());
+
+ // NB :- Second-phase constructor for CTestSuite has already been called in entryL() above.
+ // There is no need to call it again!
+
+ // set suite severity level
+ iTestSuite->SetSeverity(iLog->Severity());
+
+ // get the version information
+ TPtrC versiontxt = iTestSuite->GetVersion();
+
+ // add to log
+ iLog->LogExtra(__FILE8__, __LINE__, ESevrInfo, _L("LOAD_SUITE %S version %S loaded ok"),&aName, &versiontxt );
+ }
+
+/**
+ *
+ * CSuiteDLL destructor
+ *
+ * @xxxx
+ *
+ */
+CSuiteDll::~CSuiteDll()
+ {
+ // delete the TestSuiteObject in the loaded DLL
+ delete iTestSuite;
+
+ // close and unload the library
+ iLibrary.Close();
+ }
+
+/**
+ *
+ * CSuiteDLL accessor : suite
+ *
+ * @return "CTestSuite*"
+ * The test suite.
+ *
+ * @xxxx
+ *
+ */
+CTestSuite* CSuiteDll::Suite() const
+ {
+ return iTestSuite;
+ }
+
+/**
+ *
+ * CSuiteDLL accessor : suite name
+ *
+ * @return "TPtrC"
+ * The suite name.
+ *
+ * @xxxx
+ *
+ */
+TPtrC CSuiteDll::Name() const
+ {
+ return iName;
+ }
+
+/**
+ *
+ * CStepData
+ *
+ * @xxxx
+ *
+ */
+CStepData* CStepData::NewL(const TDesC& aStep, const TDesC& aConfig, CSuiteDll* aSuite)
+ {
+ return NewL(aStep, aConfig, KNullDesC, aSuite);
+ }
+
+CStepData* CStepData::NewL(const TDesC& aStep, const TDesC& aConfig, const TDesC& aParamSet, CSuiteDll* aSuite)
+ {
+ CStepData* self = new(ELeave) CStepData;
+ CleanupStack::PushL(self);
+ self->ConstructL(aStep, aConfig, aParamSet, aSuite);
+ CleanupStack::Pop();
+ return self;
+ }
+
+CStepData::CStepData()
+ {
+ }
+
+CStepData::~CStepData()
+ {
+ }
+
+void CStepData::ConstructL(const TDesC& aStep, const TDesC& aConfig, const TDesC& aParamSet, CSuiteDll* aSuite)
+ {
+ iStep = aStep;
+ iConfig = aConfig;
+ iParamSet = aParamSet;
+ iSuite = aSuite;
+ }
+
+const TDesC& CStepData::ParamSet() const
+ {
+ return iParamSet;
+ }
+
+