// T_OOM.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <f32file.h>
#include <apaid.h>
#include <apffndr.h>
#include <apgaplst.h>
#include <apgicnfl.h>
#include <apgdoor.h>
#include "tstapp.h"
#include <fbs.h>
#include <s32std.h> 
#include <s32stor.h> 
#include <s32file.h> 
#include <s32mem.h>
//
#if !defined(__E32TEST_H__)
#include <e32test.h>
#endif

/////////////////////////////////////////////////

const TInt KTestCleanupStack=0x40;

LOCAL_D TUid testUid={1};
LOCAL_D TFileName dllname=_L("tstapp.app");
LOCAL_D TApaAppCaption KAppCaption=_L("Test App");
LOCAL_D TFullName searchPath=_L("\\system\\apps\\");
LOCAL_D TFullName filePath=_L("c:\\docs\\tstapp.doc");
LOCAL_D TFullName tempPath=_L("c:\\system\\temp\\");
LOCAL_D TFullName appPath=_L("z:\\system\\apps\\tstapp\\tstapp.app");
LOCAL_D TFullName icnPath=_L("z:\\system\\apps\\tstapp\\tstapp.aif");
LOCAL_D TFullName iniPath=_L("c:\\system\\apps\\tstapp\\tstapp.ini");

LOCAL_D TFileName spoofName=_L("spoof.app");
LOCAL_D TFullName spoofPath=_L("c:\\system\\apps\\spoof\\spoof.app");
LOCAL_D TFullName spoofIcn=_L("c:\\system\\apps\\spoof\\spoof.aif");
LOCAL_D TFullName hiddenIcn=_L("c:\\system\\apps\\spoof\\hidden.aif");
LOCAL_D TFullName hiddenApp=_L("c:\\system\\apps\\spoof\\hidden.app");

LOCAL_D RTest test(_L("T_OOM"));
LOCAL_D CTrapCleanup* TheTrapCleanup;
LOCAL_D RFs TheFs;


LOCAL_D void setup()
	{
#if defined(__EPOC32__)
	// if we're on the rack create the directories we need
	TParse parser;
	parser.Set(filePath,NULL,NULL);
	TheFs.MkDirAll(parser.DriveAndPath());
	parser.Set(tempPath,NULL,NULL);
	TheFs.MkDirAll(parser.DriveAndPath());
#endif
	}


LOCAL_D CApaDocument* CreateTestDocL(CApaProcess* aProcess)
	{
	// create a new main doc of type tstapp
	CApaDocument* doc = aProcess->AddNewDocumentL(dllname);
	aProcess->SetMainDocument(doc);
	//
	// create the store and initialise it
	CFileStore* store = doc->CreateFileStoreLC(aProcess->FsSession(),filePath);
	CleanupStack::Pop(); // store
	((CTestAppDoc*)aProcess->MainDocument())->iStore = store;
	aProcess->SetMainDocFileName(filePath);
	//
	// initialise the document with factory settings
	doc->NewDocumentL();
	//
	return doc;
	}


LOCAL_D void CreateTestDocFileL()
	{
	// delete the file to be created by the testcode
	TheFs.Delete(filePath);
	//
	// create an appfinder and process
	CApaScanningAppFinder* finder = CApaScanningAppFinder::NewL(TheFs);
	CApaProcess* process = CApaProcess::NewL(TheFs,*finder);
	//
	CApaDocument* doc = CreateTestDocL(process);
	//
	// save it 
	doc->SaveL();
	//
	// tidy up
	process->DestroyDocument(doc);
	delete process;
	}


LOCAL_D void TestOOMConstructionL()
// Test CDictionaryFileStore construction, forcing a leave error at each
// possible stage of the process.
//
	{
	TInt failRate=0;
	//
	// CApaScanningAppFinder
	test.Next(_L("CApaScanningAppFinder construction under OOM"));
	CApaScanningAppFinder* finder=NULL;
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;
		TRAPD(ret, finder = CApaScanningAppFinder::NewL(TheFs));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			__UHEAP_MARKEND;
			test(finder==NULL);
			}
		else
			{
			test(finder!=NULL);
			delete finder;
			finder = NULL;
			__UHEAP_MARKEND;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs for c'tion: %d\n"),failRate-1);
	//
	//
	// CApaProcess
	test.Next(_L("CApaProcess construction under OOM"));
	CApaProcess* process=NULL;
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		finder = CApaScanningAppFinder::NewL(TheFs);
			test(finder!=NULL);
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;
		TRAPD(ret, process = CApaProcess::NewL(TheFs,*finder));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			__UHEAP_MARKEND;
			test(process==NULL);
			}
		else
			{
			test(process!=NULL);
			delete process;
			process = NULL;
			__UHEAP_MARKEND;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs for c'tion: %d\n"),failRate-1);
	//
	// creating CApaDocument
	test.Next(_L("CApaDocument construction under OOM"));
	CApaDocument* doc=NULL;
	//
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		finder = CApaScanningAppFinder::NewL(TheFs);
			test(finder!=NULL);
		process = CApaProcess::NewL(TheFs,*finder);
			test(process!=NULL);
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;
		TRAPD(ret, doc=process->AddNewDocumentL(appPath));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			delete process;
			__UHEAP_MARKEND;
			test(doc==NULL);
			}
		else
			{
			test(doc!=NULL);
			process->DestroyDocument(doc);
			delete process;
			__UHEAP_MARKEND;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs for c'tion: %d\n"),failRate-1);
	//
	// opening a CApaDocument
	test.Next(_L("CApaDocument Restoration under OOM"));
	TRAPD(err,CreateTestDocFileL());
		test(err==KErrNone);
	//
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		doc = NULL;
		finder = CApaScanningAppFinder::NewL(TheFs);
		process = CApaProcess::NewL(TheFs,*finder);
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;
		CFileStore* store=NULL;
		CStreamDictionary* streamDic=NULL;
		TRAPD(ret, doc=process->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			delete streamDic;
			delete store;
			delete process;
			__UHEAP_MARKEND;
			test(doc==NULL);
			}
		else
			{
			test(doc!=NULL);
			test(streamDic!=NULL);
			test(store!=NULL);
			delete streamDic;
			delete store;
			process->DestroyDocument(doc);
			delete process;
			__UHEAP_MARKEND;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs for c'tion: %d\n"),failRate-1);
	//
	// saving a CApaDocument
	test.Next(_L("CApaDocument Storing under OOM"));
	//
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		// delete the file to be created by the testcode
		TheFs.Delete(filePath);
		// create an appfinder, process and doc
		finder = CApaScanningAppFinder::NewL(TheFs);
		process = CApaProcess::NewL(TheFs,*finder);
		doc = CreateTestDocL(process);
		// attempt to save
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;
		CFileStore* store=NULL;
		CStreamDictionary* streamDic=NULL;
		TRAPD(ret, doc->SaveL());
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			process->DestroyDocument(doc);
			delete process;
			__UHEAP_MARKEND;
			}
		else
			{
			process->DestroyDocument(doc);
			delete process;
			__UHEAP_MARKEND;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs for c'tion: %d\n"),failRate-1);
	//
	}

	
LOCAL_D void TestDoorOOML()
// Test CDictionaryFileStore construction, forcing a leave error at each
// possible stage of the process.
//
	{
	CApaAppFinder* finder=NULL;
	CApaProcess* process=NULL;
	CApaDocument* doc=NULL;
	CApaDoor* door=NULL;
	TInt failRate=0;
	//
	test.Next(_L("CApaDoor construction under OOM"));
	//
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		door = NULL;
		finder = CApaScanningAppFinder::NewL(TheFs);
		process = CApaProcess::NewL(TheFs,*finder);
		doc = process->AddNewDocumentL(appPath);
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;

		door = NULL;
		TRAPD(ret,door=CApaDoor::NewL(*doc,TSize(400,400)));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			__UHEAP_MARKEND;
			delete process;
			test(door==NULL);
			}
		else
			{
			test(door!=NULL);
			delete door;
			__UHEAP_MARKEND;
			delete process;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs for c'tion: %d\n"),failRate-1);
	//
	test.Next(_L("CApaDoor Store() under OOM"));
	//
	CBufStore* store=NULL;
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		door = NULL;
		finder = CApaScanningAppFinder::NewL(TheFs);
		process = CApaProcess::NewL(TheFs,*finder); // owns finder
		doc = process->AddNewDocumentL(appPath);
		door = CApaDoor::NewL(*doc,TSize(400,400)); // owns doc
		store = CBufStore::NewL(10);
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;

		TStreamId id=KNullStreamId;
		TRAPD(ret,id=door->StoreL(*store));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			test(id==KNullStreamId);
			delete store;
			delete door;
			__UHEAP_MARKEND;
			delete process;
			}
		else
			{
			test(id!=KNullStreamId);
			delete store;
			__UHEAP_MARKEND;
			delete door;
			delete process;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs: %d\n"),failRate-1);
	//
	test.Next(_L("CApaDoor Restore() under OOM"));
	//
	for (failRate=1;;failRate++)
		{
		__UHEAP_RESET;
		door = NULL;
		finder = CApaScanningAppFinder::NewL(TheFs);
		process = CApaProcess::NewL(TheFs,*finder); // owns finder
		doc = process->AddNewDocumentL(appPath);
		door = CApaDoor::NewL(*doc,TSize(400,400)); // owns doc
		store = CBufStore::NewL(10);
		TStreamId id = door->StoreL(*store);
		__UHEAP_SETFAIL(RHeap::EDeterministic,failRate);
		__UHEAP_MARK;

		TRAPD(ret,door->RestoreL(*store,id));
			test(ret==KErrNone || ret==KErrNoMemory);
		if (ret!=KErrNone)
			{
			delete store;
			delete door;
			__UHEAP_MARKEND;
			delete process;
			}
		else
			{
			delete store;
			delete door;
			__UHEAP_MARKEND;
			delete process;
			break;
			}
		}
	__UHEAP_RESET;
	test.Printf(_L("  #allocs: %d\n"),failRate-1);
	//
	}


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);\
		});
	}


GLDEF_C TInt E32Main()
	{
	setupCleanup();
	//
	test.Title();
	test.Start(_L("Testing Apparch..."));
	//
	// set up an fbs
	FbsStartup();
	TInt ret=RFbsSession::Connect();
		test(!ret);
	//
	// set up the directory structure
	TheFs.Connect();
	setup();
	//
	// run the testcode (inside an alloc heaven harness)

 	__UHEAP_MARK;
	// RDebug::Print(_L("About to test OOM resilience"));
	TRAPD(r,TestOOMConstructionL());
		test(r==KErrNone);
	__UHEAP_MARKEND;
	
 	__UHEAP_MARK;
	// RDebug::Print(_L("About to test door OOM resilience"));
	TRAP(r,TestDoorOOML());
		test(r==KErrNone);
	__UHEAP_MARKEND;
	
	test.End();
	test.Close();
	
	delete TheTrapCleanup;
	return KErrNone;
	}

