/*
* 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;
	}
