stif/TestCombiner/src/TestCombiner.cpp
branchRCL_3
changeset 59 8ad140f3dd41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stif/TestCombiner/src/TestCombiner.cpp	Wed Oct 13 16:17:58 2010 +0300
@@ -0,0 +1,6619 @@
+/*
+* Copyright (c) 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 the implementation of 
+* CTestCombiner class member functions.
+*
+*/
+
+// INCLUDE FILES
+#include <StifTestEventInterface.h>
+#include <StifLogger.h>
+#include "TestCombiner.h"
+#include "TestKeywords.h"
+#include "TestCase.h"
+#include "TestCombinerEvent.h"
+#include "Logging.h"
+//--PYTHON-- begin
+#include "StifPython.h"
+#include "StifPythonFunComb.h"
+//--PYTHON-- end
+#include "SettingServerClient.h"
+
+// EXTERNAL DATA STRUCTURES
+// None
+
+// EXTERNAL FUNCTION PROTOTYPES  
+// None
+
+// CONSTANTS
+_LIT( KTestRunner, "CTestRunner" );
+_LIT( KRemoteTimer, "CRemoteTimer" );
+_LIT( KRemoteReceiver, "CRemoteReceiver" );
+
+// MACROS
+#ifdef LOGGER
+#undef LOGGER
+#endif
+#define LOGGER iLog
+
+// LOCAL CONSTANTS AND MACROS
+_LIT(KTitle, "title");
+_LIT(KTimeout, "timeout");
+_LIT(KPriority, "priority");
+
+//printing macros
+ _LIT( KExecute, "Execute");
+ 
+// MODULE DATA STRUCTURES
+// None
+
+// LOCAL FUNCTION PROTOTYPES
+// None
+
+// FORWARD DECLARATIONS
+// None
+
+// ==================== LOCAL FUNCTIONS =======================================
+// None
+
+// ================= MEMBER FUNCTIONS =========================================
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: CTestCombiner
+
+     Description: Default constructor
+
+     C++ default constructor can NOT contain any code, that
+     might leave.
+     
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+CTestCombiner::CTestCombiner(): 
+    iSchedulerActive( EFalse ),
+    iRunningTests( 0 ), 
+    iResult( KErrNone ),
+    iEventPckg( iEvent ),
+    iRemoteTimeout( KRemoteProtocolTimeout ),
+    iCancelIfError( EFalse ),
+    iFailedTestCase( 0 ),
+    iLoopIsUsed( EFalse )
+    {
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: ConstructL
+
+     Description: Symbian OS second phase constructor
+
+     Symbian OS default constructor can leave.
+
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None.
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::ConstructL()
+    {
+    // TRAPed to avoid crashing if logfile creation fails,
+    // so we can run test without logging to file
+    TRAPD( err, iStdLog = CStifLogger::NewL( KTestCombinerLogDir, 
+                                      KTestCombinerLogFile );
+        );
+    if( err != KErrNone )
+        {
+        iStdLog = NULL;
+        __RDEBUG( (_L("Creating logfile failed") ) );
+        }  
+    iLog = iStdLog;
+
+    //Read logger settings to check whether test case name is to be
+    //appended to log file name.
+    RSettingServer settingServer;
+    TInt ret = settingServer.Connect();
+    if(ret != KErrNone)
+        {
+        User::Leave(ret);
+        }
+    // Struct to StifLogger settigs.
+    TLoggerSettings loggerSettings; 
+    // Parse StifLogger defaults from STIF initialization file.
+    ret = settingServer.GetLoggerSettings(loggerSettings);
+    if(ret != KErrNone)
+        {
+        User::Leave(ret);
+        }
+
+    // Get engine settings
+    TEngineSettings engineSettings;
+    ret = settingServer.GetEngineSettings(engineSettings);
+    if(ret != KErrNone)
+        {
+        __TRACE(KError, (_L("Could not retrieve engine settings from SettingServer [%d]"), ret));
+        iUITestingSupport = EFalse;
+        iSeparateProcesses = EFalse;
+        }
+        else
+        {
+        iUITestingSupport = engineSettings.iUITestingSupport;
+        iSeparateProcesses = engineSettings.iSeparateProcesses;
+        __TRACE(KMessage, (_L("Engine settings retrieved from SettingServer. UITestingSupport [%d] SeparateProcesses [%d]"), iUITestingSupport, iSeparateProcesses));
+        }
+
+    // Close Setting server session
+    settingServer.Close();
+    iAddTestCaseTitleToLogName = loggerSettings.iAddTestCaseTitle;
+
+    iIndexTestModuleControllers = 1;
+    
+    __TRACE( KPrint, ( _L("New TestCombiner") ) );
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: NewL
+
+     Description: Two-phased constructor.
+          
+     Parameters:    None
+
+     Return Values: CTestCombiner*: new object
+
+     Errors/Exceptions: Leaves if new or ConstructL leaves.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+CTestCombiner* CTestCombiner::NewL()
+    {
+     
+    CTestCombiner* self = new (ELeave) CTestCombiner();
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+     
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: ~CTestCombiner
+
+     Description: Destructor
+     
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+CTestCombiner::~CTestCombiner()
+    {
+    iLoopAllocationArray.Reset();
+    iLoopAllocationArray.Close();
+    iLoopIsUsed = EFalse;
+
+    iTestCases.ResetAndDestroy();
+    iTestModules.ResetAndDestroy();
+    iEventArray.ResetAndDestroy();
+    iSlaveArray.ResetAndDestroy();
+    iSendReceive.ResetAndDestroy();
+
+    iTestCases.Close();
+    iTestModules.Close();
+    iEventArray.Close();
+    iSlaveArray.Close();
+    iSendReceive.Close();
+
+    // Stop all remaining measurement modules
+    const TInt count_meas = iTestMeasurementArray.Count();
+    for( TInt b = 0; b < count_meas; b++ )
+        {
+        iTestMeasurementArray[b]->iMeasurement->Stop();
+        }
+    iTestMeasurementArray.ResetAndDestroy();
+    iTestMeasurementArray.Close();
+
+    delete iSectionParser;
+    delete iRemoteReceiver;
+    delete iTestRunner;
+
+    iLog = NULL;
+    delete iStdLog;
+    iStdLog = NULL;
+    delete iTCLog;
+    iTCLog = NULL;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: InitL
+
+     Description: InitL is used to initialize the Test Module.
+
+     Parameters: const TFileName& aIniFile: in: Initialization file
+                 TBool aFirstTime: in: First time flag 
+
+     Return Values: Symbian OS error code
+
+     Errors/Exceptions: Leaves if ReadInitializationL leaves
+
+     Status: Draft
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestCombiner::InitL( TFileName& aIniFile, 
+                           TBool /*aFirstTime*/ )
+    {
+
+    __TRACEFUNC();
+
+    if( aIniFile.Length() > 0 )
+        {
+        // Read initialization from test case file
+        ReadInitializationL( aIniFile );
+        }
+
+    return KErrNone;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetTestCases
+
+     Description: GetTestCases is used to inquired test cases
+
+     Parameters:    const TFileName& aConfigFile: in: Config file name
+                    RPointerArray<RTestEngine::TTestCaseInfo>& aTestCases: out: 
+                          Array of TestCases 
+
+     Return Values: KErrNone: Success
+                    KErrNotFound: Testcases not found
+
+     Errors/Exceptions: Leaves if CStifParser::NewL leaves
+                        Leaves if CStifParser::SectionL leaves
+                        Leaves if CStifParser::NextSectionL leaves
+                        Leaves if memory allocation fails
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestCombiner::GetTestCasesL( const TFileName& aConfigFile, 
+                                   RPointerArray<TTestCaseInfo>& aTestCases )
+    {
+    __TRACEFUNC();
+
+    if( aConfigFile.Length() == 0 )
+        {
+        __TRACE( KError, (_L("No test case script file given") ) );
+        __RDEBUG( (_L("No test case script file given") ) );
+        return KErrNotFound;
+        }
+
+    CStifParser* parser = NULL;
+    TRAPD( err, parser = 
+        CStifParser::NewL( _L(""), aConfigFile, CStifParser::ECStyleComments ) );
+    if( err != KErrNone )
+        {
+        __TRACE( KError, (_L("Test case script file not found") ) );
+        __RDEBUG( (_L("Test case script file not found") ) );
+        return KErrNotFound;
+        }
+    CleanupStack::PushL( parser );
+    CStifSectionParser* section;
+    TPtrC tmp;
+    TInt index = 0;
+    TInt ret = KErrNone;
+
+    section = parser->SectionL( KTestStartTag, KTestEndTag );
+    if( section == NULL )
+        {
+        ret = KErrNotFound;
+        }
+    else
+        {    
+        while( section )
+            {
+            CleanupStack::PushL( section );
+             
+            if( section->GetLine( KTitle,  tmp, ENoTag ) == KErrNone )
+                 {
+                 if( tmp.Length() > KMaxName )
+                    {
+                    tmp.Set( tmp.Left( KMaxName ) );
+                    }                    
+                 TTestCaseInfo* tc = new ( ELeave ) TTestCaseInfo();
+                 CleanupStack::PushL( tc );
+                 __TRACE( KVerbose, (_L("TestCase: %S"), &tmp));
+                 tc->iTitle.Copy( tmp );
+                 tc->iCaseNumber = ++index;
+                 CStifItemParser* item = section->GetItemLineL( KTimeout );
+                 if( item )
+                    {
+                    TInt timeout; // In milliseconds
+                    ret = item->GetInt( KTimeout, timeout ); 
+                    if( ret != KErrNone )
+                        {
+                        __TRACE( KError, (_L("Illegal timeout")));
+                        User::Leave( ret ); 
+                        }
+                    tc->iTimeout = (TInt64)timeout*1000;
+                    __TRACE( KMessage, (_L("Timeout: %i"), tc->iTimeout.Int64() ));
+                    }
+                 item = section->GetItemLineL( KPriority );
+                 if( item )
+                    {
+                    ret = item->GetInt( KPriority, tc->iPriority ); 
+                    if( ret != KErrNone )
+                        {
+                        TPtrC priority;
+                        ret = item->GetString( KPriority, priority );
+                        if( ret != KErrNone )
+                            {
+                            __TRACE( KError, (_L("Illegal priority")));
+                            User::Leave( ret ); 
+                            }
+                        switch( TTCKeywords::Parse( priority, 
+                                                    TTCKeywords::Priority ) )
+                            {
+                            case TTCKeywords::EPriHigh:
+                                tc->iPriority = TTestCaseInfo::EPriorityHigh;
+                                break;
+                            case TTCKeywords::EPriNormal:
+                                tc->iPriority = TTestCaseInfo::EPriorityNormal;
+                                break;
+                            case TTCKeywords::EPriLow:
+                                tc->iPriority = TTestCaseInfo::EPriorityLow;
+                                break;
+                            default:
+                                __TRACE( KError, (_L("Illegal priority")));
+                                User::Leave( KErrArgument ); 
+                            }
+                        }
+                    __TRACE( KMessage, (_L("Priority: %i"), tc->iPriority ));
+                    }
+
+                 aTestCases.Append(tc);
+                 CleanupStack::Pop( tc );
+                 }
+            CleanupStack::PopAndDestroy( section );
+            section = parser->NextSectionL( KTestStartTag, KTestEndTag );
+            }
+        }
+
+    CleanupStack::PopAndDestroy( parser );
+
+    __TRACE( KPrint, (  _L( "Configfile '%S', testcases %d" ),
+        &aConfigFile, index ));
+
+    return ret;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: RunTestCaseL
+
+     Description: Run a specified testcase.
+
+     RunTestCaseL is used to run an individual test case specified 
+     by aTestCase. 
+
+     Parameters:    const TInt aCaseNumber: in: Testcase number 
+                    const TFileName& aConfig: in: Configuration file name
+                    TTestResult& aResult: out; test case result
+
+     Return Values: KErrNone: Test case started succesfully.
+                    KErrNotFound: Testcase not found
+                    KErrUnknown: Unknown TestCombiner error
+                    Any other SymbianOS error
+
+     Errors/Exceptions: Leaves if GetTestCaseL leaves
+                        Leaves if RunTestL leaves
+                        Leaves if memory allocation fails
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestCombiner::RunTestCaseL( const TInt aCaseNumber, 
+                                  const TFileName& aConfig, 
+                                  TTestResult& aResult )
+    {
+    __TRACEFUNC();
+
+    __TRACE( KMessage, (_L("***Testcase started***")));
+
+    //Open new log file with test case title in file name
+    if(iAddTestCaseTitleToLogName)
+        {
+        //Close test case log if exists
+        if(iTCLog)
+            {
+            delete iTCLog;
+            iTCLog = NULL;
+            }
+        TFileName logFileName;
+        TName title;
+        TestModuleIf().GetTestCaseTitleL(title);
+        
+        logFileName.Format(KTestCombinerLogFileWithTitle, &title);
+        iTCLog = CStifLogger::NewL(KTestCombinerLogDir, logFileName);
+        iLog = iTCLog;
+        }
+
+    /* 
+    * Allow memory leaks, because Defines are leaved untouched 
+    * after test case execution. Real memory leaks are detected with 
+    * UHEAP macros.
+    */
+    TestModuleIf().SetBehavior( CTestModuleIf::ETestLeaksMem );
+
+    // Read initialization from test case file
+    ReadInitializationL( aConfig );
+
+    __UHEAP_MARK;
+        
+    iSectionParser = GetTestCaseL( aCaseNumber, aConfig );
+
+    // Check parsing result
+    if( iSectionParser == NULL )
+        {
+        __TRACE( KError, (_L("***Parsing testcase failed***")));
+        __UHEAP_MARKEND;
+        return KErrNotFound;
+        }
+
+    CActiveScheduler* activeScheduler = 
+        new ( ELeave ) CActiveScheduler();
+    CleanupStack::PushL( activeScheduler );
+    CActiveScheduler::Install( activeScheduler );
+
+    // Resetting these variables to normal state @js             
+    iFailedTestCase = 0;    
+    iCancelIfError = EFalse;
+    iScriptFailed = KErrNone;
+    iScriptFailedDescription.Copy(KNullDesC);
+
+    // Run the given testcase described in iSectionParser section
+    RunTestL();
+
+    CleanupStack::PopAndDestroy( activeScheduler );
+
+    delete iSectionParser;
+    iSectionParser = NULL;
+
+    TInt ret = KErrNone;
+    // Check if test case starting failed
+    if( iResult != KErrNone )
+        {
+        TestModuleIf().Printf( KPrintPriHigh, _L("Result"), _L("Starting FAILED"));
+         __TRACE( KError, (_L("***Starting testcase FAILED***")));
+        ret = iResult;
+        aResult.iResult = -2;
+        aResult.iResultDes = _L("Testcase script execution failed");
+        }
+    else if(iScriptFailed != KErrNone)
+        {
+        TestModuleIf().Printf( KPrintPriHigh, _L("Result"), _L("Script execution FAILED"));
+        __TRACE( KError, (_L("***Sscript execution FAILED***")));
+        aResult.iResult = iScriptFailed;
+        if(iScriptFailedDescription != KNullDesC)
+            {
+            aResult.iResultDes.Copy(iScriptFailedDescription);
+            }
+        else
+            {
+            aResult.iResultDes = _L("Testcase script execution failed");
+            }
+        }
+    else
+        {
+        __TRACE( KPrint, (_L("***Testcase completed***")));
+              
+        // Testcombiner succeeded to start all testcases, 
+        // check individual testcase results
+        TInt count = iTestCases.Count();
+        TInt i = iFailedTestCase;
+        // iFailedTestCase is either 0 or the number of failed test case if 
+        // canceliferror was given and a test case has failed
+
+        for(; i < count; i++ )
+            {
+            // All cases should be completed now
+            if( iTestCases[i]->State() != CTCTestCase::ETestCaseCompleted )
+                {
+                // This is some unknown internal TestCombiner error
+                // Should not happen
+                __TRACE( KError, (_L("TestCase (%S) not completed"), 
+                    &iTestCases[i]->TestId() ));
+                ret = KErrUnknown;
+                break;
+                }
+
+            // Interpret execution result type from returned result
+            TInt executionResult = TFullTestResult::ECaseExecuted; // Ok
+            if( iTestCases[i]->iResult.iCaseExecutionResultType >= 
+                TFullTestResult::ECaseLeave )
+                {
+                // Some abnormal execution result type
+                executionResult = iTestCases[i]->iResult.iCaseExecutionResultType;
+                }
+
+            // Check expected execution result type
+            if( executionResult != iTestCases[i]->ExpectedResultCategory() ) 
+                {
+                // expected and returned result types differ
+                aResult.iResult = KErrGeneral;
+                aResult.iResultDes.Copy( _L("Test case completed with ") );
+                aResult.iResultDes.Append( 
+                    TTCKeywords::ResultCategory( 
+                    iTestCases[i]->iResult.iCaseExecutionResultType ));
+                aResult.iResultDes.Append( _L(" and expected was ") );
+                aResult.iResultDes.Append( 
+                    TTCKeywords::ResultCategory( 
+                    iTestCases[i]->ExpectedResultCategory() ));
+                AppendTestResultToResultDes(aResult.iResultDes, iTestCases[i]->iResult.iTestResult.iResultDes);
+                __TRACE( KPrint, ( _L( "%S"), &aResult.iResultDes ) );
+                break;
+                }
+
+            // Check normal test result
+            if( iTestCases[i]->ExpectedResultCategory() == 
+                TFullTestResult:: ECaseExecuted )
+                {
+                // Normal completion, check result
+                if( iTestCases[i]->iResult.iTestResult.iResult != 
+                      iTestCases[i]->ExpectedResult() )
+                    {
+                     __TRACE( KPrint, ( _L( "Test failed, expect(%d) != result(%d)"), 
+                         iTestCases[i]->ExpectedResult(),
+                         iTestCases[i]->iResult.iTestResult.iResult ));
+                    // We return the first error result as aResult
+                    if( iTestCases[i]->iResult.iTestResult.iResult != KErrNone )
+                        {
+                        aResult = iTestCases[i]->iResult.iTestResult;
+                        }
+                    else
+                        {
+                        aResult.iResult = KErrGeneral;
+                        aResult.iResultDes.Copy( _L("Test case completed with KErrNone and expected "));
+                        aResult.iResultDes.AppendNum( iTestCases[i]->ExpectedResult() );
+                        AppendTestResultToResultDes(aResult.iResultDes, iTestCases[i]->iResult.iTestResult.iResultDes);
+                        }
+                    break;
+                    }
+                }
+            else 
+                {
+                // Abnormal completion, i.e. panic, leave, exception or timeout
+                if( iTestCases[i]->iResult.iCaseExecutionResultCode != 
+                      iTestCases[i]->ExpectedResult() )
+                    {
+                    __TRACE( KPrint, ( _L( "Test failed, expect errorcode(%d) != result(%d)"), 
+                         iTestCases[i]->ExpectedResult(),
+                         iTestCases[i]->iResult.iCaseExecutionResultCode ) );
+                    // We return the first error result as aResult
+                    aResult = iTestCases[i]->iResult.iTestResult;
+                    // override result with real error code
+                    aResult.iResult = iTestCases[i]->iResult.iCaseExecutionResultCode;
+                    break;
+                    }
+                }
+            }
+        if( i == count )
+            {
+            TestModuleIf().Printf( KPrintPriHigh, _L("Result"), _L("PASSED"));
+            __TRACE( KPrint, (_L("***Test case result: PASSED***")));
+            aResult.iResult = KErrNone;
+            aResult.iResultDes.Copy( _L("Test case succeeded") );
+            }
+        else
+            {
+            TestModuleIf().Printf( KPrintPriHigh, _L("Result"), _L("FAILED"));        
+            __TRACE( KPrint, (_L("***Test case result: FAILED***")));
+            }
+        }
+
+    // Release all pending event requests
+    TEventIf event( TEventIf::ERelEvent );
+    TInt eventCount = iEventArray.Count();
+    for( TInt ind=0; ind < eventCount; ind++ )
+        {
+        event.SetName( iEventArray[ind]->Name() );
+        TestModuleIf().Event( event );
+        }
+
+    iLoopAllocationArray.Reset();
+    iLoopAllocationArray.Close();
+    iLoopIsUsed = EFalse;
+
+    // Delete all completed and checked testcases
+    // Do not change the deletion order of events and test cases!!!
+    iEventArray.ResetAndDestroy();
+    iTestCases.ResetAndDestroy();
+    iTestModules.ResetAndDestroy();
+    iSlaveArray.ResetAndDestroy();
+
+    iSendReceive.ResetAndDestroy();
+
+    // Stop all remaining measurement modules
+    const TInt count_meas = iTestMeasurementArray.Count();
+    for( TInt b = 0; b < count_meas; b++ )
+        {
+        iTestMeasurementArray[b]->iMeasurement->Stop();
+        }
+    iTestMeasurementArray.ResetAndDestroy();
+    iTestMeasurementArray.Close();
+
+    __UHEAP_MARKEND;
+
+    //If log was replaced then restore it
+    if(iAddTestCaseTitleToLogName)
+        {
+        iLog = iStdLog;
+        delete iTCLog;
+        iTCLog = NULL;
+        }
+
+    return ret;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetTestCaseL
+
+     Description: Get specified test case section from configfile.
+
+     Parameters:    const TInt aCaseNumber: in: Test case number
+                    const TFileName& aConfig: in: Configfile name 
+
+     Return Values: CSectionParser*: pointer to test case section
+
+     Errors/Exceptions: Leaves if CStifParser::NewL leaves
+                        Leaves if CStifParser::SectionL leaves
+                        Leaves if memory allocation fails
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CStifSectionParser* CTestCombiner::GetTestCaseL( const TInt aCaseNumber, 
+                                             const TFileName& aConfig )
+    {
+    __TRACEFUNC();
+    CStifParser* parser = 
+        CStifParser::NewL( _L(""), aConfig, CStifParser::ECStyleComments );
+    CleanupStack::PushL( parser );
+
+    CStifSectionParser* section = 
+        parser->SectionL( KTestStartTag, KTestEndTag, aCaseNumber );
+
+    CleanupStack::PopAndDestroy( parser );
+    return section;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: ReadInitializationL
+
+     Description: Read initialization from file.
+
+     Parameters:    const TDesC& aIniFile: in: File that contains initialization
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Draft
+
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::ReadInitializationL( const TDesC& aIniFile )
+    {
+    CStifParser* parser = NULL; 
+
+    // Open file
+    TRAPD( err, parser = 
+        CStifParser::NewL( _L(""), aIniFile, CStifParser::ECStyleComments ) );
+    if( ( err == KErrNone ) && parser )
+        {
+        CleanupStack::PushL( parser );
+        __TRACE( KMessage, (_L("Read initialization from [%S]"),
+            &aIniFile ) );
+        
+        // Read initialization parameters 
+        CStifSectionParser* section = parser->SectionL( KInitStartTag,
+                                                        KInitEndTag );
+        if( section  )
+            {
+            CleanupStack::PushL( section );
+            __TRACE( KMessage, (_L("Read initializations")) );
+
+            // Read RCP timeout            
+            CStifItemParser* item = section->GetItemLineL( KInitRcpTimeout );
+            if( item != NULL )
+                {
+                __TRACE( KMessage, (_L("Got RCP timeout definition")) );
+                CleanupStack::PushL( item );
+                
+                TInt value;
+                if( item->GetInt( KInitRcpTimeout, value ) 
+                        != KErrNone )
+                    {
+                    __TRACE( KError, (_L("No RCP timeout value given")) );
+                    User::Leave( KErrGeneral );                    
+                    } 
+                // Change from seconds to milliseconds
+                iRemoteTimeout = value*1000*1000;
+                CleanupStack::PopAndDestroy( item );
+                }
+
+            CleanupStack::PopAndDestroy( section );
+            }
+           
+        // Read defines
+        section = parser->SectionL( KDefineStartTag, KDefineEndTag );
+        while(section)
+            {
+            CleanupStack::PushL( section );
+            __TRACE( KMessage, (_L("Read defines")) );
+
+            TPtrC name;
+            TPtrC value;
+            CStifItemParser* item = section->GetItemLineL( _L("") );
+            while( item )
+                {
+                CleanupStack::PushL( item );
+                
+                if( item->GetString( _L(""), name ) != KErrNone )
+                    {
+                    __TRACE( KError, (_L("No define name given")) );
+                    User::Leave( KErrGeneral );
+                    } 
+                if( item->Remainder( value ) != KErrNone )
+                    {
+                    __TRACE( KError, (_L("No define value given")) );
+                    User::Leave( KErrGeneral );
+                    } 
+                TInt count = iDefined.Count();
+                TInt i = 0;
+                for( ; i < count; i++ )
+                    {
+                    if( iDefined[i]->Name() == name )
+                        {
+                        __TRACE( KMessage, (_L("Update define %S:%S"), &name, &value ) );
+                        // Update existing
+                        iDefined[i]->SetValueL( value );
+                        break;
+                        }
+                    }
+                if( i == count) 
+                    {
+                    // New define, store it
+                    CDefinedValue* define = CDefinedValue::NewL( name, value );
+                    CleanupStack::PushL( define );
+                    User::LeaveIfError( iDefined.Append( define ) );
+                    CleanupStack::Pop( define );
+                    }
+
+                CleanupStack::PopAndDestroy( item );
+                item = section->GetNextItemLineL();
+                }
+            CleanupStack::PopAndDestroy( section );
+            section = parser->NextSectionL(KDefineStartTag, KDefineEndTag);
+            }
+        CleanupStack::PopAndDestroy( parser );
+        }
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: RunTestL
+
+     Description: Run a testcase specified by iSectionParser.
+
+     Parameters:    None
+     
+     Return Values: None.
+
+     Errors/Exceptions: Leaves if CSectionParser::GetItemLineL leaves
+                        Leaves if CTestRunner::NewL leaves
+                        Leaves if memory allocation fails                                
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::RunTestL()
+    {
+    __TRACEFUNC();
+    iResult = KErrNone;
+
+    TPtrC line;
+    // "title" keyword must be in the first line
+    User::LeaveIfError( iSectionParser->GetLine( KTitle, line, ENoTag ) );
+     
+    iTestRunner = CTestRunner::NewL( this ); 
+    iRemoteReceiver = CRemoteReceiver::NewL( this );
+    iRemoteReceiver->Start();
+
+    __TRACE( KMessage, (_L("Run: %S"), &line));
+    
+    TestModuleIf().Printf( KPrintPriNorm, _L("Run"), _L("%S"), &line);
+    // Rest of the job is done by test runner
+    iTestRunner->SetRunnerActive();
+
+    // Start activeScheduler looping testcase lines
+    iSchedulerActive = ETrue;
+    __TRACE( KMessage, (_L("Start CActiveScheduler")));
+    CActiveScheduler::Current()->Start();
+
+    TestModuleIf().Printf( KPrintPriNorm, _L("Executed"), _L("%S"), &line);
+    __TRACE( KMessage, (_L("Executed: %S"), &line));
+        
+    delete iRemoteReceiver;
+    iRemoteReceiver = NULL;
+    delete iTestRunner;
+    iTestRunner = NULL;
+
+    }     
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetTestModuleL
+
+     Description: Load testmodule if not already loaded, otherwise return
+                  description of the loaded testmodule.
+
+     Parameters:    TDesC& aModule: in: Module name.
+                    TDesC& aIniFile: in: Ini file name.
+                    const TDesC& aConfigFile: in: Test case(config) file name.
+     
+     Return Values: CTCTestModule*: pointer to testmodules description
+     
+     Errors/Exceptions: Leaves if CTCTestModule::NewL leaves
+                        Leaves if RPointerArray::Append fails  
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CTCTestModule* CTestCombiner::GetTestModuleL( TDesC& aModule,
+                                              TDesC& aIniFile,
+                                              const TDesC& aConfigFile )
+    {
+    __TRACEFUNC();
+    TInt count = iTestModules.Count();
+    TInt i, j;
+    TInt counttc;
+    TInt running;
+    TBool newWay = EFalse;
+    
+    __TRACE(KMessage, (_L("Find test module for [%S]"), &aModule));
+
+    //Name for new module controller
+    TName newModuleName = aModule;
+
+    //Check if it is python case or UITestingSupport or SeparateProcesses mode
+    newWay = (aModule.Find(KPythonScripter) == 0)
+             || (iUITestingSupport && aModule.Find(KTestScripterName) == 0)
+             || (iSeparateProcesses); 
+
+    if(newWay)
+        {
+        __TRACE(KMessage, (_L("TCTestModule operating mode: exclusive")));
+
+        //Find module of given name
+        __TRACE(KMessage, (_L("Looking for module [%S]"), &aModule));
+        if(iUITestingSupport && aModule.Find(KTestScripterName) == 0)
+            {
+            __TRACE(KMessage, (_L("UITestingSupport option is on. New module controller will be created always")));
+            }
+        else
+            {
+            for(i = 0; i < count; i++)
+                {
+                TPtrC modName = iTestModules[i]->ModuleName();
+                if(modName.Find(aModule) == 0)
+                    {
+                    //Check if there is running test case
+                    counttc = iTestCases.Count();
+                    running = 0;
+                    for(j = 0; j < counttc; j++)
+                        {
+                        if(iTestCases[j]->TestModule() == iTestModules[i] && iTestCases[j]->State() != CTestCase::ETestCaseCompleted)
+                            {
+                            //We have found at least one running test case. There is no reason to find any more,
+                            //because there shouldn't be because test module may run only one python scripter test case.
+                            running++;
+                            __TRACE(KMessage, (_L("Module controller found [%S], but it has running test cases"), &modName));
+                            break;
+                            }
+                        }
+                    if(running == 0)
+                        {
+                        __TRACE(KMessage, (_L("Free module controller has been found [%S]"), &modName));
+                        return iTestModules[i];
+                        }
+                    }
+                }
+            }
+        //Update name of new module to be created
+        newModuleName.AppendFormat(_L("@%d_"), GetIndexForNewTestModuleController());
+        newModuleName.LowerCase();
+        }
+    else
+        {
+        __TRACE(KMessage, (_L("TCTestModule operating mode: normal")));
+        for(i = 0; i < count; i++)
+            {
+            if(iTestModules[i]->ModuleName() == aModule)
+                {
+                // Found test module, return description
+                __TRACE(KMessage, (_L("Module controller [%S] found"), &aModule));
+                return iTestModules[i];
+                }
+            }
+        }
+
+    __TRACE(KMessage, (_L("Creating new test module controller [%S] with ini [%S]"), &newModuleName, &aIniFile));
+    CTCTestModule* module = CTCTestModule::NewL(this, newModuleName, aIniFile, aConfigFile);
+    CleanupStack::PushL(module);
+
+    //Enumerate test cases
+    module->GetTestCasesForCombiner(aConfigFile);
+
+    //Append new module to list
+    User::LeaveIfError(iTestModules.Append(module));
+    CleanupStack::Pop(module);
+
+    //Log some info
+    if(newWay)
+        {    
+        __TRACE(KMessage, (_L("Module [%S] added to list. Currently there are following controllers of [%S] type:"), &newModuleName, &aModule));
+        j = 1;
+        for(i = 0; i < iTestModules.Count(); i++)
+            {
+            if(iTestModules[i]->ModuleName().Find(aModule) == 0)
+                {
+                __TRACE(KMessage, (_L("    %d. [%S]"), j, &iTestModules[i]->ModuleName()));
+                j++;
+                }
+            }
+        }
+
+    if( iLoopIsUsed )
+        {
+        User::LeaveIfError( iLoopAllocationArray.Append( module ) );
+        }
+
+    return module;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetTest
+
+     Description: Get test case from testcase array.
+
+     Parameters:    TDesC& aTestId: in: TestId for testcase
+     
+     Return Values: CTCTestCase*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+CTestCase* CTestCombiner::GetTest( TDesC& aTestId )
+    {
+    __TRACEFUNC();
+    // TestId is not mandatory, so length may be zero
+    if( aTestId.Length() == 0 )
+        {
+        return NULL;
+        }
+
+    TInt count = iTestCases.Count();
+    for( TInt i=0; i < count; i++ )
+        {
+        if( iTestCases[i]->TestId() == aTestId )
+            {
+            // Found testcase with specified TestId
+            return iTestCases[i];
+            }
+        }
+    // Test case with aTestId not found
+    return NULL;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRunningTest
+
+     Description: Get running test case.
+
+     Parameters: TDesC& aTestId: in: TestId for testcase
+     
+     Return Values: CTCTestCase*: running testcase
+                    NULL: Testcase with aTestId not running 
+
+     Errors/Exceptions: None
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CTestCase* CTestCombiner::GetRunningTest( TDesC& aTestId )
+    {
+    __TRACEFUNC();
+     
+    CTestCase* test = GetTest( aTestId );
+    if( test ) 
+        {
+        if( test->State() == CTestCase::ETestCaseRunning )
+            {
+            return test;
+            }
+        else
+            {
+             __TRACE( KMessage, (_L("GetTest: Searched task (%S) not running (%i)"), 
+                &aTestId, test->State() ));
+            }
+        }
+
+    return NULL;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetLocalTest
+
+     Description: Get local test case from testcase array.
+
+     Parameters:    TDesC& aTestId: in: TestId for testcase
+     
+     Return Values: CTCTestCase*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CTCTestCase* CTestCombiner::GetLocalTest( TDesC& aTestId )
+    {
+    __TRACEFUNC();
+    CTestCase* testCase = GetTest( aTestId );
+    if( testCase )
+        {    
+        if( testCase->Type() != CTestCase::ECaseLocal )
+            {
+            __TRACE( KMessage, (_L("GetLocalTest: Searched task (%S) not local"), 
+                      &aTestId ));
+            return NULL;
+            }
+        }
+    return ( CTCTestCase* ) testCase;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetLocalRunningTest
+
+     Description:  Get local running test case.
+
+     Parameters:    TDesC& aTestId: in: TestId for testcase
+     
+     Return Values: CTCTestCase*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CTCTestCase* CTestCombiner::GetLocalRunningTest( TDesC& aTestId )
+    {
+    __TRACEFUNC();
+    CTestCase* testCase = GetRunningTest( aTestId );
+    if( testCase )
+        {    
+        if( testCase->Type() != CTestCase::ECaseLocal )
+            {
+            __TRACE( KMessage, (_L("GetLocalRunningTest: Searched task (%S) not local"), 
+                      &aTestId ));
+            return NULL;
+            }
+        }
+        
+    return ( CTCTestCase* ) testCase;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRemoteTest
+
+     Description: Get local test case from testcase array.
+
+     Parameters:    TDesC& aTestId: in: TestId for testcase
+     
+     Return Values: CTCTestCase*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteTestCase* CTestCombiner::GetRemoteTest( TDesC& aTestId )
+    {
+    __TRACEFUNC();
+    CTestCase* testCase = GetTest( aTestId );
+    if( testCase )
+        {    
+        if( testCase->Type() != CTestCase::ECaseRemote )
+            {
+            __TRACE( KMessage, (_L("GetRemoteTest: Searched task (%S) not remote"), 
+                      &aTestId ));
+            return NULL;
+            }
+        }
+        
+    return ( CRemoteTestCase* ) testCase;
+    
+    }
+        
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRemoteTest
+
+     Description: Get remote test case from slave array.
+
+     Parameters:    TUint32 aSlaveId: in: Slave id for testcase
+     
+     Return Values: TCaseInfo*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteTestCase* CTestCombiner::GetRemoteTest( TUint32 aSlaveId )
+    {
+    
+    __TRACEFUNC();
+    
+    // Check all remote testcases
+    TInt caseCount = iTestCases.Count(); 
+    CRemoteTestCase* testCase = NULL;
+    for( TInt caseInd = 0; caseInd < caseCount; caseInd++ )
+        {
+        if( iTestCases[caseInd]->Type() == CTestCase::ECaseRemote )
+            {
+            testCase = ( CRemoteTestCase* )iTestCases[caseInd];
+            if( testCase->iSlaveId == aSlaveId )
+                {
+                return testCase;
+                }
+            }
+        }
+    
+    return NULL;
+        
+    }   
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRemoteTestRunSent
+
+     Description: Get remote test case from slave array
+
+     Parameters:    TUint32 aSlaveId: in: Slave id for testcase
+
+     Return Values: TCaseInfo*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Draft @js
+    
+-------------------------------------------------------------------------------
+*/
+    
+CRemoteTestCase* CTestCombiner::GetRemoteTestRunSent( TUint32 aSlaveId )
+    {
+    
+    __TRACEFUNC();
+    
+    // Check all remote testcases
+    TInt caseCount = iTestCases.Count(); 
+    CRemoteTestCase* testCase = NULL;
+    for( TInt caseInd = 0; caseInd < caseCount; caseInd++ )
+        {
+        if( iTestCases[caseInd]->Type() == CTestCase::ECaseRemote )
+            {
+            testCase = ( CRemoteTestCase* )iTestCases[caseInd];
+            
+            if( testCase->iRemoteState != CRemoteTestCase::ECaseRunSent )
+                {
+                continue;
+                }
+            if( testCase->iSlaveId == aSlaveId )
+                {
+                return testCase;
+                }
+            }
+        }
+    
+    return NULL;
+        
+    }       
+  
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRemoteTest
+
+     Description: Get remote test case from slave array.
+
+     Parameters:    TUint32 aSlaveId: in: Slave id for testcase
+     
+     Return Values: TCaseInfo*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteTestCase* CTestCombiner::GetRunningRemoteTest( TUint32 aSlaveId )
+    {
+    
+    __TRACEFUNC();
+    
+    // Check all remote testcases
+    TInt caseCount = iTestCases.Count(); 
+    CRemoteTestCase* testCase = NULL;
+    for( TInt caseInd = 0; caseInd < caseCount; caseInd++ )
+        {
+        if( ( iTestCases[caseInd]->Type() == CTestCase::ECaseRemote ) &&
+            ( iTestCases[caseInd]->State() == CTestCase::ETestCaseRunning ) )
+            {
+            testCase = ( CRemoteTestCase* )iTestCases[caseInd];
+            
+            if( ( testCase->iRemoteState != CRemoteTestCase::ECaseRunSent ) &&
+                ( testCase->iRemoteState != CRemoteTestCase::ECaseRunning ) && 
+                ( testCase->iRemoteState != CRemoteTestCase::ECaseCancelled ))
+                {
+                //User::Leave( KErrGeneral ); 
+                continue;                       
+                }
+                
+            if( testCase->iSlaveId == aSlaveId )
+                {
+                return testCase;
+                }
+            }
+        }
+    
+    return NULL;
+        
+    }   
+
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRemoteTestSlave
+
+     Description: Get remote test case running on slave
+
+     Parameters:    TUint32 aSlaveDevId: in: Slave id for testcase
+     
+     Return Values: CRemoteTestCase*: running/runned testcase
+                    NULL: Testcase with aTestId not running/runned 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteTestCase* CTestCombiner::GetRemoteRunningTestOnSlave( 
+                                                    TUint32 aSlaveDevId )
+    {
+    
+    __TRACEFUNC();
+    
+    // Check all remote testcases
+    TInt caseCount = iTestCases.Count(); 
+    CRemoteTestCase* testCase = NULL;
+    for( TInt caseInd = 0; caseInd < caseCount; caseInd++ )
+        {
+        if( ( iTestCases[caseInd]->Type() == CTestCase::ECaseRemote ) &&
+            ( iTestCases[caseInd]->State() == CTestCase::ETestCaseRunning ) )
+            {
+            testCase = ( CRemoteTestCase* )iTestCases[caseInd];
+            if( DEVID( testCase->iSlaveId ) == DEVID( aSlaveDevId ) )
+                {
+                return testCase;
+                }
+            }
+        }
+    
+    return NULL;
+        
+    }   
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetRemoteTestSlave
+
+     Description: Gets a correct CRemoteSendReceive object on slave with
+                  aSlaveId.
+
+     Parameters:    TUint32 aSlaveId: in: Slave id CRemoteSendReceive object
+     
+     Return Values: CRemoteSendReceive*: Current CRemoteSendReceive object.
+                    NULL: CRemoteSendReceive object do not exist or found.
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteSendReceive* CTestCombiner::GetRemoteSendReceive( TUint32 aSlaveId )
+    {
+    __TRACEFUNC();
+    
+    for( TInt sr = 0; sr < iSendReceive.Count(); sr++ )
+        {
+        if( iSendReceive[sr]->iSlaveId == aSlaveId )
+            {
+            return iSendReceive[sr];
+            }
+        }
+
+    return NULL;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetSlave
+
+     Description: Get remote slave.
+
+     Parameters:    TUint32 aSlaveId: in: Slave id 
+     
+     Return Values: CSlaveInfo*: reserved slave
+                    NULL: slave with aSlaveId not reserved 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CSlaveInfo* CTestCombiner::GetSlave( TUint32 aSlaveId )
+    {
+    
+    __TRACEFUNC();
+    
+    TInt count = iSlaveArray.Count();
+    for( TInt index = 0; index < count; index++ )
+        {
+        if( DEVID( iSlaveArray[index]->iSlaveDevId ) == DEVID( aSlaveId) )
+            {
+            return iSlaveArray[index];
+            }
+        }
+    
+    return NULL;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: GetSlave
+
+     Description: Get remote slave.
+
+     Parameters:    TDesC& aSlaveName: in: Slave name 
+     
+     Return Values: CSlaveInfo*: reserved slave
+                    NULL: slave with aSlaveId not reserved 
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CSlaveInfo* CTestCombiner::GetSlave( TDesC& aSlaveName )
+    {
+    
+    __TRACEFUNC();
+
+    TInt count = iSlaveArray.Count();
+    for( TInt index = 0; index < count; index++ )
+        {
+        if( iSlaveArray[index]->iName == aSlaveName )
+            {
+            return iSlaveArray[index];
+            }
+        }
+    
+    return NULL;
+    
+    }        
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: StartTestL
+
+     Description: Start specified test case from testmodule.
+
+     Parameters:    CStartInfo& aStartInfo: in: Test case information
+     
+     Return Values: KErrNone: Testcase started
+                    KErrAlreadyExists: testcase with same aTestId is already 
+                                       running
+                    Any other SymbianOS errorcode
+
+     Errors/Exceptions: Leaves if CTCTestCase::NewL leaves
+                        Leaves if arguments are illegal
+                        Leaves if GetTestModuleL leaves
+                        Leaves if CTestExecution::Open fails
+                        Leaves if CTCTestCase::StartL leaves
+                        Leaves if RPointerArray::Append fails
+
+     Status: Proposal
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestCombiner::StartTestL(  CStartInfo& aStartInfo )
+    {
+    __TRACEFUNC();
+    // Check that TestId is unique.
+    if( GetTest( aStartInfo.iTestId ) != NULL )
+        {
+        // If loop testing is ongoing, allow already defined testid.
+        if( iLoopIsUsed )
+            {
+            __TRACE( KVerbose, ( _L("StartTestL: TestId (%S) already in use. Loop allows already defined TestId"), 
+             &aStartInfo.iTestId ));
+            }
+        else
+            {
+            __TRACE( KError, ( _L("StartTestL: TestId (%S) already in use"), 
+                 &aStartInfo.iTestId ));
+            return KErrAlreadyExists;
+            }
+        }
+
+    __ASSERT_ALWAYS( aStartInfo.iModule.Length() < KMaxFileName, 
+        User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aStartInfo.iIniFile.Length() < KMaxFileName, 
+        User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aStartInfo.iConfig.Length() < KMaxFileName, 
+        User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aStartInfo.iTestId.Length() < KMaxName, 
+        User::Leave( KErrArgument ) );
+
+    __TRACE( KMessage, ( _L("Call GetTestModuleL") ));
+
+    // Load Test Module
+    CTCTestModule* module = NULL;
+    if( (aStartInfo.iModule.Find( KTestScripterName ) != KErrNotFound) 
+        || (aStartInfo.iModule.Find( KPythonScripter ) != KErrNotFound)
+        || (aStartInfo.iModule.Find( KTestCombinerName ) != KErrNotFound) 
+        )
+        {
+        // TestScripter in use. Give config file for parsing STIF Settings.
+        module = GetTestModuleL( aStartInfo.iModule,
+                                 aStartInfo.iIniFile,
+                                 aStartInfo.iConfig );
+        }
+    else
+        {
+        module = GetTestModuleL( aStartInfo.iModule,
+                                 aStartInfo.iIniFile,
+                                 KNullDesC );
+        }
+
+    __TRACE( KMessage, ( _L("Create CTCTestCase") ));
+
+    CTCTestCase* tc = 
+        CTCTestCase::NewL( this, 
+                           aStartInfo.iModule, 
+                           aStartInfo.iTestId, 
+                           aStartInfo.iExpectedResult, 
+                           aStartInfo.iCategory,
+                           aStartInfo.iTestCaseArguments,
+                           module ); //--PYTHON--
+
+    CleanupStack::PushL( tc );
+    
+    //If name of testcase was given, find testcase number
+    if(aStartInfo.iTitle != KNullDesC)
+        {
+        __TRACE(KMessage, (_L("Trying to find test case entitled \"%S\""), &aStartInfo.iTitle));
+        aStartInfo.iCaseNum = -1;
+        TInt ret = module->GetCaseNumByTitle(aStartInfo.iTitle, aStartInfo.iCaseNum);
+        if(ret != KErrNone)
+            {
+            __TRACE(KError, (_L("Couldn't find test case entitled \"%S\". Error %d"), &aStartInfo.iTitle, ret));
+            }
+        else
+            {
+            __TRACE(KMessage, (_L("Found test case entitled \"%S\". Case num %d"), &aStartInfo.iTitle, aStartInfo.iCaseNum));
+            }
+        }
+
+    __TRACE( KMessage, ( _L("Open TestExecution") ));
+    
+    User::LeaveIfError( tc->TestExecution().Open( module->TestServer(), 
+                                                  aStartInfo.iCaseNum, 
+                                                  aStartInfo.iConfig ) );
+
+    __TRACE( KMessage, ( _L("Start testcase runner") ));
+
+      // Enable testcase control before calling RunTestCase
+    tc->StartL();
+
+    __TRACE( KMessage, 
+        ( _L("Start: testid(%S), module(%S), ini(%S), config(%S), case(%d), expect(%d/%d), timeout(%d)"), 
+        &aStartInfo.iTestId, &aStartInfo.iModule, &aStartInfo.iIniFile, 
+        &aStartInfo.iConfig, aStartInfo.iCaseNum, aStartInfo.iExpectedResult, 
+        aStartInfo.iCategory, aStartInfo.iTimeout ));
+
+    TestModuleIf().Printf( KPrintPriLow, _L("Start"),
+        _L("testid(%S), module(%S), ini(%S), config(%S), case(%d), expect(%d)"), 
+         &aStartInfo.iTestId, &aStartInfo.iModule, &aStartInfo.iIniFile, 
+         &aStartInfo.iConfig, aStartInfo.iCaseNum, aStartInfo.iExpectedResult );
+
+    if ( tc->TestCaseArguments().Length() > 0 )
+        {
+        tc->TestExecution().RunTestCase( tc->iResultPckg, tc->TestCaseArguments(), tc->iStatus );
+        }
+    else
+        {
+        tc->TestExecution().RunTestCase( tc->iResultPckg, tc->iStatus );
+        }
+
+    iRunningTests++;
+
+    User::LeaveIfError( iTestCases.Append( tc ) );
+    if( iLoopIsUsed )
+        {
+        User::LeaveIfError( iLoopAllocationArray.Append( tc ) );
+        }
+    CleanupStack::Pop( tc );
+
+    return KErrNone;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: Complete
+
+     Description: Handle completed test case.
+
+     Parameters:    CTCTestCase* aTestCase: in: Test case to complete
+
+     Return Values: None.
+
+     Errors/Exceptions: None
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::Complete( CTestCase* aTestCase, TInt aError )
+    {
+    __TRACEFUNC();
+    
+    if( aError != KErrNone )
+        {
+        iResult = aError;
+        }
+
+    TInt count = iTestCases.Count();
+    TInt i = 0;
+    for(; i < count; i++ )
+        {
+        if( iTestCases[i] == aTestCase )
+            {
+            // Test Case completed
+            __TRACE( KPrint, (  _L( "Complete: %S result: %d, execution result: %d, expected: %d"), 
+                 &aTestCase->TestId(), aTestCase->iResult.iTestResult.iResult, 
+                 aTestCase->iResult.iCaseExecutionResultCode, aTestCase->ExpectedResult()  ));
+            TestModuleIf().Printf( KPrintPriLow, _L("Complete"),
+                _L( "%S results: test(%d) exe(%d) expect(%d)"), 
+                 &aTestCase->TestId(), aTestCase->iResult.iTestResult.iResult,
+                 aTestCase->iResult.iCaseExecutionResultCode, aTestCase->ExpectedResult() );
+            iRunningTests--;
+            break;
+            }
+        }
+    if( i == count )
+        {
+        __TRACE( KError, (_L("CTestCombiner::Complete: Test case not found!!")));
+        }
+
+    // Check if we were waiting this case to complete
+    if( ( iWaitTestCase.Length() > 0 ) && 
+        ( iWaitTestCase == aTestCase->TestId() ) )
+        {
+        // We were waiting this case to complete 
+        // Now we can proceed executing the testcase
+        __TRACE( KMessage, (_L("TestCase was waiting, set runner active")));
+        iTestRunner->SetRunnerActive();
+        iWaitTestCase.Zero();
+        
+     //return; - return removed due to STIF-509 CancelIfError won't work when used together with complete command
+     
+        }
+    else if( aTestCase->Type() == CTestCase::ECaseRemote )
+        {
+        __TRACE( KMessage, (_L("CTestCombiner::Complete: Remote case complete")));
+        // Completed testcase was remote case,
+        // check if slave should be freed
+        CRemoteTestCase* remote = ( CRemoteTestCase* )aTestCase;
+        if( remote->iFreeSlave )
+            {
+            CSlaveInfo* slave = GetSlave( remote->iSlaveId );
+            if( slave )
+                {
+                // Free slave now
+                TRAPD( err, iTestRunner->ExecuteFreeL( slave ) );
+                // Continue if freeing fails
+                if( err == KErrNone )
+                    {
+                    __TRACE( KMessage, (_L("Complete: Freeing slave")));
+                    return;
+                    }
+                else
+                    {
+                    __TRACE( KError, (_L("Complete: Freeing slave failed")));
+                    }
+                }
+            else 
+                {
+                __TRACE( KError, (_L("Complete: Slave not found")));
+                }
+            }
+        }
+
+    // If running test is 0, active scheduler is active and CTestRunner is
+    // ready then stop active scheduler.(Operations continue from 
+    // CTestCombiner::RunTestL() after active scheduler start).
+    if( ( iRunningTests == 0 ) &&
+          iSchedulerActive &&
+        ( iTestRunner->iState == CTestRunner::ERunnerReady ) )
+        {
+        // This was last running testcase, so we can stop 
+        // activescheduler
+        __TRACE( KMessage, (_L("All TestCases completed, stop CActiveScheduler")));
+        CActiveScheduler::Current()->Stop();
+        iSchedulerActive = EFalse;
+        }
+    else 
+        {
+        __TRACE( KMessage, 
+            (_L("CTestCombiner::Complete: %d test cases running"), iRunningTests ));
+        __TRACE( KMessage, 
+            (_L("CTestCombiner::Complete: active %d"), iSchedulerActive ));
+        if(iSchedulerActive)    
+            {             
+            __TRACE( KMessage, 
+                (_L("CTestCombiner::Complete: state %d"), iTestRunner->iState ));
+            }
+        }
+
+    // Checking if user wants to skip the rest of the execution in case of error @js
+    if(iCancelIfError && iSchedulerActive)    
+        {
+        // Cancel event if it was waiting event
+        if(iTestRunner->iEvent.Name() != KNullDesC && iTestRunner->iEvent.Type() == TEventIf::EWaitEvent)
+            {
+            TestModuleIf().CancelEvent(iTestRunner->iEvent, &iTestRunner->iStatus);
+            }
+
+        // Interpret execution result type from returned result
+        TInt executionResult = TFullTestResult::ECaseExecuted; // Ok
+        if( (aTestCase->iResult.iCaseExecutionResultType >= 
+            TFullTestResult::ECaseLeave ))
+            {
+            __TRACE( KMessage, (_L("The test case ended with error!")));
+
+            // Some abnormal execution result type
+            executionResult = iTestCases[i]->iResult.iCaseExecutionResultType;
+            }
+
+         // Check expected execution result type
+        if( executionResult != aTestCase->ExpectedResultCategory() ) 
+            {
+            // expected and returned result types differ
+            __TRACE( KMessage, (_L("The test case has wrong result category!")));
+            // There was an error and we must stop test case execution
+            iFailedTestCase = i;
+            iRunningTests--;
+            __TRACE( KMessage, (_L("Stopping the CActiveScheduler.")));
+            CActiveScheduler::Current()->Stop();
+            iSchedulerActive = EFalse;
+            }
+
+        // Check normal test result if activescheduler is still up & running
+        if( iSchedulerActive )
+            {
+            if( aTestCase->ExpectedResultCategory() == 
+            TFullTestResult:: ECaseExecuted)
+                {
+                // Normal completion, check result
+                if( iTestCases[i]->iResult.iTestResult.iResult != 
+                    iTestCases[i]->ExpectedResult() )
+                    { 
+                    __TRACE( KMessage, (_L("Result category is not what was expected!")));
+                    // There was an error and we must stop test case execution
+                    iFailedTestCase = i;
+                    iRunningTests = 0; //The whole test is stopped. Reset value of running tests.
+                    //This line caused that variable value to be -1. Test could not finish. //iRunningTests--;
+                    __TRACE( KMessage, (_L("Stopping the CActiveScheduler.")));
+                    CActiveScheduler::Current()->Stop();
+                    iSchedulerActive = EFalse;
+                    }
+                }
+            else 
+                {
+                // Abnormal completion, i.e. panic, leave, exception or timeout
+                if( aTestCase->iResult.iCaseExecutionResultCode != 
+                    aTestCase->ExpectedResult())
+                    {
+                    __TRACE( KMessage, (_L("The test case has abnormal completion!")));
+                    // There was an error and we must stop test case execution
+                    iFailedTestCase = i;
+                    iRunningTests--;
+                    __TRACE( KMessage, (_L("Stopping the CActiveScheduler.")));
+                    CActiveScheduler::Current()->Stop();
+                    iSchedulerActive = EFalse;
+                    }
+                }
+            }
+        }
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: NotifyEvent
+
+     Description: Asynchronous event command interface
+     
+     Check requested events and send unset to first requested
+     
+     Parameters: TEventIf& aEvent: in: Event command 
+                TRequestStatus& aStatus: in: TRequestStatus used in 
+                                                          asynchronous command 
+     
+     Return Values: ETrue: asynchronous command given
+                          EFalse: asyncronous command not given
+
+     Errors/Exceptions: None
+     
+     Status: Proposal
+     
+-------------------------------------------------------------------------------
+*/
+TBool CTestCombiner::UnsetEvent( TEventIf& aEvent, 
+                                 TRequestStatus& aStatus )
+    {
+    
+    __TRACE( KMessage, ( _L("CTestCombiner::NotifyEvent")));    
+    
+    // First check TestCombiner events
+    TInt eventCount = iEventArray.Count();
+    for( TInt i = 0; i < eventCount; i++ )
+        {
+        if( aEvent.Name() == iEventArray[i]->Name() )
+            {
+            __TRACE( KMessage, (  
+                _L( "Set unset pending for testcombiner's %S event"),  
+                    &aEvent.Name()  ));
+            iEventArray[i]->SetRequestStatus( &aStatus );
+            return ETrue;
+            }
+        }
+    
+    // Check all local testcases
+    TInt caseCount = iTestCases.Count(); 
+    TInt eventInd;
+    CTCTestCase* testCase = NULL;
+    for( TInt caseInd = 0; caseInd < caseCount; caseInd++ )
+        {
+        if( iTestCases[caseInd]->Type() == CTestCase::ECaseLocal )
+            {
+            testCase = ( CTCTestCase* )iTestCases[caseInd];
+            eventCount = testCase->EventArray().Count();
+             
+             // Check all requested events
+            for( eventInd = 0; eventInd < eventCount; eventInd++)
+                {
+                const TName& eventName = 
+                    testCase->EventArray()[eventInd]->Event().Name();
+                if( eventName == aEvent.Name() )
+                    {
+                      // Event request is pending, send control command
+                    iEvent.Copy( aEvent );
+                    __TRACE( KMessage, (  
+                        _L( "Set unset pending for client's %S event"),  
+                        &aEvent.Name()  ));
+                    testCase->TestExecution().NotifyEvent( iEventPckg, 
+                                                             aStatus );
+                    return ETrue;
+                    }
+                }
+            }
+        }
+     
+    return EFalse;
+     
+    }
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: ReceiveResponse
+
+     Description: Handles responce received from slave
+  
+     Parameters:    None
+     
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::ReceiveResponse( TDesC& aMsg )
+    {
+    
+    __TRACEFUNC();
+    
+    TBool continueTask = ETrue;
+    TRAPD( err, continueTask = iTestRunner->ReceiveResponseL( aMsg ) );
+        
+    // We start receiver again, even in error situation
+    iRemoteReceiver->Start();
+
+    if( err != KErrNone )
+        {
+        __TRACE( KError, ( _L("CTestCombiner::ReceiveResponse ERROR")));
+        iResult = err;
+        if( iTestRunner->IsActive() )
+            {
+            iTestRunner->Cancel();
+            }
+        else
+            {
+            iTestRunner->CancelTestCases();
+            }
+        return;
+        }
+        
+    if( continueTask && !iTestRunner->IsActive() )
+        {
+        iTestRunner->SetRunnerActive();
+        }
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: RemoteTimeout
+
+     Description: Handles timeouts.
+  
+     Parameters:    None
+     
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::RemoteTimeout()
+    {
+    
+    __TRACEFUNC();
+    
+    iResult = KErrTimedOut;
+    if( iTestRunner->IsActive() )
+        {
+        __TRACE( KError, (_L("Remote timeout, Cancel runner")));
+        iTestRunner->Cancel();
+        }
+    else
+        {
+        __TRACE( KError, (_L("Remote timeout, Cancel test cases")));
+        iTestRunner->CancelTestCases();
+        }
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: ExecuteMeasurementL
+
+     Description: Executes measurement script line.
+  
+     Parameters: CStifItemParser* aItem: in: parsed line
+     
+     Return Values: TBool: in no error ETrue returned
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::ExecuteMeasurementL( CStifItemParser* aItem )
+    {
+    __TRACEFUNC();
+    
+     __TRACEFUNC();
+    TPtrC type;
+    TPtrC command;
+
+    // Get command
+    if( aItem->GetNextString( command ) != KErrNone )
+        {
+        __TRACE( KError, ( 
+            _L( "Unknown argument for 'measurement' command" ) ) );
+        User::Leave( KErrArgument ); // Error in parsing => Leave
+        }
+    // Get name
+    if( aItem->GetNextString( type ) != KErrNone )
+        {
+        __TRACE( KError, ( 
+            _L( "Unknown argument for 'measurement' type" ) ) );
+        User::Leave( KErrArgument ); // Error in parsing => Leave
+        }
+
+    // Verify measurement type
+    if( !( type == KParamMeasurement01 ||
+                type == KParamMeasurement02 ||
+                type == KParamMeasurement03 ||
+                type == KParamMeasurement04 ||
+                type == KParamMeasurement05 ||
+                type == KParamMeasurementBappea ) )
+
+        {
+        __TRACE( KError, ( 
+            _L( "Unknown measurement type:[%S]" ), &type ) );
+        User::Leave( KErrArgument ); // Error in types => Leave
+        }
+
+    // Verify command
+   if( command == _L( "start" ) )
+        {
+        // START measurement's process
+        __TRACE( KMessage, ( _L( "Start 'measurement' with '%S'"), &type ) );
+        StartMeasurementL( type, aItem );
+        }
+    else if( command == _L( "stop" ) )
+        {
+        // STOP measurement's process
+        __TRACE( KMessage, ( _L( "'Stop 'measurement' with '%S'"), &type ) );
+        StopMeasurementL( type );
+        }
+    else
+        {
+        __TRACE( KError, ( 
+            _L( "Unknown command for 'measurement' command:[%S] or type:[%S]" ), &command, &type ) );
+        User::Leave( KErrArgument ); // Error in commands => Leave
+        }
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: StartMeasurementL
+
+     Description: 
+  
+     Parameters: const TDesC& aType: in: Plugin type.
+                 CStifItemParser* aItem: in: Item object for parsing.
+
+     Return Values: None.
+
+     Errors/Exceptions: Leaves is bappea start or timed operation fails.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::StartMeasurementL( const TDesC& aType,
+                                           CStifItemParser* aItem )
+    {
+    __TRACEFUNC();
+
+    CSTIFTestMeasurement* testMeasurement = NULL;
+
+    // Get Measurement configuration info
+    TPtrC configurationInfo( KNullDesC() );
+    if( aItem->Remainder( configurationInfo ) != KErrNone )
+        {
+        __TRACE( KInit, ( 
+            _L( "Using default path and file name for measurement configure" ) ) );
+        } 
+
+    if( aType == KParamMeasurement01 )
+        {
+        testMeasurement = CSTIFTestMeasurement::NewL( 
+                    this, 
+                    CSTIFTestMeasurement::KStifMeasurementPlugin01,
+                    configurationInfo );
+        }
+    else if( aType == KParamMeasurement02 )
+        {
+        testMeasurement = CSTIFTestMeasurement::NewL( 
+                    this, 
+                    CSTIFTestMeasurement::KStifMeasurementPlugin02,
+                    configurationInfo );
+        }
+    else if( aType == KParamMeasurement03 )
+        {
+        testMeasurement = CSTIFTestMeasurement::NewL( 
+                    this, 
+                    CSTIFTestMeasurement::KStifMeasurementPlugin03,
+                    configurationInfo );
+        }
+    else if( aType == KParamMeasurement04 )
+        {
+        testMeasurement = CSTIFTestMeasurement::NewL( 
+                    this, 
+                    CSTIFTestMeasurement::KStifMeasurementPlugin04,
+                    configurationInfo );
+        }
+    else if( aType == KParamMeasurement05 )
+        {
+        testMeasurement = CSTIFTestMeasurement::NewL( 
+                    this, 
+                    CSTIFTestMeasurement::KStifMeasurementPlugin05,
+                    configurationInfo );
+        }
+    else if( aType == KParamMeasurementBappea )
+        {
+        testMeasurement = CSTIFTestMeasurement::NewL( 
+                    this, 
+                    CSTIFTestMeasurement::KStifMeasurementBappeaProfiler,
+                    configurationInfo );
+        }
+    else
+        {
+        __TRACE( KError, ( _L( "Unknown plugin[%S] for 'measurement'" ), &aType ) );
+        User::Leave( KErrArgument );
+        }
+
+   // Start test measurement
+    TInt start_ret( KErrNone );
+    start_ret = testMeasurement->Start();
+    if( start_ret != KErrNone )
+        {
+        delete testMeasurement;
+        __TRACE( KError, ( 
+            _L( "CTestCombiner::StartMeasurementL(): Measurement Start() fails:[%d]" ), start_ret ) );
+        User::Leave( start_ret );
+        }
+
+    TTestMeasurement* object = new (ELeave) TTestMeasurement();
+    object->iName = aType;
+    object->iMeasurement = testMeasurement;
+
+    // Array for handling test measurement between different objects
+    TInt ret = iTestMeasurementArray.Append( object );
+    if( ret != KErrNone )
+        {
+        delete object;
+        __TRACE( KError, ( 
+            _L( "CTestCombiner::StartMeasurementL(): iTestMeasurementArray.Append fails:[%d]" ), ret ) );
+        User::Leave( ret );
+        }
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: StopMeasurementL
+
+     Description: Stops test measurement.
+  
+     Parameters: None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::StopMeasurementL( const TDesC& aType )
+    {
+    __TRACEFUNC();
+
+    TInt count = iTestMeasurementArray.Count();
+    for( TInt i = 0; i < count; i++ )
+        {
+        if( iTestMeasurementArray[i]->iName == aType )
+            {
+            // Found measurement module, stop
+            iTestMeasurementArray[i]->iMeasurement->Stop();
+            // Delete data
+            delete iTestMeasurementArray[i];
+            // Remove pointer to deleted data(Append())
+            iTestMeasurementArray.Remove( i );
+            // iTestMeasurementArray can contain only one type of measurement
+            // so we can break when type is removed.
+            break;
+            }
+        }
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestCombiner
+
+     Method: AppendTestResultToResultDes
+
+     Description: Append to TC's result description (if possible due to length) 
+                  limitation provided text in [] brackets.
+  
+     Parameters: None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CTestCombiner::AppendTestResultToResultDes(TDes& aResultDescr, const TDesC& aTestCaseResultDescr)
+    {
+    if(aTestCaseResultDescr != KNullDesC)
+        {
+        _LIT(KAdditionalInfo, " [%S]");
+        TInt len = aResultDescr.Length() + KAdditionalInfo().Length() + aTestCaseResultDescr.Length();
+
+        if(len > KStifMaxResultDes)
+            {
+            len = KStifMaxResultDes - aResultDescr.Length() - KAdditionalInfo().Length();
+            if(len > 0)
+                {
+                TPtrC descr = aTestCaseResultDescr.Mid(0, len); 
+                aResultDescr.AppendFormat(KAdditionalInfo, &descr);
+                }
+            }
+        else
+            {
+            aResultDescr.AppendFormat(KAdditionalInfo, &aTestCaseResultDescr);
+            }
+        }
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+    Class: CTestCombiner
+
+    Method: GetIndexForNewTestModuleController
+
+    Description: Returns new index for test module controller.
+                 This number is appended to module controller name.
+                 This method is used when option to run every test case in 
+                 separate process is set to on.
+
+    Parameters: None
+    
+    Return Values: None
+
+    Errors/Exceptions: None
+
+    Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestCombiner::GetIndexForNewTestModuleController(void)
+    {
+    return iIndexTestModuleControllers++;
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+    DESCRIPTION
+
+    This module contains the implementation of CTestRunner class 
+    member functions. CTestRunner is used to execute TestCombiner testcase by 
+    CTestCombiner.
+
+-------------------------------------------------------------------------------
+*/
+// MACROS
+#ifdef LOGGER
+#undef LOGGER
+#endif
+#define LOGGER iTestCombiner->iLog
+
+// ================= MEMBER FUNCTIONS =========================================
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: CTestRunner
+
+     Description: Default constructor
+
+     C++ default constructor can NOT contain any code, that
+     might leave.
+     
+     Parameters: CTestCombiner* aTestCombiner: in: Backpointer to CTestCombiner
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+CTestRunner::CTestRunner( CTestCombiner* aTestCombiner ): 
+    CActive(  CActive::EPriorityLow ), // Executed with lowest priority 
+    iState( ERunnerIdle ),
+    iTestCombiner( aTestCombiner )
+    {
+    CActiveScheduler::Add( this );
+    __TRACEFUNC();
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ConstructL
+
+     Description: Symbian OS second phase constructor
+
+     Symbian OS default constructor can leave.
+
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::ConstructL()
+    {
+    TInt ret;
+    
+    ret = iPauseTimer.CreateLocal();
+    if(ret != KErrNone)
+        {
+        __TRACE( KError, (_L("Unable to create RTimer: iPauseTimer [%d] "), ret));
+        User::Leave(ret);
+        }
+        
+    ret = iPauseCombTimer.CreateLocal();
+    if(ret != KErrNone)
+        {
+        __TRACE( KError, (_L("Unable to create RTimer: iPauseCombTimer [%d] "), ret));
+        User::Leave(ret);
+        }
+    
+    iRemoteTimer = CRemoteTimer::NewL( iTestCombiner );
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: NewL
+
+     Description: Two-phased constructor.
+          
+     Parameters: CTestCombiner* aTestCombiner: in: Backpointer to CTestCombiner
+
+     Return Values: CTestRunner*: new object
+
+     Errors/Exceptions: Leaves if new or ConstructL leaves
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+
+CTestRunner* CTestRunner::NewL( CTestCombiner* aTestCombiner )
+    {
+    CTestRunner* self = new (ELeave) CTestRunner( aTestCombiner );
+     
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ~CTestRunner
+
+     Description: Destructor
+     
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/     
+
+CTestRunner::~CTestRunner()
+    {
+    __TRACEFUNC();
+    Cancel();
+    
+    delete iRemoteTimer;
+    iRemoteTimer = 0;
+    
+    delete iLine;
+    iLine = 0;
+    
+    iPauseTimer.Close();
+    
+    iPauseCombTimer.Close();
+         
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: RunL
+
+     Description: Derived from CActive, handles testcase execution.
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::RunL()
+    {
+    __TRACEFUNC();
+    __TRACE( KMessage, (_L("CTestRunner::RunL: [%d] "), iStatus.Int() ));
+     
+    User::LeaveIfError( iStatus.Int() );
+
+    if( ( iTestCombiner == NULL ) || 
+        ( iTestCombiner->iSectionParser == NULL ) )
+        {
+        User::Leave( KErrGeneral );
+        }
+        
+    TBool continueTask = EFalse;
+    
+    // Check if there is still some time for combiner pause and we need to 
+    // continue pausing
+    if(iPauseCombRemainingTime > 0)
+        {           
+        // Maximum time for one RTimer::After request                   
+        TInt maximumTime = KMaxTInt / 1000;                       
+        
+        __TRACE( KMessage, (_L("CTestRunner::RunL: Going to reissue PauseCombiner request ") ) );           
+        __TRACE( KMessage, (_L("CTestRunner::RunL: iRemainingTimeValue = %d"), iPauseCombRemainingTime ) );        
+        
+        if( iPauseCombRemainingTime < maximumTime )
+            {                           
+            iPauseCombTimer.After(iStatus, (iPauseCombRemainingTime * 1000));
+            iPauseCombRemainingTime = 0;
+            }
+        else
+            {            
+            iPauseCombRemainingTime -= maximumTime;
+            iPauseCombTimer.After(iStatus, (maximumTime * 1000));        
+            }     
+            
+        SetActive();
+        return;
+        }     
+ 
+    // Handling runner states
+    switch( iState )
+        {
+        case ERunnerWaitTimeout:
+            {
+            __TRACE( KMessage, (_L("Resume %S"), &iPausedTestCase));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriExec, 
+                KExecute, _L("Resume %S"), &iPausedTestCase);
+             // Get running testcase identified with testid
+            CTestCase* testCase = iTestCombiner->GetRunningTest( iPausedTestCase ); 
+            if( testCase == NULL ) User::Leave( KErrNotFound );
+            iPausedTestCase.Zero();
+            if( testCase->Type() == CTestCase::ECaseLocal )
+                {
+                CTCTestCase* localTestCase = ( CTCTestCase* )testCase;
+                // Resume execution
+                User::LeaveIfError( localTestCase->TestExecution().Resume() );
+                continueTask = ETrue;
+                }
+            else // ECaseRemote
+                {
+                CRemoteTestCase* remoteTestCase = ( CRemoteTestCase* )testCase;
+                // Resume execution
+                if( ExecuteRemoteTestCtlL( NULL, 
+                                           remoteTestCase, 
+                                           TTCKeywords::EResume ) )
+                    {
+                    continueTask = ETrue;
+                    }
+                }               
+            }
+            break;
+        case ERunnerWaitUnset:
+            iState = ERunnerIdle;
+
+            // Check Unset event 
+            if( !CheckUnsetEvent() )
+                {
+                // Got event and unset has not completed 
+                // Should never come here
+                User::Panic( KTestRunner, KErrGeneral );
+                 }
+            break;
+                         
+        case ERunnerRunning:
+            {
+            iState = ERunnerIdle;
+            
+            // Get next execution line from configuration section
+            iEndLoopStartPos = iTestCombiner->iSectionParser->GetPosition();
+            TPtrC line;
+            if( iTestCombiner->iSectionParser->GetNextLine( line ) == KErrNone )
+                {
+                // Got new execution line 
+                __TRACE( KMessage, (_L("CTestRunner got line")));
+        
+                CStifItemParser* item = PreprocessLineL( line );
+            
+                if( item )
+                    {     
+                     // Got new execution line 
+                    CleanupStack::PushL( item ); 
+                      
+                    // Execute script line 
+                    if( ExecuteLineL( item ) )
+                        {
+                          __TRACE( KMessage, (_L("RunL: continueTask")));
+                         // Set CTestRunner active again to perform 
+                         // next execution line
+                         // from testcase section 
+                        continueTask = ETrue;
+                        }
+                    CleanupStack::PopAndDestroy( item );
+                    }
+                }
+            else 
+                {
+                // No more execution lines in testcase section
+                __TRACE( KMessage, 
+                    (_L("CTestRunner::RunL: Testcase script done (%d running)"), 
+                        iTestCombiner->iRunningTests));
+ 
+                if( ( iTestCombiner->iRunningTests == 0 ) &&
+                    iTestCombiner->iSchedulerActive )
+                    {
+                    __TRACE( KMessage, 
+                        (_L("RunL: All TestCases done, stop CActiveScheduler")));                     
+                    CActiveScheduler::Current()->Stop();
+                    iTestCombiner->iSchedulerActive = EFalse;
+                    }
+                // Now testcase section is executed, 
+                // so CTestRunner has done its job and stops
+                iState = ERunnerReady;
+
+                //If we're inside loop, then we have error
+                if(iTestCombiner->iLoopIsUsed)
+                    {
+                    __TRACE(KError, (_L("Endloop keyword not found. Cannot finish test case properly.")));
+                    iTestCombiner->iResult = KErrGeneral;
+                    }
+                }
+            }
+            break;
+        case ERunnerAllocate:
+        case ERunnerFree:
+        case ERunnerRemote:
+        default:
+            __TRACE( KError, 
+                (_L("CTestRunner::RunL: Entered in illegal state(%d)"), iState ));
+            User::Panic( KTestRunner, KErrGeneral );  
+            break;
+        }   
+    if( continueTask )
+        {
+        SetRunnerActive();
+        }
+           
+    }
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: DoCancel
+
+     Description: Derived from CActive handles the Cancel
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::DoCancel()
+    {
+    __TRACEFUNC();
+    __TRACE( KMessage, (_L("CTestRunner::DoCancel")));
+    iTestCombiner->TestModuleIf().Printf( KPrintPriLow, _L("Runner"), _L("DoCancel"));
+    
+    iPauseCombTimer.Cancel();
+    
+    switch( iState )
+        {
+        case ERunnerWaitTimeout:
+            iPauseTimer.Cancel();
+            break;
+        case ERunnerWaitUnset:
+            break;             
+        case ERunnerRunning:
+            break;
+        case ERunnerAllocate:
+        case ERunnerFree:
+        case ERunnerRemote:
+            // Cancel remote test cases
+            break;
+        default:
+            __TRACE( KError, 
+                (_L("CTestRunner::DoCancel: Entered in illegal state(%d)"), iState ));
+            User::Panic( KTestRunner, KErrGeneral );  
+            break;
+        }                  
+    
+    // Cancel all testcases
+    CancelTestCases();
+         
+    iState = ERunnerCancel;
+      
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: RunError
+
+     Description: Derived from CActive handles errors from active handler.
+  
+     Parameters:    TInt aError: in: error from CActive
+     
+     Return Values: KErrNone: success
+
+     Errors/Exceptions: None.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TInt CTestRunner::RunError( TInt aError )
+    {
+    __TRACEFUNC();
+    __TRACE( KMessage, (_L("CTestRunner::RunError %d"), aError));
+        
+    if ( iRunErrorMessage.Length() != 0 )
+    	{
+    	iTestCombiner->TestModuleIf().Printf( KPrintPriLow, _L("Runner"), 
+	            _L("RunError : %S"), &iRunErrorMessage );  
+	    iRunErrorMessage = KNullDesC;
+    	}
+    else
+    	{
+    	iTestCombiner->TestModuleIf().Printf( KPrintPriLow, _L("Runner"), 
+	            _L("RunError"));        	
+    	}    
+    
+    iState = ERunnerError;
+        
+    // Return error from here
+    iTestCombiner->iResult = aError;
+
+    CancelTestCases();
+    return KErrNone;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: PreprocessLineL
+
+     Description: Preprocesses script line
+  
+     Parameters:  TPtrC& line: in: script line
+                  CStifItemParser*& aItem: out: New CStifItemParser for script
+                  line.
+                    
+     Return Values: HBufC* pointer if new memory that has been allocated
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/        
+CStifItemParser* CTestRunner::PreprocessLineL( TDesC& line )
+    {
+    
+    CStifItemParser* item = NULL;
+    TPtrC tmp;
+    TInt len = 0;
+        
+    // Decide how long buffer should be allocated
+    if( line.Length() < KMaxName/2 )
+        {
+        len = KMaxName;
+        }
+    else 
+        {
+        len = line.Length() + KMaxName;
+        }
+    delete iLine;
+    iLine = 0;
+    iLine = HBufC::NewL( len );
+    TPtr parsedLine( iLine->Des() );
+    len = 0;
+    
+    item = CStifItemParser::NewL( line, 0, line.Length() );
+    CleanupStack::PushL( item);
+    
+    TInt ret = item->GetString( _L(""), tmp );
+    while( ret == KErrNone )
+        {
+        len += CheckDefined( tmp );
+        if( ( parsedLine.Length() + tmp.Length() + 1 ) > parsedLine.MaxLength() )
+            {
+            // Allocate bigger buffer
+            HBufC* tmpBuf = HBufC::NewL( parsedLine.MaxLength() + KMaxName );
+            CleanupStack::PushL( tmpBuf );
+            TPtrC ptr( iLine->Des() );
+            parsedLine.Set( tmpBuf->Des() );
+            parsedLine.Copy( ptr );
+            delete iLine;
+            iLine = tmpBuf;
+            CleanupStack::Pop( tmpBuf );
+            } 
+        parsedLine.Append( tmp );        
+        parsedLine.Append( _L(" ") );        
+        ret = item->GetNextString( tmp );
+        }
+        
+    CleanupStack::PopAndDestroy( item );
+    
+    item = CStifItemParser::NewL( parsedLine, 0, parsedLine.Length() );
+    
+    return item;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: CheckDefined
+
+     Description: Check if aWord is some defined word
+  
+     Parameters:  TPtrC& aWord: inout: Parsed word, defined or original returned
+
+     Return Values: TInt: Length difference between new and old word
+
+     Errors/Exceptions: None.
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestRunner::CheckDefined( TPtrC& aWord )
+    {
+    TInt len = 0;
+
+    // KLoopCounter word changing to current loop count value.
+    if( aWord == KLoopCounter )
+        {
+        iLoopCounterDes.Zero();
+        iLoopCounterDes.AppendNum( iLoopCounter );
+        len = iLoopCounterDes.Length() - aWord.Length();
+        aWord.Set( iLoopCounterDes );
+        return len;
+        }
+
+    TInt count = iTestCombiner->iDefined.Count();
+    for( TInt i = 0; i < count; i++ )
+        {
+        if( iTestCombiner->iDefined[i]->Name() == aWord )
+            { 
+            len = iTestCombiner->iDefined[i]->Value().Length() - aWord.Length();
+            aWord.Set( iTestCombiner->iDefined[i]->Value() );
+            break;
+            }
+        }
+    return len;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteLineL
+
+     Description: Executes script line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    TTCKeywords::TKeywords aKeyword: in: keyword index
+
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteLineL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgUnknownKeyword, "Unknown or illegal keyword %S" );
+    _LIT( KErrMsgMeasurementInvalidArgument, "Measurement : Invalid argument" );
+    TBool continueTask = ETrue;
+    TPtrC tmp;
+
+    TPtrC keywordItem;
+    // Get first word from line, i.e. keyword
+    User::LeaveIfError( aItem->GetString( _L(""), keywordItem ) );
+    // Parse keyword
+    TInt keyword = TTCKeywords::Parse( keywordItem, TTCKeywords::Keyword );
+        
+    switch( keyword )
+        {
+        // Test case execution control cases
+        case TTCKeywords::EPauseCombiner:
+        	continueTask = ExecuteCombinerPauseL( aItem );
+        	break;
+        case TTCKeywords::ERun:
+            continueTask = ExecuteRunL( aItem );
+            break;
+        case TTCKeywords::EPause:
+        case TTCKeywords::EComplete:
+        case TTCKeywords::ECancel:
+        case TTCKeywords::EResume:
+            continueTask = ExecuteTestCtlL( aItem, (TTCKeywords::TKeywords)keyword );
+            break;
+
+        // Event control cases
+        case TTCKeywords::ESet:
+              continueTask = ExecuteEventSetL( aItem );
+            break;
+        case TTCKeywords::EUnset:
+              continueTask = ExecuteEventUnsetL( aItem );
+            break;
+        case TTCKeywords::ERequest:
+        case TTCKeywords::EWait:
+        case TTCKeywords::ERelease:
+            continueTask = ExecuteEventCtlL( aItem, (TTCKeywords::TKeywords)keyword );
+            break;
+        case TTCKeywords::EPrint:
+            {
+            TName buf;
+            while( aItem->GetNextString( tmp ) == KErrNone )
+                {
+                if( buf.Length() + tmp.Length() >= buf.MaxLength() )
+                    {
+                    break;
+                    }
+                buf.Append( tmp );
+                buf.Append( _L(" ") );
+                }
+
+            __TRACE( KMessage, (_L("Test: %S"), &buf ));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriHigh, 
+                _L("Test"), 
+                _L("%S"), &buf);
+           }
+           break;
+        case TTCKeywords::EAllocate:
+            continueTask = ExecuteAllocateL( aItem );
+            break;
+        case TTCKeywords::EFree:
+            continueTask = ExecuteFreeL( aItem );
+            break;
+        case TTCKeywords::ERemote:
+            continueTask = ExecuteRemoteL( aItem );
+            break;
+        case TTCKeywords::ETimeout:
+        case TTCKeywords::EPriority:
+            // not used here
+            break;
+        case TTCKeywords::ECancelIfError:
+            // @js
+            iTestCombiner->iCancelIfError = ETrue;
+            break;
+        case TTCKeywords::EMeasurement:
+            TRAPD( retErr, iTestCombiner->ExecuteMeasurementL( aItem ) );
+        	if ( retErr == KErrArgument )
+        		{
+        		iRunErrorMessage = KErrMsgMeasurementInvalidArgument;
+        		}
+        	if ( retErr != KErrNone )
+        		{
+        		User::Leave( retErr );
+        		}
+            break;
+        case TTCKeywords::ELoop:
+            ExecuteLoopL( aItem );
+            iTestCombiner->iLoopIsUsed = ETrue;
+            break;
+        case TTCKeywords::EEndLoop:
+            continueTask = ExecuteEndLoopL();
+            break;
+        case TTCKeywords::ETitle:
+            // title has been handled already, this is duplicate
+        default:
+            {
+              __TRACE( KError, (_L("Unknown or illegal keyword") ) );
+            // Unknown or illegal keyword
+            iRunErrorMessage.Format( KErrMsgUnknownKeyword, &keywordItem );
+            User::Leave( KErrGeneral );
+            }
+            break;
+        }
+
+    __TRACE( KMessage, (_L("RunL: TestCase line executed")));
+
+    return continueTask;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRunL
+
+     Description: Executes run line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRunL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgCaseRunError, "Run : %S[case=%d] run error" );
+    __TRACE( KMessage, (_L("Run")));
+    iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, _L("Run"));
+    
+    CStartInfo* startInfo = CStartInfo::NewL();
+    CleanupStack::PushL( startInfo );
+
+    ParseRunParamsL( aItem, *startInfo );
+             
+    // Start new case with configurations parsed above                
+    
+    iRunErrorMessage.Format( KErrMsgCaseRunError, &startInfo->iModule, startInfo->iCaseNum );
+    User::LeaveIfError( 
+        iTestCombiner->StartTestL( *startInfo ) );
+    iRunErrorMessage = KNullDesC;
+    
+    CleanupStack::PopAndDestroy( startInfo );
+        
+    return ETrue;
+    
+}
+
+ 
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ParseRunParamsL
+
+     Description: Parses run parameters
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CStartInfo& aStartInfo: out: Parsed information
+     
+     Return Values: None
+     
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::ParseRunParamsL( CStifItemParser* aItem,
+                                    CStartInfo& aStartInfo )
+    {
+    _LIT( KErrMsgRunTestmoduleNameNotDefined, "Run : Testmodule name is not defined " );
+    _LIT( KErrMsgRunCfgFileNotDefined, "Run : Testmodule configuration file is not defined" );
+    _LIT( KErrMsgRunTestcaseNumberNotDefined, "Run : Testcase number is not defined or has invalid value" );
+    _LIT( KErrMsgRunCfgFileNameToLong, "Run : TestScripter test case file(config)'s name is too long. Current length[%d], allowed max length[%d]. Cannot continue" );
+    _LIT( KErrMsgRunInvalidExpectValue, "Run : Invalid expected result value" );
+    _LIT( KErrMsgRunUnknownOrIllegalCategory, "Run : Unknown or illegal result category" );
+    _LIT( KErrMsgRunInvalidTimeoutValue, "Run: Invalid testcase timeout value" );
+    _LIT( KErrMsgRunUnknowOrIllegalKeyword, "Run: Unknown or illegal keyword %S" );
+    
+    TPtrC tmp;
+    TInt ret = KErrNone;
+
+    // Get mandatory run arguments
+    // Testmodule name
+    ret = aItem->GetNextString( tmp );
+    if ( ret != KErrNone )
+    	{
+    	iRunErrorMessage = KErrMsgRunTestmoduleNameNotDefined;
+    	User::Leave( ret );
+    	}
+    
+    aStartInfo.SetModuleNameL( tmp );
+    __TRACE( KMessage, (_L("module: %S"), &aStartInfo.iModule ));
+    
+    // Configuration file
+    ret = aItem->GetNextString( tmp );
+    if ( ret != KErrNone )
+    	{
+    	iRunErrorMessage = KErrMsgRunCfgFileNotDefined;
+    	User::Leave( ret );
+    	}
+    
+    TFileName cfgFileName( tmp );
+    TStifUtil::CorrectFilePathL( cfgFileName );    
+    aStartInfo.SetConfigL( cfgFileName );
+    
+    __TRACE( KMessage, (_L("config: %S"), &aStartInfo.iConfig ));
+
+    // Check is TestScripter
+    if( aStartInfo.iModule.Find( KTestScripterName ) != KErrNotFound )
+        {
+        // TestScripter name is format: 'testscripter_testcasefilename'
+
+        TParse parse;
+        parse.Set( aStartInfo.iConfig, NULL, NULL );
+
+        // Maximum length of TestScripter's name(Max limitation from
+        // CTestModuleController creation)
+        TInt maximumLength = KMaxName - ( KTestScripterNameLength + 1 );
+
+        TFileName testScripterAndTestCaseFile; // InitL() takes TFileName
+        testScripterAndTestCaseFile.Copy( KTestScripterName );
+        testScripterAndTestCaseFile.Append( _L( "_" ) );
+        if( parse.Name().Length() < maximumLength )
+            {
+            testScripterAndTestCaseFile.Append( parse.Name() );
+            }
+        else
+            {
+            __TRACE( KInit, ( CStifLogger::ERed,
+                _L( "TestScripter test case file(config)'s name is too long. Current length[%d], allowed max length[%d]. Cannot continue" ),
+                parse.Name().Length(), maximumLength ) );
+            iRunErrorMessage.Format( KErrMsgRunCfgFileNameToLong, parse.Name().Length(), maximumLength );
+            User::Leave( KErrArgument );
+            }
+// ----
+        aStartInfo.DeleteModuleName(); // Delete old name buffer for new one
+        aStartInfo.SetModuleNameL( testScripterAndTestCaseFile );
+        }
+
+    // Testcase number
+    ret = aItem->GetInt( tmp, aStartInfo.iCaseNum );
+    if ( ret != KErrNone )
+    	{
+    	iRunErrorMessage = KErrMsgRunTestcaseNumberNotDefined;
+    	User::Leave( ret );
+    	}
+    
+    __TRACE( KMessage, (_L("testcasenum: %d"), aStartInfo.iCaseNum ) );
+     
+    // Set mode of item parser to be able to read titles with spaces inside
+    aItem->SetParsingType(CStifItemParser::EQuoteStyleParsing);
+
+    // Get optional run arguments
+    while( aItem->GetNextString( tmp ) == KErrNone )
+        {
+        TPtrC val;   
+        TPtrC arg;
+        ParseOptArgL( tmp, arg, val );
+        CheckDefined( val );
+              
+        // Parse optional argument
+        switch( TTCKeywords::Parse( arg, TTCKeywords::RunOptArg ) )
+            {
+            case TTCKeywords::EExpect:
+                {
+                TLex ptr( val );
+                ret = ptr.Val( aStartInfo.iExpectedResult );
+                if ( ret != KErrNone )
+                	{
+                	iRunErrorMessage = KErrMsgRunInvalidExpectValue;
+                    User::Leave( ret );
+                	}
+                __TRACE( KMessage, (_L("expect=%d"), aStartInfo.iExpectedResult));
+                }
+                break;
+            case TTCKeywords::ETestid:
+				{
+                aStartInfo.SetTestIdL( val );
+                __TRACE( KMessage, (_L("TestId=%S"), &val));
+				}
+                break;
+            case TTCKeywords::EIni:
+				{
+                __TRACE( KMessage, (_L("ini=%S"), &val));
+	        	TFileName iniFileName( val );
+	        	TStifUtil::CorrectFilePathL( iniFileName );
+	            aStartInfo.SetIniFileL( iniFileName );
+				}
+                break;
+            case TTCKeywords::ECategory:
+				{
+                __TRACE( KMessage, (_L("category=%S"), &val));
+                aStartInfo.iCategory = TTCKeywords::GetResultCategory( val );
+                if( aStartInfo.iCategory == TFullTestResult::ECaseOngoing )
+                    {
+                    __TRACE( KError, (_L("Unknown or illegal result category")));
+                    //Unknown or illegal category
+                    iRunErrorMessage = KErrMsgRunUnknownOrIllegalCategory;
+                    User::Leave( KErrGeneral );
+                    }
+				}
+                break;
+            case TTCKeywords::ECaseTimeout:
+                {
+                TLex ptr( val );
+                ret = ptr.Val( aStartInfo.iTimeout );
+                if ( ret != KErrNone )
+                	{
+                	iRunErrorMessage = KErrMsgRunInvalidTimeoutValue;
+                    User::Leave( ret );
+                	}
+                __TRACE( KMessage, (_L("timeout=%d"), aStartInfo.iTimeout ) );
+                }
+                break;
+           	case TTCKeywords::ECaseTitle:
+           	    {
+                __TRACE( KMessage, (_L("case title=%S"), &val));
+                aStartInfo.SetTitleL(val);
+                break;
+           	    }
+            case TTCKeywords::EArgs:
+                {
+                __TRACE( KMessage, (_L("case arguments=%S"), &val));
+                aStartInfo.SetTestCaseArgumentsL( val );
+                }
+                break;				
+            default:
+				{
+                __TRACE( KError, (_L("Unknown or illegal keyword")));
+                //Unknown or illegal keyword
+                iRunErrorMessage.Format( KErrMsgRunUnknowOrIllegalKeyword, &arg );
+                User::Leave( KErrGeneral );
+				}
+            }
+        }             
+    } 
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteTestCtlL
+
+     Description: Executes script line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    TTCKeywords::TKeywords aKeyword: in: keyword index
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteTestCtlL( CStifItemParser* aItem, 
+                                    TTCKeywords::TKeywords aKeyword )
+    {
+    _LIT( KErrMsgTestIdNotDefined, "%S : testid is not defined" );
+    _LIT( KErrMsgTestCaseNotFound, "%S : Test case %S not found" );
+    TBool continueTask = ETrue;
+    TPtrC tmp;
+    
+    TInt ret = KErrNone;
+
+	TPtrC keywordStr = TTCKeywords::Keyword( aKeyword );
+
+    // Parse testid
+    ret = aItem->GetNextString( tmp );
+    if( ret != KErrNone )
+    	{
+    	iRunErrorMessage.Format( KErrMsgTestIdNotDefined, &keywordStr );
+        User::Leave( ret );            	
+    	}
+
+    // Get testcase identified with testid
+    CTestCase* testCase = iTestCombiner->GetTest( tmp ); 
+    if( testCase == NULL )
+        {
+        __TRACE( KError, (_L("ExecuteTestCtlL: Test case %S not found"), 
+            &tmp));
+        iRunErrorMessage.Format( KErrMsgTestCaseNotFound, &keywordStr, &tmp );
+        User::Leave( KErrNotFound );
+        }  
+                              
+    switch( aKeyword )
+        {
+        // Test case execution control cases
+        case TTCKeywords::EPause:
+            continueTask = ExecutePauseL( aItem, testCase );
+            break;
+        case TTCKeywords::EComplete:
+            continueTask = ExecuteCompleteL( aItem, testCase );
+            break;
+        case TTCKeywords::ECancel:
+            __TRACE( KMessage, (_L("Cancel %S"), &tmp));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriExec, 
+                KExecute, _L("Cancel %S"), &tmp);
+            if( testCase->Type() == CTestCase::ECaseRemote )
+                {
+                continueTask = 
+                    ExecuteRemoteTestCtlL( aItem, testCase, aKeyword ); 
+                }
+            else 
+                {
+                if( testCase->State() != CTestCase::ETestCaseRunning )
+                    {
+                    __TRACE( KMessage, (_L("Cancelled task (%S) not running (%i)"), 
+                        &tmp, testCase->State() )); 
+                    User::Leave( KErrNotFound );                   
+                    }
+                CTCTestCase* test = ( CTCTestCase* )testCase;
+                // Cancel local testcase
+                test->TestExecution().CancelAsyncRequest( ETestExecutionRunTestCase );
+                }
+            break;
+        case TTCKeywords::EResume:
+            {
+            __TRACE( KMessage, (_L("Resume %S"), &tmp));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriExec, 
+                KExecute, _L("Resume %S"), &tmp);
+            if( testCase->Type() == CTestCase::ECaseRemote )
+                {
+                continueTask = 
+                    ExecuteRemoteTestCtlL( aItem, testCase, aKeyword ); 
+                }
+            else 
+                {
+                if( testCase->State() != CTestCase::ETestCaseRunning )
+                    {
+                    __TRACE( KMessage, (_L("Resumed task (%S) not running (%i)"), 
+                        &tmp, testCase->State() )); 
+                    User::Leave( KErrNotFound );                   
+                    }
+                CTCTestCase* test = ( CTCTestCase* )testCase;
+                // Resume execution
+                User::LeaveIfError( test->TestExecution().Resume() );
+                }
+            }
+            break;
+            
+        default:
+            // Should never come here
+            User::Leave( KErrGeneral );
+            break;
+        }      
+    
+    return continueTask;
+    
+    }
+
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteCombinerPauseL
+
+     Description: Executes causes pause in TestCombiner
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                         
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteCombinerPauseL( CStifItemParser* aItem )
+{
+	_LIT( KErrMsgPauseTimeoutNotDefined, "PauseCombiner : No timeout value given or value has invalid format" );
+	_LIT( KErrMsgPauseTimeoutNotPositive, "PauseCombiner : Timeout value can't be <0" );
+
+    TBool continueTask = EFalse;
+    TInt pauseTime;
+    TInt ret = KErrNone;
+    
+    // Parse testid
+    ret = aItem->GetNextInt( pauseTime );
+    if ( ret != KErrNone )
+    	{
+    	iRunErrorMessage = KErrMsgPauseTimeoutNotDefined;
+        User::Leave( ret );    	
+    	}
+
+    if( pauseTime < 0 )
+        {
+        __TRACE( KError, (_L("CTestRunner::ExecuteCombinerPauseL: Given pause value < 0")));
+        iRunErrorMessage = KErrMsgPauseTimeoutNotPositive;
+        User::Leave( KErrArgument );
+        }    
+    
+    
+    // Maximum time for one RTimer::After request
+    TInt maximumTime = KMaxTInt / 1000;
+
+    // Check if pause value is suitable for RTimer::After
+    if(pauseTime < maximumTime)
+        {
+        iPauseCombTimer.After(iStatus, pauseTime * 1000);
+        iPauseCombRemainingTime = 0;
+        }
+    else
+        {
+        // Given pause value after multiplication with 1000 is
+        // larger than KMaxTInt, so we need to split it and 
+        // re-request After with remaining value from RunL
+
+        iPauseCombRemainingTime = pauseTime - maximumTime;
+        iPauseCombTimer.After(iStatus, maximumTime * 1000);
+        }
+
+    SetActive();
+
+    __TRACE(KMessage, (_L("Executing pause, time=[%d]"), pauseTime));
+    
+    iState = ERunnerRunning;
+    
+    return continueTask;
+}
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecutePauseL
+
+     Description: Executes pause line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CTestCase* aTestcase: in: test case
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecutePauseL( CStifItemParser* aItem,
+                                    CTestCase* aTestcase )
+    {
+    _LIT( KErrMsgPauseUnknownKeyword, "Pause : Unknown or illegal keyword %S" );
+    _LIT( KErrMsgPauseTimeInvalidValue, "Pause : Pause time is not defined or has invalid value" );
+    _LIT( KErrMsgPauseTimeNotPositive, "Pause : Pause time can't be <0" );
+    TBool continueTask = ETrue;
+
+    // Get optional pause arguments
+    TPtrC tmp;
+    iPauseTime = 0;
+    while( aItem->GetNextString( tmp ) == KErrNone )
+        {
+        TPtrC val;   
+        TPtrC arg;
+        ParseOptArgL( tmp, arg, val );
+        CheckDefined( val );
+              
+        // Parse optional argument
+        switch( TTCKeywords::Parse( arg, TTCKeywords::PauseOptArg ) )
+            {
+            case TTCKeywords::ETime:
+                {
+                TLex ptr( val );
+                TInt ret = KErrNone;
+                ret = ptr.Val( iPauseTime );
+                if ( ret != KErrNone )
+                	{
+                	iRunErrorMessage = KErrMsgPauseTimeInvalidValue;
+                	User::Leave( ret );
+                	}                
+                if ( iPauseTime < 0 )
+                	{
+                	iRunErrorMessage = KErrMsgPauseTimeNotPositive;
+                	User::Leave( KErrArgument );                	
+                	}
+                __TRACE( KMessage, (_L("time=%d"), iPauseTime ));
+                }
+                break;
+            default:
+                __TRACE( KError, (_L("Unknown or illegal keyword")));
+                //Unknown or illegal keyword
+                iRunErrorMessage.Format( KErrMsgPauseUnknownKeyword, &arg );
+                User::Leave( KErrGeneral );
+            }
+        }             
+    
+    // Store paused testcase id if timeout was given as pause argument 
+    if( iPauseTime != 0 )
+        {
+        iPausedTestCase.Copy( aTestcase->TestId() );
+        }
+    
+    if( aTestcase->Type() == CTestCase::ECaseRemote )
+        {
+        return ExecuteRemoteTestCtlL( aItem, aTestcase, TTCKeywords::EPause );
+        }
+    if( aTestcase->State() != CTestCase::ETestCaseRunning )
+        {
+        __TRACE( KMessage, (_L("Paused task (%S) not running (%i)"), 
+            &aTestcase->TestId(), aTestcase->State() )); 
+        User::Leave( KErrNotFound );                   
+        }
+    CTCTestCase* test = ( CTCTestCase* )aTestcase;
+    
+    // Pause execution
+    User::LeaveIfError( test->TestExecution().Pause() );
+    
+    // Resume paused case if timeout was given 
+    if( iPauseTime != 0 )
+        {
+        continueTask = EFalse;
+        iState = ERunnerWaitTimeout;
+        iPauseTimer.After( iStatus, iPauseTime*1000 );
+        SetActive();         
+        }
+        
+    return continueTask;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteCompleteL
+
+     Description: Executes complete line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CTestCase* aTestcase: in: test case
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteCompleteL( CStifItemParser* /* aItem */, 
+                                     CTestCase* aTestcase )
+    {
+    TBool ret = ETrue;
+    
+    if( aTestcase->State() == CTestCase::ETestCaseCompleted )
+         {
+         // Requested testcase is completed already,
+         // proceed testcase execution
+          __TRACE( KMessage, (_L("Already completed")));
+         }
+    else if( aTestcase->State() == CTCTestCase::ETestCaseRunning )
+         {
+         // Wait testcase to complete                    
+         iTestCombiner->iWaitTestCase.Copy( aTestcase->TestId() );
+         // Stop testcase execution until testcase completed 
+         ret = EFalse;
+         iState = ERunnerWaitTestCase;
+         }
+    else
+        {
+        // This should newer happen
+        User::Leave( KErrGeneral );
+        }
+        
+    return ret;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteEventSetL
+
+     Description: Executes event set line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteEventSetL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgSetEventNameNotDefined, "Set : event name is not defined" );
+    _LIT( KErrMsgSetUnknownOrIllegalKeyword, "Set :Unknown or illegal keyword %S" );
+    _LIT( KErrMsgSetStateInvalidValue, "Set : State value is not defined or has invalid format" );
+    TPtrC tmp;
+    TPtrC eventName;
+    TInt ret = KErrNone;
+    
+    // Get event name
+    ret = aItem->GetNextString( eventName );
+    if( ret != KErrNone )
+    	{
+    	iRunErrorMessage = KErrMsgSetEventNameNotDefined;
+        User::Leave( ret );        
+    	}
+    __TRACE( KMessage, (_L("Set %S"), &eventName));
+    iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+        _L("Set %S"), &eventName);
+    iEvent.SetName( eventName );
+    iEvent.SetType( TEventIf::ESetEvent );
+
+    // Get optional set arguments
+    while( aItem->GetNextString( tmp ) == KErrNone )
+        {
+        TPtrC val;   
+        TPtrC arg;
+        ParseOptArgL( tmp, arg, val );
+        CheckDefined( val );
+              
+        // Parse optional set argument
+        switch( TTCKeywords::Parse( arg, TTCKeywords::EventOptArg ) )
+            {
+            case TTCKeywords::EState:
+                {
+                TLex ptr( val );
+                TInt tmpVal = 0;
+                ret = ptr.Val( tmpVal );
+                if ( ret != KErrNone )
+                	{
+                	iRunErrorMessage = KErrMsgSetStateInvalidValue;
+                	User::Leave( ret );
+                	}
+                
+                // Only value 1 has special meaning, others are ignored
+                if( tmpVal == 1 )
+                    {
+                     __TRACE( KMessage, (_L("State event")));
+                     iEvent.SetEventType( TEventIf::EState );
+                    }
+                }
+                break;
+            default:
+                __TRACE( KError, (_L("Unknown or illegal keyword")));
+                //Unknown or illegal keyword
+                iRunErrorMessage.Format( KErrMsgSetUnknownOrIllegalKeyword, &arg );
+                User::Leave( KErrGeneral );
+            }
+        }      
+
+    // Set event
+    iTestCombiner->TestModuleIf().Event( iEvent, iStatus );
+    iState = ERunnerRunning;
+    SetActive();
+            
+    return EFalse;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteEventUnsetL
+
+     Description: Executes event unset line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteEventUnsetL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgUnsetEventNameNotDefined, "Unset : Event name is not defined" );
+    TPtrC eventName;
+    TInt ret = KErrNone;
+    // Get event name
+    ret = aItem->GetNextString( eventName );
+    if ( ret != KErrNone )
+    	{
+    	iRunErrorMessage = KErrMsgUnsetEventNameNotDefined;
+    	User::Leave( ret );        
+    	}
+    
+    __TRACE( KMessage, (_L("Unset %S"), &eventName));
+    iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+        _L("Unset %S"), &eventName);
+    iEvent.Set( TEventIf::EUnsetEvent, eventName, TEventIf::EState );
+    
+    // Check if trying to unset an event that is requested 
+    // by testcombiner (otherwise testcombiner would deadlock)
+    TInt count = iTestCombiner->iEventArray.Count();
+    TInt ind = 0;
+    for(; ind < count; ind++ )
+        {
+        if( eventName == iTestCombiner->iEventArray[ind]->Name() )
+            {
+            User::Leave( KErrInUse );
+            }
+        }
+
+    // Check if some testmodule below 
+    // has event request pending
+    if( iTestCombiner->UnsetEvent( iEvent, 
+                                   iStatus ) == EFalse )
+        {
+        // If they haven't requested event,
+        // then check others above
+        iTestCombiner->TestModuleIf().Event( iEvent, iStatus );
+        iState = ERunnerRunning;
+        SetActive();
+            
+        }
+    else
+        {
+        // Some testmodule below has requested the event
+        // Wait unset to complete
+        SetActive();
+        __TRACE( KPrint, ( _L("Unset: Start" ) ) );
+        iState = ERunnerWaitUnset;
+        // Stop execution until unset has completed
+        }
+    return EFalse;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteLineL
+
+     Description: Executes script line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    TTCKeywords::TKeywords aKeyword: in: keyword index
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteEventCtlL( CStifItemParser* aItem, 
+                                     TTCKeywords::TKeywords aKeyword )
+    {
+    _LIT( KErrMsgEventNameNotDefined, "%S : Event name is not defined" );
+    _LIT( KErrMsgEequestEventAlreadyExist, "Request : Requested event %S already exists" );
+    _LIT( KErrMsgWaitEventNotRequested, "Wait :Waited event %S is not requested" );
+    _LIT( KErrMsgReleaseEventNotRequested, "Release : Released event %S is not requested" );
+    
+    TBool continueTask = ETrue;
+    TPtrC eventName;
+    TInt ret = KErrNone;
+	TPtrC keywordStr = TTCKeywords::Keyword( aKeyword );
+    // Get event name
+    ret = aItem->GetNextString( eventName );
+    if ( ret != KErrNone )
+    	{
+    	iRunErrorMessage.Format( KErrMsgEventNameNotDefined, &keywordStr );
+    	User::Leave( ret );
+    	}
+    
+    TInt count = iTestCombiner->iEventArray.Count();
+    TInt ind = 0;
+    for(; ind < count; ind++ )
+        {
+        if( eventName == iTestCombiner->iEventArray[ind]->Name() )
+            {
+            break;
+            }
+        }
+                    
+    switch( aKeyword )
+        {
+        case TTCKeywords::ERequest:
+            {
+            __TRACE( KMessage, (_L("Request %S"), &eventName));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriExec, 
+                KExecute, _L("Request %S"), &eventName);
+                
+            // Check that event is not already requested           
+            if( ind < count )
+                {
+                __TRACE( KError, (_L("Requested event %S already exists"), 
+                    &eventName));
+                iRunErrorMessage.Format( KErrMsgEequestEventAlreadyExist, &eventName );
+                User::Leave( KErrAlreadyExists );
+                }
+                
+            // Add event to event array
+            iEvent.SetName( eventName );
+            iEvent.SetType( TEventIf::EReqEvent );
+            TEventTc* event = new (ELeave) TEventTc( iTestCombiner->iLog );
+            CleanupStack::PushL( event );
+            event->Copy( iEvent );
+            User::LeaveIfError( iTestCombiner->iEventArray.Append( event ));
+            if( iTestCombiner->iLoopIsUsed )
+                {
+                User::LeaveIfError( iTestCombiner->iLoopAllocationArray.Append( event ) );
+                }
+            CleanupStack::Pop( event );
+            
+            // Request event
+            iTestCombiner->TestModuleIf().Event( iEvent, iStatus );
+            iState = ERunnerRunning;
+            SetActive();
+            continueTask = EFalse;
+            }
+            break;
+        case TTCKeywords::EWait:
+              {
+            __TRACE( KMessage, (_L("Wait %S"), &eventName));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+                _L("Wait %S"), &eventName);
+
+            // Check that event is requested           
+            if( ind == count )
+                {
+                __TRACE( KError, (_L("Waited event %S is not requested"), 
+                    &eventName));
+                iRunErrorMessage.Format( KErrMsgWaitEventNotRequested, &eventName );
+                User::Leave( KErrNotFound );
+                }            
+            iEvent.SetName( eventName );    
+            iEvent.SetType( TEventIf::EWaitEvent );     
+            // Wait event
+            iTestCombiner->TestModuleIf().Event( iEvent, iStatus );
+            iState = ERunnerRunning;
+            SetActive();
+            continueTask = EFalse;
+            }
+            break;
+        case TTCKeywords::ERelease:
+            {
+            __TRACE( KMessage, (_L("Release %S"), &eventName));
+            iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+                _L("Release %S"), &eventName);
+            // Check that event is requested           
+            if( ind == count )
+                {
+                __TRACE( KError, (_L("Released event %S is not requested"), 
+                    &eventName));
+                iRunErrorMessage.Format( KErrMsgReleaseEventNotRequested, &eventName );
+                User::Leave( KErrNotFound );
+                }            
+            // Remove event from array
+            TEventTc* event = iTestCombiner->iEventArray[ind];
+            iTestCombiner->iEventArray.Remove( ind );
+            delete event;
+            iEvent.SetName( eventName );
+            iEvent.SetType( TEventIf::ERelEvent );
+            
+            // Release event
+            iTestCombiner->TestModuleIf().Event( iEvent, iStatus );
+            iState = ERunnerRunning;
+            SetActive();
+            continueTask = EFalse;
+            }
+            break;
+        default:
+            {
+              __TRACE( KError, (_L("Illegal keyword") ) );
+            
+            // Unknown or illegal keyword
+            User::Leave( KErrGeneral );
+            }
+            break;
+     
+        }
+    return continueTask;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteAllocateL
+
+     Description: Executes allocate line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteAllocateL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgAllocateSlaveTypeNotDefined, "Allocate : Slave type was not given for allocate" );
+    _LIT( KErrMsgAllocateSlaveNameNotDefined, "Allocate : Slave name is not defined" );
+    _LIT( KErrMsgAllocateSlaveAlreadyAllocated, "Allocate : Slave with name %S already allocated" );
+    __TRACE( KMessage, (_L("Allocate")));
+       
+    TPtrC type;
+    TPtrC name;
+    // Get slave type
+    TInt ret = aItem->GetNextString( type );
+    if( ret != KErrNone )
+        {
+        __TRACE( KError, (_L("Slave type was not given for allocate")));
+        iRunErrorMessage = KErrMsgAllocateSlaveTypeNotDefined;
+        User::Leave( KErrArgument );
+        }
+    
+    // Get slave name
+    ret = aItem->GetNextString( name );
+    if( ret != KErrNone )
+        {
+        __TRACE( KError, (_L("Slave name was not given for allocate")));
+        iRunErrorMessage = KErrMsgAllocateSlaveNameNotDefined;
+        User::Leave( KErrArgument );
+        }
+
+    iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+        _L("Allocate %S"), &name );
+        
+    __TRACE( KMessage, (_L("Allocate %S [name: %S]"), &type, &name));
+    
+    if( iTestCombiner->GetSlave( name ) )
+        {
+        __TRACE( KError, (_L("Slave with name %S already allocated"), 
+            &name ) );
+        iRunErrorMessage.Format( KErrMsgAllocateSlaveAlreadyAllocated, &name );
+        User::Leave( KErrAlreadyExists );
+        } 
+        
+    CSlaveInfo* slave = CSlaveInfo::NewL( name, KRemoteProtocolMasterId );
+    CleanupStack::PushL( slave );
+    User::LeaveIfError( iTestCombiner->iSlaveArray.Append( slave ) );
+    if( iTestCombiner->iLoopIsUsed )
+        {
+        User::LeaveIfError( iTestCombiner->iLoopAllocationArray.Append( slave ) );
+        }
+    CleanupStack::Pop( slave );
+
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    req->CreateL();
+    
+    // Reserve message
+    User::LeaveIfError(
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgReserve ) );
+    // Srcid. i.e. master id
+    User::LeaveIfError(
+        req->AppendId( slave->iMasterId ) );
+    // DstId, broacast id
+    User::LeaveIfError(
+        req->AppendId( slave->iSlaveDevId ) );
+    // Slave type
+    User::LeaveIfError( req->Append( type ) );
+
+    User::LeaveIfError( 
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+        
+    iState = ERunnerAllocate;
+    slave->iState = CSlaveInfo::ESlaveReserveSent;
+
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+
+    CleanupStack::PopAndDestroy( req );
+
+    return EFalse;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteFreeL
+
+     Description: Executes free line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteFreeL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgFreeSlaveNameNotDefined, "Free : Slave name is not defined" );
+    _LIT( KErrMsgFreeSlaveNotFound, "Free : Slave %S not found" );
+    _LIT( KErrMsgFreeSlaveReserved, "Free : Slave %S in illegal state %d, cannot be released" );
+    __TRACE( KMessage, (_L("Free")));
+    
+    TPtrC name;    
+    // Get slave name
+    TInt ret = aItem->GetNextString( name );
+    if( ret != KErrNone )
+        {
+        __TRACE( KError, (_L("Slave name was not given for free")));
+        iRunErrorMessage = KErrMsgFreeSlaveNameNotDefined;
+        User::Leave( KErrArgument );
+        }
+
+    iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+        _L("Free %S"), &name );
+        
+    __TRACE( KMessage, (_L("Free %S"), &name ) );
+    
+    CSlaveInfo* slave = iTestCombiner->GetSlave( name );
+    if( slave == NULL )
+        {
+        __TRACE( KError, (_L("Slave %S not found"), &name ));
+        iRunErrorMessage.Format( KErrMsgFreeSlaveNotFound, &name );
+        User::Leave( KErrNotFound );
+        }
+    if( slave->iState != CSlaveInfo::ESlaveReserved )
+        {
+        __TRACE( KError, (_L("Slave %S in illegal state %d, cannot be released"), 
+            &name, slave->iState ));
+        iRunErrorMessage.Format( KErrMsgFreeSlaveReserved, &name, slave->iState );
+        User::Leave( KErrGeneral );
+        } 
+        
+    ExecuteFreeL( slave );
+    
+    return EFalse;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteFreeL
+
+     Description: Executes free line
+  
+     Parameters:    CSlaveInfo* aSlave: in: slave info
+     
+     Return Values: None
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::ExecuteFreeL( CSlaveInfo* aSlave )
+    {    
+    
+    CRemoteTestCase* testCase = 
+        iTestCombiner->GetRemoteRunningTestOnSlave( aSlave->iSlaveDevId );
+          
+    if( testCase )
+        {
+        __TRACE( KMessage, 
+            (_L("Postpone free until testcases completed")));
+        // Test cases still running on slave,
+        // Free slave after test case has completed
+        testCase->iFreeSlave = ETrue;
+        return;
+        }
+    
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    req->CreateL();
+    
+    // Release message
+    User::LeaveIfError( 
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgRelease ) );
+    // Srcid. i.e. master id
+    User::LeaveIfError( 
+        req->AppendId( aSlave->iMasterId ) );
+    // DstId is device broadcast
+    User::LeaveIfError( 
+        req->AppendId( SETID( DEVID( aSlave->iSlaveDevId ), 0 ) ) );
+    
+    User::LeaveIfError( 
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+        
+    iState = ERunnerFree;
+    aSlave->iState = CSlaveInfo::ESlaveReleaseSent;
+
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+   
+    CleanupStack::PopAndDestroy( req );
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRemoteL
+
+     Description: Executes remote line
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRemoteL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgRemoteSlaveNameNotDefined, "Remote : Slave name is not defined" );
+    _LIT( KErrMsgRemoteSlaveNotFound, "Remore : Slave %S not found" );
+    _LIT( KErrMsgRemoteIllegalState, "Remote : Slave %S in illegal state %d, cannot send remote call" );
+    _LIT( KErrMsgRemoteCommandNotDefined, "Slave command name was not given for remote" );
+    TPtrC name;    
+    TPtrC command;    
+    // Get slave name
+    TInt ret = aItem->GetNextString( name );
+    if( ret != KErrNone )
+        {
+        __TRACE( KError, (_L("Slave name was not given for remote")));
+        iRunErrorMessage = KErrMsgRemoteSlaveNameNotDefined;
+        User::Leave( KErrArgument );
+        }
+        
+    __TRACE( KMessage, (_L("Remote command to %S"), &name));
+    
+    CSlaveInfo* slave = iTestCombiner->GetSlave( name );
+    if( slave == NULL )
+        {
+        __TRACE( KError, (_L("Slave %S not found"), &name ));
+        iRunErrorMessage.Format( KErrMsgRemoteSlaveNotFound, &name );
+        User::Leave( KErrArgument );
+        }
+    if( slave->iState != CSlaveInfo::ESlaveReserved )
+        {
+        __TRACE( KError, (_L("Slave %S in illegal state %d, cannot send remote call"), 
+            &name, slave->iState ));
+        iRunErrorMessage.Format( KErrMsgRemoteIllegalState, &name, slave->iState );
+        User::Leave( KErrNotReady );
+        } 
+        
+    // Get remote command name
+    ret = aItem->GetNextString( command );
+    if( ret != KErrNone )
+        {
+        __TRACE( KError, (_L("Slave command name was not given for remote")));
+        iRunErrorMessage = KErrMsgRemoteCommandNotDefined;
+        User::Leave( KErrArgument );
+        }
+
+    iTestCombiner->TestModuleIf().Printf( KPrintPriExec, KExecute, 
+        _L("remote %S %S"), &name, &command );
+
+    __TRACE( KPrint, (_L("remote %S %S"), &name, &command ) );
+
+    // Parse command name
+    TInt key = TTCKeywords::Parse( command, TTCKeywords::Keyword );    
+    TBool continueTask = ETrue;
+    
+    switch( key )
+        {
+        // Test case starting
+        case TTCKeywords::ERun:
+            continueTask = ExecuteRemoteRunL( aItem, slave );
+            break;
+                   
+        // Event control cases
+        case TTCKeywords::ERequest:
+        case TTCKeywords::EWait:
+        case TTCKeywords::ERelease:
+            continueTask = ExecuteRemoteEventCtlL( aItem, slave, key );
+            break;
+
+        case TTCKeywords::ESet:
+        case TTCKeywords::EUnset:
+            continueTask = ExecuteRemoteSetUnsetEventL(aItem, slave, key);
+			break;
+        // asynchronous 'sendreceive'
+        case TTCKeywords::ESendReceive:
+            continueTask = ExecuteRemoteSendReceiveL( aItem, slave );
+            break;
+
+        default:
+            // Some unknown remote command, forward as such 
+            continueTask = ExecuteRemoteUnknownL( aItem, slave, command );
+            break;
+        }
+    
+    return continueTask;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRemoteRunL
+
+     Description: Handles remote run 
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CSlaveInfo* aSlave: in: slave info
+                    HBufC *aSetUnsetEvent: in: data needed for startInfo
+                    TInt aCaseNumber: in: data needed for startInfo
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution and wait response
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRemoteRunL( CStifItemParser* aItem,
+                                        CSlaveInfo* aSlave,
+                                        HBufC *aSetUnsetEvent,
+                                        TInt aCaseNumber )
+    {
+    
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    req->CreateL();
+    
+    CStartInfo* startInfo = CStartInfo::NewL();
+    CleanupStack::PushL( startInfo );
+    //if aSetUnsetEvent is given, then get start info from this argument
+    if(aSetUnsetEvent != NULL)
+    	{
+    	TBuf<10> tmpModuleName;
+    	tmpModuleName.Copy(_L("suevent"));
+    	startInfo->SetModuleNameL(tmpModuleName);
+    	startInfo->SetConfigL(*aSetUnsetEvent);
+    	startInfo->iCaseNum = aCaseNumber;
+    	}
+    else
+    	{
+    ParseRunParamsL( aItem, *startInfo );   
+}
+    
+    if( iTestCombiner->GetTest( startInfo->iTestId ) )
+        {
+        /*        
+        __TRACE( KError, (_L("´Slave test running already with testid %S"), 
+            &startInfo->iTestId  ) );
+        */
+        User::Leave( KErrAlreadyExists );
+        }
+        
+    CRemoteTestCase* remote = 
+        CRemoteTestCase::NewL( iTestCombiner, 
+                               startInfo->iTestId,
+                               startInfo->iExpectedResult,
+                               startInfo->iCategory ); 
+    
+    CleanupStack::PushL( remote );
+        
+    // Remote message
+    User::LeaveIfError( 
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgRemote ) );
+    // Srcid. i.e. master id
+    User::LeaveIfError( req->AppendId( aSlave->iMasterId ) );
+    // DstId is device broadcast
+    User::LeaveIfError( 
+        req->AppendId( SETID( DEVID( aSlave->iSlaveDevId ), 0 ) ) );
+    // Run command
+    User::LeaveIfError( 
+        req->Append( CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdRun ) );
+    // Run parameters
+    User::LeaveIfError(
+        req->Append( CStifTFwIfProt::RunParams, 
+                CStifTFwIfProt::ERunModule, 
+                startInfo->iModule ) );
+    User::LeaveIfError(
+        req->Append( CStifTFwIfProt::RunParams, 
+                CStifTFwIfProt::ERunTestcasenum, 
+                startInfo->iCaseNum ));
+    if( startInfo->iIniFile.Length() > 0 )
+        {
+        // Initialization file
+        __TRACE( KMessage, (_L("ini: %S"), &startInfo->iIniFile ));     
+        User::LeaveIfError(
+            req->Append( CStifTFwIfProt::RunParams, 
+                    CStifTFwIfProt::ERunInifile, 
+                    startInfo->iIniFile ) );
+        }
+    if( startInfo->iConfig.Length() > 0 )
+        {
+        // Initialization file
+        __TRACE( KMessage, (_L("config: %S"), &startInfo->iConfig ));     
+        User::LeaveIfError(
+            req->Append( CStifTFwIfProt::RunParams, 
+                    CStifTFwIfProt::ERunTestcasefile, 
+                    startInfo->iConfig ));
+        } 
+    //Title (must be given between quotation marks in case of any spaces inside
+    if( startInfo->iTitle.Length() > 0 )
+        {
+        __TRACE(KMessage, (_L("title: %S"), &startInfo->iTitle));
+        TName tit;
+        tit.Format(_L("\"title=%S\""), &startInfo->iTitle);
+        User::LeaveIfError(req->Append(tit));
+        }
+    
+    User::LeaveIfError(
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+        
+    remote->iRemoteState = CRemoteTestCase::ECaseRunSent;
+    remote->iSlaveId = aSlave->iSlaveDevId;
+    remote->StartL();
+    User::LeaveIfError( iTestCombiner->iTestCases.Append( remote ) );
+    if( iTestCombiner->iLoopIsUsed )
+        {
+        User::LeaveIfError( iTestCombiner->iLoopAllocationArray.Append( remote ) );
+        }
+    CleanupStack::Pop( remote );
+    
+    CleanupStack::PopAndDestroy( startInfo );
+    
+    iTestCombiner->iRunningTests++;
+    
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+
+    iState = ERunnerRemote;
+
+    CleanupStack::PopAndDestroy( req );
+
+    return EFalse;
+         
+    }
+    
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRemoteTestCtlL
+
+     Description: Handles remote testcase controlling
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CTestCase* aTestCase: in: test case
+                    TInt aCmd: in: remote command 
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution and wait response
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRemoteTestCtlL( CStifItemParser* /* aItem */, 
+                                          CTestCase* aTestCase, 
+                                          TInt aCmd )
+    {
+    
+    CRemoteTestCase* caseInfo = ( CRemoteTestCase* ) aTestCase;
+    
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    req->CreateL();
+    // Remote message
+    User::LeaveIfError( 
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgRemote ) );
+    // Srcid. i.e. master id
+    //req->AppendId( ( TUint32 ) this );
+    User::LeaveIfError(
+        req->AppendId( KRemoteProtocolMasterId ));
+    // DstId, i.e.slave id
+    User::LeaveIfError(
+        req->AppendId( caseInfo->iSlaveId ));
+    
+    switch( aCmd )
+        {
+        case TTCKeywords::EPause:
+            if( caseInfo->iRemoteState != CRemoteTestCase::ECaseRunning )
+                {
+                __TRACE( KError, (_L("Test case with testid %S not running"), 
+                    &aTestCase->TestId() ));
+                User::Leave( KErrGeneral );
+                }
+            // Pause command
+            User::LeaveIfError(
+                req->Append( CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdPause ) );
+            caseInfo->iRemoteState = CRemoteTestCase::ECasePauseSent;
+            break;
+        case TTCKeywords::EResume:
+            if( caseInfo->iRemoteState != CRemoteTestCase::ECasePaused )
+                {
+                __TRACE( KError, (_L("Test case with testid %S not paused"), 
+                    &aTestCase->TestId() ));
+                User::Leave( KErrGeneral );
+                }
+            // Resume command
+            User::LeaveIfError( 
+                req->Append( CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdResume ));
+            caseInfo->iRemoteState = CRemoteTestCase::ECaseResumeSent;
+            break;            
+        case TTCKeywords::ECancel:
+            if( ( caseInfo->iRemoteState != CRemoteTestCase::ECaseRunning ) &&
+                ( caseInfo->iRemoteState != CRemoteTestCase::ECasePaused ) )
+                {
+                __TRACE( KError, (_L("Test case with testid %S not running"),
+                    &aTestCase->TestId() ));
+                User::Leave( KErrGeneral );
+                }
+            // Cancel command
+            User::LeaveIfError( 
+                req->Append( CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdCancel ));    
+            caseInfo->iRemoteState = CRemoteTestCase::ECaseCancelSent;
+            break;      
+        case TTCKeywords::EComplete:
+            if( caseInfo->iRemoteState == CRemoteTestCase::ECaseCompleted )
+                {
+                __TRACE( KError, (_L("Test case with testid %S already completed"), 
+                    &aTestCase->TestId() ));
+                CleanupStack::PopAndDestroy( req );
+                return ETrue;
+                }
+            else
+                {
+                iTestCombiner->iWaitTestCase = aTestCase->TestId();
+                CleanupStack::PopAndDestroy( req );
+                return EFalse;
+                }    
+        default:
+            // Should never come here
+            User::Leave( KErrGeneral );            
+        }
+    
+    User::LeaveIfError( 
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+            
+    iState = ERunnerRemote;
+    
+    CleanupStack::PopAndDestroy( req );
+    
+    return EFalse;
+   
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRemoteEventCtlL
+
+     Description: Handles remote event controlling
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CSlaveInfo* aSlave: in: slave info
+                    TInt aCmd: in: remote command 
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution and wait response
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRemoteEventCtlL( CStifItemParser* aItem, 
+                                           CSlaveInfo* aSlave, 
+                                           TInt aCmd )
+    {
+    
+    TPtrC eventName;
+    // Get event name
+    TInt ret = aItem->GetNextString( eventName );
+    if( ret != KErrNone )
+        {
+        __TRACE( KError, (_L("Event name was not given for remote")));
+        User::Leave( KErrArgument );
+        }
+    
+    if( aCmd == TTCKeywords::EWait )
+        {
+        TEventTc* event = aSlave->GetEvent( eventName );
+        if( event == NULL )
+            {
+            __TRACE( KError, (_L("Waited event %S not requested"), 
+                &eventName  ) );
+            User::Leave( KErrNotFound );
+            }
+        iState = ERunnerRunning;
+        SetActive();
+        event->WaitEvent( iStatus );     
+        // Execution continue if waited event is set or after it is set       
+        return EFalse;
+        }
+    
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    
+    req->CreateL();
+    // Remote message
+    User::LeaveIfError( 
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgRemote ));
+    // Srcid. i.e. master id
+    User::LeaveIfError( req->AppendId( aSlave->iMasterId ) );
+    // DstId, i.e.slave device id
+    User::LeaveIfError( req->AppendId( aSlave->iSlaveDevId ) );
+           
+    switch( aCmd )
+        {       
+        // Event control cases
+        case TTCKeywords::ERequest:
+            {
+            TEventTc* event = aSlave->GetEvent( eventName );
+            if( event != NULL )
+                {
+                __TRACE( KError, (_L("Event %S already requested"), 
+                    &eventName  ) );
+                User::Leave( KErrNotFound );
+                }
+            event = new( ELeave ) TEventTc( (TName&)eventName, 
+                                             iTestCombiner->iLog );
+            CleanupStack::PushL( event );
+            User::LeaveIfError( aSlave->iEvents.Append( event ) );
+            CleanupStack::Pop( event );
+            // Request event
+            User::LeaveIfError( 
+                req->Append( CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdRequest ));  
+            }
+            break;
+                        
+        case TTCKeywords::ERelease:
+            {
+            TEventIf* event = NULL;
+            TInt count = aSlave->iEvents.Count();
+            TInt i = 0;
+            for( ; i < count; i++ )
+                {
+                if( aSlave->iEvents[i]->Name() == eventName )
+                    {
+                    event = aSlave->iEvents[i];
+                    break;
+                    }
+                }
+            if( event == NULL )
+                {
+                __TRACE( KError, (_L("Event not found %S"), 
+                    &eventName  ) );
+                User::Leave( KErrNotFound );
+                }
+                                                  
+            aSlave->iEvents.Remove(i);
+            delete event;
+            // Release event
+            User::LeaveIfError(
+                req->Append( CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdRelease ));  
+            }
+            break;
+        
+        case TTCKeywords::ESet:
+        	{
+        		__TRACE( KPrint, (_L("JIRA51 CTestRunner::ExecuteRemoteEventCtlL case ESet")));
+	            User::LeaveIfError(req->Append(CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdSetEvent));
+        		break;
+        	}
+       	case TTCKeywords::EUnset:
+        	{
+        		__TRACE( KPrint, (_L("JIRA51 CTestRunner::ExecuteRemoteEventCtlL case EUnset")));
+	            User::LeaveIfError(req->Append(CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdUnsetEvent));
+        		break;
+        	}
+        default:
+             // Should never come here
+            User::Leave( KErrGeneral );            
+        }
+        
+    // Event name
+    User::LeaveIfError( req->Append( eventName ) );  
+    
+	if(aCmd == TTCKeywords::ESet)
+		{
+ 		TPtrC stateEvent;
+		TInt ret = aItem->GetNextString(stateEvent);
+		if(ret == KErrNotFound) //indication event - add indicate keyword to message
+			{
+	            User::LeaveIfError(req->Append(CStifTFwIfProt::EventType, TEventIf::EIndication));
+			}
+		else if(ret == KErrNone) //possibly state event
+			{
+			if(stateEvent.Compare(_L("state")) == 0) //state event - add state keyword to message
+				{
+	            User::LeaveIfError(req->Append(CStifTFwIfProt::EventType, TEventIf::EState));
+				}
+			else //syntax error in the line
+				{
+		        __TRACE(KError, (_L("Unknown keyword %S"), &stateEvent));
+				}
+			}
+		else //syntax error in the line
+			{
+	        __TRACE(KError, (_L("Unknown keyword (2) %S"), &stateEvent));
+			}
+		}
+    User::LeaveIfError( 
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+                
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+
+    iState = ERunnerRemote;
+    
+    CleanupStack::PopAndDestroy( req );
+    
+    return EFalse;
+    
+    }    
+
+TBool CTestRunner::ExecuteRemoteSetUnsetEventL(CStifItemParser* aItem,
+                                               CSlaveInfo* aSlave,
+                                               TInt aCmd)
+	{
+	TPtrC eventName;
+	// Get event name
+	TInt ret = aItem->GetNextString(eventName);
+	if(ret != KErrNone)
+		{
+		__TRACE(KError, (_L("Event name was not given for remote")));
+		User::Leave(KErrArgument);
+		}
+	// Check if this is a state set, indication set, or unset command
+	TInt caseNumber = -1;
+	if(aCmd == TTCKeywords::ESet)
+		{
+ 		TPtrC stateEvent;
+		TInt ret = aItem->GetNextString(stateEvent);
+		if(ret == KErrNotFound) //indication event - add indicate keyword to message
+			{
+			caseNumber = 1;
+			}
+		else if(ret == KErrNone) //possibly state event
+			{
+			if(stateEvent.Compare(_L("state")) == 0) //state event - add state keyword to message
+				{
+				caseNumber = 0;
+				}
+			else //syntax error in the line
+				{
+				__TRACE(KError, (_L("Unknown keyword %S"), &stateEvent));
+				}
+			}
+		else //syntax error in the line
+			{
+			}
+		}
+	else //TTCKeyword::EUnset
+		{
+		caseNumber = 2;
+		}
+
+	if(caseNumber == -1)
+		{
+			__TRACE(KError, _L("Should never occur"));
+		}
+	// Build new descriptor with command to run hardcoded suevent test case on remote phone
+	HBufC* cmd = HBufC::NewL(100);
+	CleanupStack::PushL(cmd);
+	TPtr cmdPtr(cmd->Des());
+	cmdPtr.Copy(eventName);
+	// Run remotely test case
+RDebug::Print(_L("CTestRunner::ExecuteRemoteSetUnsetEventL calling ExecuteRemoteRun"));
+	TBool retval = ExecuteRemoteRunL(aItem, aSlave, cmd, caseNumber);
+	// Clean data
+	CleanupStack::PopAndDestroy(cmd);
+RDebug::Print(_L("CTestRunner::ExecuteRemoteSetUnsetEventL end"));
+	return retval;
+    }
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRemoteSendReceiveL
+
+     Description: Handles asynchronous remote sendreceive controlling
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CSlaveInfo* aSlave: in: slave info
+
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution and wait response
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRemoteSendReceiveL( CStifItemParser* aItem, 
+                                           CSlaveInfo* aSlave )
+    {
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    
+    // Create CRemoteSendReceive object for taking sendreceive information to
+    // save for later use.
+    CRemoteSendReceive* remoteSendReceive = 
+        CRemoteSendReceive::NewL( iTestCombiner );
+    
+    CleanupStack::PushL( remoteSendReceive );
+
+    req->CreateL();
+    // Remote message
+    User::LeaveIfError(
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgRemote ) );
+    // Srcid. i.e. master id
+    User::LeaveIfError( req->AppendId( aSlave->iMasterId ) );
+    // DstId, i.e.slave device id
+    User::LeaveIfError( req->AppendId( aSlave->iSlaveDevId ) );
+    // Run command
+    User::LeaveIfError( req->Append( 
+        CStifTFwIfProt::CmdType, CStifTFwIfProt::ECmdSendReceive ) );
+    // asynchronous sendreceive's parameters    
+    TPtrC tmp;    
+
+    while( aItem->GetNextString( tmp ) == KErrNone )
+        {        
+        // Append parameters
+        User::LeaveIfError( req->Append( tmp ) );  
+        }
+    
+    User::LeaveIfError( 
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+
+    remoteSendReceive->iRemoteState = CRemoteSendReceive::ECaseSend;
+    remoteSendReceive->iSlaveId = aSlave->iSlaveDevId;
+
+    // Take CRemoteSendReceive object to save in array. This can be used in
+    // TestCombiner when handling responses.
+    User::LeaveIfError( 
+            iTestCombiner->iSendReceive.Append( remoteSendReceive ) );
+    if( iTestCombiner->iLoopIsUsed )
+        {
+        User::LeaveIfError( 
+            iTestCombiner->iLoopAllocationArray.Append( remoteSendReceive ) );
+        }
+    CleanupStack::Pop( remoteSendReceive );
+
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+
+    iState = ERunnerRemote;
+    
+    CleanupStack::PopAndDestroy( req );
+    
+    // Return EFalse=>start waiting response...
+    return EFalse;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteRemoteUnknownL
+
+     Description: Forwards messages as such
+  
+     Parameters:    CStifItemParser* aItem: in: script line
+                    CSlaveInfo* aSlave: in: slave info
+                    TInt aCmd: in: remote command 
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution and wait response
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteRemoteUnknownL( CStifItemParser* aItem, 
+                                          CSlaveInfo* aSlave,
+                                          TDesC& aCommand )
+    {
+    
+    CStifTFwIfProt* req = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( req );
+    
+    req->CreateL();
+    // Remote message
+    User::LeaveIfError(
+        req->Append( CStifTFwIfProt::MsgType, CStifTFwIfProt::EMsgRemote ) );
+    // Srcid. i.e. master id
+    User::LeaveIfError( req->AppendId( aSlave->iMasterId ) );
+    // DstId, i.e.slave device id
+    User::LeaveIfError( req->AppendId( aSlave->iSlaveDevId ) );
+    
+    // Append command name
+    User::LeaveIfError( req->Append( aCommand ) );
+    
+    TPtrC tmp;         
+    while( aItem->GetNextString( tmp ) == KErrNone )
+        {        
+        // Append parameters
+        User::LeaveIfError( req->Append( tmp ) );  
+        }
+    
+    User::LeaveIfError( 
+        iTestCombiner->TestModuleIf().RemoteSend( req->Message() ) );
+                
+    // Start timer    
+    iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+
+    iState = ERunnerRemote;
+    
+    CleanupStack::PopAndDestroy( req );
+    
+    return EFalse;
+    
+    }    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ReceiveResponseL
+
+     Description: Handles responce received from slave
+  
+     Parameters:    TDesC& aMsg: in: message
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ReceiveResponseL( TDesC& aMsg )
+    {
+    __TRACE( KMessage, (_L("ReceiveResponse")));
+    
+    iRemoteTimer->Cancel();
+    
+    CStifTFwIfProt* msg = CStifTFwIfProt::NewL();
+    CleanupStack::PushL( msg );
+    TRAPD( err, msg->SetL( aMsg ); );
+    if( err != KErrNone )
+        {
+        __TRACE( KError, (_L("Response parsing failed")));
+        User::Leave( err );
+        }
+    
+    // Check protocol identifiers
+    if( ( msg->SrcDevId() == 0 ) ||
+        ( msg->DstDevId() == 0 ) ||
+        ( msg->DstTestId() == 0 ) )
+        {
+        __TRACE( KError, (_L("Illegal deviceid received")));
+        User::Leave( KErrGeneral );
+        }
+    
+    // This is master, cannot receive anything else but responses
+    if( msg->iMsgType != CStifTFwIfProt::EMsgResponse )
+        {
+        __TRACE( KError, (_L("Illegal message received %d"), 
+            msg->iMsgType ));
+        User::Leave( KErrGeneral );        
+        }
+        
+    TBool continueTask = ETrue;
+    switch( msg->iRespType )
+        {
+        case CStifTFwIfProt::EMsgReserve:
+            {
+            __TRACE( KMessage, (_L("ReceiveResponse Reserve")));
+            if( iState != ERunnerAllocate )
+                {
+                __TRACE( KError, (_L("Response reserve received in illegal state %d"), 
+                    iState ));
+                User::Leave( KErrGeneral );    
+                }
+            // Check protocol Src test id
+            if( msg->SrcTestId() != 0 )
+                {
+                __TRACE( KError, (_L("Illegal deviceid received")));
+                User::Leave( KErrGeneral );
+                }
+            if( msg->iResult != KErrNone )
+                {
+                __TRACE( KError, (_L("Response with error %d"), msg->iResult ));
+                User::Leave( msg->iResult );
+                }
+            CSlaveInfo* slave = NULL;
+            TInt count = iTestCombiner->iSlaveArray.Count();
+            for( TInt index = 0; index < count; index++ )
+                {
+                slave = iTestCombiner->iSlaveArray[index];
+                if( ( slave->iSlaveDevId == 0 ) &&
+                    ( slave->iState ==  CSlaveInfo::ESlaveReserveSent ) )
+                    {
+                    break;
+                    }
+                slave = NULL;
+                }
+            if( slave == NULL )
+                {
+                User::Leave( KErrNotFound );
+                }
+            slave->iSlaveDevId = msg->SrcId();
+            slave->iState = CSlaveInfo::ESlaveReserved;
+            __TRACE( KMessage, (_L("Slave allocated succesfully, continue execution")));
+            }
+            break;
+        case CStifTFwIfProt::EMsgRelease:
+            {
+            __TRACE( KMessage, (_L("ReceiveResponse Release")));
+            if( iState != ERunnerFree )
+                {
+                __TRACE( KError, (_L("Response release received in illegal state %d"), 
+                    iState ));
+                User::Leave( KErrGeneral );    
+                }
+            // Check protocol Src test id
+            if( msg->SrcTestId() != 0 )
+                {
+                __TRACE( KError, (_L("Illegal deviceid received")));
+                User::Leave( KErrGeneral );
+                }                
+            if( msg->iResult != KErrNone )
+                {
+                __TRACE( KError, (_L("Response with error %d"), msg->iResult ));
+                User::Leave( msg->iResult );
+                }
+
+            CSlaveInfo* slave = iTestCombiner->GetSlave( msg->SrcId() );
+            if( slave == NULL )
+                {
+                User::Leave( KErrNotFound );
+                }
+            slave->iState = CSlaveInfo::ESlaveReleased;
+            __TRACE( KMessage, (_L("Slave freed succesfully, continue execution")));
+            }            
+            break;
+        case CStifTFwIfProt::EMsgRemote:
+            {         
+            __TRACE( KMessage, (_L("ReceiveResponse Remote")));
+            switch( msg->iCmdType )
+                {
+                case CStifTFwIfProt::ECmdRun:
+                    continueTask = ReceiveResponseRunL( *msg );
+                    break;
+                case CStifTFwIfProt::ECmdPause:
+                case CStifTFwIfProt::ECmdResume:
+                case CStifTFwIfProt::ECmdCancel:
+                    continueTask = ReceiveResponseTestCtlL( *msg );
+                    break;
+                case CStifTFwIfProt::ECmdRequest:
+                case CStifTFwIfProt::ECmdRelease:
+                case CStifTFwIfProt::ECmdSetEvent:
+                case CStifTFwIfProt::ECmdUnsetEvent:
+                    continueTask = ReceiveResponseEventCtlL( *msg );                    
+                    break;
+                case CStifTFwIfProt::ECmdSendReceive:
+                    continueTask = ReceiveResponseSendReceiveL( *msg );                    
+                    break;
+                default:
+                    continueTask = ReceiveResponseUnknownL( *msg );                    
+                    break;
+                }
+            }            
+            break;
+        default:
+            User::Leave( KErrGeneral );
+        } 
+               
+    
+    CleanupStack::PopAndDestroy( msg );    
+    return continueTask;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ReceiveResponseRunL
+
+     Description: Handles response for run received from slave
+  
+     Parameters:    CStifTFwIfProt& aMsg: in: protocol message parser
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/    
+TBool CTestRunner::ReceiveResponseRunL( CStifTFwIfProt& aMsg )
+    {
+
+    TPtrC tmp = CStifTFwIfProt::RunStatus(aMsg.iRunStatus); 
+    __TRACE( KMessage, (_L("ReceiveResponse Remote Run %S"), &tmp ));
+
+    TBool continueTask = ETrue; 
+    switch( aMsg.iRunStatus )
+        {
+        case CStifTFwIfProt::ERunStarted:
+            {
+            // Locate testcase    
+            CRemoteTestCase* tcase = 
+                iTestCombiner->GetRemoteTestRunSent( GETDEVID( aMsg.SrcId() ) );
+            if( tcase == NULL ) 
+                {
+                __TRACE( KError, (_L("Testcase not found")));
+                User::Leave( KErrNotFound );        
+                }
+            tcase->iSlaveId = aMsg.SrcId();
+
+            tcase->iRemoteState = CRemoteTestCase::ECaseRunning;
+            }
+            break;
+        case CStifTFwIfProt::ERunError:
+        case CStifTFwIfProt::ERunReady:
+            {
+            // Locate testcase    
+            CRemoteTestCase* tcase = 
+                iTestCombiner->GetRunningRemoteTest( aMsg.SrcId() );
+            if( tcase == NULL ) 
+                {
+                __TRACE( KError, (_L("Testcase not found")));
+                User::Leave( KErrNotFound );        
+                }
+
+            switch( aMsg.iResultCategory )
+                {
+                case CStifTFwIfProt::EResultNormal:
+                    tcase->iResult.iCaseExecutionResultType = 
+                        TFullTestResult::ECaseExecuted;
+                    tcase->iResult.iTestResult.iResult = aMsg.iResult;
+                    tcase->iResult.iCaseExecutionResultCode = 0;
+                    break;
+                case CStifTFwIfProt::EResultPanic:
+                    tcase->iResult.iCaseExecutionResultType = 
+                        TFullTestResult::ECasePanic;
+                    tcase->iResult.iTestResult.iResult = KErrGeneral;
+                    tcase->iResult.iCaseExecutionResultCode = aMsg.iResult;
+                    break;
+                case CStifTFwIfProt::EResultException:
+                    tcase->iResult.iCaseExecutionResultType = 
+                        TFullTestResult::ECaseException;
+                    tcase->iResult.iTestResult.iResult = KErrGeneral;
+                    tcase->iResult.iCaseExecutionResultCode = aMsg.iResult;
+                    break;
+                case CStifTFwIfProt::EResultTimeout:
+                    tcase->iResult.iCaseExecutionResultType = 
+                        TFullTestResult::ECaseTimeout;                
+                    tcase->iResult.iTestResult.iResult = KErrGeneral;
+                    tcase->iResult.iCaseExecutionResultCode = aMsg.iResult;
+                    break;
+                case CStifTFwIfProt::EResultLeave:
+                    tcase->iResult.iCaseExecutionResultType = 
+                        TFullTestResult::ECaseLeave;                
+                    tcase->iResult.iTestResult.iResult = KErrGeneral;
+                    tcase->iResult.iCaseExecutionResultCode = aMsg.iResult;
+                    break;
+                default:
+                    User::Leave( KErrGeneral );
+                }
+                    
+            if( ( tcase->iRemoteState == CRemoteTestCase::ECaseCancelled ) ||
+                ( tcase->iRemoteState == CRemoteTestCase::ECaseRunSent ) )
+                {
+                // Complete for cancelled testcase or error for run request, 
+                // set runner active again
+                continueTask = ETrue; 
+                }
+            else
+                {
+                // Continued from Complete in state ECaseRunning
+                continueTask = EFalse; 
+                }
+                
+            tcase->iRemoteState = CRemoteTestCase::ECaseCompleted;
+
+        __TRACE( KMessage, (_L("ReceiveResponse Remote Run rq comp")));
+            
+            TRequestStatus* rs = &tcase->iStatus;
+            // Complete testcase
+            User::RequestComplete( rs, KErrNone );
+            
+            }
+            break;
+        default:
+            // Should never come here
+            User::Leave( KErrGeneral );    
+        }        
+    
+    return continueTask;
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ReceiveResponseTestCtlL
+
+     Description: Handles responses for test control commands 
+        received from slave
+  
+     Parameters:    CStifTFwIfProt& aMsg: in: protocol message parser
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/    
+TBool CTestRunner::ReceiveResponseTestCtlL( CStifTFwIfProt& aMsg )
+    {
+
+    if( aMsg.iResult != KErrNone )
+        {
+        __TRACE( KError, (_L("Response with error %d"), aMsg.iResult ));
+        User::Leave( aMsg.iResult );
+        }
+    
+    // Locate testcase    
+    CRemoteTestCase* tcase = iTestCombiner->GetRemoteTest( aMsg.SrcId() );
+    if( tcase == NULL ) 
+        {
+        __TRACE( KError, (_L("Testcase not found")));
+        User::Leave( KErrNotFound );        
+        }
+    
+    TBool continueTask = ETrue;
+    
+    switch( aMsg.iCmdType )
+        {
+        case CStifTFwIfProt::ECmdPause:
+            __TRACE( KMessage, (_L("ReceiveResponse Remote Pause")));
+
+            if( tcase->iRemoteState != CRemoteTestCase::ECasePauseSent )
+                {
+                __TRACE( KError, (_L("Pause response received in illegal state")));
+                User::Leave( KErrGeneral );                        
+                }
+            tcase->iRemoteState = CRemoteTestCase::ECasePaused;
+            
+            // Start pause timer if timeout was given 
+            if( ( iPausedTestCase.Length() > 0 ) &&
+                ( iPauseTime != 0 ) )
+                {
+                continueTask = EFalse;
+                iState = ERunnerWaitTimeout;
+                iPauseTimer.After( iStatus, iPauseTime*1000 );
+                SetActive();         
+                }
+            break;
+        case CStifTFwIfProt::ECmdResume:
+            __TRACE( KMessage, (_L("ReceiveResponse Remote Resume")));
+
+            if( tcase->iRemoteState != CRemoteTestCase::ECaseResumeSent )
+                {
+                __TRACE( KError, (_L("Resume response received in illegal state")));
+                User::Leave( KErrGeneral );                        
+                }
+            tcase->iRemoteState = CRemoteTestCase::ECaseRunning;
+            break;
+        case CStifTFwIfProt::ECmdCancel:
+            __TRACE( KMessage, (_L("ReceiveResponse Remote Cancel")));
+
+            if( tcase->iRemoteState != CRemoteTestCase::ECaseCancelSent )
+                {
+                __TRACE( KError, (_L("Cancel response received in illegal state")));
+                User::Leave( KErrGeneral );                        
+                }
+            tcase->iRemoteState = CRemoteTestCase::ECaseCancelled;
+            // Need to wait Run response with KErrCancel
+            continueTask = EFalse;
+            // Start timer    
+            iRemoteTimer->SetTimerActive( iTestCombiner->iRemoteTimeout );
+            break;
+        default:
+            // Should never come here
+            User::Leave( KErrGeneral );
+        }
+    
+    return continueTask;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ReceiveResponseEventCtlL
+
+     Description: Handles responses for event system control commands 
+        received from slave
+  
+     Parameters:    CStifTFwIfProt& aMsg: in: protocol message parser
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution 
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ReceiveResponseEventCtlL( CStifTFwIfProt& aMsg )
+    {
+        
+    CSlaveInfo* slave = iTestCombiner->GetSlave( aMsg.SrcId() );
+    if( slave == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }
+    
+    TBool continueTask = ETrue;
+    switch( aMsg.iCmdType )
+        {
+        case CStifTFwIfProt::ECmdRequest:
+            {
+            __TRACE( KMessage, (_L("ReceiveResponse Request")));
+ 
+            TEventTc* event = slave->GetEvent( aMsg.iEventName );
+            if( event == NULL )
+                {
+                User::Leave( KErrNotFound );
+                }
+            switch( aMsg.iEventStatus )
+                {
+                case CStifTFwIfProt::EEventActive:
+                    __TRACE( KMessage, (_L("Event %S active"), &aMsg.iEventName ));
+                    break;
+                case CStifTFwIfProt::EEventSet:
+                    __TRACE( KMessage, (_L("Event %S set"), &aMsg.iEventName ));
+                    // Set event
+                    event->SetEvent( aMsg.iEventType );
+                    continueTask = EFalse;
+                    break;
+                case CStifTFwIfProt::EEventError:
+                    __TRACE( KMessage, (_L("Event %S error %d"), 
+                        &aMsg.iEventName, aMsg.iResult ));
+                    User::Leave( aMsg.iResult );
+                default:
+                    User::Leave( KErrGeneral );
+                }
+            }
+            break;
+        case CStifTFwIfProt::ECmdRelease:
+            __TRACE( KMessage, (_L("ReceiveResponse Release")));
+            if( aMsg.iResult != KErrNone )
+                {
+                __TRACE( KError, (_L("Response with error %d"), aMsg.iResult ));
+                User::Leave( aMsg.iResult );
+                }
+
+            // Everything ok, no need to do anything
+            break;
+        case CStifTFwIfProt::ECmdSetEvent:
+            __TRACE( KMessage, (_L("ReceiveResponse SetEvent")));
+            if( aMsg.iResult != KErrNone )
+                {
+                __TRACE( KError, (_L("Response with error %d"), aMsg.iResult ));
+                User::Leave( aMsg.iResult );
+                }
+
+            // Everything ok, no need to do anything
+            break;
+        case CStifTFwIfProt::ECmdUnsetEvent:
+            __TRACE( KMessage, (_L("ReceiveResponse Unset")));
+            if( aMsg.iResult != KErrNone )
+                {
+                __TRACE( KError, (_L("Response with error %d"), aMsg.iResult ));
+                User::Leave( aMsg.iResult );
+                }
+            // Everything ok, no need to do anything
+            break;
+        default:
+            // Should never come here
+            User::Leave( KErrGeneral );
+        }
+
+    return continueTask;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ReceiveResponseSendReceiveL
+
+     Description: Handles responses for asynchronous sendreceive commands 
+                  received from slave
+  
+     Parameters: CStifTFwIfProt& aMsg: in: protocol message parser
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution 
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ReceiveResponseSendReceiveL( CStifTFwIfProt& aMsg )
+    {
+        
+    TPtrC tmp = CStifTFwIfProt::RunStatus(aMsg.iRunStatus); 
+    __TRACE( KMessage, (
+        _L("ReceiveResponseSendReceiveL asynchronous Remote SendReceive %S"),
+        &tmp ) );
+
+    TBool continueTask = EFalse; 
+    switch( aMsg.iRunStatus )
+        {
+        case CStifTFwIfProt::ERunStarted:
+            {
+            // Locate CRemoteSendReceive object
+            CRemoteSendReceive* sendreceive = 
+                            iTestCombiner->GetRemoteSendReceive( GETDEVID(
+                            aMsg.SrcId() ) );
+            if( sendreceive == NULL ) 
+                {
+                __TRACE( KError, (_L("CRemoteSendReceive object not found")));
+                User::Leave( KErrNotFound );        
+                }
+            sendreceive->iRemoteState = CRemoteSendReceive::ECaseSend;
+
+            // continueTask is EFalse=>stop script file execution
+            break;
+            }
+        case CStifTFwIfProt::ERunError:
+        case CStifTFwIfProt::ERunReady:
+            {
+            if( aMsg.iResult != KErrNone )
+                    {
+                    __TRACE( KError, (_L("sendreceive response with error %d"), aMsg.iResult ));
+                    User::Leave( aMsg.iResult );
+                    }
+
+            // Locate CRemoteSendReceive object
+            CRemoteSendReceive* sendreceive = 
+                iTestCombiner->GetRemoteSendReceive( aMsg.SrcId() );
+            if( sendreceive == NULL ) 
+                {
+                __TRACE( KError, (_L("CRemoteSendReceive object not found")));
+                User::Leave( KErrNotFound );        
+                }
+
+            // continueTask is ETrue=>continue script file execution
+            continueTask = ETrue;
+              
+            sendreceive->iRemoteState = CRemoteSendReceive::ECaseCompleted;
+
+            __TRACE( KMessage, (
+                _L( "ReceiveResponseSendReceiveL asynchronous Remote SendReceive rq comp" ) ) );
+            break;
+            }
+        default:
+            {
+            // Should never come here
+            User::Leave( KErrGeneral );    
+            }
+        }
+    return continueTask;
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ReceiveResponseUnknownL
+
+     Description: Handles responses for unspecified commands
+  
+     Parameters:    CStifTFwIfProt& aMsg: in: protocol message parser
+     
+     Return Values: ETrue: continue script file execution
+                    EFalse: stop script file execution 
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ReceiveResponseUnknownL( CStifTFwIfProt& aMsg )
+    {
+        
+    CSlaveInfo* slave = iTestCombiner->GetSlave( aMsg.SrcId() );
+    if( slave == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }
+    if( aMsg.iResult != KErrNone )
+        {
+        __TRACE( KError, (_L("Response with error %d"), aMsg.iResult ));
+        User::Leave( aMsg.iResult );
+        }
+    
+    return ETrue;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ParseOptArgL
+
+     Description: Parses optional argument 
+  
+     Parameters: const TDesC& aOptArg: in: 
+                    argument-value pair (format arg=value)
+                 TPtrC& aArg: out: parsed argument  
+                 TPtrC& aVal: out: parsed value
+     
+     Return Values: None
+
+     Errors/Exceptions: Leaves if parsing fails.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::ParseOptArgL( const TDesC& aOptArg, TPtrC& aArg, TPtrC& aVal)
+    { 
+    _LIT( KErrMsgUnknownOrIllegalKeyword, "Unknown or illegal argument %S" );
+    _LIT( KErrMsgValueNotDefined, "Value of optional argument %S is not defined" );
+    TInt length = aOptArg.Length();
+    for( TInt i=0; i < length; i++) 
+        {
+        // find the '=' sign 
+        if( aOptArg[i] == '=' )
+            {
+            if( i+1 >= length )
+                {
+                __TRACE( KError, 
+                    (_L("Illegal optional argument(%S), no value"), 
+                    &aOptArg ));    
+				TPtrC tmp = aOptArg.Left( i );
+                iRunErrorMessage.Format( KErrMsgValueNotDefined, &tmp );
+                User::Leave( KErrArgument );
+                }
+            aArg.Set( aOptArg.Left( i ) );
+            aVal.Set( aOptArg.Mid( i+1 ) );
+            __TRACE( KMessage, (  _L( "arg '%S', val '%S'" ),
+                &aArg, &aVal ));        
+            return;
+            }
+        }
+    __TRACE( KError, (_L("Illegal optional argument(%S)"), &aOptArg ));    
+    iRunErrorMessage.Format( KErrMsgUnknownOrIllegalKeyword, &aOptArg );
+    User::Leave( KErrArgument );
+    
+    }     
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: CancelTestCases
+
+     Description: Cancels all running testcases
+  
+     Parameters:    None
+     
+     Return Values: None
+
+     Errors/Exceptions: None.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::CancelTestCases()
+    {
+    __TRACEFUNC();
+
+    TInt count = iTestCombiner->iTestCases.Count();
+    for( TInt i=0; i < count; i++ )
+        {
+        if( iTestCombiner->iTestCases[i]->State() == 
+            CTCTestCase::ETestCaseRunning )
+            {
+            iTestCombiner->iTestCases[i]->Cancel();
+            }
+        }
+        
+    if( ( iTestCombiner->iRunningTests == 0 ) &&
+        iTestCombiner->iSchedulerActive ) 
+        {
+        // Stop execution
+        CActiveScheduler::Current()->Stop();
+        iTestCombiner->iSchedulerActive = EFalse;
+        return;
+        }
+        
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: SetRunnerActive
+
+     Description: Set CTestRunner active and complete.
+  
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::SetRunnerActive()
+     {
+     __TRACEFUNC();
+     
+     if( IsActive() )
+        {
+        __TRACE( KError, ( _L("Runner already active %d"), iState ));
+        User::Panic( KTestRunner, KErrInUse );
+        }
+ 
+     // Update state
+     iState = ERunnerRunning;
+ 
+     iStatus = KRequestPending;
+     TRequestStatus* rs = &iStatus;
+     SetActive();
+     User::RequestComplete( rs, KErrNone );
+     
+     }
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: CheckUnsetEvent
+
+     Description: Check unset event.
+     
+     Parameters: None
+         
+     Return Values: ETrue: Unset event completed
+                    EFalse: No unset event pending
+
+     Errors/Exceptions: None
+
+     Status: Approved
+    
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::CheckUnsetEvent()
+    {
+    if( iEvent.Name().Length() == 0 )
+        {
+        return EFalse;
+        }
+        
+    __TRACE( KMessage, (_L("Unset event completed") ));
+    // Check if some testmodule below has still event request pending
+    if( iTestCombiner->UnsetEvent( iEvent, iStatus ) == EFalse )
+        {
+         // No event request pending
+        // then check other testmodules (may block)
+        TInt res = iTestCombiner->TestModuleIf().Event( iEvent );
+        if( res != KErrNone )
+            {
+            iTestCombiner->iResult = res;
+            }
+            
+        __TRACE( KPrint, (_L("Unset: Complete") ) );
+        iEvent.SetName( _L("") );
+        // Proceed testcase section execution
+        SetRunnerActive();
+        }    
+    else
+        {
+        iState = ERunnerWaitUnset;
+        // Wait for unset to complete 
+        SetActive();
+        }
+         
+    return ETrue;
+    }
+
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteLoopL
+
+     Description: Handle the loop keyword operations.
+
+     Parameters: CStifItemParser* aItem: in: Pointer to parsed item object.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Proposal
+
+-------------------------------------------------------------------------------
+*/
+void CTestRunner::ExecuteLoopL( CStifItemParser* aItem )
+    {
+    _LIT( KErrMsgLoopNestedLoop, "Loop: Nested loops are not supported " );
+    _LIT( KErrMsgLoopInvalidLoopCountParam, "Loop: No loop count value given for loop or value has invalid format" );
+    _LIT( KErrMsgLoopUnknownUnexpectedOption, "Loop: Unknown or unexpected loop option");
+    _LIT( KErrMsgLoopPasslimitInvalidValue, "Loop: No passlimit value given for loop or value has invalid format" );
+    _LIT( KErrMsgLoopPasslimitNotInRange, "Loop: Passlimit value is lower than 0 or higher than loop count" );
+    __TRACEFUNC();
+
+    if( iLoopTimes != 0 )
+        {
+        __TRACE( KError, (_L("ExecuteLoopL: Nested loop are not supported")));
+        iRunErrorMessage = KErrMsgLoopNestedLoop;
+        User::Leave( KErrNotSupported );
+        }
+
+    iLoopTimes = 0;
+    iLoopCounter = 0;
+    iPasslimitEnabled = EFalse;
+    iTimedLoop = EFalse;
+    
+    if( aItem->GetNextInt( iLoopTimes ) != KErrNone )
+        {
+        __TRACE( KError, (_L("ExecuteLoopL: No loop count value given for loop")));
+        iRunErrorMessage = KErrMsgLoopInvalidLoopCountParam;
+        User::Leave( KErrArgument );
+        }
+    __TRACE( KMessage, (_L("ExecuteLoopL: Loop for %d times" ), iLoopTimes ) );
+
+    //Check loop options
+    TPtrC option;
+    TInt ret = aItem->GetNextString(option); 
+    if(ret == KErrNone)
+        {
+        if(option.Compare(_L("msec")) == 0) //time loop option
+            {
+            iTimedLoop = ETrue;
+            iStartTime.HomeTime();
+            iExpectedLoopTime = TInt64(iLoopTimes) * TInt64(1000); //convert to micro seconds
+            __TRACE(KMessage, (_L("ExecuteLoopL: Timed loop for %d msec" ), iLoopTimes));
+            
+            ret = aItem->GetNextString(option); //Get next option
+            }
+        }
+        
+    if(ret == KErrNone)
+        {
+        if(option.Compare(_L("passlimit")) == 0) //passlimit option
+            {
+            iPasslimit = 0;
+            if( aItem->GetNextInt( iPasslimit ) != KErrNone )
+                {
+                __TRACE( KError, ( _L( "ExecuteLoopL: No passlimit value given for loop." ) ) );
+                iRunErrorMessage = KErrMsgLoopPasslimitInvalidValue;
+                User::Leave( KErrArgument );
+                }
+            __TRACE( KMessage, ( _L( "ExecuteLoopL: Passlimit set on %d" ), iPasslimit ) );
+            //Check if passlimit has valid value
+            if(iPasslimit < 0 || (iPasslimit > iLoopTimes && !iTimedLoop))
+                {
+                __TRACE( KError, ( _L( "ExecuteLoopL: Passlimit value is lower than 0 or higher than loop count." ) ) );
+                iRunErrorMessage = KErrMsgLoopPasslimitNotInRange;
+                User::Leave( KErrArgument );
+                }
+            iPasslimitEnabled = ETrue;
+
+            ret = aItem->GetNextString(option); //Get next option
+            }
+        }
+        
+    if(ret == KErrNone)
+        {
+        __TRACE( KError, ( _L( "ExecuteLoopL: Unknown or unexpected loop option [%S]" ), &option ) );
+        iRunErrorMessage = KErrMsgLoopUnknownUnexpectedOption;
+        User::Leave( KErrNotSupported );
+        }
+
+	iPassedIterationCnt = 0;
+
+    iLoopStartPos = iTestCombiner->iSectionParser->GetPosition();
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CTestRunner
+
+     Method: ExecuteEndLoopL
+
+     Description: Handle the endloop keyword operations.
+
+     Parameters: None.
+
+     Return Values: TBool: Boolean value for indicate can testing continue.
+
+     Errors/Exceptions: None.
+
+     Status: Proposal
+
+-------------------------------------------------------------------------------
+*/
+TBool CTestRunner::ExecuteEndLoopL()
+    {
+    __TRACEFUNC();
+
+    // Fail test case if there was no loop started
+    if(iTestCombiner->iLoopIsUsed == EFalse)
+        {
+        __TRACE(KError, (_L("Encountered \'endloop\' without \'loop\'. Aborting test case.")));
+        iTestCombiner->iResult = KErrGeneral;
+        iState = ERunnerError;
+        CancelTestCases();
+        return ETrue; // Test case file parsing can be continue
+        }
+
+	TBool iterationFailed = EFalse; //Has last iteration failed (at least one of test cases has failed)
+
+    // First we check is all test cases that is set to run inside the loop
+    // completed. If not completed we wait until test case completes.
+    // Is some loop executions fails that is not allowed then loop execution
+    // will be stopped and error result is given to TestCombiner
+
+    for( TInt s = 0; s < iTestCombiner->iTestCases.Count(); s++ )
+        {
+        CTestCase* testCase = (CTestCase*)iTestCombiner->iTestCases[s]; 
+        if( testCase == NULL )
+            {
+            __TRACE( KError, (_L("ExecuteEndLoopL: CTestCase object not found") ) );
+            return ETrue;
+            }
+        // Check that testCase object is allocated inside the loop
+        TBool isLoopTestCase( EFalse );
+        for( TInt p = 0; p < iTestCombiner->iLoopAllocationArray.Count(); p++ )
+            {
+            if( iTestCombiner->iLoopAllocationArray[p] == testCase )
+                {
+                isLoopTestCase = ETrue;
+                break;
+                }
+            }
+        // testCase object is allocated inside loop
+        if( isLoopTestCase )
+            {
+            // Test case is completed
+            //if( testCase->State() == CTCTestCase::ETestCaseCompleted )
+            if(testCase->IsCompletelyFinished())
+                {
+                // Check normal test result
+                if( testCase->iExpectedResultCategory == TFullTestResult:: ECaseExecuted )
+                    {
+                    // Normal completion, check result
+                    if( testCase->iResult.iTestResult.iResult != testCase->iExpectedResult )
+                        {
+                        __TRACE( KPrint, ( _L( "Test failed, expect(%d) != result(%d)"), 
+                             testCase->iExpectedResult,
+                             testCase->iResult.iTestResult.iResult ));
+                        //If no passlimit is provided behave in old way
+                        if( !iPasslimitEnabled )
+                             {
+                            // We return the first error result as aResult
+                            if( testCase->iResult.iTestResult.iResult != KErrNone )
+                                {
+                                iTestCombiner->iScriptFailed = testCase->iResult.iCaseExecutionResultCode;
+                                iTestCombiner->iScriptFailedDescription.Copy(testCase->iResult.iTestResult.iResultDes);
+                                }
+                            else
+                                {
+                                iTestCombiner->iScriptFailed = testCase->iResult.iCaseExecutionResultCode;
+                                iTestCombiner->iScriptFailedDescription.Copy(_L("Test case has not finished with expected result (in loop)."));
+                                }
+
+                            iState = ERunnerError;
+                            CancelTestCases();
+                            return ETrue; // Test case file parsing can be continue
+                            }
+                        else
+                            {
+                            // Set flag that one of test cases has failed, so whole iteration is failed
+                            iterationFailed = ETrue;
+                            }
+                        }
+                    }
+                // Abnormal completion, i.e. panic, leave, exception or timeout
+                else 
+                    {
+                    if( testCase->iResult.iCaseExecutionResultCode != testCase->iExpectedResult )
+                        {
+                        __TRACE( KPrint, ( _L( "Test failed, expect errorcode(%d) != result(%d)"), 
+                             testCase->iExpectedResult,
+                             testCase->iResult.iCaseExecutionResultCode ) );
+                        //If no passlimit is provided behave in old way
+                        if( !iPasslimitEnabled )
+                            {
+                            // We return the first error result as aResult
+                            iTestCombiner->iScriptFailed = testCase->iResult.iCaseExecutionResultCode;
+                            iTestCombiner->iScriptFailedDescription.Copy(_L("Test case has not finished with expected execution error (in loop)."));
+
+                            iState = ERunnerError;
+                            // Return error from here
+                            CancelTestCases();
+                            return ETrue; // Test case file parsing can be continue
+                            }
+                        else
+                            {
+                            // Set flag that one of test cases has failed, so whole iteration is failed
+                            iterationFailed = ETrue;
+                            }
+                        }
+
+                    // Requested testcase is completed already,
+                    // proceed testcase execution
+                    __TRACE( KMessage, (_L("Already completed")));
+                    }
+                } // End "Test case is completed"
+            // Test case is running state, set to wait the test case complete
+            else if( testCase->State() == CTCTestCase::ETestCaseRunning )
+                 {
+                 // Wait testcase to complete. If no id there should generate
+                 // id that test case complete will be handled correctly
+                 if( testCase->TestId().Length() == 0 )
+                    {
+                    TPtrC generatedTestId( _L( "stif" ) );
+                    delete testCase->iTestId;
+                    testCase->iTestId = generatedTestId.Alloc();
+                    }
+                iTestCombiner->iWaitTestCase.Copy( testCase->TestId() );
+                 // Stop testcase execution until testcase completed 
+                 iState = ERunnerWaitTestCase;
+                // Go to beginning of the endloop
+                User::LeaveIfError(
+                    iTestCombiner->iSectionParser->SetPosition( iEndLoopStartPos ));
+
+                // Testing is ongoing, test case file parsing cannot
+                // be continue. Next line will be run when some AO
+                // will be complete and allow parsing to continue
+                return EFalse; 
+                }
+            else if(testCase->State() == CTCTestCase::ETestCaseCompleted)
+                {
+                // Go to beginning of the endloop
+                User::LeaveIfError(iTestCombiner->iSectionParser->SetPosition(iEndLoopStartPos));
+
+                // Testing is ongoing, test case file parsing cannot
+                // be continue. Next line will be run when some AO
+                // will be complete and allow parsing to continue
+                return ETrue;
+                }
+            else
+                {
+                // This should newer happen
+                __TRACE( KError, (_L("ExecuteEndLoopL: Illegal branch") ) );
+                }
+            }
+        } // end for-loop
+
+    iLoopCounter++;
+    __TRACE( KMessage, (_L("ExecuteLineL: Loop executed for %d times" ), 
+            iLoopCounter ) );
+
+    //If passlimit (endurance) is enabled, we must check if any of test case in this iteration has failed
+    if( iPasslimitEnabled && !iterationFailed )
+    	{
+    	iPassedIterationCnt++;
+    	}
+
+    TTime currTime;
+    currTime.HomeTime();
+    //if( iLoopCounter < iLoopTimes )
+    if(((!iTimedLoop) && (iLoopCounter < iLoopTimes)) //Normal loop
+       ||
+       iTimedLoop && (currTime.MicroSecondsFrom(iStartTime) < iExpectedLoopTime)) //Timed loop
+        {
+        // Go to beginning of the loop
+        User::LeaveIfError(
+            iTestCombiner->iSectionParser->SetPosition( iLoopStartPos ));
+        }
+    else
+        {
+        // End looping
+        if( iPasslimitEnabled )
+        	{
+	        __TRACE(KMessage, (_L("ExecuteLoopL: Loop executed. Iterations: %d, passed: %d, expected: %d"), iLoopCounter, iPassedIterationCnt, iPasslimit));
+        	}
+
+        iLoopCounter = 0;
+        iLoopTimes = 0;
+        iLoopStartPos = 0;
+        // Loop related initializations
+        iTestCombiner->iLoopIsUsed = EFalse;
+        //--LOOPBUG-- Do not zero counter because there could be some test cases run before the loop (Stif-83)
+        //--LOOPBUG-- iTestCombiner->iRunningTests = 0;
+
+        //If passlimit was given and number of passed test is less then expected, stop execution of combiner's test case
+        if( iPasslimitEnabled && iPassedIterationCnt < iPasslimit )
+        	{
+	        __TRACE( KMessage, ( _L( "ExecuteLoopL: Loop has failed (passlimit). Finishing with KErrCompletion." ) ) );
+            iTestCombiner->iScriptFailed = KErrCompletion;
+            iTestCombiner->iScriptFailedDescription = _L("Loop has not reached passlimit requirement.");
+            iState = ERunnerError;
+            CancelTestCases();
+            return ETrue; // Test case file parsing can be continue
+        	}
+        else if( iPasslimitEnabled && iPassedIterationCnt >= iPasslimit )
+        	{
+	        __TRACE( KMessage, ( _L( "ExecuteLoopL: Loop has passed (passlimit)" ) ) );
+        	}
+        iPassedIterationCnt = 0;
+        iPasslimit = 0;
+        iPasslimitEnabled = EFalse;
+        }
+
+    // Loop time is executed, free allocations that is allocated during loop
+    TInt a( 0 );
+    TInt b( 0 );
+
+    for( b = 0; b < iTestCombiner->iLoopAllocationArray.Count(); b++ )
+        {
+        //for( a = 0; a < iTestCombiner->iLoopAllocationArray.Count(); a++ )
+        for( a = 0; a < iTestCombiner->iTestCases.Count(); a++ )
+            {
+            if( a < iTestCombiner->iTestCases.Count() && iTestCombiner->iTestCases[a] == iTestCombiner->iLoopAllocationArray[b] )
+                {
+                delete iTestCombiner->iTestCases[a];
+                iTestCombiner->iTestCases.Remove( a );
+                }
+            }
+        }
+
+    for( b = 0; b < iTestCombiner->iLoopAllocationArray.Count(); b++ )
+        {
+        //for( a = 0; a < iTestCombiner->iLoopAllocationArray.Count(); a++ )
+        for( a = 0; a < iTestCombiner->iTestModules.Count(); a++ )
+            {
+            if( a < iTestCombiner->iTestModules.Count() && iTestCombiner->iTestModules[a] == iTestCombiner->iLoopAllocationArray[b] )
+                {
+                delete iTestCombiner->iTestModules[a];
+                iTestCombiner->iTestModules.Remove( a );
+                }
+            }
+        }
+
+    for( b = 0; b < iTestCombiner->iLoopAllocationArray.Count(); b++ )
+        {
+        //for( a = 0; a < iTestCombiner->iLoopAllocationArray.Count(); a++ )
+        for( a = 0; a < iTestCombiner->iEventArray.Count(); a++ )
+            {
+            if( a < iTestCombiner->iEventArray.Count() && iTestCombiner->iEventArray[a] == iTestCombiner->iLoopAllocationArray[b] )
+                {
+                delete iTestCombiner->iEventArray[a];
+                iTestCombiner->iEventArray.Remove( a );
+                }
+            }
+        }
+    for( b = 0; b < iTestCombiner->iLoopAllocationArray.Count(); b++ )
+        {
+        //for( a = 0; a < iTestCombiner->iLoopAllocationArray.Count(); a++ )
+        for( a = 0; a < iTestCombiner->iSlaveArray.Count(); a++ )
+            {
+            if( a < iTestCombiner->iSlaveArray.Count() && iTestCombiner->iSlaveArray[a] == iTestCombiner->iLoopAllocationArray[b] )
+                {
+                delete iTestCombiner->iSlaveArray[a];
+                iTestCombiner->iSlaveArray.Remove( a );
+                }
+            }
+        }
+    for( b = 0; b < iTestCombiner->iLoopAllocationArray.Count(); b++ )
+        {
+        //for( a = 0; a < iTestCombiner->iLoopAllocationArray.Count(); a++ )
+        for( a = 0; a < iTestCombiner->iSendReceive.Count(); a++ )
+            {
+            if( a < iTestCombiner->iSendReceive.Count() && iTestCombiner->iSendReceive[a] == iTestCombiner->iLoopAllocationArray[b] )
+                {
+                delete iTestCombiner->iSendReceive[a];
+                iTestCombiner->iSendReceive.Remove( a );
+                }
+            }
+        }
+
+    // Test operation can be continued
+    return ETrue; // Test case file parsing can be continue
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+    DESCRIPTION
+
+    This module contains the implementation of CRemoteTimer class 
+    member functions. 
+
+-------------------------------------------------------------------------------
+*/
+// MACROS
+#ifdef LOGGER
+#undef LOGGER
+#endif
+#define LOGGER iTestRunner->iTestCombiner->iLog
+
+// ================= MEMBER FUNCTIONS =========================================
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: CRemoteTimer
+
+     Description: Default constructor
+
+     C++ default constructor can NOT contain any code, that
+     might leave.
+     
+     Parameters: CTestRunner* aTestRunner: in: Backpointer to CTestRunner
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteTimer::CRemoteTimer( CTestCombiner* aTestCombiner ): 
+    CActive(  CActive::EPriorityLow ), // Executed with lowest priority 
+    iState( ETimerIdle ),
+    iTestCombiner( aTestCombiner )
+    {
+    CActiveScheduler::Add( this );
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: ConstructL
+
+     Description: Symbian OS second phase constructor
+
+     Symbian OS default constructor can leave.
+
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteTimer::ConstructL()
+    {
+    
+    iTimer.CreateLocal();
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: NewL
+
+     Description: Two-phased constructor.
+          
+     Parameters: CTestCombiner* aTestCombiner: in: Backpointer to CTestCombiner
+
+     Return Values: CRemoteTimer*: new object
+
+     Errors/Exceptions: Leaves if new or ConstructL leaves
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+
+CRemoteTimer* CRemoteTimer::NewL(  CTestCombiner* aTestCombiner )
+    {
+    
+    CRemoteTimer* self = new (ELeave) CRemoteTimer( aTestCombiner );
+     
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: ~CRemoteTimer
+
+     Description: Destructor
+     
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/     
+
+CRemoteTimer::~CRemoteTimer()
+    {
+    
+    Cancel();
+    
+    iTimer.Close();
+         
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: RunL
+
+     Description: Derived from CActive, handles testcase execution.
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteTimer::RunL()
+    {
+        
+    if( iState != ETimerPending )
+        {
+        User::Panic( KRemoteTimer, KErrGeneral );
+        }
+    
+    if( iStatus.Int() != KErrNone )
+        {
+        User::Panic( KRemoteTimer, KErrDied );
+        }
+    
+    iState = ETimerIdle;
+    
+    iTestCombiner->RemoteTimeout();
+    
+    }
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: DoCancel
+
+     Description: Derived from CActive handles the Cancel
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteTimer::DoCancel()
+    {
+    iTimer.Cancel();
+    iState = ETimerIdle;
+      
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteTimer
+
+     Method: SetTimerActive
+
+     Description: Starts timer
+
+     Parameters:   TTimeIntervalMicroSeconds32 anInterval: in: Timeout
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Draft
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteTimer::SetTimerActive( TTimeIntervalMicroSeconds32 anInterval )
+    {
+    if( iState != ETimerIdle )
+        {
+        User::Panic( KRemoteTimer, KErrGeneral );
+        }
+        
+    iState = ETimerPending;
+    
+    iTimer.After( iStatus, anInterval );
+    SetActive();         
+    
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+    DESCRIPTION
+
+    This module contains the implementation of CRemoteReceiver class 
+    member functions. 
+
+-------------------------------------------------------------------------------
+*/
+// MACROS
+#ifdef LOGGER
+#undef LOGGER
+#endif
+#define LOGGER iTestCombiner->iLog
+
+// ================= MEMBER FUNCTIONS =========================================
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: CRemoteReceiver
+
+     Description: Default constructor
+
+     C++ default constructor can NOT contain any code, that
+     might leave.
+     
+     Parameters: CTestCombiner* aTestCombiner: in: Backpointer to CTestCombiner
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+CRemoteReceiver::CRemoteReceiver( CTestCombiner* aTestCombiner ): 
+    CActive(  CActive::EPriorityStandard ), 
+    iState( EReceiverIdle ),
+    iTestCombiner( aTestCombiner )
+    {
+    CActiveScheduler::Add( this );
+    __TRACEFUNC();
+    
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: ConstructL
+
+     Description: Symbian OS second phase constructor
+
+     Symbian OS default constructor can leave.
+
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteReceiver::ConstructL()
+    {
+    
+
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: NewL
+
+     Description: Two-phased constructor.
+          
+     Parameters: CTestCombiner* aTestCombiner: in: Backpointer to CTestCombiner
+
+     Return Values: CRemoteReceiver*: new object
+
+     Errors/Exceptions: Leaves if new or ConstructL leaves
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+
+CRemoteReceiver* CRemoteReceiver::NewL( CTestCombiner* aTestCombiner )
+    {
+    CRemoteReceiver* self = new (ELeave) CRemoteReceiver( aTestCombiner );
+     
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: ~CRemoteReceiver
+
+     Description: Destructor
+     
+     Parameters:    None
+
+     Return Values: None
+
+     Errors/Exceptions: None
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/     
+
+CRemoteReceiver::~CRemoteReceiver()
+    {
+    __TRACEFUNC();
+    Cancel();
+
+         
+    }
+    
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: StartL
+
+     Description: Activates receiving.
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteReceiver::Start()
+    {
+    __TRACEFUNC();
+    __ASSERT_ALWAYS( iState == EReceiverIdle, 
+        User::Panic( KRemoteReceiver, KErrGeneral ) );
+    iState = EReceiverPending;
+    
+    iTestCombiner->TestModuleIf().RemoteReceive( iRemoteMsg, iStatus );        
+    SetActive();
+                 
+    }
+
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: RunL
+
+     Description: Derived from CActive, handles testcase execution.
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: Leaves on error situations.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteReceiver::RunL()
+    {
+    __TRACEFUNC();
+    
+    __ASSERT_ALWAYS( iState == EReceiverPending, 
+        User::Panic( KRemoteReceiver, KErrGeneral ) );
+    iState = EReceiverIdle;
+    
+    iTestCombiner->ReceiveResponse( iRemoteMsg );
+                 
+    }
+     
+/*
+-------------------------------------------------------------------------------
+
+     Class: CRemoteReceiver
+
+     Method: DoCancel
+
+     Description: Derived from CActive handles the Cancel
+
+     Parameters:    None.
+
+     Return Values: None.
+
+     Errors/Exceptions: None.
+
+     Status: Proposal
+    
+-------------------------------------------------------------------------------
+*/
+void CRemoteReceiver::DoCancel()
+    {
+    __TRACEFUNC();
+    
+    iTestCombiner->TestModuleIf().RemoteReceiveCancel();
+ 
+    }
+    
+// ================= OTHER EXPORTED FUNCTIONS =================================
+
+/*
+-------------------------------------------------------------------------------
+    
+     Function: LibEntryL
+
+     Description: Polymorphic Dll Entry Point
+
+     Parameters:    None.
+
+     Return Values: CTestCombiner*: pointer to new CTestCombiner
+
+     Errors/Exceptions: Leaves if NewL leaves.
+
+     Status: Approved
+     
+-------------------------------------------------------------------------------
+*/
+
+EXPORT_C CTestCombiner* LibEntryL()
+    {
+    return CTestCombiner::NewL();
+    }
+
+// End of File