sl@0: // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "IpuTestUtils.h" sl@0: #include sl@0: // sl@0: // Constants sl@0: _LIT(KTestPanic, "IpuTestHarness"); sl@0: const TInt KFailedTestsGranularity = 10; sl@0: const TInt KMaxLogEntrySize = 256; sl@0: sl@0: // sl@0: // CIpuTestHarness sl@0: // sl@0: CIpuTestHarness::CIpuTestHarness(const TDesC& aTitle) sl@0: : iTest(aTitle) sl@0: // sl@0: // Default c'tor sl@0: { sl@0: LogRTestToFile(iTest); sl@0: iTest.Title(); sl@0: iCanStartTest = ETrue; sl@0: } sl@0: sl@0: CIpuTestHarness::~CIpuTestHarness() sl@0: // sl@0: // D'tor sl@0: { sl@0: TTime endtime; sl@0: endtime.UniversalTime(); sl@0: sl@0: // Do resource handle leak test? sl@0: if (iDoResourceLeakTest) sl@0: ResourceLeakTest(); sl@0: sl@0: // End of tests - see if failed or ok sl@0: if (iFailedTests->Count()) sl@0: { sl@0: TestHarnessFailed(); sl@0: } sl@0: else sl@0: { sl@0: TestHarnessComplete(); sl@0: } sl@0: sl@0: iFailedTests->ResetAndDestroy(); sl@0: delete iFailedTests; sl@0: sl@0: // Log finish time sl@0: TDateTime t = endtime.DateTime(); sl@0: LogIt(_L("Ended @ %d:%d:%d:%d"),t.Hour(),t.Minute(),t.Second(),t.MicroSecond()); sl@0: TTime difftime(endtime.Int64() - iStartTime.Int64()); sl@0: t = difftime.DateTime(); sl@0: LogIt(_L("Execution time %d:%d:%d:%d"),t.Hour(),t.Minute(),t.Second(),t.MicroSecond()); sl@0: sl@0: // Close logs and test harness sl@0: iFlogger.CloseLog(); sl@0: sl@0: // iTest test harness performs UHEAP MARK/UNMARK check upon creation/destruction sl@0: // therefore, it must be destroyed last since it is created first in sl@0: // CIpuTestHarness sl@0: iTest.Close(); sl@0: } sl@0: sl@0: EXPORT_C CIpuTestHarness* CIpuTestHarness::NewLC(const TDesC& aTitle) sl@0: // sl@0: // Static factory c'tor sl@0: { sl@0: CIpuTestHarness* self = new (ELeave) CIpuTestHarness(aTitle); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aTitle); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CIpuTestHarness* CIpuTestHarness::NewL(const TDesC& aTitle) sl@0: // sl@0: // Static factiry c'tor sl@0: { sl@0: CIpuTestHarness* self = CIpuTestHarness::NewLC(aTitle); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: void CIpuTestHarness::ConstructL(const TDesC& aTitle) sl@0: // sl@0: // Non-trivial c'tor sl@0: { sl@0: // Create iFailedTests sl@0: iFailedTests = new (ELeave) CArrayPtrFlat (KFailedTestsGranularity); sl@0: sl@0: // Start up logging server connection sl@0: TBuf<64> temp(aTitle); sl@0: DefaultLogFileName(temp); sl@0: CreateFlogger(temp, EFalse, EFalse); sl@0: sl@0: iStartTime.UniversalTime(); sl@0: TDateTime t = iStartTime.DateTime(); sl@0: LogIt(_L("Started @ %d:%d:%d:%d"),t.Hour(),t.Minute(),t.Second(),t.MicroSecond()); sl@0: sl@0: // Find number of open resource handles sl@0: TInt processHandleCount=0; sl@0: RThread().HandleCount(processHandleCount,iStartHandleCount); sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::StartTestL(const TDesC& aName) sl@0: // sl@0: // Logs start of test aName sl@0: { sl@0: if (iCanStartTest) sl@0: { sl@0: // - increment test count sl@0: ++iTestCount; sl@0: sl@0: if (iTestMode == ETestModeNormal) // don't add this info when we are doing memory leak testing otherwise it sl@0: // would get leaked! sl@0: { sl@0: sl@0: // Add this test to failed test list - set errorcode to zero sl@0: CTestInfo* temp = CTestInfo::NewLC(aName, iTestCount, 0); sl@0: iFailedTests->AppendL(temp); sl@0: CleanupStack::Pop(); // temp sl@0: sl@0: // Stop new test being started until this one has ended sl@0: iTest.Start(aName); sl@0: iCanStartTest = EFalse; sl@0: } sl@0: sl@0: sl@0: TBuf buf; sl@0: buf.Format(KTestStartingWithDesc, iTestCount, &aName); sl@0: WriteComment(buf); sl@0: sl@0: // Reset iStepNumber - start at 1 sl@0: iStepNumber = 1; sl@0: } sl@0: else sl@0: { sl@0: // Panic client - bad usage - not allowed to nest tests sl@0: Panic(EBadStartTest); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::NextStep(const TDesC& aStepName) sl@0: // sl@0: // Logs the next step in a test - for informative use. sl@0: { sl@0: if (!iCanStartTest) sl@0: { sl@0: TBuf buf; sl@0: buf.Format(KNextTestStepWithDesc, iTestCount, iStepNumber, &aStepName); sl@0: WriteComment(buf); sl@0: iTest.Next(aStepName); sl@0: ++iStepNumber; sl@0: } sl@0: else sl@0: { sl@0: // Panic client - bad usage - test not started sl@0: Panic(EBadStartTest); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::EndTest(TInt aErrorCode) sl@0: // sl@0: // Logs end of test sl@0: { sl@0: if (!iCanStartTest) sl@0: { sl@0: if (iTestMode == ETestModeNormal) sl@0: { sl@0: // Get ptr to this test's entry in failed list - will be the last entry sl@0: TBuf buf; sl@0: TInt index = iFailedTests->Count(); sl@0: CTestInfo* ptr = iFailedTests->At(--index); sl@0: if (aErrorCode) sl@0: { sl@0: // Set the error code sl@0: ptr->SetErrorCode(aErrorCode); sl@0: buf.Format(KTestFailed, iTestCount, aErrorCode); sl@0: WriteComment(buf); sl@0: } sl@0: else sl@0: { sl@0: // Remove entry from list of failed tests sl@0: delete ptr; sl@0: iFailedTests->Delete(index); sl@0: } sl@0: sl@0: } sl@0: // Allow new test to start sl@0: iTest.End(); sl@0: iCanStartTest = ETrue; sl@0: } sl@0: else sl@0: { sl@0: if (iTestMode == ETestModeNormal) sl@0: // Panic client - bad usage - test not started sl@0: Panic(EBadEndTest); sl@0: // don't panic when we are memory leak testing as EndTestL will never get called to reset the test properly sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::LogIt(TRefByValue aFmt, ...) sl@0: // sl@0: // Messages to the front end emulator and to the Inu log sl@0: { sl@0: VA_LIST list; sl@0: VA_START(list,aFmt); sl@0: sl@0: TBuf buf; sl@0: buf.Append(KTestCommentPrepend); sl@0: buf.AppendFormatList(aFmt,list); sl@0: VA_END(list); sl@0: sl@0: WriteComment(buf); sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::operator()(TInt aResult,TInt aLineNum) sl@0: // sl@0: // Overload operator () sl@0: { sl@0: iTest(aResult, aLineNum); sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::operator()(TInt aResult) sl@0: // sl@0: // Overload operator () sl@0: { sl@0: iTest(aResult); sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::PressAnyKey() sl@0: // sl@0: // Request a key press from user and wait - unless we are running a script sl@0: { sl@0: if (!iScriptRunning) sl@0: { sl@0: iTest.Printf(TRefByValue_L("\nPress a key")); sl@0: iTest.Getch(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::DumpData(HBufC8& aData, TBool logIt) sl@0: // sl@0: // Do a formatted dump of binary data, optionally logging it sl@0: { sl@0: // Iterate the supplied block of data in blocks of 16 bytes sl@0: TInt pos = 0; sl@0: TBuf logLine; sl@0: TBuf anEntry; sl@0: while (pos < aData.Length()) sl@0: { sl@0: anEntry.Format(TRefByValue_L("%04x : "), pos); sl@0: logLine.Append(anEntry); sl@0: sl@0: // Hex output sl@0: TInt offset = 0; sl@0: for (offset = 0; offset < 16; offset++) sl@0: { sl@0: if (pos + offset < aData.Length()) sl@0: { sl@0: TInt nextByte = aData[pos + offset]; sl@0: anEntry.Format(TRefByValue_L("%02x "), nextByte); sl@0: logLine.Append(anEntry); sl@0: } sl@0: else sl@0: { sl@0: anEntry.Format(TRefByValue_L(" ")); sl@0: logLine.Append(anEntry); sl@0: } sl@0: } sl@0: anEntry.Format(TRefByValue_L(": ")); sl@0: logLine.Append(anEntry); sl@0: sl@0: // Char output sl@0: for (offset = 0; offset < 16; offset++) sl@0: { sl@0: if (pos + offset < aData.Length()) sl@0: { sl@0: TInt nextByte = aData[pos + offset]; sl@0: if ((nextByte >= 32) && (nextByte <= 127)) sl@0: { sl@0: anEntry.Format(TRefByValue_L("%c"), nextByte); sl@0: logLine.Append(anEntry); sl@0: } sl@0: else sl@0: { sl@0: anEntry.Format(TRefByValue_L(".")); sl@0: logLine.Append(anEntry); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: anEntry.Format(TRefByValue_L(" ")); sl@0: logLine.Append(anEntry); sl@0: } sl@0: } sl@0: if (logIt) sl@0: { sl@0: LogIt(TRefByValue_L("%S"), &logLine); sl@0: } sl@0: else sl@0: { sl@0: iTest.Printf(TRefByValue_L("%S\n"), &logLine); sl@0: } sl@0: logLine.Zero(); sl@0: sl@0: // Advance to next 16 byte segment sl@0: pos += 16; sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CIpuTestHarness::GetAnEntry(const TDesC& ourPrompt, TDes& currentstring) sl@0: // sl@0: // Get an input string from the user, displaying a supplied prompt and default string value sl@0: { sl@0: // If we're scripting, try reading from script first sl@0: TInt readScriptErr = KErrNotFound; sl@0: if (iScriptRunning) sl@0: { sl@0: readScriptErr = ReadLineFromScript(currentstring); sl@0: } sl@0: if (!readScriptErr) sl@0: return; sl@0: sl@0: // Either not scripting, or hit end of script - continue with user input sl@0: TBuf16 ourLine; sl@0: TBuf tempstring; //tempstring is a unicode descriptor sl@0: //create a temporary buffer where the sl@0: //unicode strings are stored in order to sl@0: //be displayed sl@0: ourLine.Zero (); sl@0: tempstring.Copy(currentstring); //Copy current string to Unicode buffer sl@0: TKeyCode key = EKeyNull; //current string buffer is 8 bits wide. sl@0: //Unicode string bufffer (tempstring) is 16 bits wide. sl@0: for (;;) sl@0: { sl@0: if (ourLine.Length () == 0) sl@0: { sl@0: iTest.Console()->SetPos (0, iTest.Console()->WhereY ()); sl@0: iTest.Console()->Printf (_L ("%S"), &ourPrompt); sl@0: if (tempstring.Length () != 0) //get tempstring's number of items sl@0: iTest.Console()->Printf (_L (" = %S"), &tempstring); //if not zero print them to iTest.Console() sl@0: iTest.Console()->Printf (_L (" : ")); sl@0: iTest.Console()->ClearToEndOfLine (); sl@0: } sl@0: key = iTest.Getch(); sl@0: sl@0: if (key == EKeyBackspace) sl@0: { sl@0: if (ourLine.Length() !=0) sl@0: { sl@0: ourLine.SetLength(ourLine.Length()-1); sl@0: iTest.Console()->Printf (_L ("%c"), key); sl@0: iTest.Console()->SetPos(iTest.Console()->WhereX(),iTest.Console()->WhereY()); sl@0: iTest.Console()->ClearToEndOfLine(); sl@0: } // end if (ourLine.Length() !=0) sl@0: } // end if (key == KeyBackSpace) sl@0: sl@0: sl@0: if (key == EKeyDelete) sl@0: { sl@0: ourLine.Zero(); sl@0: iTest.Console()->SetPos (0, iTest.Console()->WhereY ()); sl@0: iTest.Console()->ClearToEndOfLine (); sl@0: tempstring.Copy(ourLine); sl@0: break; sl@0: } sl@0: sl@0: if (key == EKeyEnter) sl@0: break; sl@0: sl@0: if (key < 32) sl@0: { sl@0: continue; sl@0: } sl@0: sl@0: ourLine.Append (key); sl@0: iTest.Console()->Printf (_L ("%c"), key); sl@0: iTest.Console()->SetPos(iTest.Console()->WhereX(),iTest.Console()->WhereY()); sl@0: iTest.Console()->ClearToEndOfLine(); sl@0: if (ourLine.Length () == ourLine.MaxLength ()) sl@0: break; sl@0: } // end of for statement sl@0: sl@0: if ((key == EKeyEnter) && (ourLine.Length () == 0)) sl@0: tempstring.Copy (currentstring); //copy contents of 8 bit "ourLine" descriptor sl@0: sl@0: iTest.Console()->SetPos (0, iTest.Console()->WhereY ()); sl@0: iTest.Console()->ClearToEndOfLine (); sl@0: iTest.Console()->Printf (_L ("%S"), &ourPrompt); sl@0: sl@0: if ((key == EKeyEnter) && (ourLine.Length() !=0)) sl@0: tempstring.Copy(ourLine); sl@0: if (tempstring.Length () != 0) //if temstring length is not zero sl@0: { sl@0: iTest.Console()->Printf (_L (" = %S\n"), &tempstring); //print the contents to iTest.Console() sl@0: LogIt(_L ("%S = %S\n"), &ourPrompt, &tempstring); sl@0: } sl@0: sl@0: else sl@0: //iTest.Console()->Printf (_L (" is empty")); sl@0: iTest.Console()->Printf (_L ("\n")); sl@0: currentstring.Copy(tempstring); //copy 16 bit tempstring descriptor back sl@0: } sl@0: sl@0: sl@0: EXPORT_C TInt CIpuTestHarness::GetSelection(const TDesC& ourPrompt, const TDesC& validChoices) sl@0: // sl@0: // Present the user with a list of options, and get their selection sl@0: { sl@0: // If we're scripting, try reading from script first sl@0: TInt readScriptErr = KErrNotFound; sl@0: if (iScriptRunning) sl@0: { sl@0: TBuf<1> oneCharBuf; sl@0: readScriptErr = ReadLineFromScript(oneCharBuf); sl@0: if (!readScriptErr) sl@0: { sl@0: return validChoices.Locate((TChar)oneCharBuf[0]); sl@0: } sl@0: } sl@0: sl@0: // Either not scripting, or hit end of script - continue with user input sl@0: TKeyCode key = EKeyNull; sl@0: iTest.Console()->SetPos (0, iTest.Console()->WhereY ()); sl@0: iTest.Console()->Printf(_L("%S "), &ourPrompt); sl@0: iTest.Console()->Printf(_L("[%S] :"), &validChoices); sl@0: TInt retVal = KErrNotFound; sl@0: while (retVal == KErrNotFound) sl@0: { sl@0: key = iTest.Getch(); sl@0: sl@0: // Check that key is in the list of valid choices sl@0: retVal = validChoices.Locate((TChar)key); sl@0: } sl@0: iTest.Console()->Printf(_L("%c\n\n"), key); sl@0: return retVal; sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CIpuTestHarness::SetScript(RFile& scriptFile) sl@0: // sl@0: // Sets the file to be used for a test script - ie. a file that contains commands used by sl@0: // GetEntry() and GetSelection() sl@0: { sl@0: iScriptFile = &scriptFile; sl@0: iScriptRunning = ETrue; sl@0: LogIt(_L("***SCRIPT STARTING***\n")); sl@0: } sl@0: sl@0: TInt CIpuTestHarness::ReadLineFromScript(TDes& aBuffer) sl@0: // sl@0: // Reads the next line from the script file, and sets the passed-in descriptor with its contents. sl@0: // Returns KErrNone if reading succeeded; KErrNotFound if the EOF was reached. When EOF is reached, sl@0: // the file is closed. sl@0: { sl@0: // ********************************* sl@0: // Assume script is 8-bit text file sl@0: // ********************************* sl@0: TBool isAComment = ETrue; sl@0: TInt err = KErrNone; sl@0: TBuf<512> line; sl@0: while (isAComment && !err) sl@0: { sl@0: TFileText text; sl@0: text.Set(*iScriptFile); sl@0: line.SetLength(0); sl@0: for(;;) sl@0: { sl@0: TBuf8<2> c; sl@0: err = iScriptFile->Read(c,1); sl@0: if (err && err != KErrEof) sl@0: { sl@0: iTest.Printf(_L("Error reading file: %d\n"), err); sl@0: break; sl@0: } sl@0: if (c.Length() == 0) sl@0: { sl@0: err = KErrEof; sl@0: break; sl@0: } sl@0: else sl@0: { sl@0: if (c[0] == '\n') // break out if it is CR sl@0: break; sl@0: else if (c[0] != (TUint8)(0x0d)) // otherwise append the char, _unless_ it is a LF sl@0: line.Append(c[0]); sl@0: } sl@0: } sl@0: if (err == KErrNone && line.Locate('/') != 0) // comment (only works if it's the first character) sl@0: { sl@0: isAComment = EFalse; sl@0: } sl@0: } sl@0: sl@0: // The line read is not a comment, or have hit end of file sl@0: if (!err) sl@0: { sl@0: // copy to passed in descriptor, but do not allow an overflow sl@0: aBuffer.Copy(line.Left(aBuffer.MaxLength())); sl@0: LogIt(_L("***SCRIPT : read command '%S' ***\n"), &aBuffer); sl@0: } sl@0: else sl@0: { sl@0: iScriptFile->Close(); sl@0: err = KErrNotFound; sl@0: iScriptRunning = EFalse; sl@0: LogIt(_L("***SCRIPT ENDED***\n")); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: void CIpuTestHarness::Panic(TInt aPanic) sl@0: // sl@0: // Panic the client program. sl@0: { sl@0: User::Panic(KTestPanic,aPanic); sl@0: } sl@0: sl@0: void CIpuTestHarness::TestHarnessComplete() sl@0: // sl@0: // Test harness completed without failures sl@0: { sl@0: _LIT(KTestCompleteFormat, "Total Tests %d, Failed Tests %d"); sl@0: TBuf<50> text; sl@0: text.AppendFormat(KTestCompleteFormat, iTestCount, iFailedTests->Count()); sl@0: WriteComment(text); sl@0: WriteComment(KTestHarnessCompleted); sl@0: } sl@0: sl@0: void CIpuTestHarness::TestHarnessFailed() sl@0: // sl@0: // Test harness has a failure - log information sl@0: { sl@0: TBuf buf; sl@0: buf.Format(KTestHarnessFailed, iFailedTests->Count()); sl@0: WriteComment(buf); sl@0: // Log fialed tests' information sl@0: for (TInt ii=0; iiCount(); ++ii) sl@0: { sl@0: CTestInfo* failed = iFailedTests->At(ii); sl@0: TPtrC name = failed->Name(); sl@0: LogIt(KTestFailInfo, failed->Number(), &name, failed->ErrorCode()); sl@0: } sl@0: } sl@0: sl@0: void CIpuTestHarness::ResourceLeakTest() sl@0: // sl@0: // Creates a new test that fails if any there are any leaked resource handles sl@0: { sl@0: // Start new test sl@0: _LIT(KResourceTestName, "Resource Handle Leak Test"); sl@0: TRAPD(testError, StartTestL(KResourceTestName)); sl@0: if(testError==KErrNone) sl@0: { sl@0: // Find number of opened handles sl@0: TInt processHandleCount=0; sl@0: TInt threadHandleCount=0; sl@0: RThread().HandleCount(processHandleCount,threadHandleCount); sl@0: TInt openHandleCount = iStartHandleCount-threadHandleCount; sl@0: TInt err = KErrNone; sl@0: if ( openHandleCount !=0 ) sl@0: { sl@0: err = KErrGeneral; sl@0: LogIt(_L("Number leaked handles is %D"), openHandleCount); sl@0: } sl@0: EndTest(err); sl@0: } sl@0: else sl@0: { sl@0: _LIT(KTxtResourceTestRunError, "Unable to complete Resource Leak Test, error: %d"); sl@0: LogIt(KTxtResourceTestRunError, testError); sl@0: EndTest(testError); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // CTestInfo sl@0: // sl@0: CIpuTestHarness::CTestInfo::CTestInfo() sl@0: // sl@0: // Default c'tor sl@0: { sl@0: } sl@0: sl@0: CIpuTestHarness::CTestInfo::~CTestInfo() sl@0: // sl@0: // D'tor sl@0: { sl@0: delete iName; sl@0: } sl@0: sl@0: CIpuTestHarness::CTestInfo* CIpuTestHarness::CTestInfo::NewLC(const TDesC& aName, TInt aNumber, TInt aErrorCode) sl@0: // sl@0: // Static factory c'tor sl@0: { sl@0: CTestInfo* self = new (ELeave) CTestInfo(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aName, aNumber, aErrorCode); sl@0: return self; sl@0: } sl@0: sl@0: CIpuTestHarness::CTestInfo* CIpuTestHarness::CTestInfo::NewL(const TDesC& aName, TInt aNumber, TInt aErrorCode) sl@0: // sl@0: // Static factory c'tor sl@0: { sl@0: CTestInfo* self = NewLC(aName, aNumber, aErrorCode); sl@0: CleanupStack::Pop(); // self sl@0: return self; sl@0: } sl@0: sl@0: void CIpuTestHarness::CTestInfo::ConstructL(const TDesC& aName, TInt aNumber, TInt aErrorCode) sl@0: // sl@0: // Non-trivial c'tor sl@0: { sl@0: iName = aName.AllocLC(); sl@0: CleanupStack::Pop(); // iName sl@0: sl@0: iNumber = aNumber; sl@0: iErrorCode = aErrorCode; sl@0: } sl@0: sl@0: void CIpuTestHarness::CTestInfo::SetNameL(const TDesC& aName) sl@0: // sl@0: // Sets iName sl@0: { sl@0: HBufC* temp = aName.AllocLC(); sl@0: CleanupStack::Pop(); // temp sl@0: delete iName; sl@0: iName = temp; sl@0: } sl@0: sl@0: void CIpuTestHarness::CTestInfo::SetNumber(TInt aNumber) sl@0: // sl@0: // Sets iNumber sl@0: { sl@0: iNumber = aNumber; sl@0: } sl@0: sl@0: void CIpuTestHarness::CTestInfo::SetErrorCode(TInt aErrorCode) sl@0: // sl@0: // Sets iErrorCode sl@0: { sl@0: iErrorCode = aErrorCode; sl@0: }