networkingtestandutils/networkingintegrationtest/scheduleTest/parseline.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkingtestandutils/networkingintegrationtest/scheduleTest/parseline.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1562 @@
+// Copyright (c) 2003-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.
+// 
+//
+
+/**
+ @file parseLine.cpp
+*/
+
+// system includes
+#include <e32base.h>
+#include <e32cons.h>
+#include "f32file.h"
+
+// test system includes
+#include "../inc/Log.h"
+#include "../inc/TestUtils.h"
+#include "../inc/TestStep.h"
+#include "../inc/TestSuite.h"
+#include "script.h"
+#include "parseline.h"
+
+/** 
+DLL fullpath 
+@internalComponent
+*/
+_LIT(KTxtDLLpath,"c:\\;c:\\system\\libs\\;d:\\;d:\\system\\libs\\");
+
+#ifdef __WINS__
+/** 
+Holds ced_exe DLL string constant 
+@internalComponent
+*/
+_LIT(KTxtcedDLL,"ced_exe.dll");
+#endif
+
+/** 
+Thread name format 
+@internalComponent
+*/
+_LIT(KThreadNameFmt, "DoTestThread_%d");
+
+/** 
+Maximum test thread heap size 
+@internalComponent
+*/
+const TInt KMaxTestThreadHeapSize = 0x10000;
+
+/**
+extern global data - pointer to test utils
+@internalComponent
+*/
+GLDEF_D	CTestUtils *		pTestUtils;
+
+/**
+extern global data - pointer to Log system
+@internalComponent
+*/
+GLDEF_D CLog *				pLogSystem;
+
+/**
+extern global data - running in automated, non-interactive, stop-for-nothing mode
+@internalComponent
+*/
+GLDEF_D TBool				automatedMode = EFalse;
+
+/**
+extern global data - pointer to console
+@internalComponent
+*/
+GLDEF_D CConsoleBase *		console;
+
+
+CParseLine::CParseLine():iTestVerdict(EPass)
+/**
+constructor
+*/
+	{}
+void CParseLine::ConstructL(CScript * ptr)
+/**
+create a new Array to store the test steps in
+*/
+	{
+	// create a new Array to store the test steps in
+	iArrayLoadedSuiteDll = new(ELeave) CArrayPtrFlat<CSuiteDll>(1);
+	
+	iScript = ptr;
+	iSeverity = ESevrAll;
+	iBreakOnError = EFalse;
+	iThreadNameSuffix = User::TickCount();
+	}
+
+CParseLine* CParseLine::NewL( CScript * ptr)
+/**
+NewL static constructor
+*/
+	{
+	CParseLine * self = new(ELeave) CParseLine;
+	CleanupStack::PushL(self);
+	self->ConstructL(ptr);
+	CleanupStack::Pop();
+	return self;
+	}
+
+CParseLine::~CParseLine()
+/**
+Delete all objects in iArrayLoadedSuiteDll.
+This will unload any loaded test suite DLLS.
+*/
+	{
+	
+	// unload DLLs and their records
+	if (iArrayLoadedSuiteDll)
+		{
+		// delete all objects in iArrayLoadedSuiteDll
+		// the destructors will unload any loaded DLLS
+		iArrayLoadedSuiteDll->ResetAndDestroy();
+		delete iArrayLoadedSuiteDll;
+		}
+	
+	}
+
+void CParseLine::ProcessLineL(const TPtrC8 &aNrrowline, TInt8 lineNo)
+/**
+Process a line from the script file
+
+@param aNrrowline The line to be parsed
+@param lineNo The current line number
+*/
+	{
+	// make a local unicode buffer
+	TBuf<MAX_SCRIPT_LINE_LENGTH> LineBuf;
+	//If the lenght of the command line is more than MAX_SCRIPT_LINE_LENGTH=200
+	//Igore the line with Warning and the test result would be Inconclusive	
+	if (aNrrowline.Length() > LineBuf.MaxLength())
+	{
+		TLex8 lex(aNrrowline);
+		// start at the begining
+		TPtrC8 token=lex.NextToken();
+		TInt firstChar = aNrrowline[0];
+		if(firstChar == '\r' || firstChar == '\n' || firstChar == '#' || firstChar == '/' || token.CompareF((TPtrC8((const TText8 *)("PRINT")))) == 0 || token.CompareF((TPtrC8((const TText8 *)("PAUSE_AT_END")))) == 0 || token.CompareF((TPtrC8((const TText8 *)("PAUSE")))) == 0)
+		{
+			// ignore command line	with comments	
+		}
+		else
+		{
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("WARNING : Command line too Long (Exceeds length of 200)  Line:%d"), lineNo);
+			iTestVerdict = EInconclusive;
+		}
+		
+		return;
+	}
+
+	LineBuf.Fill( '\0',MAX_SCRIPT_LINE_LENGTH);
+	
+	// convert the narrow script file to Unicode
+	TFileName testnameU;
+	testnameU.Copy(aNrrowline);
+	
+	// find the end of the line
+	TInt end= testnameU.Locate('\n');
+	
+	// copy the line into LineBuf
+	if ((end != -1) && (end < MAX_SCRIPT_LINE_LENGTH))
+		LineBuf = testnameU.Left(end-1);
+	else
+		LineBuf = testnameU;
+	
+	// the parser relies on spaces between tokens. Commas are
+	// allowed but are just replaced with spaces
+	while ( LineBuf.Locate(TChar(',')) != KErrNotFound )
+		{
+		// found a comma so replave with space
+		LineBuf.Replace(LineBuf.Locate(TChar(',')),1,_L(" "));
+		}
+	
+	// for debugging display the line with a line no
+#ifdef SCRIPT_DEBUG
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Line:%d %s "), lineNo, LineBuf.Ptr()  );
+#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.Find(_L("TEST_COMPLETE"))==0)
+			{
+			TestComplete( LineBuf );
+			
+			// reset flag now test complete found
+			iBreakOnError = EFalse;
+			}
+		
+		// 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
+		{
+		// use Tlex to decode the cmd
+		TLex lex(LineBuf);
+		// start at the begining
+		TPtrC token=lex.NextToken();
+		
+		if (token.CompareF(_L("LOAD_SUITE"))==0)
+			{
+			LoadSuiteL( LineBuf );
+			}
+		else if (token.CompareF(_L("RUN_SCRIPT"))==0)
+			{
+			RunScriptL( LineBuf );
+			}
+		else if (token.CompareF(_L("RUN_TEST_STEP"))==0)
+			{
+			RunTestStep( LineBuf );
+			}
+		else if (token.CompareF(_L("RUN_PANIC_STEP"))==0)
+			{
+			RunPanicTestStep( LineBuf );
+			}
+		else if (token.CompareF(_L("RUN_UTILS"))==0)
+			{
+			RunUtil( LineBuf );
+			}
+		else if (token.CompareF(_L("CED"))==0)
+			{
+			RunCed( LineBuf );
+			}
+		else if (token.CompareF(_L("RUN_PROGRAM"))==0)
+			{
+			RunProgram( LineBuf );
+			}
+		else if (token.CompareF(_L("UNLOAD"))==0)
+			{
+			Unload(LineBuf);
+			}
+		else if (token.CompareF(_L("HEAP_MARK"))==0)
+			{
+			HeapMark();
+			}
+		else if (token.CompareF(_L("HEAP_MARKEND"))==0)
+			{
+			HeapCheck();
+			}
+		else if (token.CompareF(_L("REQUEST_MARK"))==0)
+			{
+			RequestMark();
+			}
+		else if (token.CompareF(_L("REQUEST_CHECK"))==0)
+			{
+			RequestCheck();
+			}
+		else if (token.CompareF(_L("HANDLES_MARK"))==0)
+			{
+			HandlesMark();
+			}
+		else if (token.CompareF(_L("HANDLES_CHECK"))==0)
+			{
+			HandlesCheck();
+			}
+		else if (token.CompareF(_L("PRINT"))==0)
+			{
+			scriptPrint( LineBuf );
+			}
+		else if (token.CompareF(_L("DELAY"))==0)
+			{
+			Delay( LineBuf );
+			}
+		else if (token.CompareF(_L("SEVERITY"))==0)
+			{
+			SetSeverity( LineBuf );
+			}
+		else if (token.CompareF(_L("PAUSE_AT_END"))==0)
+			{
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Pause at end enabled "));
+			iScript->iPauseAtEnd = ETrue;
+			}
+		else if (token.CompareF(_L("MULTITHREAD"))==0)
+			{
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Multithread operation enabled "));
+			iScript->iMultThread = ETrue;
+			}
+		else if (token.CompareF(_L("SINGLETHREAD"))==0)
+			{
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Single thread operation enabled "));
+			iScript->iMultThread = EFalse;
+			}
+		else if (token.CompareF(_L("PAUSE"))==0)
+			{
+			iScript->Pause();
+			}
+		else if (token.CompareF(_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 (token.CompareF(_L("TEST_COMPLETE"))==0)
+			{
+			// use Tlex to decode the cmd line
+			TestComplete( LineBuf );
+			}
+		else if (token.CompareF(_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
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Error in script line:%d - %s "), lineNo, LineBuf.Ptr()  );
+			}
+		}
+	
+}
+
+void CParseLine::TestComplete( const TDesC& Text )
+/**
+This function implements the script test complete keyword
+
+@param The contents of Text are added to the log file with the result
+*/
+	{
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+	// step over the keyword
+	token.Set(lex.NextToken());
+	
+	if (token.Length() !=0 )
+		iCurrentStepName = token;
+	
+	// Test cases must be careful to clean up after themselves - any stray signals generated in a test case 
+	// lead here to automatic failure of the step. They are caught here to allow further cases to run 
+	// without crashing.
+	while (RThread().RequestCount()!=0)
+	{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Warning! Test case generated stray signal! (cleaning up)") );
+		User::WaitForAnyRequest();
+		iTestVerdict = EFail;
+	}
+
+	// add the current result to the script
+	iScript->AddResult( iTestVerdict );
+	
+	// reset for next test
+	iTestVerdict = EPass;
+	}
+
+void CParseLine::scriptPrint(  const TDesC& Text )
+/**
+This function implements the script PRINT Keyword
+
+@param Text The text to be added to the log file 
+*/
+	{
+	// display the text after the PRINT and 1 space = 6
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("%s "), (Text.Ptr()+6) );
+	}
+
+void CParseLine::Delay(  const TDesC& Text )
+/**
+This function implements the script Delay Keyword
+
+@param Text contains the time to delay in milliseconds
+*/
+	{
+	// if the test has already failed skip the delay
+	if ( iTestVerdict != EPass )
+		{
+		pLogSystem->Log(_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(Text);
+	TimeOut.NextToken();
+	TPtrC token=TimeOut.NextToken();
+	
+	// convert the value into a int
+	TLex timeoutLex(token);
+	TInt GuardTimerValue =2500;
+	if (timeoutLex.Val(GuardTimerValue) != KErrNone  )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr,
+			_L("error in guard timer value could not decode >%S< as value"),
+			&token,
+			GuardTimerValue );
+		return;
+		}
+	
+	// display the text after the PRINT and 1 space = 6
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr,
+		_L("Delay for %d mS"), GuardTimerValue );
+	
+	// wait for the required delay
+	RTimer GuardTimer;
+	GuardTimer.CreateLocal();			// create for this thread
+	TRequestStatus TimerStatus;
+	GuardTimer.After(TimerStatus,GuardTimerValue * 1000);
+	User::WaitForRequest(TimerStatus);
+	GuardTimer.Cancel();
+	
+	}
+
+void CParseLine::SetSeverity(  const TDesC& Text )
+/**
+This function implements the script SetSeverity Keyword
+
+@param Text contains the severity level
+*/
+	{
+	// get the required time for the delay
+	// first get the value as a string
+	TLex SeverityOut(Text);
+	SeverityOut.NextToken();
+	TPtrC token=SeverityOut.NextToken();
+	
+	// convert the value into a int
+	TLex Severity(token);
+	TInt SeverityValue = 7;
+	if (Severity.Val(SeverityValue) != KErrNone  )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr,
+			_L("Error in severity level value could not decode >%S< as value"),
+			&token,
+			SeverityValue );
+		return;
+		}
+	
+	if(SeverityValue & ~7)
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__,
+			ESevrErr, _L("Error in severity value."));
+		SeverityValue = 7;
+		return;
+		}
+	else
+		{
+		iSeverity = SeverityValue;
+		
+		TInt NoOfDlls = iArrayLoadedSuiteDll->Count();
+		for ( TInt i=0; i < NoOfDlls; i++ )
+			{
+			CSuiteDll * ptrSuite = iArrayLoadedSuiteDll->At(i);
+			ptrSuite->iTestSuite->SetSeverity(iSeverity);
+			}
+		}
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Severity is set to %d"), SeverityValue );
+	}
+
+void CParseLine::RunScriptL( const TDesC& Text )
+/**
+This function implements the script RUN_SCRIPT Keyword
+
+@param Text contains the script file name
+*/
+	{
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+	// step over the keyword
+	token.Set(lex.NextToken());
+	
+	// format for printing
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("RUN_SCRIPT %S"),&token );
+	
+	// create a new Script object (but use the current parse
+	// as it has the dll loaded record
+	CScript* newScript=CScript::NewL(this);
+	CleanupStack::PushL(newScript);
+	
+	// read in the script file
+	TFileName scriptFileName=token;
+	if ( newScript->OpenScriptFile( scriptFileName ))
+		{
+		// process it
+		iTestVerdict = newScript->ExecuteScriptL();
+		
+		/* verdicts for scripts are not really useful so forget! */
+		/* pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("The final result for test script %S was %s"),
+		&token,
+		pLogSystem->TestResultText( iTestVerdict ) ); */
+		
+		// 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(newScript);
+	
+	}
+
+void CParseLine::RunTestStep( const TDesC& Text )
+/**
+RunTestStep
+
+@param Text contains the test step name
+@return KErrNone or an error code
+*/
+	{
+	TPtrC suite, step, config;
+	
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC timeout=lex.NextToken();
+	
+	// step over the keyword
+	timeout.Set(lex.NextToken());
+	
+	// get the other parameters
+	suite.Set(lex.NextToken());
+	step.Set(lex.NextToken());
+	config.Set(lex.NextToken());
+	
+	// save the name of the current test step
+	iCurrentStepName = step;
+	
+	// conert the guard timer value to a TInt
+	TLex lexTimeOut(timeout);
+	TInt GuardTimerValue;
+	if (lexTimeOut.Val(GuardTimerValue) != KErrNone  )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("error in guard timer value:%S using default 100mS"), &timeout);
+		GuardTimerValue = 100;
+		}
+	
+	// log the start of a test step
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("RUN_TEST_STEP:%S suite:%S timeout:%dmS config:%S"),
+		&step,
+		&suite,
+		GuardTimerValue,
+		&config );
+	
+	// run the test step
+	enum TVerdict CurrentTestVerdict;
+	
+	// check which thread mode selected!
+	if ( iScript->iMultThread )
+		CurrentTestVerdict = DoTestNewThread( suite, step, GuardTimerValue, config );
+	else
+		CurrentTestVerdict = DoTestCurrentThread( suite, step, config );
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("TEST_STEP:%S returned:%s "), &step, pLogSystem->TestResultText(CurrentTestVerdict));
+	
+	// this result is only significant if every thing else has passed
+	if ( iTestVerdict == EPass )
+		iTestVerdict = CurrentTestVerdict;
+	
+	}
+
+void CParseLine::RunPanicTestStep( const TDesC& Text )
+/**
+This function implements the script RUN_PANIC_STEP Keyword.  
+This step is expected to panic and gives a pass result if it panics
+and a fail if it does not.
+
+@param Text contains the test step name
+*/
+	{
+	TPtrC suite, step, config;
+	
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC timeout=lex.NextToken();
+	
+	// step over the keyword
+	timeout.Set(lex.NextToken());
+	
+	// get the other parameters
+	suite.Set(lex.NextToken());
+	step.Set(lex.NextToken());
+	config.Set(lex.NextToken());
+	
+	// save the name of the current test step
+	iCurrentStepName = step;
+	
+	// conert the guard timer value to a TInt
+	TLex lexTimeOut(timeout);
+	TInt GuardTimerValue;
+	if (lexTimeOut.Val(GuardTimerValue) != KErrNone  )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("error in guard timer value:%S using default 10000"), &timeout);
+		GuardTimerValue = 1000000;
+		}
+	
+	// log the start of a test step
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("RUN_PANIC_STEP:%S suite:%S timeout:%dmS config:%S"),
+		&step,
+		&suite,
+		GuardTimerValue,
+		&config );
+	
+	// run the test step
+	enum TVerdict CurrentTestVerdict;
+	
+	// check which thread mode selected!
+	CurrentTestVerdict = DoPanicTest( suite, step, GuardTimerValue, config );
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("TEST_STEP:%S returned:%s "), &step, pLogSystem->TestResultText(CurrentTestVerdict));
+	
+	// this result is only significant if every thing else has passed
+	if ( iTestVerdict == EPass )
+		iTestVerdict = CurrentTestVerdict;
+	
+	}
+
+
+void CParseLine::RunUtil( const TDesC& Text )
+/**
+This function implements the script RUN_UTILS Keyword
+
+@param Text contains the util name
+*/
+	{
+	// Call the utils
+	pTestUtils->RunUtils( Text );
+	}
+
+void CParseLine::Reboot(void)
+/**
+This function implements the script REBOOT Keyword
+*/
+	{
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("REBOOT ") );
+	}
+
+TInt CParseLine::threadfn ( TAny * ptr )
+/**
+Static function to call DoTestStep() which is run
+in a separate thread
+
+@param ptr Contains the test step name, and configuration parameters passed to the new thread. 
+@return The test result as a TVerdict.
+*/
+	{
+	// get clean-up stack
+	CTrapCleanup* Cleanup=CTrapCleanup::New();
+	
+	// get the data for the test
+	CStepData * data = (CStepData *)ptr;
+	
+	// do the test step
+	TVerdict result =  data->iSuite->iTestSuite->DoTestStep( data->step, data->config);
+	
+	// done with the clean up stack
+	delete Cleanup;
+	
+	// return the test result
+	return result;
+	}
+
+enum TVerdict CParseLine::DoTestNewThread(TPtrC suite, TPtrC step, TInt GuardTimerValue, const TPtrC &config)
+/**
+Call the test step in the correct suite
+
+@param suite The test suite to use.
+@param step The test step name
+@param the guard timer in milliseconds
+@param reference to the configuration file
+@return The test result as a TVerdict
+*/
+	{
+	//	get the number of suites loaded
+	TInt NoOfDlls = iArrayLoadedSuiteDll->Count();
+	
+	TVerdict result = ETestSuiteError;
+	
+	// search the list of loaded test suite DLLs for the required one
+	for ( TInt i=0; i < NoOfDlls; i++ )
+		{
+		CSuiteDll * ptrSuite = iArrayLoadedSuiteDll->At(i);
+		
+		if(ptrSuite->SuiteNameMatch(suite))
+			{
+			
+			// do a test in a new thread
+			RThread NewThread;
+			
+			CStepData data;
+			data.step = step;
+			data.config = config;
+			data.iSuite = ptrSuite;
+			
+			// run in a new thread, with a new heap
+			TBuf<32> threadName;
+			threadName.Format(KThreadNameFmt, iThreadNameSuffix++);
+			TInt res=NewThread.Create(threadName,
+				threadfn,
+				KDefaultStackSize,
+				KMinHeapSize,
+				KMaxTestThreadHeapSize,
+				&data);
+			
+			if (res != KErrNone)
+				{
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("unable to create test thread ") );
+				return EFail;
+				}
+			
+			// start the thread and request the status
+			TRequestStatus ThreadStatus;
+			NewThread.Logon(ThreadStatus);
+			
+			// if the guard timer value is -1 don't time at all
+			if ( GuardTimerValue == -1 )
+				{
+				// 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();
+				GuardTimer.After(TimerStatus,GuardTimerValue * 1000);
+				User::WaitForRequest(ThreadStatus, TimerStatus);
+				if (TimerStatus==KRequestPending)
+					{
+					GuardTimer.Cancel();
+					User::WaitForRequest(TimerStatus);
+					}
+				GuardTimer.Close();
+				}
+			
+			// get the test result
+			result =  (TVerdict)ThreadStatus.Int();
+			
+			// check terminated ok
+			switch(NewThread.ExitType() )
+				{
+				case EExitTerminate:
+				case EExitKill:
+					break;
+				case EExitPanic:
+					pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("thread had a panic") );
+					result = EFail;
+					break;
+				case EExitPending:
+					// if the thread is still pending then the guard timer must have expired
+					pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("thread timed out") );
+					// kill the test step thread
+					NewThread.Kill(1);
+					User::WaitForRequest(ThreadStatus);
+					result = EFail;
+					break;
+				default:
+					break;
+				}
+			
+			// done with the test thread
+			NewThread.Close();
+			
+			// send the log data a line at a time
+			// find the end of the first line
+			TInt nl= ptrSuite->iTestSuite->iLogData.Locate(TChar('\n'));
+			
+			// get each  line in turn
+			while ( nl != KErrNotFound )
+				{
+				// display line
+				TPtrC16 line = ptrSuite->iTestSuite->iLogData.Left(nl);
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("%S"), &line );
+				
+				// remove the line displayed
+				ptrSuite->iTestSuite->iLogData.Replace(0,nl+1,_L(""));
+				
+				// find the next newline
+				nl= ptrSuite->iTestSuite->iLogData.Locate(TChar('\n'));
+				}
+			
+			// return the test verdict
+			return result;
+			}
+		}
+		
+		// the required suite has not been found
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Error in test step:%S cannot find suite:%S" ),
+			&step,
+			&suite );
+		
+		return ETestSuiteError;
+}
+
+// DoTest
+enum TVerdict CParseLine::DoPanicTest(TPtrC suite, TPtrC step, TInt GuardTimerValue, const TPtrC &config)
+/**
+Call the test step which is expected to Panic
+
+@param suite The test suite to use.
+@param step The test step name
+@param the guard timer in milliseconds
+@param reference to the configuration file
+@return The test result as a TVerdict
+*/
+	{
+	//	get the number of suites loaded
+	TInt NoOfDlls = iArrayLoadedSuiteDll->Count();
+	
+	TVerdict result;
+	
+	// search the list of loaded test suite DLLs for the required one
+	for ( TInt i=0; i < NoOfDlls; i++ )
+		{
+		CSuiteDll * ptrSuite = iArrayLoadedSuiteDll->At(i);
+		
+		if(ptrSuite->SuiteNameMatch(suite))
+			{
+			
+			// do a test in a new thread
+			RThread t;
+			
+			CStepData data;
+			data.step = step;
+			data.config = config;
+			data.iSuite = ptrSuite;
+			
+			// run in a new thread, with a new heap
+			TBuf<32> threadName;
+			threadName.Format(KThreadNameFmt, iThreadNameSuffix++);
+			TInt res=t.Create(threadName,
+				threadfn,
+				KDefaultStackSize,
+				KMinHeapSize,
+				KMaxTestThreadHeapSize,
+				&data);
+			
+			if (res != KErrNone)
+				{
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("unable tp create test thread ") );
+				return EFail;
+				}
+			
+			// start the thread and request the status
+			TRequestStatus ThreadStatus;
+			t.Logon(ThreadStatus);
+			
+			// if the guard timer value is -1 don't time at all
+			if ( GuardTimerValue == -1 )
+				{
+				// no guard timer
+				t.Resume();
+				User::WaitForRequest( ThreadStatus );
+				}
+			else
+				{
+				// wait for either test thread or timer to end
+				RTimer GuardTimer;
+				GuardTimer.CreateLocal();			// create for this thread
+				TRequestStatus TimerStatus;
+				t.Resume();
+				GuardTimer.After(TimerStatus,GuardTimerValue * 1000);
+				User::WaitForRequest(ThreadStatus, TimerStatus);
+				GuardTimer.Cancel();
+				User::WaitForAnyRequest();
+				}
+			
+			// get the test result
+			result =  (TVerdict)ThreadStatus.Int();
+			
+			TExitCategoryName category(t.ExitCategory());
+			// check terminated ok
+			switch(t.ExitType() )
+				{
+				case EExitPanic:
+					pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Panic occurred of category %S and reason %d"), &category, t.ExitReason());
+					result =
+						category.Left(4)==_L("KERN") || category.Left(3)==_L("E32") ? EFail : EPass;
+					break;
+				case EExitPending:
+					// if the thread is still pending then the guard timer must have expired
+					pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("thread timed out") );
+					// kill the test step thread
+					t.Kill(1);
+					result = EFail;
+					break;
+				case EExitTerminate:
+				case EExitKill:
+				default:
+					pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Test did not panic so fail") );
+					result = EFail;
+					break;
+				}
+			
+			// done with the test thread
+			t.Close();
+			
+			// send the log data a line at a time
+			// find the end of the first line
+			TInt nl= ptrSuite->iTestSuite->iLogData.Locate(TChar('\n'));
+			
+			// get each  line in turn
+			while ( nl != KErrNotFound )
+				{
+				// display line
+				TPtrC16 line = ptrSuite->iTestSuite->iLogData.Left(nl);
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("%S"), &line );
+				
+				// remove the line displayed
+				ptrSuite->iTestSuite->iLogData.Replace(0,nl+1,_L(""));
+				
+				// find the next newline
+				nl= ptrSuite->iTestSuite->iLogData.Locate(TChar('\n'));
+				}
+			
+			// return the test verdict
+			return result;
+			}
+		}
+		
+		// the required suite has not been found
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Error in test step:%S cannot find suite:%S" ),
+			&step,
+			&suite );
+		
+		return ETestSuiteError;
+}
+
+// DoTestCurrentThread
+enum TVerdict CParseLine::DoTestCurrentThread(TPtrC suite, TPtrC step, TPtrC config)
+/**
+Call the test step in the current Thread
+
+@param suite The test suite to use.
+@param step The test step name
+@param reference to the configuration file
+@return The test result as a TVerdict
+*/
+	{
+	//	get the number of suites loaded
+	TInt NoOfDlls = iArrayLoadedSuiteDll->Count();
+	
+	TVerdict    result;
+
+	// search the list of loaded test suite DLLs for the required one
+	for ( TInt i=0; i < NoOfDlls; i++ )
+		{
+
+        CSuiteDll * ptrSuite = iArrayLoadedSuiteDll->At(i);
+
+        if(ptrSuite->SuiteNameMatch(suite))
+			{
+			//  execute in the current thread
+			result =  ptrSuite->iTestSuite->DoTestStep(step, config);
+			
+			// send the log data a line at a time
+			// find the end of the first line
+			TInt nl= ptrSuite->iTestSuite->iLogData.Locate(TChar('\n'));
+			
+			// get each  line in turn
+			while ( nl != KErrNotFound )
+				{
+				// display line
+				TPtrC16 line = ptrSuite->iTestSuite->iLogData.Left(nl);
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("%S"), &line );
+				
+				// remove the line displayed
+				ptrSuite->iTestSuite->iLogData.Replace(0,nl+1,_L(""));
+				
+				// find the next newline
+				nl= ptrSuite->iTestSuite->iLogData.Locate(TChar('\n'));
+				}
+			
+			// return the test verdict
+			return result;
+			}
+		}
+	
+	// the required suite has not been found
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Error in test step:%S cannot find suite:%S" ),
+		&step,
+		&suite );
+	
+	return ETestSuiteError;
+	}
+
+
+
+// RunCed
+void CParseLine::RunCed( const TDesC& Text )
+/**
+This function runs CED the commdb tool....
+
+@param text The name of tge ced.cfg file to use
+*/
+	{
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+	// step over the keyword "ced" and get the rest
+	token.Set(lex.Remainder());
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Run Ced parameters %S"), &token);
+	
+	// In the ARM and EKA2 emulator builds run ced as a new process
+	RProcess ced;
+	TBuf<100> CmdLine;
+	CmdLine.Format(_L("-i %S"),&token);
+	TInt ret = ced.Create( _L("z:\\system\\libs\\ced.exe"), CmdLine );
+	
+	if ( ret != KErrNone )
+		{
+		TPtrC Errortxt = CLog::EpocErrorToText(ret);
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Failed to start ced process %S"),&Errortxt );
+		return;
+		}
+	else
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("ced.exe started %S"), &CmdLine);
+		
+		// create and start a guard timer
+		RTimer GuardTimer;
+		TRequestStatus TimerStatus(KRequestPending);
+		GuardTimer.CreateLocal();			// create for this thread
+		GuardTimer.After(TimerStatus,120 * 1000 *1000);
+		
+		// start ced
+		TRequestStatus ThreadStatus;
+		ced.Logon(ThreadStatus);
+		ced.Resume();
+		
+		// wait for guard timer or ced
+		User::WaitForRequest(ThreadStatus, TimerStatus);
+		
+		// cancel the guard timer now a request has happened
+		GuardTimer.Cancel();
+		
+		if(ThreadStatus==KRequestPending)
+			{
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("<font size=5 color=FF0000>CED TIMED OUT</font>\n") );
+			}
+
+		User::WaitForAnyRequest();	//Need this to balance up the requests/completions
+		//as User::WaitForRequest(ThreadStatus, TimerStatus) only makes one request
+		
+		// check return type
+		TVerdict cedVerdict = EInconclusive;
+		TExitType cedExitType = ced.ExitType();
+		if ( cedExitType == EExitTerminate || cedExitType == EExitKill )
+			{
+			TInt exitReason = ced.ExitReason();
+			if(exitReason == 0)
+				{
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("ced exited with success") );
+				cedVerdict = EPass;
+				}
+			else
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("ced exited with failure %d"), exitReason );
+			}
+		else
+			{
+			// Describe what specifically happened
+			if ( cedExitType == EExitPanic)
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("ced exited with EExitPanic") );
+			else if ( cedExitType == EExitPending)
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("ced still running (!)") );
+			else
+				pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("ced exited with unknown type %d"), cedExitType );
+			}
+		// this result is only significant if every thing else has passed
+		if( iTestVerdict == EPass )
+			{
+			iTestVerdict = cedVerdict;
+			}
+		}
+	
+	
+	
+}
+
+void CParseLine::RunProgram( const TDesC& Text )
+/**
+This function implements the script RunProgram command
+
+@param Text The name of the program to run
+*/
+	{
+	TPtrC Param;
+	
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+	// step over the keyword
+	token.Set(lex.NextToken());
+	
+	// get the parameters
+	Param.Set(lex.NextToken());
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Run Program "));
+	
+#ifdef __WINS__
+	// this is not supportted in WINS builds
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Warning RUN_PROGRAM is not supported on WINS") );
+#endif
+	
+	// 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);
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Failed to start process %S"),&Errortxt );
+		return;
+		}
+	else
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Program started") );
+		
+		// start program
+		TRequestStatus ThreadStatus;
+		program.Logon(ThreadStatus);
+		program.Resume();
+		
+		// wait for guard timer or ced
+		User::WaitForRequest(ThreadStatus);
+		
+		// check return type
+		if ( program.ExitType() == EExitPanic)
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("program returned EExitPanic") );
+		else if ( program.ExitType() == EExitPending)
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("program returned EExitPending") );
+		else
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("program returned EExitTerminate") );
+		}
+	}
+
+void CParseLine::LogSettings(  const TDesC& Text )
+/**
+This function parses "LOG_SETTNGS" command
+Command format is LOG_SETTINGS "put src." (1/0),
+"HTML format" (1/0)
+
+@param string to parse
+*/
+	{
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+	// step over the keyword
+	//Get information about source
+	token.Set(lex.NextToken());
+	
+	TLex oSrcLex(token);
+	TInt isSrc = ETrue; //Shall we put src information?
+	if (oSrcLex.Val(isSrc) != KErrNone  )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr,
+			_L("Error in LOG_SETTINGS  value could not decode >%S< as value(0/1)"),
+			&token);
+		}
+	else
+		{
+		pLogSystem->SetPutSrcInfo(isSrc) ;
+		}
+	//Get information about format
+	//TInt isHtml = ETrue; //Shall we use HTML log format?
+	token.Set(lex.NextToken());
+	TLex oHtmlLex(token);
+	
+	if (oHtmlLex.Val(isSrc) != KErrNone  )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr,
+			_L("Error in LOG_SETTINGS  value could not decode >%S< as value(0/1)"),
+			&token);
+		}
+	else
+		{
+		pLogSystem->SetHtmlLogMode(isSrc) ;
+		}
+	}
+
+
+void CParseLine::LoadSuiteL( const TDesC& Text )
+/** 
+LoadSuite
+This function loads a required test suite DLL
+It also creates a CtestSuite object as a record
+of the loaded dll
+
+@param suite dll name
+*/
+	{
+	// use Tlex to decode the cmd line
+ 	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+	// step over the keyword
+	token.Set(lex.NextToken());
+	
+	
+    RLibrary lib;
+	TInt err = lib.Load(token, KTxtDLLpath);
+    if (err == KErrNone)
+        {
+        lib.Close();
+        }
+	
+	if ( err==KErrNotFound )
+		{
+		// this is not going to load !
+		// 		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Test suite %S could not be found"),&token );
+		//return;
+		}
+	
+	// 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);
+		
+		// check the names
+		if ( ptrSuite->iName.CompareF( token ) == 0 )
+			{
+			// this suite DDL is already loaded
+			pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("warning Test suite %S already loaded not re-loaded"),&token );
+			return;
+			}
+		}
+	
+	// create a new suitedll object to store info on loaded DLL
+	CSuiteDll * newRef = CSuiteDll::NewL( token );
+	CleanupStack::PushL(newRef);
+	
+	// set default severity and logging system
+	newRef->iTestSuite->SetSeverity(iSeverity);
+	newRef->iTestSuite->SetLogSystem(pLogSystem);
+	
+	// add to data
+	iArrayLoadedSuiteDll->AppendL( newRef );
+	CleanupStack::Pop(newRef);
+	}
+
+// unload all the loaded DLLS
+void CParseLine::Unload(const TDesC& Text)
+/**
+This function implements the script Unload command
+*/
+	{
+	// use Tlex to decode the cmd line
+	TLex lex(Text);
+	
+	// start at the begining
+	TPtrC token=lex.NextToken();
+	
+
+	if (!lex.Eos())
+		{
+		// step over the keyword
+		token.Set(lex.NextToken());
+		TInt NoOfDlls = iArrayLoadedSuiteDll->Count();
+		for ( TInt i=0; i < NoOfDlls; i++ )
+			{
+			CSuiteDll * ptrSuite = iArrayLoadedSuiteDll->At(i);
+		
+			// check the names
+			if ( ptrSuite->iName.CompareF( token )==0 )
+				{
+				if (NoOfDlls==1)
+					{
+					iArrayLoadedSuiteDll->ResetAndDestroy();
+					}
+				else
+					{
+					// this suite DDL is to be unloaded.
+					iArrayLoadedSuiteDll->Delete(i);
+					iArrayLoadedSuiteDll->Compress();
+					delete ptrSuite;
+					}
+				return;
+				}
+			}
+		}
+	else
+		{
+		if (iArrayLoadedSuiteDll)
+			{
+			// unload all the loaded DLLS and their records
+			iArrayLoadedSuiteDll->ResetAndDestroy();
+			}
+		}
+	}
+
+void CParseLine::HeapMark(void)
+/**
+This function implements the script HeapMark command
+*/
+	{
+	__UHEAP_MARK;
+	}
+
+
+void CParseLine::HeapCheck(void)
+/**
+This function implements the script HeapCheck command
+*/
+	{
+	__UHEAP_MARKEND;
+	}
+
+void CParseLine::RequestMark(void)
+/**
+This function implements the script RequestMark command
+*/
+	{
+	// get number of outstanding requetsts on thread before we run the test
+	iReqsAtStart = RThread().RequestCount();
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Requests at the start %d "),iReqsAtStart);
+	}
+
+
+void CParseLine::RequestCheck(void)
+/**
+This function implements the script RequestCheck command
+*/
+	{
+	// check the number of outstanding requests against recorded value
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Requests at the start %d now %d"),
+		iReqsAtStart,
+		RThread().RequestCount() );
+	
+	if ( iReqsAtStart != RThread().RequestCount())
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Test failed on requests count"));
+		
+		// this result is only significant if every thing else has passed
+		if ( iTestVerdict == EPass )
+			iTestVerdict = EFail;
+		
+		}
+	}
+
+
+void CParseLine::HandlesMark(void)
+/**
+This function implements the script HandlesMark command
+*/
+	{
+	// get number of Handles *before* we start the program
+	RThread().HandleCount(iProcessHandleCountBefore, iThreadHandleCountBefore);
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Process handles count %d thread handle count %d"),
+		iProcessHandleCountBefore,
+		iThreadHandleCountBefore );
+	}
+
+void CParseLine::HandlesCheck(void)
+/**
+This function implements the script HandlesCheck command
+*/
+	{
+	TInt processHandleCountAfter;
+	TInt threadHandleCountAfter;
+	RThread().HandleCount(processHandleCountAfter, threadHandleCountAfter);
+	
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Process handles count %d thread handle count %d"),
+		processHandleCountAfter,
+		threadHandleCountAfter );
+	
+	// check that we are closing all the threads
+	if(iThreadHandleCountBefore != threadHandleCountAfter)
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Test failed on thread handle count"));
+		
+		// this result is only significant if every thing else has passed
+		if ( iTestVerdict == EPass )
+			iTestVerdict = EFail;
+		}
+	
+	// check that we are closing all the handles
+	if(iProcessHandleCountBefore != processHandleCountAfter)
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Test failed on Process handle count"));
+		
+		// this result is only significant if every thing else has passed
+		if ( iTestVerdict == EPass )
+			iTestVerdict = EFail;
+		}
+	}
+
+CSuiteDll* CSuiteDll::NewL( const TDesC& aName )
+	{
+	CSuiteDll* self = new(ELeave) CSuiteDll(aName);
+	CleanupStack::PushL( self );
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CSuiteDll::CSuiteDll( const TDesC& aName )
+/**
+Constructor.
+@param aName The name of the test suite DLL to be loaded (can contain file path)
+*/
+	{
+	// save the name
+	iName.Copy( aName );
+	}
+
+
+/**
+Load a test suite dll and save the name and test
+test suite pointers
+*/
+void CSuiteDll::ConstructL()
+	{
+	// load DLL by name
+	TInt ret = iLibrary.Load(iName, KTxtDLLpath);
+	if ( ret != KErrNone )
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Test suite %S found but would not load"),&iName );
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("check any other Dlls required by %S "),&iName );
+		User::Leave(ret);
+		}
+
+	// save the suite name dll without file path
+	TParse parse;
+    parse.Set(iName, NULL, NULL);
+    iName.Copy(parse.NameAndExt());
+
+	// get the interface pointer at ordinal 1
+	TLibraryFunction  entry=iLibrary.Lookup(1);
+
+    // 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 = (CTestSuite*) entry();
+
+    // Second-phase constructor for CTestSuite
+    TRAPD(error,iTestSuite->ConstructL() );
+
+    //-- set the suite name (internal variable) the same as suite name dll file name (without extention)
+    iTestSuite->OverrideSuiteName(parse.NameAndExt());
+
+	if (error)
+		{
+		pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("Failed to contruct test suite"));
+		User::Leave(error);
+		}
+
+	// set suite severity level
+	iTestSuite->SetSeverity(pLogSystem->Severity());
+
+	// get the version information
+	TPtrC Versiontxt = iTestSuite->GetVersion();
+
+	// add to log
+	pLogSystem->LogExtra(((TText8*)__FILE__), __LINE__, ESevrErr, _L("LOAD_SUITE %S version %S loaded ok"),&iName, &Versiontxt );
+	}
+
+
+CSuiteDll::~CSuiteDll()
+/**
+destructor Delete the TestSuiteObject in the loaded DLL and close
+and unload the library
+*/
+	{
+	// delete the TestSuiteObject in the loaded DLL
+	if (iTestSuite)
+		{
+		delete iTestSuite;
+		}
+
+	// close and unload the library
+	iLibrary.Close();
+	}
+
+/**
+*   Find out if the suite name matches the suite dll name.
+*
+*   @param  aSuiteName suite name (without file extention)
+*   @return ETrue if the given suite name matches suite name dll file name.
+*/
+TBool CSuiteDll::SuiteNameMatch(const TDesC& aSuiteName) const
+{
+    TParse parse;
+
+    //-- iName contains suite dll name with file extention, strip the extention
+    parse.Set(iName, NULL, NULL);
+
+    //-- using CompareF instead of FindF to avoid situation when "AAA" suite name can match "AAA123"
+    TBool bFound =  (aSuiteName.CompareF(parse.Name()) ==0 ) ? ETrue : EFalse;
+    
+    return bFound;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+