// T_PRO.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <f32file.h>
#include <fbs.h>
#include <s32std.h> 
#include <s32stor.h> 
#include <s32file.h> 

#include <apaid.h>
#include "..\apparc\apadll.h"
#include <apffndr.h>
#include <apgaplst.h>
#include <apgicnfl.h>
#include <apgdoor.h>
#include <apffndr.h>
#include <apfrec.h>
#include <apfctlf.h>
#include <apgctl.h>
#include <apgaplst.h>
#include <apaflrec.h>
#include <apgcli.h>
#include <apacmdln.h>
#include <apsserv.h>
#include "..\apserv\apsclsv.h" // so I can start the server
#include "tstapp.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 appPathRam=_L("c:\\system\\apps\\tstapp\\tstapp.app");
LOCAL_D TFullName icnPathRam=_L("c:\\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_Pro"));
LOCAL_D CTrapCleanup* TheTrapCleanup;
LOCAL_D CApaProcess* TheProcess;
LOCAL_D RFs TheFs;

////////////////////

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);\
		});
	}

//////////////////////

class CDummyShell : public CBase, public MApaAppStarter
	{
public:
	static TInt ThreadStart(TAny* aArg);
	TThreadId StartAppL(const CApaCommandLine&) { return *(TThreadId*)this; }
private:
	void ConstructL();
public:
	CApaAppList* iAppList;
	CApaFileRecognizer* iFileRecognizer;
	CApaAppListServer* iServer;
	RFs iFs;
	RFbsSession iFbs;
	};


GLDEF_C TInt CDummyShell::ThreadStart(TAny* anArg)
// Start up a new server
	{
	setupCleanup();
	// convert argument into semaphore reference
	RSemaphore& semaphore=*(RSemaphore*)anArg;
	//
	// start scheduler and server
	CActiveScheduler *pA=new CActiveScheduler;
	CActiveScheduler::Install(pA);
	//
	// construct shell
	CDummyShell* shell=new CDummyShell();
	TRAPD(ret,shell->ConstructL());
	//
	// signal that we've started
	semaphore.Signal();
	//
	// start fielding requests from clients
	CActiveScheduler::Start();
	//
	// finished
	return(ret);
	}


void CDummyShell::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	User::LeaveIfError(iFbs.Connect());
	//
	// create app list & recognizer
	CApaAppFinder* appFinder=CApaScanningAppFinder::NewL(iFs);
	iAppList = CApaAppList::NewL(iFs,appFinder);	// takes ownership of appFinder
	iAppList->UpdateL();
	iFileRecognizer = CApaScanningFileRecognizer::NewL(iFs,this);
	iServer = CApaAppListServer::NewL(iAppList,iFileRecognizer);
	}


LOCAL_C TInt StartServerInThread()
// Starts a server in a new thread
// This function is exported from the DLL and called from the client 
    {
	TInt res=KErrNone;
	// create server - if one of this name does not already exist
	TFindServer findServer(KAppListServerName);
	TFullName name;
	if (findServer.Next(name)!=KErrNone) // we don't exist already
		{
		RThread thread;
		RSemaphore semaphore;
		semaphore.CreateLocal(0); // create a semaphore so we know when thread finished

		RThread myThread;
		res=thread.Create(KAppListServerName,CDummyShell::ThreadStart,KDefaultStackSize,myThread.Heap(),&semaphore);

		if (res==KErrNone) // thread created ok - now start it going
			{
			thread.SetPriority(EPriorityNormal);
			thread.Resume(); // start it going
			semaphore.Wait(); // wait until it's initialized
			thread.Close(); // we're no longer interested in the other thread
			}
		else // thread not created ok
			{
			thread.Close(); // therefore we've no further interest in it
			}
		semaphore.Close();
		// notify the kernel that a server has started.
		#if defined (__WINS__)
		UserSvr::ServerStarted();
		#endif
		}
	else 
		return KErrAlreadyExists;
    return res;
    }


////////////////////


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 void DoTest(TInt aReturnValue)
	{
	if (aReturnValue!=KErrNone)
		test.Printf(_L("\nError: %D\n"),aReturnValue);
	test(aReturnValue==KErrNone);
	}


LOCAL_D void loadDllL()
	{
	test.Next(_L("Load the test app straight"));
	RLibrary dll;
	// load the dll
	// RDebug::Print(_L("load the dll"));
	TInt ret=dll.Load(appPath);
		DoTest(ret);
	//
	// get lib name
	TFileName filename=dll.FileName();
		test(filename.CompareF(appPath)==0);
	// get a handle to the 1st ordinal function
	TLibraryFunction constructor=dll.Lookup(1);
	// call the constructor
	CApaApplication* app=(CApaApplication*)((*constructor)()); // move onto return in time...
	delete app;
	//
	dll.Close();
	}

/*
// class no longer exported - cant test :-(
LOCAL_D void testCApaDllL()
	{
	test.Next(_L("Testing CApaDll and CApaScanningAppFinder"));
	//
	// work out a search path
	TParse path;
	path.SetNoWild(dllname,&searchPath,NULL);
	// search the path
	CApaDll* dll=new(ELeave) CApaDll();
	CleanupStack::PushL(dll);
	TFileName fileName;
	//
	// creating an app
	TRAPD(ret,dll->CreateApplicationL(TheFs,appPath));
		DoTest(ret);
	//
	// Test CApaDll::FileName()
		test(dll->FileName().CompareF(appPath)==0);
	//
	CleanupStack::PopAndDestroy(); // dll
	}
*/


LOCAL_C void testAppIdentifierL()
	{
	test.Next(_L("Testing TApaAppIdentifier"));
	// create a process
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	TRAPD(ret,TheProcess = CApaProcess::NewL(TheFs,*finder));
		DoTest(ret);
	// create a temporary store and stream dictionary
	TParse newFilePath;
	newFilePath.Set(tempPath,&_L("temp.idf"),NULL);
	TheFs.MkDirAll(newFilePath.DriveAndPath());
	CDirectFileStore* store = CDirectFileStore::ReplaceLC(TheFs,newFilePath.FullName(),EFileWrite);
	store->SetTypeL(TUidType(KDirectFileStoreLayoutUid,testUid,testUid));
	CStreamDictionary* streamDic=CStreamDictionary::NewL();
	CleanupStack::PushL(streamDic);
	// set up an id
	TApaAppIdentifier origId(testUid,_L("FileName"));
	//
	// write it out and read it in again
	TheProcess->WriteAppIdentifierL(*store,*streamDic,origId);
	TApaAppIdentifier copyId=TheProcess->ReadAppIdentifierL(*store,*streamDic);
		test(origId.iAppUid==copyId.iAppUid);
		test(origId.iFullName==copyId.iFullName);
	//
	// tidy up
	CleanupStack::PopAndDestroy(2); // store,streamDic
	delete TheProcess;
	TheFs.Delete(newFilePath.FullName());
	}


LOCAL_C void testGenerateFileName()
	{
	test.Next(_L("Testing CApaApplication::GenerateFileName()"));
	TFileName rootName;
	//
	// delete the test files just in case...
	TheFs.Delete(_L("c:\\path\\name"));
	TheFs.Delete(_L("c:\\path\\name.ext"));
	//
	// try it with a root that doesn't exist
	rootName = _L("c:\\path\\name");
	TInt ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrNone);
		test(rootName.CompareF(_L("c:\\path\\name"))==0);
	//
	// try it with a root (inc ext) that doesn't exist
	rootName = _L("c:\\path\\name.ext");
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrNone);
		test(rootName.CompareF(_L("c:\\path\\name.ext"))==0);
	//
	// create a couple of files
	RFile file;
	file.Create(TheFs,_L("c:\\path\\name"),EFileWrite);
	file.Close();
	file.Create(TheFs,_L("c:\\path\\name.ext"),EFileWrite);
	// file.Close(); // purposely don't close this one
	//
	// try it with a root that exists
	rootName = _L("c:\\path\\name");
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrNone);
		test(rootName.CompareF(_L("c:\\path\\name(01)"))==0);
	//
	// try it with a root (inc ext) that exists
	rootName = _L("c:\\path\\name.ext");
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrNone);
		test(rootName.CompareF(_L("c:\\path\\name(01).ext"))==0);
	//
	// try with illegal paths
	rootName = _L("c:name");
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrArgument);
	rootName = _L("\\dir\\name");
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrArgument);
	rootName = _L("c:\\dir\\");
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrBadName);
	//
	// try with a path that's too long
/*	rootName = _L("c:\\xxxxxxxxxxx");
	for (TInt i=0 ; i<24 ; i++)
		rootName.Insert(3,_L("123456789\\"));
		test(rootName.Length()==254);
	ret=CApaApplication::GenerateFileName(TheFs,rootName);
		test(ret==KErrOverflow);
*/	//
	// tidy up
	file.Close();
	TheFs.Delete(_L("c:\\path\\name"));
	TheFs.Delete(_L("c:\\path\\name.ext"));
	}


LOCAL_C void testDocCreationL()
	{
	test.Next(_L("Testing CApaProcess"));
	//
	TheFs.MkDirAll(filePath);
	//
	// delete the file to be created by the testcode
	// RDebug::Print(_L("1"));
	TheFs.Delete(filePath);
	// create a process
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	// RDebug::Print(_L("2"));
	TRAPD(ret,TheProcess = CApaProcess::NewL(TheFs,*finder));
		DoTest(ret);
	// RDebug::Print(_L("3"));
	//
	// create a new doc passing the full path of the app dll
	CApaDocument* doc=NULL;
	TRAP(ret,doc=TheProcess->AddNewDocumentL(appPath));
		DoTest(ret);
	// RDebug::Print(_L("4"));
	TheProcess->DestroyDocument(doc);
	// RDebug::Print(_L("5"));
	doc = NULL;
	TRAP(ret,TheProcess->ResetL());
		DoTest(ret);
	// RDebug::Print(_L("6"));
	// create a new doc passing the full path of the app dll and the uid
	TRAP(ret,doc=TheProcess->AddNewDocumentL(appPath,KUidTestApp));
		DoTest(ret);
	// RDebug::Print(_L("7"));
	TheProcess->DestroyDocument(doc);
	// RDebug::Print(_L("8"));
	doc = NULL;
	TRAP(ret,TheProcess->ResetL());
		DoTest(ret);
	// RDebug::Print(_L("9"));
	//
	// create a new main doc of type tstapp
	TRAP(ret,doc=TheProcess->AddNewDocumentL(dllname));
		DoTest(ret);
	// RDebug::Print(_L("10"));
	TheProcess->SetMainDocument(doc);
	CFileStore* store=NULL;
	// create the store and initialise it
	TRAP(ret, {
		store=doc->CreateFileStoreLC(TheProcess->FsSession(),filePath);
		CleanupStack::Pop(); // store 
		});
		DoTest(ret);
	// RDebug::Print(_L("11"));
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
	TheProcess->SetMainDocFileName(filePath);
	// RDebug::Print(_L("12"));
	// initialise the document with factory settings
	TRAP(ret, doc->NewDocumentL() );
		DoTest(ret);
	// RDebug::Print(_L("13"));
	//
	// close it 
	TRAP(ret,doc->SaveL());
		DoTest(ret);
	// RDebug::Print(_L("14"));
	TRAP(ret, TheProcess->ResetL() );
		DoTest(ret);
	store = NULL;
	doc = NULL;
	// RDebug::Print(_L("15"));
	//
	// try re-opening it
	CStreamDictionary* streamDic;
	TRAP(ret,doc=TheProcess->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite));
		DoTest(ret);
	// RDebug::Print(_L("16"));
	delete streamDic;
	streamDic = NULL;
	// RDebug::Print(_L("17"));
	TheProcess->SetMainDocument(doc);
	TheProcess->SetMainDocFileName(filePath);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store; // kludge!
	// RDebug::Print(_L("18"));
	//
	// get the caption
	CApaAppInfoFileReader* reader=NULL;
	TRAP(ret, reader=TheProcess->MainDocument()->Application()->OpenAppInfoFileL());
		DoTest(ret); 
	// RDebug::Print(_L("19"));
	CleanupStack::PushL(reader);
	TApaAppCaption caption;
	TRAP(ret,caption=reader->CaptionL(ELangEnglish));
		DoTest(ret); 
	//test.Printf(caption);
	//test.Printf(_L("\n"));
	// get a bitmap
	CApaMaskedBitmap* bitmap=NULL;
	TRAP(ret,bitmap=reader->CreateMaskedBitmapL(32));
		DoTest(ret);
//		test(bitmap->SizeInPixels().iWidth==32);
	// RDebug::Print(_L("20"));
	delete bitmap;
	CleanupStack::PopAndDestroy(); // reader
	// remove the main document
	TheProcess->DestroyDocument(TheProcess->MainDocument());
		test(TheProcess->MainDocument()==NULL);
	//
	// try re-opening the doc without the app in memory
	TheProcess->ResetL();
	delete TheProcess;
	finder=CApaScanningAppFinder::NewL(TheFs);
	TRAP(ret,TheProcess = CApaProcess::NewL(TheFs,*finder));
		DoTest(ret);
	TRAP(ret,doc=TheProcess->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite));
		DoTest(ret);
	TheProcess->DestroyDocument(doc);
	delete store;
	delete streamDic;
	//
	// tidy up
	TheProcess->ResetL();
	// RDebug::Print(_L("21"));
	delete TheProcess;
	//
	// delete the file created by the testcode
	TheFs.Delete(filePath);
	}


LOCAL_C void testEmbeddingL()
	{
	test.Next(_L("Test Embedding"));
	//
	// delete the file to be created by the testcode
	TheFs.Delete(filePath);
	// create a process
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	TRAPD(ret,TheProcess = CApaProcess::NewL(TheFs,*finder));
		DoTest(ret);
	//
	// create a new main doc of type tstapp
	CApaDocument* doc=NULL;
	TRAP(ret,doc=TheProcess->AddNewDocumentL(dllname));
		DoTest(ret);
	TheProcess->SetMainDocument(doc);
	CFileStore* store=NULL;
	// create the store and initialise it
	TRAP(ret, {
		store=doc->CreateFileStoreLC(TheProcess->FsSession(),filePath);
		CleanupStack::Pop(); // store 
		});
		DoTest(ret);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
	TheProcess->SetMainDocFileName(filePath);
	// initialise the document with factory settings
	TRAP(ret, doc->NewDocumentL() );
		DoTest(ret);
	//
	// edit it
	TRAP(ret,TheProcess->MainDocument()->EditL(NULL));
		DoTest(ret);
	// embed another tstapp doc inside it
	test.Next(_L("...Embed a doc"));
	TRAP(ret,((CTestAppDoc*)TheProcess->MainDocument())->EmbedNewDocL(dllname));
		DoTest(ret);
		test(((CTestAppDoc*)TheProcess->MainDocument())->iEmbedList->Count()==1);
	// edit that doc
	TRAP(ret,((CTestAppDoc*)TheProcess->MainDocument())->EditEmbeddedDocL(0));
		DoTest(ret);
	//
	// close the main doc and reload it
	TRAP(ret,TheProcess->MainDocument()->SaveL());
		DoTest(ret);
	TheProcess->ResetL();
	CStreamDictionary* streamDic=NULL;
	TRAP(ret,doc=TheProcess->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite));
		DoTest(ret);
	delete streamDic;
	streamDic = NULL;
	TheProcess->SetMainDocument(doc);
	TheProcess->SetMainDocFileName(filePath);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
		test(((CTestAppDoc*)TheProcess->MainDocument())->iEmbedList->Count()==1);
	//
	// close the main doc and reload it again...
	TRAP(ret,TheProcess->MainDocument()->SaveL());
		DoTest(ret);
	TheProcess->ResetL();
	TRAP(ret,doc=TheProcess->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite));
		DoTest(ret);
	delete streamDic;
	streamDic = NULL;
	TheProcess->SetMainDocument(doc);
	TheProcess->SetMainDocFileName(filePath);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
		test(((CTestAppDoc*)TheProcess->MainDocument())->iEmbedList->Count()==1);
	//
	// detach the main doc from it's store & access the embedded doc
	TRAP(ret, TheProcess->MainDocument()->DetachFromStoreL(CPicture::EDetachFull) );
		DoTest(ret);
	TRAP(ret, ((CTestAppDoc*)TheProcess->MainDocument())->EmbeddedDoor(0)->DocumentL() );
		DoTest(ret);
	//
	// save it, then save it again immediately
	TRAP(ret,TheProcess->MainDocument()->SaveL());
		DoTest(ret);
	TRAP(ret,TheProcess->MainDocument()->SaveL());
		DoTest(ret);
	//
	// load the doc and get a handle to the embedded doc
	TheProcess->ResetL();
	TRAP(ret,doc=TheProcess->OpenNewDocumentL(store,streamDic,filePath,EFileShareExclusive|EFileWrite));
		DoTest(ret);
	delete streamDic;
	streamDic = NULL;
	TheProcess->SetMainDocument(doc);
	TheProcess->SetMainDocFileName(filePath);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
		test(((CTestAppDoc*)TheProcess->MainDocument())->iEmbedList->Count()==1);
	TRAP(ret, ((CTestAppDoc*)TheProcess->MainDocument())->EmbeddedDoor(0)->DocumentL() );
		DoTest(ret);
	//
	// try to set the embedded doc's format to glass
	TRAP(ret, ((CTestAppDoc*)TheProcess->MainDocument())->EmbeddedDoor(0)->SetFormatToGlassL() );
		test(ret==KErrNotSupported);
	//
	// tidy up and delete the file created by the testcode
	delete TheProcess;
	TheFs.Delete(filePath);
	}


LOCAL_C void testIniFilesL()
	{
	test.Next(_L("Test Ini files"));
	//
	// delete the files to be created by the testcode
	TheFs.Delete(filePath);
	TheFs.Delete(iniPath);
	// create a process
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	TRAPD(ret,TheProcess = CApaProcess::NewL(TheFs,*finder));
		DoTest(ret);
	//
	// create a new main doc of type tstapp
	CApaDocument* doc=NULL;
	TRAP(ret,doc=TheProcess->AddNewDocumentL(dllname));
		DoTest(ret);
	TheProcess->SetMainDocument(doc);
	CFileStore* store=NULL;
	// create the store and initialise it
	TRAP(ret, {
		store=doc->CreateFileStoreLC(TheProcess->FsSession(),filePath);
		CleanupStack::Pop(); // store 
		});
		DoTest(ret);
	((CTestAppDoc*)TheProcess->MainDocument())->iStore = store;
	TheProcess->SetMainDocFileName(filePath);
	// initialise the document with factory settings
	TRAP(ret, doc->NewDocumentL() );
		DoTest(ret);
	//
	// create a new ini file for the app
	CDictionaryStore* iniFile=NULL;
	TRAP(ret, {
		iniFile=TheProcess->MainDocument()->Application()->OpenIniFileLC(TheFs);
		CleanupStack::Pop();
		});
		DoTest(ret);
	// add some data to it
	RDictionaryWriteStream writeStream;
	TRAP(ret, writeStream.AssignL(*iniFile,testUid) );
		DoTest(ret);
	TInt data=17;
	TRAP(ret, writeStream.WriteInt8L(data) );
		DoTest(ret);
	TRAP(ret, writeStream.CommitL() );
		DoTest(ret);
	writeStream.Close();
	// close it
	TRAP(ret, iniFile->CommitL() );
		DoTest(ret);
	delete iniFile;
	iniFile = NULL;
	// re-open it
	TRAP(ret, {
		iniFile=TheProcess->MainDocument()->Application()->OpenIniFileLC(TheFs);
		CleanupStack::Pop();
		});
		DoTest(ret);
	// check the contents
	RDictionaryReadStream readStream;
	TRAP(ret, readStream.OpenL(*iniFile,testUid) );
		DoTest(ret);
	TInt check=0;
	TRAP(ret, check=readStream.ReadInt8L() );
		DoTest(ret);
		test(check==data);
	readStream.Close();
	// close it
	delete iniFile;
	//
	// tidy up
	delete TheProcess;
	TheFs.Delete(filePath);
	TheFs.Delete(iniPath);
	}


LOCAL_C void testAppListL()
	{
	test.Next(_L("Testing CApaAppList"));
	//
	// delete the second app just in case
	TheFs.Delete(appPathRam);
	TheFs.Delete(icnPathRam);
	//
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	CApaAppList* list = CApaAppList::NewL(TheFs,finder); // takes ownership of finder
	//
	// check that a newly created (empty) list functions OK
	test( list->Count()==0);
	test( list->FirstApp()==NULL);
	test( list->AppDataByUid(KUidTestApp)==NULL);
	test( list->UpdateCounter()==0);
	list->Purge(); // this should do nothing
	//
	// update the list to find all available apps
	TRAPD(ret, list->UpdateL() );
		DoTest(ret);
	//
	// test the updated list
	test( list->UpdateCounter()==1);
	test( list->Count()>0);
	test( list->AppDataByUid(KUidTestApp)!=NULL);
	//
	CApaAppData* app=list->FirstApp();
		test( app!=NULL);
	TInt count=0;
	while (app)
		{
		app = list->NextApp(app);
		count++;
		}
	test(count==list->Count());
	//
	// update the list again - there should be no change
	TRAP(ret, list->UpdateL() );
		DoTest(ret);
		test(list->UpdateCounter()==1);
		test(list->Count()==count);
	// 
	// copy app to c: - should override the one in the list
	CFileMan* fileMan=CFileMan::NewL(TheFs);
	ret=fileMan->Copy(appPath,appPathRam);
		DoTest(ret);
	ret=fileMan->Copy(icnPath,icnPathRam);
		DoTest(ret);
	TRAP(ret, list->UpdateL() );
		DoTest(ret);
		test(list->UpdateCounter()==2);
		test(list->Count()==count);
	list->Purge(); 
		test(list->UpdateCounter()==2);
		test(list->Count()==count);
	CApaAppData* data=list->AppDataByUid(KUidTestApp);
		test(data!=NULL);
		test(data->IsPresent());
	TApaAppEntry entry = data->AppEntry();
	TParsePtrC ptr(entry.iFullName);
		test(ptr.Drive().CompareF(_L("c:"))==0);
	//
	// tweak an aif and update - change should be picked up
	TTime time;
	ret = TheFs.Modified(icnPathRam,time);
		DoTest(ret);
	time += TTimeIntervalDays(1);
	ret = TheFs.SetModified(icnPathRam,time);
		DoTest(ret);
	TRAP(ret, list->UpdateL() );
		DoTest(ret);
		test(list->UpdateCounter()==3);
		test(list->Count()==count);
	//
	// try a purge for good measure
	list->Purge(); // this should do nothing
		test(list->UpdateCounter()==3);
		test(list->Count()==count);
	//
	// delete the second app just in case
	TheFs.SetAtt(appPathRam,0,KEntryAttReadOnly);
	ret=TheFs.Delete(appPathRam);
		DoTest(ret);
	TheFs.SetAtt(icnPathRam,0,KEntryAttReadOnly);
	ret=TheFs.Delete(icnPathRam);
		DoTest(ret);
	//
	// clean up
	delete list;
	delete fileMan;
	}


LOCAL_C void testAppDataL()
	{
	test.Next(_L("Testing CApaAppData"));
	//
	CApaScanningAppFinder* finder=CApaScanningAppFinder::NewL(TheFs);
	CApaAppList* list = CApaAppList::NewL(TheFs,finder); // takes ownership of finder
	//
	TRAPD(ret, list->UpdateL() );
		DoTest(ret);
		test(list->Count()>0);
	//
	// get the data for testapp
	CApaAppData* data=list->AppDataByUid(KUidTestApp);
		test(data!=NULL);
		test(data->IsPresent());
	//
	// check the app entry
	TApaAppEntry entry = data->AppEntry();
		test(entry.iUidType[1]==KUidApp);
		test(entry.iUidType[2]==KUidTestApp);
		test(entry.iFullName.CompareF(appPath)==0);
	//
	// check the caption and icon
		test(data->Caption().Length()>0);
		test(data->Icon(0)!=NULL);
	// check the data type information
		// !! TODO
	//
	// clean up
	delete list;
	}

const TUid KUidMinimalControl={98};
LOCAL_D TFileName ctlName=_L("m_ctrl.ctl");
LOCAL_D TFileName ctlCaption=_L("m_ctrl");
LOCAL_D TFileName ctlPath=_L("z:\\system\\controls\\m_ctrl.ctl");
LOCAL_D TFileName newCtlPath=_L("c:\\system\\controls\\m_ctrl.ctl");
LOCAL_D TFileName ctlDir=_L("c:\\system\\controls\\");
LOCAL_D TFileName defaultAifPath=_L("z:\\system\\data\\default.aif");
#if defined(__EPOC32__)
LOCAL_D TFileName sourcePath=_L("z:\\system\\data\\m_ctrl.ctl");
#else
LOCAL_D TFileName sourcePath=_L("z:\\system\\controls\\m_ctrl.ctl");
#endif

LOCAL_C void testControlsL()
	{
	test.Next(_L("Testing CApaSystemControlList"));
	//
	// delete the second ctl just in case
	TheFs.Delete(newCtlPath);
	//
	// create a scanner
	// RDebug::Print(_L("1"));
	CApaScanningControlFinder* finder=CApaScanningControlFinder::NewL(TheFs);
	CFileMan* fileMan=CFileMan::NewL(TheFs);
	// RDebug::Print(_L("2"));
	//
	// create a list (automatically does an update)
	CApaSystemControlList* list=NULL;
	TRAPD(ret, list=CApaSystemControlList::NewL(TheFs,*finder,defaultAifPath));
		DoTest(ret);
		test(list->Count()==1);
		test(list->UpdateCount()==1);
	// RDebug::Print(_L("3"));
	//
	// do an update - there should be no changes
	TRAP(ret, list->UpdateL());
		DoTest(ret);
		test(list->Count()==1);
		test(list->UpdateCount()==1);
		test(list->Control(0)->FileName().CompareF(ctlPath)==0);
	// RDebug::Print(_L("4"));
	//
	// copy control to c: - this should override the one in the ROM
	TheFs.MkDirAll(ctlDir);
	// RDebug::Print(_L("5"));
	ret=fileMan->Copy(sourcePath,newCtlPath);
		DoTest(ret);
	// RDebug::Print(_L("6"));
	TRAP(ret, list->UpdateL());
		DoTest(ret);
		test(list->Count()==1);
		test(list->UpdateCount()==2);
	// RDebug::Print(_L("7"));
	TFileName name=list->Control(0)->FileName();
	//	test(name.CompareF(newCtlPath)==0); // - cant test this until E32 is fixed to remove \epoc32 etc
	//
/*	// hide the control and do an update - there should be changes
	ret=TheFs.Delete(newCtlPath); // fails access denied
		DoTest(ret);
	TRAP(ret, list->UpdateL());
		DoTest(ret);
		test(list->Count()==1);
		test(list->UpdateCount()==3);
		test(list->Control(0)->FileName().CompareF(ctlPath)==0);
*/	//
	test.Next(_L("Testing CApaSystemControl"));
	//
	// get the control from the list and check it's type and caption
	CApaSystemControl* control=list->Control(0);
		test(control!=NULL);
		test(control->Type()==KUidMinimalControl);
	TFileName caption=control->Caption();
		test(caption.CompareF(ctlCaption)==0);
		test(control->Icon()!=NULL);
	// RDebug::Print(_L("8"));
	//
	// run the control
	TRAP(ret, control->CreateL()); // this control is synchronous
	// RDebug::Print(_L("9"));
	//
	// tidy up
	delete list;
	delete finder;
	delete fileMan;
	}


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();
	//
	// set up the server
	ret=StartServerInThread();
		test(ret==KErrNone);
	//
	// run the testcode (inside an alloc heaven harness)

	__UHEAP_MARK;
	// RDebug::Print(_L("About to load dll"));
	TRAPD(r,loadDllL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	__UHEAP_MARK;
	// RDebug::Print(_L("About to test TApaAppIdentifier"));
	TRAP(r,testAppIdentifierL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	__UHEAP_MARK;
	// RDebug::Print(_L("About to test CApaApplication::GenerateFileName()"));
	TRAP(r,testGenerateFileName());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	__UHEAP_MARK;
	// RDebug::Print(_L("About to test doc creation"));
	TRAP(r,testDocCreationL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	__UHEAP_MARK;
	// RDebug::Print(_L("About to test embedding"));
	TRAP(r,testEmbeddingL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

/*	__UHEAP_MARK;
	// RDebug::Print(_L("About to test embedding with a missing icn file"));
	TRAP(r,testEmbeddingWithNoIcnL());
		test(r==KErrNone);
	__UHEAP_MARKEND;*/

	__UHEAP_MARK;
	// RDebug::Print(_L("About to test ini files"));
	TRAP(r,testIniFilesL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	__UHEAP_MARK;
	// RDebug::Print(_L("About to test App lists"));
	TRAP(r,testAppListL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

 	__UHEAP_MARK;
	// RDebug::Print(_L("About to test cached App data"));
	TRAP(r,testAppDataL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

 	__UHEAP_MARK;
	// RDebug::Print(_L("About to test cached system controls"));
	TRAP(r,testControlsL());
		test(r==KErrNone);
	__UHEAP_MARKEND;

	test.End();
	test.Close();
	
	delete TheTrapCleanup;
	return KErrNone;
	}

