testexecfw/symbianunittestfw/sutfw/sutfwcore/sutfwframework/src/symbianunittest.cpp
changeset 0 3e07fef1e154
child 1 bbd31066657e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecfw/symbianunittestfw/sutfw/sutfwcore/sutfwframework/src/symbianunittest.cpp	Mon Mar 08 15:03:44 2010 +0800
@@ -0,0 +1,624 @@
+/*
+* 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:  
+*
+*/
+
+#include "symbianunittestresult.h"
+#include "symbianunittestobserver.h"
+#include "sutlogger.h"
+#include <symbianunittest.h>
+#include <e32math.h>
+#include <utf.h>
+#include <e32debug.h>
+
+// Assertion failure message formats:
+_LIT8( KIntsNotEqualFormat, "Asserted: expected=%d, actual=%d" );
+_LIT8( KDesCsNotEqualFormat, "Asserted: expected='%S', actual='%S'" );
+_LIT8( KAssertLeaveFormat1, "'%S' expected to leave: expected=%d, actual=%d" );
+_LIT8( KAssertLeaveFormat2, "'%S' expected to leave but did not leave" );
+
+const TInt KMaxSizeOfTwoIntsAsText = 80;
+const TInt KErrSymbianUnitTestAssertionFailed = -99999999;
+_LIT( KTestThreadName, "SymbianUnitTestThread" );
+const TInt KTestThreadMaxHeapSize = 0x400000; // 4 MB
+_LIT8( KDoubleColon8, "::" );
+_LIT( KDoubleColon16, "::" );
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::ConstructL( const TDesC8& aName )
+    {    
+    TInt doubleColonPos( aName.FindF( KDoubleColon8 ) );
+    TPtrC8 classNamePtr( aName );
+    if ( doubleColonPos > 0 )
+        {
+        classNamePtr.Set( aName.Left( doubleColonPos ) );
+        }
+    iName = CnvUtfConverter::ConvertToUnicodeFromUtf8L( classNamePtr );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CSymbianUnitTest::CSymbianUnitTest()
+ : iAllocFailureType( RHeap::ENone ),
+   iAllocFailureRate( 0 )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CSymbianUnitTest::~CSymbianUnitTest() 
+    { 
+    delete iName;
+    iTestCases.ResetAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// From MSymbianUnitTestInterface
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::ExecuteL(
+    MSymbianUnitTestObserver& aObserver,
+    CSymbianUnitTestResult& aResult,
+    MSymbianUnitTestInterface::TFailureSimulation aFailureSimulation,
+    const CDesCArray& aTestCaseNames,
+    TInt aTimeout )
+    {
+    if ( aFailureSimulation == EMemAllocFailureSimulation )
+        {
+        iAllocFailureType = RHeap::EDeterministic;
+        }
+    else
+        {
+        iAllocFailureType = RHeap::ENone;
+        }      
+    SUT_LOG_FORMAT(_L("start testing, total test cases[%d]"), iTestCases.Count());
+    //print the test cases name in the log
+    for ( TInt i = iTestCases.Count() -1; i >=0 ; i-- )
+        {
+        CSymbianUnitTestCase& testCase = *( iTestCases[ i ] );
+	//check the specified test case list if any
+	if ( aTestCaseNames.Count() > 0 )
+	    {
+	    TInt index=0;
+	    TInt ret = aTestCaseNames.Find(testCase.Name(), index );
+	    if (ret != 0)
+	        {
+		//the case isn't in the specified test case names, skip it
+                SUT_LOG_FORMAT(_L("skip test case[%S]"), &testCase.Name());
+		delete iTestCases[i];
+                iTestCases.Remove(i);
+                continue;
+	        }
+	    }
+	SUT_LOG_FORMAT(_L("TestCase[%S]"), &testCase.Name());
+        }
+
+    for ( TInt i = 0; i < iTestCases.Count(); i++ )
+        {
+        CSymbianUnitTestCase& testCase = *( iTestCases[ i ] );
+
+        aResult.StartTestL( testCase.Name() );
+        ExecuteTestCaseInThreadL( testCase, aResult, aTimeout );
+        aResult.EndTestL();
+        aObserver.IncrementExecutedTestsCount();        
+        }
+    SUT_LOG_FORMAT(_L("testing finished, total passed test cases[%d]"), aResult.PassedTestCount());
+    }
+
+// -----------------------------------------------------------------------------
+// From MSymbianUnitTestInterface
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CSymbianUnitTest::TestCaseCount()
+    {
+    return iTestCases.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// From MSymbianUnitTestInterface
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const TDesC& CSymbianUnitTest::Name() const
+    {
+    if ( iName )
+        {
+        return *iName;
+        }
+    return KNullDesC;
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::SetupL()
+    {
+    // The default implementation is no operation
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::Teardown()
+    {
+    // The default implementation is no operation
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CSymbianUnitTest::IsMemoryAllocationFailureSimulationUsed() const
+    {
+    return ( iAllocFailureType == RHeap::EDeterministic );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::AddTestCaseL( 
+    const TDesC& aName,
+    FunctionPtr aSetupFunction,
+    FunctionPtr aTestFunction,
+    FunctionPtr aTeardownFunction )
+    {
+    const TInt KTestCaseNameLength = 
+        Name().Length() + KDoubleColon16().Length() + aName.Length(); 
+    HBufC* name = HBufC::NewLC( KTestCaseNameLength );
+    name->Des().Append( Name() );
+    name->Des().Append( KDoubleColon16 );
+    name->Des().Append( aName ); 
+    CSymbianUnitTestCase* testCase = 
+        CSymbianUnitTestCase::NewL( 
+            *name, aSetupFunction, aTestFunction, aTeardownFunction );
+    CleanupStack::PopAndDestroy( name );
+    CleanupStack::PushL( testCase );
+    iTestCases.AppendL( testCase );
+    CleanupStack::Pop( testCase );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::AssertEqualsL(
+    TInt aExpectedValue, 
+    TInt aActualValue, 
+    TInt aLineNumber,
+    const TDesC8& aFileName )
+    {
+    if ( aExpectedValue != aActualValue )
+        {
+        StopAllocFailureSimulation();
+        HBufC8* msg = HBufC8::NewLC( 
+            KIntsNotEqualFormat().Size() + KMaxSizeOfTwoIntsAsText );
+        msg->Des().Format( KIntsNotEqualFormat, aExpectedValue, aActualValue );
+        AssertionFailedL( *msg, aLineNumber, aFileName );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::AssertEqualsL(
+    const TDesC8& aExpectedValue,
+    const TDesC8& aActualValue,
+    TInt aLineNumber,
+    const TDesC8& aFileName )
+    {
+    if ( aExpectedValue.Compare( aActualValue ) != 0 )
+        {
+        StopAllocFailureSimulation();
+        TInt size = 
+            KDesCsNotEqualFormat().Size() + 
+            aExpectedValue.Size() + 
+            aActualValue.Size();
+        HBufC8 *msg = HBufC8::NewLC( size );
+        msg->Des().Format( KDesCsNotEqualFormat, 
+                           &aExpectedValue, 
+                           &aActualValue );
+        AssertionFailedL( *msg, aLineNumber, aFileName );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::AssertEqualsL(
+    const TDesC16& aExpectedValue,
+    const TDesC16& aActualValue,
+    TInt aLineNumber,
+    const TDesC8& aFileName )
+    {
+    if ( aExpectedValue.Compare( aActualValue ) != 0 )
+        {
+        StopAllocFailureSimulation();
+        HBufC8* msg = NotEqualsMessageLC( aExpectedValue, aActualValue );
+        AssertionFailedL( *msg, aLineNumber, aFileName );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::AssertLeaveL(
+    const TDesC8& aStatement,
+    TInt aActualLeaveCode,
+    TInt aExpectedLeaveCode,
+    TInt aLineNumber,
+    const TDesC8& aFileName )
+    {
+    if ( aActualLeaveCode == KErrNoMemory &&
+         aExpectedLeaveCode != KErrNoMemory &&
+         iAllocFailureType == RHeap::EDeterministic )
+        {
+        User::Leave( KErrNoMemory );
+        }   
+    if ( aActualLeaveCode != aExpectedLeaveCode )
+        {
+        StopAllocFailureSimulation();
+        HBufC8* msg = HBufC8::NewLC( 
+            KAssertLeaveFormat1().Size() + 
+            aStatement.Size() + 
+            KMaxSizeOfTwoIntsAsText );
+        msg->Des().Format( KAssertLeaveFormat2, &aStatement, 
+                           aExpectedLeaveCode, aActualLeaveCode );        
+        AssertionFailedL( *msg, aLineNumber, aFileName );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::RecordNoLeaveFromStatementL(
+    const TDesC8& aStatement,
+    TInt aLineNumber,
+    const TDesC8& aFileName )
+    {
+    StopAllocFailureSimulation();
+    HBufC8* msg = 
+        HBufC8::NewLC( KAssertLeaveFormat1().Size() + aStatement.Size() );
+    msg->Des().Format( KAssertLeaveFormat1, &aStatement );        
+    AssertionFailedL( *msg, aLineNumber, aFileName );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CSymbianUnitTest::AssertionFailedL(
+    const TDesC8& aFailureMessage,
+    TInt aLineNumber,
+    const TDesC8& aFileName )
+    {
+    TInt dummy( 0 );
+    TInt heapCellsBeforeAddingTheFailure( User::Heap().AllocSize( dummy ) );
+    
+    if ( iTestResult )
+        {
+        User::LeaveIfError( iTestResult->AddAssertFailure( 
+            aFailureMessage, aLineNumber, aFileName ) );
+        }
+        
+    TInt heapCellsAfterAddingTheFailure( User::Heap().AllocSize( dummy ) );
+    iHeapCellsReservedByAssertFailure = 
+        heapCellsAfterAddingTheFailure - heapCellsBeforeAddingTheFailure;
+    User::Leave( KErrSymbianUnitTestAssertionFailed );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+CSymbianUnitTest::CSymbianUnitTestCase* 
+CSymbianUnitTest::CSymbianUnitTestCase::NewL( 
+    const TDesC& aName,
+    FunctionPtr aSetupFunction,
+    FunctionPtr aTestFunction,
+    FunctionPtr aTeardownFunction )
+    {
+    CSymbianUnitTestCase* self = 
+        new( ELeave )CSymbianUnitTestCase( 
+            aSetupFunction, aTestFunction, aTeardownFunction );
+    CleanupStack::PushL( self );
+    self->ConstructL( aName );
+    CleanupStack::Pop( self );
+    return self;    
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+CSymbianUnitTest::CSymbianUnitTestCase::CSymbianUnitTestCase( 
+    FunctionPtr aSetupFunction,
+    FunctionPtr aTestFunction,
+    FunctionPtr aTeardownFunction ) :
+    iSetupFunction( aSetupFunction ),
+    iTestFunction( aTestFunction ),
+    iTeardownFunction( aTeardownFunction )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CSymbianUnitTest::CSymbianUnitTestCase::ConstructL( const TDesC& aName )
+    {
+    iName = aName.AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+CSymbianUnitTest::CSymbianUnitTestCase::~CSymbianUnitTestCase()
+    {
+    delete iName;
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+const TDesC& CSymbianUnitTest::CSymbianUnitTestCase::Name() const
+    {
+    return *iName;
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+HBufC8* CSymbianUnitTest::NotEqualsMessageLC(
+    const TDesC16& aExpectedValue,
+    const TDesC16& aActualValue )
+    {
+    TInt length = 
+        KDesCsNotEqualFormat().Length() + 
+        aExpectedValue.Length() + 
+        aActualValue.Length();
+    HBufC8* msg = HBufC8::NewLC( length );
+
+    HBufC8* expected = 
+        CnvUtfConverter::ConvertFromUnicodeToUtf8L( aExpectedValue );
+    CleanupStack::PushL( expected );
+
+    HBufC8* actual = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aActualValue );
+    CleanupStack::PushL( actual );
+
+    msg->Des().Format( KDesCsNotEqualFormat, expected, actual );
+
+    CleanupStack::PopAndDestroy( actual );
+    CleanupStack::PopAndDestroy( expected );
+    
+    return msg;
+    }
+    
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CSymbianUnitTest::ExecuteTestCaseInThreadL(
+    CSymbianUnitTestCase& aTestCase,
+    CSymbianUnitTestResult& aResult,
+    TInt aTimeout )
+    {
+    iCurrentTestCase = &aTestCase;
+    iTestResult = &aResult;
+
+    //create exec thread
+    TName threadName( KTestThreadName );
+    // Append a random number to make the name unique
+    const TInt KThreadIdWidth = 10;
+    threadName.AppendNumFixedWidthUC( Math::Random(), EHex, KThreadIdWidth );
+    RThread execThread;
+    TInt err = execThread.Create( threadName,
+                              TestThreadEntryFunction,
+                              KDefaultStackSize,
+                              KMinHeapSize,
+                              KTestThreadMaxHeapSize,
+                              this );
+    User::LeaveIfError( err );
+    CleanupClosePushL( execThread );
+    
+
+    //start exec thread
+    TRequestStatus status;
+    execThread.Logon( status );
+    execThread.Resume();
+    
+    TBool timedOut = EFalse;
+    if (aTimeout > 0 )
+        {
+	SUT_LOG_DEBUGF(_L("run test case with timeout %d"), aTimeout);
+	//run test case with timeout control
+        TRequestStatus waitStatus = KRequestPending;
+        RTimer timer;
+        User::LeaveIfError(timer.CreateLocal());
+        CleanupClosePushL(timer);
+        timer.After(waitStatus, aTimeout*1000000);
+        User::WaitForRequest( status, waitStatus );
+        if (waitStatus.Int() == KRequestPending)
+            {
+            timer.Cancel();
+            }
+
+        if (status.Int() == KRequestPending)
+            {
+	    //test case did not complete in time
+	    //terminate the exec thread
+	    SUT_LOG_DEBUG(" test case timed out, kill the exec thread");
+	    timedOut = ETrue;
+            execThread.Kill(KErrTimedOut);
+	    aResult.AddTimeOutErrorL( aTimeout );
+            } 
+        CleanupStack::PopAndDestroy( &timer );
+	}
+    else 
+        {
+	SUT_LOG_DEBUG(" run test case without timeout");
+	//exec test case without timeout control
+        User::WaitForRequest(status);
+        }
+    if (status.Int() != KErrNone && !timedOut)
+        {
+        SUT_LOG_DEBUG("testcase exec thread panic");
+        aResult.AddPanicInfoL( 
+        execThread.ExitCategory(), 
+        execThread.ExitReason(), 
+        iAllocFailureRate );
+        }
+    CleanupStack::PopAndDestroy( &execThread );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TInt CSymbianUnitTest::TestThreadEntryFunction( TAny* aPtr )
+    {
+    CSymbianUnitTest* self = reinterpret_cast< CSymbianUnitTest* >( aPtr );
+    TInt err = KErrNoMemory;
+    CTrapCleanup* cleanupStack = CTrapCleanup::New();
+    if ( cleanupStack )
+        {
+        // Operator new used without ELeave on purpose to avoid using TRAP.
+        CActiveScheduler* scheduler = new CActiveScheduler;
+        if ( scheduler )
+            {
+            CActiveScheduler::Install( scheduler );
+            TRAP( err, self->ExecuteTestCaseL() )
+            delete scheduler;
+            }
+        }
+    delete cleanupStack;
+    return err;
+    }    
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CSymbianUnitTest::ExecuteTestCaseL()
+    {    
+    __ASSERT_ALWAYS( iTestResult, User::Leave( KErrNotFound ) );
+    __ASSERT_ALWAYS( iCurrentTestCase, User::Leave( KErrNotFound ) );
+    iAllocFailureRate = 0;
+    iLeakedMemory = 0;
+    TInt leaveCodeFromTest( KErrNoMemory );
+    if ( iAllocFailureType == RHeap::EDeterministic )
+        {
+        TUint counter( 1 );
+        while ( leaveCodeFromTest == KErrNoMemory )
+            {
+            iAllocFailureRate = counter;
+            DoExecuteTestCaseL( leaveCodeFromTest );
+            counter++;
+            }
+        }
+    else
+        {
+        DoExecuteTestCaseL( leaveCodeFromTest );
+        }
+    // Add the possible failure or memory leak to the results
+    if ( leaveCodeFromTest == KErrNone )
+        {
+        if ( iLeakedMemory > 0 )
+            {
+            iTestResult->AddMemoryLeakInfoL( iLeakedMemory, iAllocFailureRate );
+            }     
+        }
+    else if ( leaveCodeFromTest != KErrSymbianUnitTestAssertionFailed )
+        {
+        iTestResult->AddLeaveFromTestL( leaveCodeFromTest, iAllocFailureRate );
+        }
+    else
+        {
+        // No operation here. 
+        // Assertion failure has happened and it has been added to the results.
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CSymbianUnitTest::DoExecuteTestCaseL( TInt& aLeaveCodeFromTest )
+    {
+    __ASSERT_ALWAYS( iTestResult, User::Leave( KErrNotFound ) );
+    __ASSERT_ALWAYS( iCurrentTestCase, User::Leave( KErrNotFound ) );
+    
+    aLeaveCodeFromTest = KErrNone;
+    iHeapCellsReservedByAssertFailure = 0;
+    TInt memoryBeforeTest( 0 ); 
+    TInt heapCellsBeforeTest( User::Heap().AllocSize( memoryBeforeTest ) );
+    
+    TRAPD( err, ( this->*iCurrentTestCase->iSetupFunction )() )
+    if ( err != KErrNone )
+        {       
+        ( this->*iCurrentTestCase->iTeardownFunction )();
+        iTestResult->AddSetupErrorL( err );
+        return;
+        }
+    
+    StartAllocFailureSimulation();
+    TRAP( aLeaveCodeFromTest, ( this->*iCurrentTestCase->iTestFunction )() );
+    StopAllocFailureSimulation();
+       
+    ( this->*iCurrentTestCase->iTeardownFunction )();
+
+    TInt memoryAfterTest( 0 );
+    TInt heapCellsAfterTest( User::Heap().AllocSize( memoryAfterTest ) );
+    TInt leakedHeapCells = 
+        heapCellsAfterTest - 
+            ( heapCellsBeforeTest + iHeapCellsReservedByAssertFailure );
+    if ( leakedHeapCells > 0 )
+        {
+        iLeakedMemory = memoryAfterTest - memoryBeforeTest;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CSymbianUnitTest::StartAllocFailureSimulation()
+    {
+    __UHEAP_SETFAIL( iAllocFailureType, iAllocFailureRate );
+    }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CSymbianUnitTest::StopAllocFailureSimulation()
+    {
+    __UHEAP_RESET;
+    }