diff -r 000000000000 -r 3e07fef1e154 testexecfw/symbianunittestfw/sutfw/sutfwcore/sutfwframework/src/symbianunittest.cpp --- /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 +#include +#include +#include + +// 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; + }