diff -r 000000000000 -r e35f40988205 xml/wbxmlparser/test/rtest/tsrc/stabilitytestclass.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/wbxmlparser/test/rtest/tsrc/stabilitytestclass.cpp Thu Dec 17 09:29:21 2009 +0200 @@ -0,0 +1,819 @@ +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// These tests are to allow the parser to parse a wide range of valid +// documents allowing for greater coverage of its functionality. +// The fact that the documents are not parsed correctly is not the scope of +// these tests, but instead the stability of the parser is. +// The tests also incorporates indirect iTesting of the StringDictionaries +// as the parser uses these during its paring phase. +// If these iTest were to fail, it would give a good indication that the parser, +// dictionary, or document being parsed where at fault. As the document being +// parsed should never change (except for the addition of new documents), +// this should narrow the search. +// The output of what is parsed is withheld to speed up the processing of +// this automated iTest. Uncommenting the macro __SHOW_MANUAL_OUTPUT__ within +// the MMP file should allow for the output to be produced if the user so +// wishes. +// Specific tests taking into account what the parser parses should also be +// supplied for a fully comprehensive test suite. +// +// + +#include + +#include +#include +#include + +#include +#include + +#include "stabilitytestclass.h" +#include "testdocuments.h" + +using namespace Xml; + +#ifdef __COMPARE_OUTPUT__ +#define INSERT_INTO_OUTPUT_BUFFER(output) \ + iOutput->Insert(iOutput->Length(), output) +#define FORMAT_OUTPUT_BUFFER(format, data) \ + iFormat->Format(format, data) + +#else +#define INSERT_INTO_OUTPUT_BUFFER (output) +#define FORMAT_OUTPUT_BUFFER (format, data) +#endif //__COMPARE_OUTPUT__ + +// +// The way data is formatted: +// - Data is built up into iBuffer. +// - This is then inserted into iFormat, adding formatting, +// e.g. start < and end >. +// - If the test compares the data this formatted data is then +// inserted into iCompare for comparision. +// - iBuffer is cleared and rebuilt on each element. +// - iFormat is also used as a secondary buffer of iBuffer so as +// to convert TDesC8s into TDesC16s. +// - iOutput is only used for those tests that compare data, +// i.e. what's generated to what's expected. +// + + + +CStabilityTestClass* CStabilityTestClass::NewL(RTest& aTest, + TBool aIsOomTest, + TInt aChunkSize) + { + CStabilityTestClass* self = new(ELeave) CStabilityTestClass(aTest, aIsOomTest, aChunkSize); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + + +CStabilityTestClass::CStabilityTestClass(RTest& aTest, + TBool aIsOomTest, + TInt aChunkSize) +: iTest(aTest), + iChunkSize(aChunkSize), + iIsOomTest(aIsOomTest) + { + // do nothing; + } + + +CStabilityTestClass::~CStabilityTestClass() + { + iFs.Close(); + iCurrentIndex.Reset(); + iEntries.ResetAndDestroy(); + +#ifdef __COMPARE_OUTPUT__ + delete iOutput; +#endif // __COMPARE_OUTPUT__ + + delete iBuffer; + +#ifdef __SHOW_MANUAL_OUTPUT__ + delete iFormat; +#endif // __SHOW_MANUAL_OUTPUT__ + } + + +void CStabilityTestClass::ConstructL() + { + User::LeaveIfError(iFs.Connect()); + +#ifdef __COMPARE_OUTPUT__ + iOutput = new(ELeave) TBuf16; +#endif // __COMPARE_OUTPUT__ + + iBuffer = new(ELeave) TBuf16; + +#ifdef __SHOW_MANUAL_OUTPUT__ + iFormat = new(ELeave) TBuf16; +#endif // __SHOW_MANUAL_OUTPUT__ + } + + +// From MContentHandler + +void CStabilityTestClass::OnStartDocumentL(const RDocumentParameters& /*aDocParam*/, TInt aErrorCode) + { + iTest.Printf(_L("CStabilityTestClass::OnStartDocumentL Error code:%d\n"), aErrorCode); + iError = aErrorCode; + } + + +void CStabilityTestClass::OnEndDocumentL(TInt aErrorCode) + { + iTest.Printf(_L("\nCStabilityTestClass::OnEndDocumentL Error code:%d\n"), aErrorCode); + iError = aErrorCode; + } + + +#ifdef __SHOW_MANUAL_OUTPUT__ +void CStabilityTestClass::OnStartElementL(const RTagInfo& aElement, const RAttributeArray& aAttribute, TInt aErrorCode) +#else +void CStabilityTestClass::OnStartElementL(const RTagInfo& /*aElement*/, const RAttributeArray& /*aAttribute*/, TInt aErrorCode) +#endif + { + iError = aErrorCode; + +#ifdef __SHOW_MANUAL_OUTPUT__ + // element + iBuffer->Copy (aElement.LocalName().DesC()); + + // check for the namespace + if (aElement.Uri().DesC() != KNullDesC8()) + { + iBuffer->Append (_L(" xmlns=\'")); + iFormat->Copy(aElement.Uri().DesC()); + iBuffer->Append (*iFormat); + iBuffer->Append (_L("\'")); + } + + if (aAttribute.Count() == 0) + { + RDebug::Print(_L("<%S>"), iBuffer); + + FORMAT_OUTPUT_BUFFER(_L("<%S>"), iBuffer); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + } + else + { + RPointerArray > attr_list; + + for (TInt p=0; p *attr_ns = new(ELeave) TBuf16<256>; + TBool present=EFalse; + TInt x=0; + attr_ns->Copy(aAttribute[p].Attribute().Uri().DesC()); + + while (!present && xCompare(*attr_ns)==0) + { + present=ETrue; + } + else + { + ++x; + } + } + + if (!present) + { + attr_list.Append(attr_ns); + } + else + { + delete attr_ns; + } + } + } + + for (TInt j=0; jAppend (_L(" xmlns='")); + iBuffer->Append (*attr_list[j]); + iBuffer->Append (_L("'")); + } + + RDebug::Print(_L("<%S"), iBuffer); + attr_list.ResetAndDestroy(); + + FORMAT_OUTPUT_BUFFER(_L("<%S"), iBuffer); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + + for (TInt i=0; iCopy(aAttribute[i].Attribute().LocalName().DesC()); + iBuffer->Append(_L("=\"")); + + // value + iFormat->Copy(aAttribute[i].Value().DesC()); + + iBuffer->Append(*iFormat); + iBuffer->Append(_L("\"")); + + RDebug::Print(_L("%S"), iBuffer); + + FORMAT_OUTPUT_BUFFER(_L("%S"), iBuffer); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + } + RDebug::Print(_L(">")); + INSERT_INTO_OUTPUT_BUFFER( _L(">")); + } +#endif // __SHOW_MANUAL_OUTPUT__ + } + + +#ifdef __SHOW_MANUAL_OUTPUT__ +void CStabilityTestClass::OnEndElementL(const RTagInfo& aElement, TInt aErrorCode) +#else +void CStabilityTestClass::OnEndElementL(const RTagInfo& /*aElement*/, TInt aErrorCode) +#endif + { + iError = aErrorCode; + +#ifdef __SHOW_MANUAL_OUTPUT__ + iBuffer->Copy (aElement.LocalName().DesC()); + RDebug::Print(_L(""), iBuffer); + + FORMAT_OUTPUT_BUFFER(_L(""), iBuffer); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + +#endif // __SHOW_MANUAL_OUTPUT__ + } + + + +void CStabilityTestClass::OnContentL(const TDesC8& aBytes, TInt aErrorCode) + { + iError = aErrorCode; + + iBuffer->Copy (aBytes); + + if (aBytes.Length() && aBytes[0] == 0x02) // SyncML opaque data only + { + if (iParseMode & ERawContent) + { + // raw bytes + // Write to a new file to be parsed later + RFile opaqueFile; + CleanupClosePushL(opaqueFile); + + // loose the last '\' + TPtrC path (iFileName.Path().Ptr(), iFileName.Path().Length()-1); + TInt pos = 0; + User::LeaveIfError(pos = path.LocateReverse('\\')); + TPtrC mid = path.Mid(++pos); + + TFileName name(KOpaqueDirectory()); + name.Append (KDirSeperator()); + + TInt err = KErrNone; + err = iFs.MkDirAll(name); + + if (err != KErrNone && err != KErrAlreadyExists) + { + User::Leave(err); + } + + name.Append (mid); + name.Append (KUnderscore()); + name.Append (iFileName.NameAndExt()); + + err = (opaqueFile.Replace(iFs, name, EFileWrite)); + User::LeaveIfError(opaqueFile.Write(aBytes)); + + opaqueFile.Close(); + CleanupStack::Pop(&opaqueFile); + +#ifdef __SHOW_MANUAL_OUTPUT__ + // Print the data to the logs anyway, even if its unreadable + for (TInt i=0; iCopy (aTarget); + iFormat->Append(_L("=\"")); + iBuffer->Append(*iFormat); + + // attrvalue + iFormat->Copy(aData); + iFormat->Append(_L("\"")); + iBuffer->Append(*iFormat); + + RDebug::Print(_L("{{%S}}"), iBuffer); + + FORMAT_OUTPUT_BUFFER(_L("{{%S}}"), iBuffer); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + +#endif // __SHOW_MANUAL_OUTPUT__ + } + + +#ifdef __SHOW_MANUAL_OUTPUT__ +void CStabilityTestClass::OnExtensionL(const RString& aData, TInt aToken, TInt aErrorCode) +#else +void CStabilityTestClass::OnExtensionL(const RString& /*aData*/, TInt /*aToken*/, TInt aErrorCode) +#endif + { + iError = aErrorCode; + +#ifdef __SHOW_MANUAL_OUTPUT__ + iBuffer->Copy (aData.DesC()); + RDebug::Print(_L("[[0x%x : %S]]"), aToken, iBuffer); + + FORMAT_OUTPUT_BUFFER(_L("[[0x%x : "), aToken); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + FORMAT_OUTPUT_BUFFER(_L("%S]]"), iBuffer); + INSERT_INTO_OUTPUT_BUFFER(*iFormat); + +#endif // __SHOW_MANUAL_OUTPUT__ + } + + +void CStabilityTestClass::OnError(TInt aErrorCode) + { + iError = aErrorCode; + iTest.Printf(_L("\nCStabilityTestClass::OnError Error code:%d\n"), aErrorCode); + } + + +TAny* CStabilityTestClass::GetExtendedInterface(const TInt32 aUid) +/** +This method obtains the interface matching the specified uid. +@return 0 if no interface matching the uid is found. + Otherwise, the this pointer cast to that interface. +@param aUid the uid identifying the required interface. +*/ + { + if (aUid == MWbxmlExtensionHandler::EExtInterfaceUid) + { + return static_cast(this); + } + return 0; + } + + +//---------------------------------------------------------------------------- +//Parser Tests + + +void CStabilityTestClass::StabilityTestL(const TDesC& aAbsoluteDirPath, const TDesC& aExt, + ClassFuncPtrL aTestFuncL) + { + iTest.Next(_L("StabilityTestL")); + + // Set up for heap leak checking + __UHEAP_MARK; + + // and leaking thread handles + TInt startProcessHandleCount; + TInt startThreadHandleCount; + TInt endProcessHandleCount; + TInt endThreadHandleCount; + + // Test Starts... + + RThread thisThread; + thisThread.HandleCount(startProcessHandleCount, startThreadHandleCount); + + //-------------- + + ParseDirL(aAbsoluteDirPath, aExt, aTestFuncL); + iEntries.Close(); + iCurrentIndex.Close(); + + + //-------------- + // Check for open handles + thisThread.HandleCount(endProcessHandleCount, endThreadHandleCount); + + iTest(startThreadHandleCount == endThreadHandleCount); + + // Test Ends... + + __UHEAP_MARKEND; + } + + +void CStabilityTestClass::ParseDirL(const TDesC& aAbsoluteDirPath, + const TDesC& aExt, ClassFuncPtrL aTestFuncL) + { + iError = KErrNone; + + TFileName fileDirNameWithSep; + fileDirNameWithSep = aAbsoluteDirPath; + fileDirNameWithSep.Append(KDirSeperator); + + CDir *dirList = NULL; + CDir *entries = NULL; + + User::LeaveIfError (iFs.GetDir(fileDirNameWithSep, KEntryAttNormal|KEntryAttDir, ESortNone, entries, dirList)); + delete dirList; + dirList = NULL; + + iEntries.Append(entries); + iCurrentIndex.Append(entries->Count()); + + entries = NULL; + CleanupStack::PushL(iEntries[iEntries.Count()-1]); + + // Point to last test that ran (OOM) or to be run + CDir*& entry = iEntries[iEntries.Count()-1]; + TInt& ind = iCurrentIndex[iCurrentIndex.Count()-1]; + + TParse entryName; + + // Also acts as base test for recursiveness + while (--ind >= 0) + { + entryName.Set((*entry)[ind].iName, &fileDirNameWithSep, NULL); + + if (!(*entry)[ind].IsDir()) + { + if (entryName.Ext() == aExt) + { + ParseEntryL(entryName.FullName(), aTestFuncL); + } + } + else + { + ParseDirL(entryName.FullName(), aExt, aTestFuncL); + } + } + + CleanupStack::PopAndDestroy(iEntries[iEntries.Count()-1]); + + iCurrentIndex.Remove(iCurrentIndex.Count()-1); + iEntries.Remove(iEntries.Count()-1); + } + + +void CStabilityTestClass::ParseEntryL(const TDesC& aAbsoluteFilename, + ClassFuncPtrL aTestFuncL) + { + // Need to set this for OnContentL + iFileName.Set (aAbsoluteFilename, NULL, NULL); + iTest.Printf(_L("\n")); + + iParseMode = EErrorOnUnrecognisedTags| + ERawContent; + + if(iIsOomTest) + { + OomProcess(aTestFuncL); + } + else + { + (this->*aTestFuncL)(aAbsoluteFilename); + } + } + + +void CStabilityTestClass::TestWholeL(const TDesC& aFileName) + { + iTest.Next(_L("TestWholeL")); + + // Set up for heap leak checking + __UHEAP_MARK; + + // and leaking thread handles + TInt startProcessHandleCount; + TInt startThreadHandleCount; + TInt endProcessHandleCount; + TInt endThreadHandleCount; + + // Test Starts... + + RThread thisThread; + thisThread.HandleCount(startProcessHandleCount, startThreadHandleCount); + + //-------------- + + iTest.Printf(_L("\nParsing document: %S\n"),&aFileName); + + // Load the Parser and parse the buffer + + iParser = CParser::NewLC(KWbxmlParserDataType, *this); + + User::LeaveIfError(iParser->EnableFeature(iParseMode)); + + // We parse to completion - parser will stop the ActiveSchedular + ParseL(*iParser, iFs, aFileName); + + CleanupStack::PopAndDestroy(iParser); + REComSession::FinalClose(); // Don't want leaks outside the iTest + + + if(iIsOomTest) + { + // Only receives KErrNoMemory on OOM tests. + // Do this so the calling function knows we need to keep parsing + // the same document. + if (iError == KErrNoMemory) + { + User::Leave(iError); + } + } + else + { + iTest(iError == KErrNone); + } + + //-------------- + // Check for open handles + thisThread.HandleCount(endProcessHandleCount, endThreadHandleCount); + + iTest(startThreadHandleCount == endThreadHandleCount); + + // Test Ends... + + __UHEAP_MARKEND; + } + + +void CStabilityTestClass::TestChunkL(const TDesC& aFileName) + { + iTest.Next(_L("TestChunkL")); + + // Create the Parser without a uid list + // The data will be streamed a bit at a time + // so as to iTest the reaction of the parser. + // =========================================== + + // Set up for heap leak checking + __UHEAP_MARK; + + // and leaking thread handles + TInt startProcessHandleCount; + TInt startThreadHandleCount; + TInt endProcessHandleCount; + TInt endThreadHandleCount; + + // Test Starts... + + RThread thisThread; + thisThread.HandleCount(startProcessHandleCount, startThreadHandleCount); + + //-------------- + + iTest.Printf(_L("\nParsing document: %S\n"),&aFileName); + + // Read the file into the buffer + + RFile xmlFile; + CleanupClosePushL(xmlFile); + + User::LeaveIfError(xmlFile.Open(iFs, aFileName, EFileRead)); + + TInt streamSize; + User::LeaveIfError(xmlFile.Size(streamSize)); + + // Load the Parser and parse the buffer + + iParser = CParser::NewLC(KWbxmlParserDataType, *this); + + User::LeaveIfError(iParser->EnableFeature(iParseMode)); + + // Always size to the max as we can not choose, compilation errors. + TBuf8 data; + User::LeaveIfError(xmlFile.Read(data, iChunkSize)); + TInt length = data.Length(); + + iError = KErrNone; + + while (length) + { + iParser->ParseL(data); + + // When no more data is read descriptors length is 0. + // Will throw another KErrEof + User::LeaveIfError(xmlFile.Read(data, iChunkSize)); + length = data.Length(); + } + + iParser->ParseEndL(); + + // OnError should report only XML parsing specific errors + iTest(iError == KErrNone || iError <= KErrXmlFirst && iError >= KErrXmlLast); + + CleanupStack::PopAndDestroy(iParser); + CleanupStack::PopAndDestroy(&xmlFile); // Closes as well + REComSession::FinalClose(); // Don't want leaks outside the iTest + + + //-------------- + // Check for open handles + thisThread.HandleCount(endProcessHandleCount, endThreadHandleCount); + + iTest(startThreadHandleCount == endThreadHandleCount); + + // Test Ends... + + __UHEAP_MARKEND; + } + + + +void CStabilityTestClass::OomProcess(ClassFuncPtrL aTestFuncL) + { + iTest.Next(_L("OomProcess test")); + TInt err, tryCount = 0; + do + { + User::__DbgSetAllocFail(RHeap::EUser, RHeap::EFailNext, ++tryCount); + User::__DbgMarkStart(RHeap::EUser); + TRAP(err, (this->*aTestFuncL)(iFileName.FullName())); + User::__DbgMarkEnd(RHeap::EUser, 0); + } while(err==KErrNoMemory); + + if(err==KErrNone) + { + // Reset + User::__DbgSetAllocFail(RHeap::EUser,RHeap::ENone,1); + } + else + { + User::Panic(_L("Unexpected leave reason"),err); + } + + iTest.Printf(_L("- server succeeded at heap failure rate of %i\n"), tryCount); + } + + +void CStabilityTestClass::TestBehaviour(const TDesC& aSrc, TPassOrFailureSettings& aTestSettings) + { + iTest.Next(_L("TestBehaviour")); + + TRAPD(err, BehaviourTestL(aSrc, aTestSettings)); + iTest (err == aTestSettings.iExpectedCode); + } + + +void CStabilityTestClass::BehaviourTestL(const TDesC& aSrc, TPassOrFailureSettings& aTestSettings) + { + iTest.Next(_L("BehaviourTestL")); + + // Test the parser with the values provided + // =========================================== + + + // Set up for heap leak checking + __UHEAP_MARK; + + // and leaking thread handles + TInt startProcessHandleCount; + TInt startThreadHandleCount; + TInt endProcessHandleCount; + TInt endThreadHandleCount; + + // Test Starts... + + RThread thisThread; + thisThread.HandleCount(startProcessHandleCount, startThreadHandleCount); + + //-------------- + + iError = 0; + + // iLoad the parser and parse the data + + iParser = CParser::NewLC(KWbxmlParserDataType, *this); + + iParser->AddPreloadedDictionaryL(*(aTestSettings.iStringDictionaryUri)); + + User::LeaveIfError(iParser->EnableFeature(aTestSettings.iParseMode)); + + if (aTestSettings.iDoParseDocument) + { + if (aTestSettings.iFilenameProvided) + { + ParseL(*iParser, iFs, aSrc); + } + else + { + TBuf8<256> buf8; + + // copy will ignore the upper byte if the byte-pair < 256, otherwise the value 1 is used. + buf8.Copy(aSrc); + + // whole file should be in descriptor/ + ParseL(*iParser, buf8); + } + } + + CleanupStack::PopAndDestroy(iParser); + + REComSession::FinalClose(); // Don't want leaks outside the iTest + + + //-------------- + // Check for open handles + thisThread.HandleCount(endProcessHandleCount, endThreadHandleCount); + + iTest(startThreadHandleCount == endThreadHandleCount); + + // Test Ends... + + __UHEAP_MARKEND; + + + User::LeaveIfError(iError); + } +