textrendering/texthandling/ttext/T_RICH1A.CPP
changeset 0 1fb32624e06b
child 51 a7c938434754
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/texthandling/ttext/T_RICH1A.CPP	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,1053 @@
+/*
+* Copyright (c) 1997-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 <e32test.h>
+#include <txtrich.h>
+#include <gdi.h>
+#include <conpics.h>
+#include <s32stor.h>
+#include "../incp/T_PMLPAR.H"
+
+#define UNUSED_VAR(a) a = a
+
+LOCAL_D CTrapCleanup* TheTrapCleanup;
+LOCAL_D RTest test(_L("CRichText Document"));
+LOCAL_D const TInt KTestCleanupStack=0x200;
+
+class MAtomicTest
+	{
+public:
+	/** Test that the object is correctly set at stage aStage, then advance it
+	to stage aStage+1 with an atomic (with respect to leaving) operation.
+
+	The test at each stage should test that the previous stage really happened
+	and that no part of the new stage has happened.
+
+	RunAtomicTest will test that each of these operations really is atomic.
+	@param aStage The stage to test this object is at.
+	@return
+		ETrue if this object was successfully advanced to the next stage.
+		EFalse if there were no more stages to be advanced to.
+	*/
+	virtual TBool TestAndRunStageL(TInt aStage) = 0;
+	/** Tests that the leave reported in aError is suitable as an error code
+	from aStage. Panics if not.
+
+	@param aError Code that TestAndRunStageL(aStage) left with.
+	@param aStage Stage at which the leave occurred. */
+	virtual void TestErrorCondition(TInt aStage, TInt aError) = 0;
+	void RunAtomicTest();
+	};
+
+/** Runs TestAndRunStage repeatedly with different out-of-memory test
+conditions.
+
+It checks that the operations defined at each stage either leave and leave this
+object in the same condition, or return successfully and leave the object in
+the next stage. */
+void MAtomicTest::RunAtomicTest()
+	{
+	TInt stage = 0;
+	TInt failRate = 1;
+	TBool more = ETrue;
+	while (more)
+		{
+		__UHEAP_SETFAIL(RHeap::EDeterministic, failRate);
+		TRAPD(err, more = TestAndRunStageL(stage));
+		if (err == KErrNone)
+			{
+			failRate = 1;
+			++stage;
+			}
+		else
+			{
+			TestErrorCondition(stage, err);
+			++failRate;
+			}
+		}
+	__UHEAP_RESET;
+	}
+
+template<class S,class T,CEditableText::TDocumentStorage D>
+class CRichTest : public CRichText, public MAtomicTest
+	{
+public:
+	static CRichTest* NewL(CParaFormatLayer* aPara,CCharFormatLayer* aChar);
+
+	void DoFlatTests();
+	void RegisterMethodsL();
+	void InsertWithDelimsL();
+	void TestResetL();
+	void TestDelete1L();
+	void TestDelete2L();
+    void TestApplyRemoveCharFormat();
+	void TestRemSpecParaFmtL();
+	void DoPML();
+	void TestForDefectTET5DHEWWL();
+	void TestForDefectINC010183L();
+	void TestForDefectINC064162L();
+	void TestForDefectINC109323L();
+	// Tests SetInsertCharFormat and friends for atomicity.
+	TBool TestAndRunStageL(TInt aStage);
+	void TestErrorCondition(TInt aStage, TInt aError);
+protected:
+	CRichTest(CParaFormatLayer* aPara,CCharFormatLayer* aChar);
+	};
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+CRichTest<S,T,D>* CRichTest<S,T,D>::NewL(CParaFormatLayer* aPara,CCharFormatLayer* aChar)
+	{
+	CRichTest<S,T,D>* tmp=new(ELeave)CRichTest<S,T,D>(aPara,aChar);
+	tmp->ConstructL(D,EDefaultTextGranularity,EMultiPara);
+	return tmp;
+	}
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+CRichTest<S,T,D>::CRichTest(CParaFormatLayer* aPara,CCharFormatLayer* aChar)
+	:CRichText(aPara,aChar)
+	{}
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::DoFlatTests()
+	{
+	test.Start(_L("Registering all methods"));
+	RegisterMethodsL();
+	test.Next(_L("Inserting with embedded paragraph delimiters"));
+	InsertWithDelimsL();
+	test.End();
+	}
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::InsertWithDelimsL()
+	{
+	test.Start(_L("Inserting into shared para"));
+
+	Reset();
+	TBuf<512> testbuf(_L("a"));
+	for (TInt ii=0;ii<8;ii++)
+		{
+		testbuf.Append('a');
+		testbuf.Append(CEditableText::EParagraphDelimiter);
+		}
+	InsertL(0,testbuf);
+	test(DocumentLength()==17);
+	test(ParagraphCount()==9);
+
+	Reset();
+	TBufC<512> bufC;
+	InsertL(0,bufC);
+		
+	Reset();
+	TBuf<512> buf(_L("Herewith"));
+	InsertL(0,buf);
+
+	InsertL(4,CEditableText::EParagraphDelimiter);
+	// THE ABOVE IS TEMPORARY ONLY _ REMOVE IT AS SOON AS YOUVE DONE.
+	
+	Reset();
+//	TBuf<512> buf(_L("Herewith"));
+	buf.Append(EParagraphDelimiter);
+	InsertL(0,buf);
+
+	buf.Append(_L("Is para one"));
+	buf.Append(EParagraphDelimiter);
+	InsertL(4,buf);
+
+	buf.Append(_L(" trailing text"));
+	InsertL(DocumentLength()-1,buf);
+	//////////////////////////////////
+	// Pathalogical case (1)
+	// Inserting text with delimiters between 2 adjacent pictures.
+	test.Next(_L("Inserting text with delimiters between 2 adjacent pictures."));
+	//
+	Reset();
+	CXzePicture* picA=CXzePicture::NewL('Z');
+	TPictureHeader hdrA;
+	hdrA.iPictureType=KUidXzePictureType;
+	hdrA.iPicture=picA;
+	//
+	CXzePicture* picB=CXzePicture::NewL('X');
+	TPictureHeader hdrB;
+	hdrB.iPictureType=KUidXzePictureType;
+	hdrB.iPicture=picB;
+	//
+	InsertL(0,hdrA);
+	InsertL(DocumentLength(),hdrB);
+	buf.SetLength(0);
+	buf.Append(_L("some"));
+	buf.Append(CEditableText::EParagraphDelimiter);
+	buf.Append(_L("trailing text"));
+	InsertL(1,buf);
+	//
+	Reset();  // Destroys all pictures.
+	picA=CXzePicture::NewL('Z');
+	hdrA.iPictureType=KUidXzePictureType;
+	hdrA.iPicture=picA;
+	picB=CXzePicture::NewL('X');
+	hdrB.iPictureType=KUidXzePictureType;
+	hdrB.iPicture=picB;
+	InsertL(0,hdrA);
+	InsertL(DocumentLength(),hdrB);
+	buf.SetLength(5);  // A single para delimiter, with no trailing text.
+	InsertL(1,buf);
+	////////////////////////////////
+	// Pathalogical case (2)
+	// Insert text with delimiters after a picture
+	test.Next(_L("Insert text with delimiters after a picture"));
+	//
+	Reset();  // Destroys all pictures.
+	picA=CXzePicture::NewL('Z');
+	hdrA.iPictureType=KUidXzePictureType;
+	hdrA.iPicture=picA;
+	InsertL(0,hdrA);
+	buf.SetLength(7);
+	InsertL(1,buf);
+
+	////////////////////////////////
+	// Pathalogical case (3)
+	// Insert text with delimiters before a picture
+	test.Next(_L("Insert text with delimiters before a picture"));
+	//
+	Reset();  // Destroys all pictures.
+	picA=CXzePicture::NewL('Z');
+	hdrA.iPictureType=KUidXzePictureType;
+	hdrA.iPicture=picA;
+	InsertL(0,hdrA);
+	buf.SetLength(7);
+	InsertL(0,buf);
+	//	
+	Reset();
+	test.End();
+	}
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::RegisterMethodsL()
+//
+// 1st part of testing, involves all methods being called to ensure that all
+// methods exist and run without panicking.
+//
+	{
+	test.Start(_L("CRichText::NewL()"));
+
+	// InsertL()
+	test.Next(_L("InsertL()"));
+	TPtrC buf(_L("Herewith"));
+	InsertL(0,buf);
+
+//	11.3.97 DavidA defect test 
+	TCharFormat charFormat;
+	TCharFormatMask charFormatMask;
+	TInt lastChar=DocumentLength();
+	ApplyCharFormatL(charFormat,charFormatMask,lastChar,1);
+//	end of addition.
+
+
+	TPtrC buf2(_L("Hello"));
+	InsertL(0,buf2);
+
+	DeleteL(3,7);
+
+	// SetInsertCharFormatL()
+	test.Next(_L("SetInsertCharFormatL()"));
+	TCharFormat format; TCharFormatMask mask;
+	format.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+	mask.SetAttrib(EAttFontStrokeWeight);
+	SetInsertCharFormatL(format,mask,3);
+	// Test for alloc heaven when doing multiple simultaneous SetInsertCharFormat()s.
+	format.iFontSpec.iFontStyle.SetPosture(EPostureItalic);
+	mask.SetAttrib(EAttFontPosture);
+	SetInsertCharFormatL(format,mask,3);
+	//
+	TPtrC buf3(_L(" is bold."));
+	InsertL(3,buf3);
+	CancelInsertCharFormat();
+
+	// Inserting new paragraph
+	test.Next(_L("Inserting paragraph delimiter (Insert(TChar))"));
+	InsertL(4,CEditableText::EParagraphDelimiter);
+
+	// Delete()
+	test.Next(_L("DeleteL()"));
+	DeleteL(5,1);
+
+	// Sensing character format over a specified range.
+	test.Next(_L("GetCharFormat()"));
+	TCharFormat charFormat1; TCharFormatMask undeterminedMask;
+	GetCharFormat(charFormat1,undeterminedMask,0,4);
+
+	// Sensing paragraph format over a specified range.
+	test.Next(_L("SenseParagraphFormatL()"));
+	CParaFormat* pParaFormat=NULL;
+	TRAPD(r,pParaFormat=CParaFormat::NewL());
+	test(r==KErrNone);
+	TParaFormatMask undeterminedParaMask;
+	GetParaFormatL(pParaFormat,undeterminedParaMask,0,DocumentLength());
+	delete pParaFormat;
+	
+	// DelSetInsertCharFormatL()
+	test.Next(_L("DelSetInsertCharFormatL()"));
+	TPtrC buf4(_L("This is para 2."));
+	InsertL(0,buf4);
+	SetInsertCharFormatL(format,mask,15);
+	TPtrC buf5(_L("In italic."));
+	InsertL(15,buf5);
+	DelSetInsertCharFormatL(4,5);
+	
+	// CancelInsertCharFormat()
+	test.Next(_L("CancelInsertCharFormat()"));
+	CancelInsertCharFormat();
+	
+	// ApplyParaFormatL()
+	test.Next(_L("ApplyParaFormatL()"));
+	CParaFormat* paraFormat=CParaFormat::NewL(); TParaFormatMask paraMask;
+	paraFormat->iHorizontalAlignment=CParaFormat::ECenterAlign;
+	paraMask.SetAttrib(EAttAlignment);
+	ApplyParaFormatL(paraFormat,paraMask,0,DocumentLength());
+
+	// ApplyCharFormatL()
+	test.Next(_L("ApplyCharFormatL()"));
+	format.iFontSpec.iFontStyle.SetPosture(EPostureItalic); mask.SetAttrib(EAttFontPosture);
+	format.iFontPresentation.iStrikethrough=EStrikethroughOn; mask.SetAttrib(EAttFontStrikethrough);
+	ApplyCharFormatL(format,mask,0,DocumentLength());
+
+	// SenseParaFormatL()
+	test.Next(_L("SenseParaFormatL()"));
+	GetParagraphFormatL(paraFormat,DocumentLength()-1);
+
+	// CountParas()
+	test.Next(_L("ParagraphCount()"));
+	ParagraphCount();
+
+	// ParagraphStart()
+	test.Next(_L("ParagraphStart()"));
+	TInt aPos=0;
+	ToParagraphStart(aPos);
+
+	// Reset
+	Reset();
+
+	delete paraFormat;
+
+	test.End();
+	}
+
+/**
+@SYMTestCaseID 			SYSLIB-ETEXT-UT-3548
+@SYMTestCaseDesc  		Testing behaviour of function ApplyCharFormatL() when called at end of document
+						that contains plain text. Applied formatting should work on subsequent text
+@SYMTestPriority  		High
+@SYMTestActions 		1. Insert text1
+						2. Switch on bold formatting
+						3. Insert text2
+						4. Test that first char of text1 is not bold and a character of text 2 is bold. 
+@SYMTestExpectedResults	ApplyCharFormatL() applies formatting from end of doc to subsequent character.
+@SYMDEF					INC109323
+*/
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestForDefectINC109323L()
+	{
+	__UHEAP_MARK;
+	test.Next(_L(" @SYMTestCaseID:SYSLIB-ETEXT-UT-3548 Test ApplyCharFormatL() for bold at end positions of text "));	
+	_LIT(KText1, "Testing Bold format");
+	_LIT(KText2, "bold");	
+
+	CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
+	CleanupStack::PushL(paraLayer);
+	CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
+	CleanupStack::PushL(charLayer);
+	CRichText* doc = CRichText::NewL(paraLayer,charLayer,D);
+	CleanupStack::PushL(doc);
+	TCharFormat format1;
+	TCharFormat fmtCheck1;
+	format1.iFontPresentation.iUnderline = EUnderlineOff;
+	// initilizing format attributes
+	TCharFormatMask mask1;
+	TCharFormatMask mask2;	
+	fmtCheck1.iFontPresentation.iUnderline = EUnderlineOff;	
+	//Test document containing test string and cursor positioned at end of doc.
+	//Turn on bold formatting and subsequent characters are in bold format.
+	doc->InsertL(0, KText1);
+	format1.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+	mask1.SetAttrib(EAttFontStrokeWeight);//Set Bold
+	doc->ApplyCharFormatL(format1, mask1, doc->DocumentLength(),0);//Apply Bold	
+	doc->InsertL(19, KText2);//These should be in bold
+	mask1.ClearAttrib(EAttFontStrokeWeight);//Remove bold formatting
+	doc->GetCharFormat(format1, mask1, 0, 1);//Get format of characters at position 0
+	doc->GetCharFormat(fmtCheck1, mask2, 22, 1);//Get format of characters at position 22
+	test(format1.iFontSpec.iFontStyle.StrokeWeight()!=EStrokeWeightBold);
+	test(fmtCheck1.iFontSpec.iFontStyle.StrokeWeight()==EStrokeWeightBold);	
+	//tidyup
+	CleanupStack::PopAndDestroy(doc);
+	CleanupStack::PopAndDestroy(charLayer);
+	CleanupStack::PopAndDestroy(paraLayer);	
+	__UHEAP_MARKEND;
+	}
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestRemSpecParaFmtL()
+//
+// Test the RemoveSpecificParaFormatL() method of CRichText.
+//
+	{
+	__UHEAP_MARK;
+	test.Next(_L("RemoveSpecificParaFormatL()"));
+	CParaFormat* globalParaFormat=CParaFormat::NewLC();
+	TParaFormatMask globalParaMask;
+	globalParaFormat->iHorizontalAlignment=CParaFormat::ECenterAlign;
+	globalParaMask.SetAttrib(EAttAlignment);
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(globalParaFormat,globalParaMask);
+	CCharFormatLayer* charLayer=CCharFormatLayer::NewL();
+	CRichText* doc=NULL;
+	TRAPD(ret,doc=CRichText::NewL(paraLayer,charLayer,D));
+	if (ret!=KErrNone)
+		{
+		test(doc==NULL);
+		User::Leave(ret);
+		}
+	TPtrC buf1(_L("Here is paragraph one text."));
+	doc->InsertL(0,buf1);
+	//
+	// Apply specific paragraph format
+	CParaFormat* format=CParaFormat::NewLC();
+	TParaFormatMask mask;
+	format->iHorizontalAlignment=CParaFormat::ERightAlign;
+	mask.SetAttrib(EAttAlignment);
+	doc->ApplyParaFormatL(format,mask,1,1);
+	CParaFormat* sensedFormat=CParaFormat::NewLC();
+	doc->GetParagraphFormatL(sensedFormat,0);
+	test(sensedFormat->iHorizontalAlignment==CParaFormat::ERightAlign);
+	//
+	// Remove specific para format and test
+	doc->RemoveSpecificParaFormatL(0,1);
+	doc->GetParagraphFormatL(sensedFormat,0);
+	test(sensedFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
+	//
+	CleanupStack::PopAndDestroy(3); // the 2 para formats.
+	delete doc;
+	delete paraLayer;
+	delete charLayer;
+
+	__UHEAP_MARKEND;
+	}
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestDelete1L()
+//
+// Test the DeleteL() method of CRichText.
+//
+	{
+	__UHEAP_MARK;
+	test.Next(_L("DeleteL()"));
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL();
+	CCharFormatLayer* charLayer=CCharFormatLayer::NewL();
+	CRichText* doc=NULL;
+	TRAPD(ret,doc=CRichText::NewL(paraLayer,charLayer,D));
+	if (ret!=KErrNone)
+		{
+		test(doc==NULL);
+		User::Leave(ret);
+		}
+	TPtrC buf1(_L("Here is paragraph one text."));
+	TPtrC buf2(_L("Here is paragraph one text."));
+	doc->InsertL(0,buf1);
+	doc->InsertL(doc->DocumentLength(),EParagraphDelimiter);
+	doc->InsertL(doc->DocumentLength(),buf2);
+	//
+	// Apply formatting
+	TCharFormat applyFormat;
+	TCharFormatMask applyMask;
+	applyFormat.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+	applyMask.SetAttrib(EAttFontStrokeWeight);
+	doc->ApplyCharFormatL(applyFormat,applyMask,8,28);
+	//
+	// Now try the delete - should end up with a single shared paragraph!!!
+	doc->DeleteL(8,28);
+	TInt documentLength=doc->DocumentLength();
+	test(documentLength==27);
+	//
+	delete doc;
+	delete paraLayer;
+	delete charLayer;
+
+	__UHEAP_MARKEND;
+	}
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestDelete2L()
+//
+// Test the DeleteL() method of CRichText.
+// Deleting the paragraph delimiter between 2 paras of constant character format, but of varying
+// paragraph formats.
+//
+	{
+	__UHEAP_MARK;
+	test.Next(_L("DeleteL()"));
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL();
+	CCharFormatLayer* charLayer=CCharFormatLayer::NewL();
+	CRichText* doc=NULL;
+	TRAPD(ret,doc=CRichText::NewL(paraLayer,charLayer,D));
+	if (ret!=KErrNone)
+		{
+		test(doc==NULL);
+		User::Leave(ret);
+		}
+	TPtrC buf1(_L("A"));
+	TPtrC buf2(_L("B"));
+	TPtrC buf3(_L("C"));
+	doc->InsertL(0,buf1);
+	doc->InsertL(doc->DocumentLength(),EParagraphDelimiter);
+	doc->InsertL(doc->DocumentLength(),buf2);
+	doc->InsertL(doc->DocumentLength(),EParagraphDelimiter);
+	doc->InsertL(doc->DocumentLength(),buf3);
+	//
+	// Apply formatting
+	CParaFormat* applyFormat=CParaFormat::NewLC();
+	TParaFormatMask applyMask;
+	applyFormat->iHorizontalAlignment=CParaFormat::ERightAlign;
+	applyMask.SetAttrib(EAttAlignment);
+	//
+	// Make 1st & 3rd para the same para format, different to para 2.
+	
+	doc->ApplyParaFormatL(applyFormat,applyMask,1,1);
+	doc->ApplyParaFormatL(applyFormat,applyMask,5,1);
+	CleanupStack::PopAndDestroy();  // para format
+	//
+	// Now try the delete - should end up with a single shared paragraph!!!
+	/*TBool parasMerged=*/doc->DeleteL(3,1);  // delete para 2 delimiter
+	TInt documentLength=doc->DocumentLength();
+	test(documentLength==4);
+	//
+	delete doc;
+	delete paraLayer;
+	delete charLayer;
+
+	__UHEAP_MARKEND;
+	}
+
+
+/**
+@SYMTestCaseID             SYSLIB-ETEXT-UT-3431
+@SYMTestCaseDesc          Testing behaviour of functions ApplyCharFormatL() and RemoveSpecificFormatL();
+    formatting of text including end of document character
+@SYMTestPriority          High
+@SYMTestActions         1. format text and compare attribute values for equality
+                        2. testing for fix of INC097216 whether EOD also formatted
+                        3. remove formatting of text and compare attribute values for equality
+                        4. testing for fix of DEF104149 whether EOD also has formatting removed
+@SYMTestExpectedResults    ApplyCharFormatL() and RemoveSpecificFormatL() apply and remove formatting from
+    specified range of text including end of document character
+@SYMDEF                    DEF104149
+*/
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestApplyRemoveCharFormat()
+    {
+    __UHEAP_MARK;
+    test.Next(_L(" @SYMTestCaseID:SYSLIB-ETEXT-UT-3431 Test ApplyCharFormatL() & RemoveSpecificCharFormat() "));	
+    CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
+    CleanupStack::PushL(paraLayer);
+    CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
+    CleanupStack::PushL(charLayer);
+    CRichText* doc = CRichText::NewL(paraLayer,charLayer,D);
+    CleanupStack::PushL(doc);
+    _LIT(KText1, "Hello there!");
+    doc->InsertL(0, KText1);
+    test(doc->DocumentLength()==12);
+   
+    // initilizing format (ie.underline) values
+    TCharFormat formatCheck;
+    formatCheck.iFontPresentation.iUnderline = EUnderlineOff;
+    TCharFormat fmatCheck;
+    formatCheck.iFontPresentation.iUnderline = EUnderlineOff;
+    TCharFormat format;
+    format.iFontPresentation.iUnderline = EUnderlineOn;
+    TCharFormat formatNone;
+    formatCheck.iFontPresentation.iUnderline = EUnderlineOff;
+
+    // initilizing format attributes
+    TCharFormatMask maskCheck;   
+    TCharFormatMask mask;
+    mask.SetAttrib(EAttFontUnderline);
+   
+    // underline KText1 and compare its attribute values with EUnderlineOn for equality
+    doc->ApplyCharFormatL(format, mask, 0, 12);   
+    doc->GetCharFormat(formatCheck, maskCheck, 0, 12);
+    // testing for fix of INC097216 whether EOD also formatted
+    doc->GetCharFormat(fmatCheck, maskCheck, 12, 1);
+    test(format.IsEqual(formatCheck));
+    test(format.IsEqual(fmatCheck));
+
+    // remove underlining of KText1 and compare its attribute values with EUnderlineOff for equality
+    doc->RemoveSpecificCharFormatL(0, 12);
+    doc->GetCharFormat(formatCheck, maskCheck, 0, 12);
+    // testing for fix of INC104149 whether EOD also has formatting removed
+    doc->GetCharFormat(fmatCheck, maskCheck, 12, 1);
+    test(formatCheck.IsEqual(formatNone));
+    test(fmatCheck.IsEqual(formatNone));
+   
+    CleanupStack::PopAndDestroy(doc);
+    CleanupStack::PopAndDestroy(charLayer);
+    CleanupStack::PopAndDestroy(paraLayer);   
+    __UHEAP_MARKEND;
+    }
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestResetL()
+//
+// Test the Reset() method of CRichText.
+//
+	{
+	__UHEAP_MARK;
+	test.Next(_L("Reset()"));
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL();
+	CCharFormatLayer* charLayer=CCharFormatLayer::NewL();
+	CRichText* doc=NULL;
+	TRAPD(ret,doc=CRichText::NewL(paraLayer,charLayer,D));
+	if (ret!=KErrNone)
+		{
+		test(doc==NULL);
+		User::Leave(ret);
+		}
+	TPtrC buf1(_L("Here is paragraph one text."));
+	TPtrC buf2(_L("And here is that of the second paragraph"));
+	doc->InsertL(0,buf1);
+	doc->InsertL(doc->DocumentLength(),EParagraphDelimiter);
+	doc->InsertL(doc->DocumentLength(),buf2);
+	//
+	doc->Reset();
+	test(doc->ParagraphCount()==1);
+	doc->Reset();
+	test(doc->ParagraphCount()==1);
+	doc->Reset();
+	test(doc->ParagraphCount()==1);
+	delete doc;
+	delete paraLayer;
+	delete charLayer;
+
+	__UHEAP_MARKEND;
+	}
+	
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::DoPML()
+//
+// Use PML source translator to produce a RichText component.
+//
+	{
+ 	__UHEAP_MARK;
+	test.Next(_L("Checking PML sourced RichText Component"));
+ 	// set filename
+	TFileName theFileName=_L("z:\\test\\app-framework\\etext\\t_rich1a.pml");
+	// Parse PML
+	CParser* myParser=NULL;
+	CRichText* richTextDoc=NULL;
+	TRAPD(ret, myParser=CParser::NewL());
+	CleanupStack::PushL(myParser);
+	TRAP(ret, richTextDoc=myParser->ParseL(theFileName));
+	CleanupStack::PushL(richTextDoc);
+	CParaFormatLayer* pl = const_cast<CParaFormatLayer*>(
+		richTextDoc->GlobalParaFormatLayer());
+	CleanupStack::PushL(pl);
+	CCharFormatLayer* cl = const_cast<CCharFormatLayer*>(
+		richTextDoc->GlobalCharFormatLayer());
+	CleanupStack::PushL(cl);
+	
+	TInt paraCount=richTextDoc->ParagraphCount();
+	test(paraCount==2);
+	TBool hasMarkupData=richTextDoc->HasMarkupData();
+	test(hasMarkupData==EFalse);
+
+	// Testing overloaded senseChars - looking at the indeterminate mask.
+//	TCharFormat charFormat;	TCharFormatMask charFormatMask;
+//	richTextDoc->GetCharFormat(0,17,charFormat,charFormatMask);
+//	test(charFormatMask==0);
+
+//	richTextDoc->GetCharFormat(17,10,charFormat,charFormatMask);
+
+	CParaFormat* paraFormat = 0;
+	paraFormat=CParaFormat::NewLC();
+	TParaFormatMask paraFormatMask;
+	richTextDoc->GetParaFormatL(paraFormat,paraFormatMask,0,2);
+	richTextDoc->GetParaFormatL(paraFormat,paraFormatMask,17,3);  // All para 2 and just para1
+
+	CleanupStack::PopAndDestroy(paraFormat);
+	CleanupStack::PopAndDestroy(cl);
+	CleanupStack::PopAndDestroy(pl);
+	CleanupStack::PopAndDestroy(richTextDoc);
+	CleanupStack::PopAndDestroy(myParser);
+	__UHEAP_MARKEND;
+	}
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestForDefectTET5DHEWWL()
+//
+// Test the CRichTextIndex::InsertL() for defect TET-5DHEWW which 
+// should not be present from 15/10/02.
+//
+	{
+	__UHEAP_MARK;
+
+	test.Next(_L("Testing for the presence of defect TET-5DHEWW"));
+
+	CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
+	CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
+
+	CRichText* doc = NULL;
+	TRAPD(ret, doc = CRichText::NewL(paraLayer,charLayer,D));
+	if (ret!=KErrNone)
+		{
+		test(doc==NULL);
+		User::Leave(ret);
+		}
+
+	TPtrC buf1(_L("sometext "));
+	doc->InsertL(0, buf1);
+
+	TCharFormat charFormat12(_L("Times New Roman"), 240);
+	TCharFormatMask charMask12;
+	charMask12.SetAttrib(EAttFontHeight);
+	doc->SetInsertCharFormatL(charFormat12, charMask12, doc->DocumentLength());
+
+	TPtrC buf2(_L("sometext "));
+	doc->InsertL(doc->DocumentLength(), buf2);
+
+	doc->SetInsertCharFormatL(charFormat12, charMask12, doc->DocumentLength());
+	doc->InsertL(doc->DocumentLength(), EParagraphDelimiter);
+
+	// Defect present in CRichTextIndex if test executable crashes/panics on the 
+	// previous line on a debug build. Should this test method return normally then 
+	// the EText library used does not contain the defect.
+
+	TInt docLen = doc->DocumentLength();
+	test(docLen==19);
+
+	test.Printf(_L("RTEST:                        Test PASSED - defect not present!\n"));
+
+	delete doc;
+	delete paraLayer;
+	delete charLayer;
+
+	__UHEAP_MARKEND;
+	}
+
+// CRichTextIndex::GetParaFormatL doesn't set TParaFormatMask correctly
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestForDefectINC010183L()
+	{
+	__UHEAP_MARK;
+
+	test.Next(_L("Testing for the presence of defect INC010183"));
+
+	CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
+	CleanupStack::PushL(paraLayer);
+	CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
+	CleanupStack::PushL(charLayer);
+
+	CRichText* doc = CRichText::NewL(paraLayer,charLayer,D);
+	CleanupStack::PushL(doc);
+
+	TPtrC buf1(_L("para1\x2029para2\x2029para3"));
+	doc->InsertL(0, buf1);
+
+	CParaFormat* pFormat = CParaFormat::NewLC();
+	pFormat->iBullet = new(ELeave) TBullet;
+	pFormat->iBullet->iHeightInTwips = 1;
+	TParaFormatMask pMask;
+	pMask.SetAttrib(EAttBullet);
+
+	doc->ApplyParaFormatL(pFormat, pMask, 8, 1);
+	doc->GetParaFormatL(pFormat, pMask, 0, 14);
+
+	// test that the bullet's "varies" flag is set.
+	test(pMask.AttribIsSet(EAttBullet));
+
+	doc->GetParaFormatL(pFormat, pMask, 7, 6);
+
+	// test that the bullet's "varies" flag is set.
+	test(pMask.AttribIsSet(EAttBullet));
+
+	CleanupStack::PopAndDestroy(pFormat);
+	CleanupStack::PopAndDestroy(doc);
+	CleanupStack::PopAndDestroy(charLayer);
+	CleanupStack::PopAndDestroy(paraLayer);
+
+	__UHEAP_MARKEND;
+	}
+
+
+// CRichTextIndex::InsertL, Insertion of zero-length text should not cancel the pending new TCharFormat.
+// This test sets the Strikethrough option on and applies it to a zero length section of text before checking
+// the format has been applied correctly. Then it inputs 3 characters and checks to see if the format of these
+// characters also has the character format applied to them.  
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestForDefectINC064162L()
+	{
+	__UHEAP_MARK;
+	
+	test.Next(_L("INC064162 - Testing insertion of zero-length text doesn't cancel the pending TCharFormat"));
+	
+	TInt length = 3;	
+	TPtrC bufPtrLetterNone(_L(""));
+	TPtrC bufPtrLettersABC(_L("ABC"));
+	
+	CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
+	CleanupStack::PushL(paraLayer);
+	CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
+	CleanupStack::PushL(charLayer);
+
+	CRichText* doc = CRichText::NewL(paraLayer,charLayer,D);
+	CleanupStack::PushL(doc);
+
+	TCharFormat cFormatCheck;
+	cFormatCheck.iFontPresentation.iStrikethrough = EStrikethroughOff;
+	
+	TCharFormat cFormat;
+	cFormat.iFontPresentation.iStrikethrough = EStrikethroughOn;
+
+	TCharFormatMask cMaskCheck;
+	
+	TCharFormatMask cMask;
+	cMask.SetAttrib(EAttFontStrikethrough);
+	
+	// Applying the strikethrough format on a zero length section of text.
+	doc->ApplyCharFormatL(cFormat,cMask,0,0);	
+
+	doc->InsertL(0, bufPtrLetterNone);
+	
+	doc->GetCharFormat(cFormatCheck, cMaskCheck,0,0);
+
+	// testing the format of the empty buf
+	test(cFormat.IsEqual(cFormatCheck));
+
+	doc->InsertL(0, bufPtrLettersABC);	
+	doc->GetCharFormat(cFormatCheck, cMaskCheck,0,length);
+	
+	// testing the format of the 3 characters
+	test(cFormat.IsEqual(cFormatCheck));
+ 
+	CleanupStack::PopAndDestroy(doc);
+	CleanupStack::PopAndDestroy(charLayer);
+	CleanupStack::PopAndDestroy(paraLayer);
+
+	__UHEAP_MARKEND;
+	}
+
+
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+TBool CRichTest<S,T,D>::TestAndRunStageL(TInt aStage)
+	{
+	_LIT(KSomeText, "Text\x2029par ");
+	_LIT(KSomeTextPlus3, "Text\x2029par \x2029z ");
+	TCharFormat format;
+	TCharFormatMask mask;
+	TCharFormatMask varies;
+	switch (aStage)
+		{
+	case 0:
+		Reset();
+		return ETrue;
+	case 1:
+		test(DocumentLength() == 0);
+		InsertL(0, KSomeText);
+		return ETrue;
+	case 2:
+			{
+			TBuf<100> buf;
+			test(DocumentLength() == KSomeText().Length());
+			Extract(buf, 0, KSomeText().Length());
+			test(0 == buf.Compare(KSomeText));
+			TCharFormat format0;
+			GetCharFormat(format, varies, 0, KSomeText().Length());
+			test(varies.IsNull());		// format should not vary
+			test(format.IsEqual(format0));
+			}
+		// Set an insert char format for font height 100
+		mask.SetAttrib(EAttFontHeight);
+		format.iFontSpec.iHeight = 100;
+		SetInsertCharFormatL(format, mask, 9);
+		return ETrue;
+	case 3:
+		test(DocumentLength() == KSomeText().Length());
+		// Insert a carriage return and cancel the insert char format.
+		// This stands in place of moving the cursor away from the
+		// insertion point and back again.
+		InsertL(9, 0x2029);
+		return ETrue;
+	case 4:
+		test(DocumentLength() == KSomeText().Length() + 1);
+		CancelInsertCharFormat();
+		return ETrue;
+	case 5:
+		test(DocumentLength() == KSomeText().Length() + 1);
+		GetCharFormat(format, varies, 0, 9);
+			{
+			TCharFormat format0;
+			test(format.IsEqual(format0));
+			test(varies.IsNull());
+			}
+		GetCharFormat(format, varies, 9, 1);
+		test(varies.IsNull());
+		test(format.iFontSpec.iHeight == 100);
+		// Insert a character after the new carriage return. It should
+		// have height 100. This is what the defect INC038479 is
+		// complaining about. In fact it is a long-standing problem,
+		// long assumed to be too difficult to solve in a reasonable
+		// time.
+		InsertL(10, 'z');
+		return ETrue;
+	case 6:
+		test(DocumentLength() == KSomeText().Length() + 2);
+		GetCharFormat(format, varies, 9, 2);
+		test(varies.IsNull());
+		test(format.iFontSpec.iHeight == 100);
+		// Insert a space. This prepares us for checking for a regression
+		// that was introduced then fixed in the fix for INC038479.
+		InsertL(11, ' ');
+		return ETrue;
+	case 7:
+			{
+			TBuf<100> buf;
+			test(DocumentLength() == KSomeTextPlus3().Length());
+			Extract(buf, 0, KSomeTextPlus3().Length());
+			test(0 == buf.Compare(KSomeTextPlus3));
+			TCharFormat format0;
+			GetCharFormat(format, varies, 0, KSomeText().Length());
+			test(varies.IsNull());		// format should not vary across the original bit
+			test(format.IsEqual(format0));
+			GetCharFormat(format, varies, KSomeText().Length(), 3);
+			test(format.iFontSpec.iHeight == 100);
+			test(varies.IsNull());
+			}
+		// Set a new insert character format for bold
+		mask.SetAttrib(EAttFontStrokeWeight);
+		format.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+		SetInsertCharFormatL(format, mask, 9);
+		return ETrue;
+	case 8:
+		// and unset the insert character format again
+		mask.SetAttrib(EAttFontStrokeWeight);
+		format.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
+		SetInsertCharFormatL(format, mask, 9);
+		return ETrue;
+	case 9:
+		test(DocumentLength() == KSomeTextPlus3().Length());
+		// Add a carriage return.
+		InsertL(12, 0x2029);
+		return ETrue;
+	case 10:
+		test(DocumentLength() == KSomeTextPlus3().Length() + 1);
+		GetCharFormat(format, varies, KSomeTextPlus3().Length(), 1);
+		test(varies.IsNull());
+		test(format.iFontSpec.iFontStyle.StrokeWeight() == EStrokeWeightNormal);
+		return EFalse;
+	default:
+		return ETrue;
+		}
+	}
+
+template<class S, class T,CEditableText::TDocumentStorage D>
+void CRichTest<S,T,D>::TestErrorCondition(TInt aStage, TInt aError)
+	{
+	// No leaves possible except NoMemory.
+	test(aError == KErrNoMemory);
+	// Stage 4 should not leave at all.
+	test(aStage != 4);
+	}
+
+
+template<class S, class T, CEditableText::TDocumentStorage D>
+void TestClassesL()
+	{
+	__UHEAP_MARK;
+
+	CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
+	CleanupStack::PushL(paraLayer);
+	CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
+	CleanupStack::PushL(charLayer);
+	CRichTest<S, T, D>* doc = CRichTest<S, T, D>::NewL(paraLayer, charLayer);
+	CleanupStack::PushL(doc);
+
+	doc->DoFlatTests();
+	doc->TestResetL();
+	doc->TestDelete1L();
+	doc->TestDelete2L();
+	doc->TestApplyRemoveCharFormat();
+	doc->TestRemSpecParaFmtL();
+	doc->DoPML();
+	doc->TestForDefectTET5DHEWWL();
+	doc->TestForDefectINC010183L();
+	doc->TestForDefectINC064162L();
+	doc->TestForDefectINC109323L();
+	test.Next(_L("INC038479 - Email editor: font settings made at doc end can be lost and returned to default"));
+	// Also tests SetInsetCharFormat more thoroughly.
+	doc->RunAtomicTest();
+
+	CleanupStack::PopAndDestroy(doc);
+	CleanupStack::PopAndDestroy(charLayer);
+	CleanupStack::PopAndDestroy(paraLayer);
+
+	__UHEAP_MARKEND;
+	}
+
+void DoTestsL()
+	{
+	test.Start(_L("CRichText - Flat"));
+	TestClassesL<TText,TPtrC,CEditableText::EFlatStorage>();
+	test.Next(_L("CRichText - Segmented"));
+	TestClassesL<TText,TPtrC,CEditableText::ESegmentedStorage>();
+	test.End();
+	}
+
+	
+LOCAL_C void setupCleanup()
+//
+// Initialise the cleanup stack.
+//
+	{
+
+	TheTrapCleanup=CTrapCleanup::New();
+	TRAPD(r,\
+		{\
+		for (TInt i=KTestCleanupStack;i>0;i--)\
+			CleanupStack::PushL((TAny*)1);\
+		test(r==KErrNone);\
+		CleanupStack::Pop(KTestCleanupStack);\
+		});
+	}
+
+TInt E32Main()
+	{
+	setupCleanup();
+	test.Title();
+	__UHEAP_MARK;
+	
+	TRAPD(ret,DoTestsL());
+    test(ret == KErrNone);
+	
+	test.Close();
+	__UHEAP_MARKEND;
+	delete TheTrapCleanup;
+	return 0;
+	}