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