lowlevellibsandfws/pluginfw/Framework/DiscovererTest/t_discoverer.cpp
author Stefan Karlsson <stefan.karlsson@nokia.com>
Mon, 29 Mar 2010 12:27:51 +0100
branchCompilerCompatibility
changeset 14 69a2780c0013
parent 0 e4d67989cc36
permissions -rw-r--r--
Merge.

// Copyright (c) 2004-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:
// This file contains test classes and their implementations
// to test production class CDiscoverer. Where necessary stubs
// are implemented to help in writing test harness using RTest.
// 
//

#include "Discoverer.h"
#include "EComErrorCodes.h"
#include "ImplementationInformation.h"
#include "DiscovererObserver.h"
#include "../EcomTestUtils/EcomTestUtils.h"
#include "EComUidCodes.h"
#include "RegistryData.h"
#include "DriveInfo.h"

#include <ecom/ecompanics.h>
#include <e32test.h>
#include <bautils.h>
#include <s32file.h>
#include <barsread2.h>
#include <e32uid.h>
#include <startup.hrh>
#include "baspi.h"
#include <sacls.h>


//New RSC based plugins
_LIT(KNewResourceFileName,		 		"C:\\resource\\plugins\\EComExample5.rsc");
_LIT(KNewExampleDllFileName,	 		"C:\\sys\\bin\\EComExample5.dll");
_LIT(KNewResourceFileNameOnZ,   		"z:\\RAMOnly\\EComExample5.rsc");
_LIT(KNewExampleDllFileNameOnZ, 		"z:\\RAMOnly\\EComExample5.dll");
_LIT(KNewExampleDllFileNameOnly,		"EComExample5.dll");
_LIT(KNewResourceSearchPath,			"\\resource\\plugins\\*");
//PlugIn3 RSC based plugins
_LIT(KPlugIn3ResourceFileName,		 		"C:\\resource\\plugins\\EComExample12.rsc");
_LIT(KPlugIn3ExampleDllFileName,	 		"C:\\sys\\bin\\EComExample12.dll");
_LIT(KPlugIn3ResourceFileNameOnZ,   		"z:\\RAMOnly\\EComExample12.rsc");
_LIT(KPlugIn3ExampleDllFileNameOnZ, 		"z:\\RAMOnly\\EComExample12.dll");
_LIT(KPlugIn3ExampleDllFileNameOnly,		"EComExample12.dll");

//Old DLL based plugins

// spi test file
_LIT(KEComSpiTestFilePathAndName, "Z:\\Test\\Data\\EcomTest.spi");
_LIT(KEComSpiTestFilePlugIn3PathAndName, "Z:\\Test\\Data\\EcomTestType3.spi");
// file name detremined from example spi file
_LIT(KEComSpiTestFileDllPathAndName, "Z:\\sys\\bin\\EComExample5.dll");
_LIT(KEComSpiTestFilePlugIn3DllPathAndName, "Z:\\sys\\bin\\EComExample12.dll");

// spi file
_LIT(KEComSPIFilePathAndName, "Z:\\private\\10009D8F\\Ecom.spi");

const TInt KOneSecond = 1000000;

LOCAL_D RFs	TheFs;

LOCAL_D RTest test(_L("t_discoverer.exe"));

LOCAL_D CTrapCleanup* 	  TheTrapCleanup 	 = NULL;

LOCAL_D CActiveScheduler* TheActiveScheduler = NULL;

// Used for supressing warning in OOM tests
#define __UNUSED_VAR(var) var = var

// Used for OOM test
#define TEST_OOM_ERR if(err == KErrNoMemory) User::Leave(err)

/**
Stub classes are provided to act as replacement members for the class
under test. This ensures the test class is constructed correctly and its
behaviour is also correct within the context of the test. It allows the
class to be tested in isolation. Other tests are available that test the
interoperability of the class
*/
class CObserverStub : public CBase, public MDiscovererObserver
{
public:
	enum OSState
		{
		OSS_Undefined,
		OSS_NoPlugins,
		OSS_CriticalPlugins,
		OSS_DiscoverNonCriticalPlugins,
		OSS_AllPlugins
		};
	static CObserverStub* NewL();
	virtual ~CObserverStub();

	// Inherited from MDiscovererObserver
	virtual void DiscoveriesBegin();
	virtual void RegisterDiscoveryL(const TDriveName& aDrive,CPluginBase*& aDirEntry,TBool aDatFileExists);
	virtual void DiscoveriesComplete(TBool aSuccessful, TPluginProcessingTypeIdentifier aProcessingType);
	virtual void DriveRemovedL(TDriveUnit aDrive);
	virtual void DriveReinstatedL(TDriveUnit aDrive);
	virtual void DriveIsSpiBasedL(const TDriveUnit& /*aDrive*/){}
	virtual TBool NotifiedWithErrorCode(TInt aError);
	virtual TBool IsAnyDllRegisteredWithDriveL(const TDriveUnit aDrive) const;
	virtual void SetDiscoveryFlagL(const TDriveUnit &aDrive);
	virtual void LanguageChangedL(TBool& aLanguageChanged);


	// Result verifing methods
	TBool IsDriveMounted(const TDriveUnit aDrive);
	TBool IsEntryProcessed(CPluginBase*& aDirEntry);
	//TBool IsSpiEntryProcessed(const TEntry& aEntry);
	TBool IsDiscoveriesCompleteSuccessfully();
	void SetDiscoverer(CDiscoverer* aDiscoverer);
	OSState GetState();

private:
	CObserverStub();

private:
	/** Base class ecom entry */
	CPluginBase* iEntryBase;

	/** Information of the dll which contains interface implementations */
	//TEComEntryDetails		iEntry;

	/** Information of the spi file which contains interface implementations */
	//TEComSpiResourceEntryDetails		iSpiEntry;

	/** iDriveUnit is drive mounted */
	TDriveUnit	iDriveUnit;

	/** Flag to indicate whether iDriveUnit is mounted or not */
	TBool		iDriveMounted;

	/** Flag to indicate whether iEntry is processed or not */
	TBool		iEntryProcessed;

	/** Flag to indicate whether iSpiEntry is processed or not */
	TBool		iSpiEntryProcessed;

	/** Flag to indicate whether Discovery process is Complete or not */
	TBool		iDiscoveriesComplete;

	/** The current start-up state of this object */
	OSState     iState;

	/** A reference to the CDiscoverer object that this class is observing*/
	CDiscoverer* iDiscoverer;
};  // End of CObserverStub declaration


/**
The TDiscoverer_StateAccessor class allows to access the private and protected
members of production code class CDiscoverer, as its a friend class.
*/
class TDiscoverer_StateAccessor
	{
public:

	// Auxiliary functions that provide access to
	// CDiscoverer private/protected members
	void ScanDirectoryL(CDiscoverer& aDiscoverer, TDriveUnit aDriveUnit);
	void ScanDirectoryCancel(CDiscoverer& aDiscoverer);
	void CompleteNotificationProcessing(CDiscoverer& aDiscoverer);
	void ValidateEntryL(CDiscoverer& aDiscoverer,
						const TEntry& aEntry,
						const TDriveName& aDriveName,
						CPluginBase*& aEntryToFill,
						TBool aIsRO);
	void ValidateEntryL(CDiscoverer& aDiscoverer,
						RResourceArchive& aRscArchive,
						CPluginBase*& aEntryToFill);
	void ProcessEntryL(CDiscoverer& aDiscoverer,const TDriveName& aDrive, CPluginBase*& aEntry, TBool aDatFileExists);
	void DriveMountedL(CDiscoverer& aDiscoverer, const TDriveUnit aDrive);
	void DriveUnmountedL(CDiscoverer& aDiscoverer, const TDriveUnit aDrive);
	void SwiChangeNotificationL(CDiscoverer& aDiscoverer, TInt aSwiOperation);
	void IdleScanningTimerRunErrorL(CDiscoverer& aDiscoverer, TInt aError);
	void DirChangeNotifierRunErrorL(CDiscoverer& aDiscoverer, TInt aError);
	void SwiChangeNotifierRunError(CDiscoverer& aDiscoverer, TInt aError);

	// Verification functions to check the state of CDiscoverer object against tests
	TBool IsDriveMounted(CDiscoverer& aDiscoverer, const TDriveUnit aDrive);
	TBool IsDiscovererActive(CDiscoverer& aDiscoverer);
	TBool IsDirectoryScanCancelled(CDiscoverer& aDiscoverer);
	TBool IsScanDirectoryComplete(CDiscoverer& aDiscoverer);
	TBool IsScanDirectoryPending(CDiscoverer& aDiscoverer, TDriveUnit aDrive);
	TUint PendingDriveListCount(CDiscoverer& aDiscoverer);
	CDiscoverer::TDiscovererState State(CDiscoverer& aDiscoverer);
	CObserverStub::OSState GetDiscovererObserverState(CDiscoverer& aDiscoverer);
	void ScanDriveL(CDiscoverer& aDiscoverer, TDriveUnit aDrive,  TBool aIsRO);
	void LanguageChangedL(CDiscoverer& aDiscoverer);
	};

/**
Scans plugin directories

@param		aDiscoverer The CDiscoverer class object under test
@return		void
*/
void TDiscoverer_StateAccessor::ScanDirectoryL(CDiscoverer& aDiscoverer, TDriveUnit aDriveUnit)
	{
	aDiscoverer.RediscoveryScanDirectoryL(aDriveUnit);
	}

/**
Stops scanning of the plugin directories

@param		aDiscoverer The CDiscoverer class object under test
*/
void TDiscoverer_StateAccessor::ScanDirectoryCancel(CDiscoverer& aDiscoverer)
	{
	aDiscoverer.ScanDirectoryCancel();
	}

/**
Signals that the directory change has been fully processed.

@param		aDiscoverer The CDiscoverer class object under test
*/
void TDiscoverer_StateAccessor::CompleteNotificationProcessing(CDiscoverer& aDiscoverer)
	{
	aDiscoverer.CompleteNotificationProcessing();
	}

/**
Verifies that the discovered entry is valid.
Used to test the Interface Implementation Collection entry

@param		aDiscoverer The CDiscoverer class object under test
@param		aEntry The plugin name
@param		aDriveName The drive containing the entry
@param		aEntryToFill On return points to complete
			plugin file name(with path) i.e. aPath + aEntry
*/
void TDiscoverer_StateAccessor::ValidateEntryL(CDiscoverer& aDiscoverer,
											   const TEntry& aEntry,
											   const TDriveName& aDriveName,
											   CPluginBase*& aEntryToFill,
											   TBool aIsRO)
	{
	aDiscoverer.ValidateEntryL(aEntry, aDriveName, aEntryToFill, aIsRO);
	}

/**
Verifies that the discovered entry is valid.
Used to test the Interface Implementation Collection entry

@param		aDiscoverer The CDiscoverer class object under test
@param		aRscArchive reference to the resource archive
@param		aEntryToFill On return points to complete
			plugin file name(with path) i.e. aPath + aEntry
*/
void TDiscoverer_StateAccessor::ValidateEntryL(CDiscoverer& aDiscoverer,
											RResourceArchive& aRscArchive,
											CPluginBase*& aEntryToFill)
	{
	aDiscoverer.ValidateEntryL(aRscArchive,aEntryToFill);
	}
/**
Registers an Interface Implementation Collection

@param		aDiscoverer The CDiscoverer class object under test
@param		aEntry This is the plugin name that needs to be registered
*/
void TDiscoverer_StateAccessor::ProcessEntryL(CDiscoverer& aDiscoverer,const TDriveName& aDrive,
										  CPluginBase*& aEntry, TBool aDatFileExists)
	{
	aDiscoverer.ProcessEntryL(aDrive,aEntry,aDatFileExists);
	}

/**
Notifies the discoverer of an SWI operation change

@param		aDiscoverer The CDiscoverer class object under test
@param		aSwiOperation This new SWI state
*/
void TDiscoverer_StateAccessor::SwiChangeNotificationL(CDiscoverer& aDiscoverer, TInt aSwiOperation)
	{
	aDiscoverer.SwiChangeNotificationL(aSwiOperation);
	}

/**
Signals that a drive is available

@param		aDiscoverer The CDiscoverer class object under test
@param		aDrive Drive that needs to be mounted
*/
void TDiscoverer_StateAccessor::DriveMountedL(CDiscoverer& aDiscoverer,
											  const TDriveUnit aDrive)
	{
	aDiscoverer.DriveMountedL(aDrive);
	}

/**
Signals that a drive is unavailable

@param		aDiscoverer The CDiscoverer class object under test
@param		aDrive Drive that needs to be unmounted/removed
*/
void TDiscoverer_StateAccessor::DriveUnmountedL(CDiscoverer& aDiscoverer,
												const TDriveUnit aDrive)
	{
	aDiscoverer.DriveUnmountedL(aDrive);
	}

/**
Checks whether CDiscoverer object has successfully completed with
the scanning of the plugin directories on all drives

@param		aDiscoverer The CDiscoverer class object under test
@return		true if notification has been processed on all drives.
			false if there is notification processing pending on any drive
*/
TBool TDiscoverer_StateAccessor::IsScanDirectoryComplete(CDiscoverer& aDiscoverer)
	{
	// check state of discoverer to see if all pending drives have been scanned.
	return(aDiscoverer.State() == CDiscoverer::EDisc_AllPluginsDisc);
	}

/**
Checks whether a notification has been signaled but not processed on specified drive.

Error Condition	: Leaves with KErrNotFound if the drive is not registered.
@param		aDiscoverer The CDiscoverer class object under test
@param		aDrive The drive to check
@return		true if notification has been processed on the specified drive.
			false if notification processing is pending
*/
TBool TDiscoverer_StateAccessor::IsScanDirectoryPending(CDiscoverer& aDiscoverer, TDriveUnit aDrive)
	{
	if(aDiscoverer.iScanningTimer->iPendingDriveList.Find(aDrive)!=KErrNotFound)
		{
		return ETrue;
		}
	else
		{
		return EFalse;
		}
	}

/**
Checks the current count of drives in the list waiting for processing.

@param		aDiscoverer The CDiscoverer class object under test
@return		TUint
*/
TUint TDiscoverer_StateAccessor::PendingDriveListCount(CDiscoverer& aDiscoverer)
	{
	return(aDiscoverer.iScanningTimer->iPendingDriveList.Count());
	}

/**
Checks that CDiscoverer object is not scanning the plugin directories.

@param		aDiscoverer The CDiscoverer class object under test
@return		true if plugin dirctory scanning is stopped.
*/
TBool TDiscoverer_StateAccessor::IsDirectoryScanCancelled(CDiscoverer& aDiscoverer)
	{
	if(!aDiscoverer.iDirScanner)
		{
		return ETrue;
		}
	return EFalse;
	}

/**
Checks that CDiscoverer object is currently activated for the plugin dir scanning

@param		aDiscoverer The CDiscoverer class object under test
@return		true if Discoverer object is tracking changes in the plugin directories in each drive.
*/
TBool TDiscoverer_StateAccessor::IsDiscovererActive(CDiscoverer& aDiscoverer)
	{
	//Return ETrue if both iScanningTimer & directory notifier(s) are active
	TBool isActive = ETrue;

	  for(TInt index = 0; index <aDiscoverer.iRscDirNotifierList.Count(); index++)
	  	{
	  	if(!(aDiscoverer.iRscDirNotifierList[index]&& aDiscoverer.iRscDirNotifierList[index]->IsActive()))
			{
			// iRscDirNotifierList should be active, as each active object on list is constantly
			// looking for changes in the plugin directories in each drive.
			isActive = EFalse;
			break;
			}
		}
	return isActive;
	}

/**
Verifies whether given drive is registered

@param		aDiscoverer The CDiscoverer class object under test
@param		aDrive Drive that needs to be verified for registration
@return		return true if given drive is installed
*/
TBool TDiscoverer_StateAccessor::IsDriveMounted(CDiscoverer& aDiscoverer,
												const TDriveUnit aDrive)
	{
	TBool isMounted = ETrue;
	if(aDiscoverer.iDrivesDiscovered.Find(aDrive) == KErrNotFound)
		{
		isMounted = EFalse;
		}
	return isMounted;
	}

/**
Scans plugin directories

@param		aDiscoverer The CDiscoverer class object under test
@param 		aDrive	The drive which is scanned
@param		aIsRO	Whether the drive is ready-only
@return		true if plugin directorie in each drive get scaned successfully
*/
void TDiscoverer_StateAccessor::ScanDriveL(CDiscoverer& aDiscoverer, TDriveUnit aDrive,  TBool aIsRO)
	{
	return aDiscoverer.iDirScanner->ScanDriveL(aDrive, aIsRO);
	}
void TDiscoverer_StateAccessor::LanguageChangedL(CDiscoverer& aDiscoverer)
	{
	aDiscoverer.LanguageChangeNotificationL();
	}
/**
Retrieve the object's current state.

@param		aDiscoverer The CDiscoverer class object under test
@return 	TDiscovererState the current state of the CDiscoverer
class object under test
*/
CDiscoverer::TDiscovererState TDiscoverer_StateAccessor::State(CDiscoverer& aDiscoverer)
	{
	return aDiscoverer.State();
	}

CObserverStub::OSState TDiscoverer_StateAccessor::GetDiscovererObserverState(CDiscoverer& aDiscoverer)
	{
	CObserverStub* discovererObserver =
		static_cast<CObserverStub*>(&aDiscoverer.iDiscovererObserver);
	return discovererObserver->GetState();
	}

/**
Call the CIdleScanningTimer RunError funtion

@param		aDiscoverer The CDiscoverer class object under test
@param 		aError The error code to pass to the RunError function
*/
void TDiscoverer_StateAccessor::IdleScanningTimerRunErrorL(CDiscoverer& aDiscoverer, TInt aError)
	{
	aDiscoverer.iScanningTimer->RunError(aError);
	}

/**
Call the CDirChangeNotifier RunError funtion

@param		aDiscoverer The CDiscoverer class object under test
@param 		aError The error code to pass to the RunError function
*/
void TDiscoverer_StateAccessor::DirChangeNotifierRunErrorL(CDiscoverer& aDiscoverer, TInt aError)
	{
	aDiscoverer.iRscDirNotifierList[0]->RunError(aError);
	}

/**
Call the CSwiChangeNotifier RunError funtion

@param		aDiscoverer The CDiscoverer class object under test
@param 		aError The error code to pass to the RunError function
*/
void TDiscoverer_StateAccessor::SwiChangeNotifierRunError(CDiscoverer& aDiscoverer, TInt aError)
	{
	aDiscoverer.iSwiChangeNotifier->RunError(aError);
	}

/**
Creates an instance of CObserverStub class.

@return		The new'ed object.
*/
CObserverStub* CObserverStub::NewL()
	{
	return new(ELeave) CObserverStub();
	}

/**
Destructor

@post		This object is properly destroyed.
*/
CObserverStub::~CObserverStub()
	{
	// do nothing;
	}

/**
Default constructor.

@post		The object is properly constructed.
*/
CObserverStub::CObserverStub()
				:CBase(),
				iDriveUnit(EDriveC),
				iDriveMounted(EFalse),
				iEntryProcessed(EFalse),
				iSpiEntryProcessed(EFalse),
				iDiscoveriesComplete(EFalse),
				iState(OSS_NoPlugins)
	{
	// do nothing;
	}

/**
MDiscovererObserver callback method, to signal that a discovery
session is starting.
*/
void CObserverStub::DiscoveriesBegin()
	{
	iDiscoveriesComplete = EFalse;
	}

void CObserverStub::SetDiscoveryFlagL(const TDriveUnit & /*aDrive*/)
	{
	iDiscoveriesComplete = ETrue;
	}
/**
MDiscovererObserver callback method to register an Ecom Spi file.

@param		aEntry The Ecom file  that needs to be registered
*/
void CObserverStub::RegisterDiscoveryL(const TDriveName& /* aDriveName */,CPluginBase*& aEntry,TBool /* aDatFileExists*/)
	{
	iEntryBase = aEntry;
	iSpiEntryProcessed = ETrue;
	}

/**
MDiscovererObserver callback method, to signal that a discovery
session is complete.

@param		aSuccessful Indicates discoveries process completed successfully or not
@param		aProcessingType indicates the type of processing for plugins
			for ensuring that plugins are not processed multiple times
			during start-up phase
*/
void CObserverStub::DiscoveriesComplete(TBool aSuccessful, TPluginProcessingTypeIdentifier aProcessingType)
	{
	iDiscoveriesComplete = aSuccessful;

	switch(iState)
		{
		case OSS_NoPlugins:
			if(aProcessingType == EPluginProcessingTypeCriticalOnly &&
			   iDiscoverer->State() == CDiscoverer::EDisc_CriticalPluginsDisc)
				{
				iState = OSS_CriticalPlugins;
				}
			else if(aProcessingType == EPluginProcessingTypeAll &&
				    iDiscoverer->State() == CDiscoverer::EDisc_AllPluginsDisc)
				{
				iState = OSS_AllPlugins;
				}
			break;
		case OSS_CriticalPlugins:
			if(aProcessingType == EPluginProcessingTypeNonCriticalOnly &&
			   iDiscoverer->State() == CDiscoverer::EDisc_AllPluginsDisc)
				{
				iState = OSS_AllPlugins;
				}
			break;
		}
	}

/**
Verifies whether given plugin entry is registered

@param		aDirEntry The Ecom plugin that to be checked for registration.
@return		true if given plugin is registered
*/
TBool CObserverStub::IsEntryProcessed(CPluginBase*& aDirEntry)
	{
	if(iEntryProcessed && (iEntryBase->iDllThirdUid == aDirEntry->iDllThirdUid))
		{
		return ETrue;
		}

	return EFalse;
	}

/**
MDiscovererObserver callback method, to signal that a Drive
is removed/dismounted.

@param		aDrive The drive that is removed.
*/
void CObserverStub::DriveRemovedL(TDriveUnit aDrive)
	{
	iDriveMounted = EFalse;
	iDriveUnit = aDrive;
	}

/**
MDiscovererObserver callback method, to signal that a Drive
is reinstalled.

@param		aDrive The drive that is available now.
*/
void CObserverStub::DriveReinstatedL(TDriveUnit aDrive)
	{
	iDriveMounted = ETrue;
	iDriveUnit = aDrive;
	}

/**
MDiscovererObserver callback method, to signal that
during a discovery session an error has occured.

@param		aError The notification error code.
@return		true if aError is one of the acceptable error codes
*/
TBool CObserverStub::NotifiedWithErrorCode(TInt aError)
	{
	// Test the safe error codes
	return (aError == KErrNotReady ||		// Drive removed
			aError == KErrPathNotFound);	// Directory deleted
	}

/**
MDiscovererObserver callback method,to retrieve the drive unit's DAT
file infor.

@param 		aDrive the identifier of the drive to retrieve DAT file infor from.
@return		ETrue if DAT file exists on the drive unit, otherwise EFlase.

*/
TBool CObserverStub::IsAnyDllRegisteredWithDriveL(const TDriveUnit /*aDrive*/) const
	{
	// To pass the build always returns EFalse to mean no Dll is discovered in the drive,
	// it is not used in this test.
	return EFalse;
	}

/**
Verification method that checks whether given drive is available

@param		aDrive The drive that to be checked.
@return		true if given drive is registered
*/
TBool CObserverStub::IsDriveMounted(const TDriveUnit aDrive)
	{
	TBool mounted = EFalse;
	if(iDriveMounted && (aDrive == iDriveUnit))
		{
		mounted = ETrue;
		}
	return mounted;
	}

/**
Verification method that checks whether discovery process is completed successfully

@return		true if discovery process is completed successfully
*/
TBool CObserverStub::IsDiscoveriesCompleteSuccessfully()
	{
	return iDiscoveriesComplete;
	}

/**
Returns the current start-up state of this object

@return	    The current start-up state of this object
*/
CObserverStub::OSState CObserverStub::GetState()
	{
	return iState;
	}

void CObserverStub::SetDiscoverer(CDiscoverer* aDiscoverer)
	{
	iDiscoverer = aDiscoverer;
	}

void CObserverStub::LanguageChangedL(TBool& aLanguageChanged)
	{
	aLanguageChanged = EFalse;
	}
class CDiscovererTestShutdown : public CTimer
	{
public:
	inline CDiscovererTestShutdown();
	inline void ConstructL();
	inline void StartAfter(TTimeIntervalMicroSeconds32 aTimeInterval);

private:
	void RunL();
	};

inline CDiscovererTestShutdown::CDiscovererTestShutdown()
:CTimer(EPriorityHigh)// Priority set higher than CIdleScanningTimer
	{
	CActiveScheduler::Add(this);
	}

inline void CDiscovererTestShutdown::ConstructL()
	{
	CTimer::ConstructL();
	}

inline void CDiscovererTestShutdown::StartAfter(TTimeIntervalMicroSeconds32 aTimeInterval)
	{
	After(aTimeInterval);
	}
void CDiscovererTestShutdown::RunL()
	{
	CActiveScheduler::Stop();
	}

/**
Test class for object CDiscoverer.
This class provides the parameters and behaviour that
allows this class to behave normally under a test
scenario.
*/
class CDiscovererTest : public CBase
	{
public:
	static CDiscovererTest* NewL();
	virtual ~CDiscovererTest();

	void ResumeSuspendTestL();
	void DriveMountUnmountTestL();
	void ProcessEntryTestL();
	void ProcessSpiEntryTestL();
	void ValidateSpiEntryTestL();
	void ValidateSpiPluginsTestL();
	void ValidateEntryTestL();
	void ProcessEntryPlugIn3TestL();
	void ProcessSpiEntryPlugIn3TestL();
	void ValidateSpiEntryPlugIn3TestL();
	void ValidateEntryPlugIn3TestL();
	void ScanDirectoryIncrementTestL();
	void ScanDirectoryTestL();
	void ScanDirectoryCancelTestL();
	void StagedDiscoveryStateTransitionTestL();
	void AllAtOnceDiscoveryStateTransitionTestL();
	void MultipleNotificationProcessingTestL();
	void SWINotificationProcessingTestL();
	void IdleScanningTimerRunErrorL();
	void DirChangeNotifierRunErrorL();
	void SwiChangeNotifierRunError();
	void LanguageChangedNotificationTestL();

private:
	CDiscovererTest();
	void ConstructL();

public:
	/** The instance of the class under test */
	CDiscoverer* iDiscoverer;

	/** The instance of the state accessor interface */
	TDiscoverer_StateAccessor* iStateAccessor;

	/** The instance of the observer stub of the CDiscoverer */
	CObserverStub* iDiscovererObserver;

	/** Unique Id of the ECOM dll */
	TUid		iDllUid;

	/** The drive on which interface implementations can be found */
	TDriveUnit	iDriveUnit;

	/** Information on a dll which contains interface implementations */
	TEntry		iDllEntry;

	/** A shutdown timer to manipulate the Active Scheduler of testing server */
	CDiscovererTestShutdown	iShutdown;

	CEComCachedDriveInfo* iCachedDriveInfo;
	};

/**
Standardised safe construction which
leaves nothing on the cleanup stack.

@post			CDiscovererTest is fully constructed and initialised
@return			The new'ed object.
*/
CDiscovererTest* CDiscovererTest::NewL()
	{
	CDiscovererTest* self = new (ELeave) CDiscovererTest();
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

/**
Default constructor.

@post	The object is properly constructed.
*/
CDiscovererTest::CDiscovererTest()
				:CBase(),
				 iDriveUnit(EDriveC)
	{
	TUid uid1 = {0};
	TUid uid2 = {0};

	iDllUid.iUid	= 0x10009DB6; // Dll Uid for EComRomOnlyExampleOnC.dll
	iDllEntry.iType = TUidType(uid1, uid2, iDllUid);
	}

/**
Destructor.

@post		This object is properly destroyed.
*/
CDiscovererTest::~CDiscovererTest()
	{
	delete iDiscoverer;
	delete iStateAccessor;
	delete iDiscovererObserver;
	delete iCachedDriveInfo;
	}

/**
Standardized 2nd(Initialization) phase of two phase construction.
Creates supporting class objects for the execution of test.

@post			CDiscovererTest is fully constructed.
*/
void CDiscovererTest::ConstructL()
	{
	iStateAccessor		= new(ELeave) TDiscoverer_StateAccessor;
	iDiscovererObserver	= CObserverStub::NewL();
	iDiscoverer			= CDiscoverer::NewL(*iDiscovererObserver, TheFs);
	iDiscovererObserver->SetDiscoverer(iDiscoverer);
	iShutdown.ConstructL();
	iCachedDriveInfo = CEComCachedDriveInfo::NewL(TheFs);
	}

/**
The test executes by first suspending the discoverer then by
resuming it.

@SYMTestCaseID          SYSLIB-ECOM-CT-0716
@SYMTestCaseDesc	    Tests for resuming and suspending Discoverer
@SYMTestPriority 	    High
@SYMTestActions  	    Suspend if Discoverer is active and then resume. Check for the error conditions(OOM)
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
void CDiscovererTest::ResumeSuspendTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0716 "));
	// Perform an initial discovery and start the notifiers.
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);

	TBool isDiscActive = iStateAccessor->IsDiscovererActive(*iDiscoverer);
	// Notifiers should be active.
	test(isDiscActive);

	TInt err = iDiscoverer->Suspend();
	TEST_OOM_ERR;
	test(err == KErrNone);

	// Notifiers should still be active.
	isDiscActive = iStateAccessor->IsDiscovererActive(*iDiscoverer);
	test(isDiscActive);

	// Test that there are no drives pending a scan before we copy the plugin.
	test(!iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveC));

	// Raise a plugin change notification on C: drive. This simulates a plugin being copied.
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveC);
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveC);

	// Test that the drive we copied the plugin to still has a scan pending.
	test(iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveC));

	isDiscActive = iStateAccessor->IsDiscovererActive(*iDiscoverer);
	// Notifiers should still be active.
	test(isDiscActive);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check that notifications have not been processed.
	test(!iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	err = iDiscoverer->Resume();
	TEST_OOM_ERR;
	test(err == KErrNone);

	isDiscActive = iStateAccessor->IsDiscovererActive(*iDiscoverer);
	// Notifiers should still be active.
	test(isDiscActive);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check if notifications have been processed on all drives.
	test(iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));
	}

/**
The test executes by first making the test drive unmounted and
then testing for Mount and Unmount.

@SYMTestCaseID          SYSLIB-ECOM-CT-0717
@SYMTestCaseDesc	    Tests for drive mount and unmount
@SYMTestPriority 	    High
@SYMTestActions  	    First remove the drive if its already there, then test for Mount then for unmount
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
void CDiscovererTest::DriveMountUnmountTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0717 "));
	TInt err;
	TDriveUnit drive(EDriveC);
	//First remove the drive if its already there, then test for Mount then for unmount
	if(iStateAccessor->IsDriveMounted(*iDiscoverer, drive))
		{
		TRAP(err, iStateAccessor->DriveUnmountedL(*iDiscoverer, drive));
		TEST_OOM_ERR;
		test(err == KErrNone);
		}

	// Drive should not be present
	test(!iStateAccessor->IsDriveMounted(*iDiscoverer, drive));

	// Test Mount
	TRAP(err, iStateAccessor->DriveMountedL(*iDiscoverer, drive));
	TEST_OOM_ERR;
	test(err == KErrNone);

	// CDiscoverer->DriveMountedL/DriveUnmountedL updates both itself and
	// DiscovererObserver class for Mount/Unmount of drives. So testing for both
	test(iStateAccessor->IsDriveMounted(*iDiscoverer, drive));
	test(iDiscovererObserver->IsDriveMounted(drive));

	// Test Unmount
	TRAP(err, iStateAccessor->DriveUnmountedL(*iDiscoverer, drive));
	TEST_OOM_ERR;
	test(err == KErrNone );

	// CDiscoverer->DriveMountedL/DriveUnmountedL updates both itself and
	// DiscovererObserver class for Mount/Unmount of drives. So testing for both
	test(!iStateAccessor->IsDriveMounted(*iDiscoverer, drive));
	test(!iDiscovererObserver->IsDriveMounted(drive));
	}


/**
@SYMTestCaseID          SYSLIB-ECOM-UT-3559
@SYMTestCaseDesc	    Tests for process entry of PLUGIN3 type.
@SYMTestPriority 	    High
@SYMTestActions  	    Call CDiscoverer::ProcessEntryL().
@SYMTestExpectedResults The entry is registered successfully and no leave occurred.
@SYMEC	                EC43
*/
void CDiscovererTest::ProcessEntryPlugIn3TestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-3559 "));
	CPluginBase* entryBase = NULL;
	TInt err = KErrNone;

	//This part refers to testing of the entry containing the RSC
	_LIT(KExampleRscFileNameOnly,"EComExample12.rsc");
	TDriveName driveName1(iDriveUnit.Name());
	TParse path1;
	path1.Set(KNewResourceSearchPath(),NULL,&driveName1);
	//Creating a entry that represents the Rsc disovered during scanning of \\resource\\plugins
	TEntry rscEntry;
	rscEntry.iName = KExampleRscFileNameOnly;
	rscEntry.iType = TUidType(KNullUid,KUidInterfaceImplementationCollectionInfo,KNullUid);
	entryBase = CSecurePlugin::NewL(TheFs,rscEntry,driveName1, EFalse);
	CleanupStack::PushL(entryBase);

	// ProcessEntryL() updates entryToFill with information on a rsc specified by the other params.
	TRAP(err, iStateAccessor->ProcessEntryL(*iDiscoverer,driveName1,entryBase,ETrue));
	TEST_OOM_ERR;
	test(err == KErrNone);
	CleanupStack::PopAndDestroy(entryBase);
	}

/**
@SYMTestCaseID			SYSLIB-ECOM-UT-3560
@SYMTestCaseDesc 		Check that the ProcessEntryL for spi data works correctly when using PLUGIN3 entries in the spi file.
@SYMTestPriority 		High
@SYMTestActions  		Call CDiscoverer::ProcessEntryL().
@SYMTestExpectedResults ecomtesttype3.spi is processed successfully and no leave occurred.
@SYMEC					EC43
*/
void CDiscovererTest::ProcessSpiEntryPlugIn3TestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-3560 "));
	TEntry spiEntry;
	test(TheFs.Entry(KEComSpiTestFilePlugIn3PathAndName, spiEntry) == KErrNone);
	TParse spiPath;
	spiPath.Set(KEComSpiTestFilePlugIn3PathAndName, NULL, NULL);

	RResourceArchive resourceArchive;
	resourceArchive.OpenL(TheFs, KEComSpiTestFilePlugIn3PathAndName);
	CleanupClosePushL(resourceArchive);

	// check SPI file type
	TUid type = resourceArchive.Type();
	test(type == KEcomSpiFileTypeUid);

	// there is only 1 resource file
	while(!resourceArchive.End())
		{
		CPluginBase* entry = CSpiPlugin::NewL(resourceArchive);
		CleanupStack::PushL(entry);

		TRAPD(err, iStateAccessor->ProcessEntryL(*iDiscoverer,spiPath.Drive(), entry,ETrue));
		TEST_OOM_ERR;
		test(err == KErrNone);

		CleanupStack::PopAndDestroy(entry);
		entry = NULL;
		}
	CleanupStack::PopAndDestroy(&resourceArchive);
	}
/**
@SYMTestCaseID          SYSLIB-ECOM-UT-3561
@SYMTestCaseDesc	    Tests for the reference of the entry containing the DLL of PLUGIN3 type.
@SYMTestPriority 	    High
@SYMTestActions  	    Call CDiscoverer::ValidateEntryL(). Check the entry returned.
@SYMTestExpectedResults The entry is validated successfully and no leave occurred.
@SYMEC	                EC43
*/
void CDiscovererTest::ValidateEntryPlugIn3TestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-3561 "));
	TInt err = KErrNone;

	//This part refers to testing of the entry containing the RSC
	_LIT(KExampleRscFileNameOnly,"EComExample12.rsc");
	TDriveName driveName1(iDriveUnit.Name());
	CPluginBase *entryToFill1 = NULL;
	//Creating an entry that represents the Rsc disovered during scanning of \\resource\\plugins
	TEntry rscEntry;
	rscEntry.iName = KExampleRscFileNameOnly;
	rscEntry.iType = TUidType(KNullUid,KUidInterfaceImplementationCollectionInfo,KNullUid);

	TUid dllUid1 = {KDynamicLibraryUidValue};
	TUid example12Uid = {0x10009E3E};
	TUidType dllUidType = TUidType(dllUid1,KUidInterfaceImplementationCollection,example12Uid);

	//Now call ValidateEntryL() with this entry containg the rsc
	TRAP(err,iStateAccessor->ValidateEntryL(*iDiscoverer,rscEntry,driveName1,entryToFill1, EFalse));
	TEST_OOM_ERR;
	test(err == KErrNone);
	test(entryToFill1->iDllThirdUid == dllUidType[2]);
	TParse dllParse;
	dllParse.Set(KPlugIn3ExampleDllFileName,NULL,NULL);
	test(entryToFill1->iDllName->CompareF(dllParse.NameAndExt()) == 0);

	delete entryToFill1;
	}

/**
@SYMTestCaseID			SYSLIB-ECOM-UT-3562
@SYMTestCaseDesc 		Check that the ValidateEntryL for spi data works correctly when using PLUGIN3 entries in the spi file.
@SYMTestPriority 		High
@SYMTestActions  		Call CDiscoverer::ValidateEntryL(). Check the entry returned.
@SYMTestExpectedResults ecomtesttype3.spi file is validated successfully and no leave occurred.
@SYMEC					EC43
*/
void CDiscovererTest::ValidateSpiEntryPlugIn3TestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-3562 "));
	TEntry spiEntry;
	test(TheFs.Entry(KEComSpiTestFilePlugIn3PathAndName, spiEntry) == KErrNone);
	TParse spiPath;
	spiPath.Set(KEComSpiTestFilePlugIn3PathAndName, NULL, NULL);

	TEntry TestEntry;
	TUid uid1 = {0x10000079};
	TUid uid2 = {0x10009D93};
	TUid uid3 = {0x10009E3E}; // Uid for EComExample12.dll
	TestEntry.iType = TUidType(uid1, uid2, uid3);
	TestEntry.iName = KPlugIn3ExampleDllFileNameOnly;

	RResourceArchive resourceArchive;
	resourceArchive.OpenL(TheFs, KEComSpiTestFilePlugIn3PathAndName);
	CleanupClosePushL(resourceArchive);

	// check SPI file type
	TUid type = resourceArchive.Type();
	test(type == KEcomSpiFileTypeUid);

	// there is only 1 resource file
	while(!resourceArchive.End())
		{
		CPluginBase* entryToFill = NULL;
		TRAPD(err, iStateAccessor->ValidateEntryL(*iDiscoverer,resourceArchive,entryToFill));
		CleanupStack::PushL(entryToFill);

		TEST_OOM_ERR;
		test(err == KErrNone);
		test(entryToFill->iDllThirdUid == TestEntry.iType[2]);

		TFileName name1(KEComSpiTestFilePlugIn3DllPathAndName);
		TFileName name2(*(entryToFill->iDllName));
		name1.LowerCase();
		name2.LowerCase();
		TParse dllparse;
		dllparse.Set(name1,NULL,NULL);
		test(dllparse.NameAndExt()== name2);

		CleanupStack::PopAndDestroy(entryToFill); // resourceFile, resourceName, entryToFill
		entryToFill = NULL;
		}
	CleanupStack::PopAndDestroy(&resourceArchive);
	}

/**
The test executes by Registering an Interface Implementation Collection
and later verifing it

@SYMTestCaseID          SYSLIB-ECOM-CT-0718
@SYMTestCaseDesc	    Tests for process entry.
@SYMTestPriority 	    High
@SYMTestActions  	    Register an interface implementation collection and later verifies it.
                        Check for OOM error.
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
void CDiscovererTest::ProcessEntryTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0718 "));
	CPluginBase* entryBase=NULL;
	TInt err=KErrNone;

	//This part refers to testing of the entry containing the RSC
	_LIT(KExampleRscFileNameOnly,"EComExample5.rsc");
	TDriveName driveName1(iDriveUnit.Name());
	TParse path1;
	path1.Set(KNewResourceSearchPath(),NULL,&driveName1);
	//Creating a entry that represents the Rsc disovered during scanning of \\resource\\plugins
	TEntry rscEntry;
	rscEntry.iName=KExampleRscFileNameOnly;
	rscEntry.iType=TUidType(KNullUid,KUidInterfaceImplementationCollectionInfo,KNullUid);
	TUid dllUid1 = {KDynamicLibraryUidValue};
	TUid example5Uid={0x101F847B};
	TUidType dllUidType=TUidType(dllUid1,KUidInterfaceImplementationCollection,example5Uid);
	entryBase=CSecurePlugin::NewL(TheFs,rscEntry,driveName1, EFalse);
	CleanupStack::PushL(entryBase);

	// ProcessEntryL() updates entryToFill with information on a rsc specified by the other params.
	TRAP(err, iStateAccessor->ProcessEntryL(*iDiscoverer,driveName1,entryBase,ETrue));
	TEST_OOM_ERR;
	test(err == KErrNone);
	CleanupStack::PopAndDestroy(entryBase);
	entryBase=NULL;

	}

/**
@SYMTestCaseID		SYSLIB-ECOM-CT-0091
@SYMTestCaseDesc 	Check that the ProcessEntryL for spi data works correctly.
@SYMTestPriority 	High
@SYMTestActions  	Ensure ecomtest.spi can be processed successfully
					and no leave occurred.
@SYMTestExpectedResults The test must not fail.
@SYMREQ REQ3655
*/
void CDiscovererTest::ProcessSpiEntryTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0091 "));
	TEntry spiEntry;
	test(TheFs.Entry(KEComSpiTestFilePathAndName, spiEntry) == KErrNone);
	TParse spiPath;
	spiPath.Set(KEComSpiTestFilePathAndName, NULL, NULL);

	RResourceArchive resourceArchive;
	resourceArchive.OpenL(TheFs, KEComSpiTestFilePathAndName);
	CleanupClosePushL(resourceArchive);

	// check SPI file type
	TUid type = resourceArchive.Type();
	test(type == KEcomSpiFileTypeUid);

	// there is only 1 resource file
	while(!resourceArchive.End())
		{
		CPluginBase* entry = CSpiPlugin::NewL(resourceArchive);
		CleanupStack::PushL(entry);

		TRAPD(err, iStateAccessor->ProcessEntryL(*iDiscoverer,spiPath.Drive(), entry,ETrue));
		TEST_OOM_ERR;
		test(err == KErrNone);

		CleanupStack::PopAndDestroy(entry);
		entry = NULL;
		}
	CleanupStack::PopAndDestroy(&resourceArchive);
	}
/**
The test executes by checking whether discovered plugin entry is valid

@SYMTestCaseID          SYSLIB-ECOM-CT-0719
@SYMTestCaseDesc	    Tests for plugin that resides on C drive
@SYMTestPriority 	    High
@SYMTestActions  	    Tests for the reference of the entry containing in the DLL
                        Check for OOM error.
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
void CDiscovererTest::ValidateEntryTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0719 "));
	TInt err=KErrNone;

	//This part refers to testing of the entry containing the RSC
	_LIT(KExampleRscFileNameOnly,"EComExample5.rsc");
	TDriveName driveName1(iDriveUnit.Name());
	TParse path1;
	CPluginBase *entryToFill1 = NULL;
	path1.Set(KNewResourceSearchPath(),NULL,&driveName1);
	//Creating a entry that represents the Rsc disovered during scanning of \\resource\\plugins
	TEntry rscEntry;
	rscEntry.iName=KExampleRscFileNameOnly;
	rscEntry.iType=TUidType(KNullUid,KUidInterfaceImplementationCollectionInfo,KNullUid);

	TUid dllUid1 = {KDynamicLibraryUidValue};
	TUid example5Uid={0x101F847B};
	TUidType dllUidType=TUidType(dllUid1,KUidInterfaceImplementationCollection,example5Uid);

	//Now call ValidateEntryL() with this entry containg the rsc
	TRAP(err,iStateAccessor->ValidateEntryL(*iDiscoverer,rscEntry,driveName1,entryToFill1, EFalse));
	TEST_OOM_ERR;
	test(err==KErrNone);
	test(entryToFill1->iDllThirdUid==dllUidType[2]);
	TParse dllParse;
	dllParse.Set(KNewExampleDllFileName,NULL,NULL);
	test(entryToFill1->iDllName->CompareF(dllParse.NameAndExt())==0);

	delete entryToFill1;
	}

/**
@SYMTestCaseID		SYSLIB-ECOM-CT-0092
@SYMTestCaseDesc 	Check that the ValidateEntryL for spi data works correctly.
@SYMTestPriority 	High
@SYMTestActions  	Ensure ecomtest.spi can be validated successfully
					and no leave occurred.
@SYMTestExpectedResults The test must not fail.
@SYMREQ REQ3655
*/
void CDiscovererTest::ValidateSpiEntryTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0092 "));
	TEntry spiEntry;
	test(TheFs.Entry(KEComSpiTestFilePathAndName, spiEntry) == KErrNone);
	TParse spiPath;
	spiPath.Set(KEComSpiTestFilePathAndName, NULL, NULL);

	TEntry TestEntry;
	TUid uid1 = {0x10000079};
	TUid uid2 = {0x10009D8D};
	TUid	 uid3 = {0x101F847B}; // Uid for EComExample5.dll
	TestEntry.iType = TUidType(uid1, uid2, uid3);
	TestEntry.iName = KNewExampleDllFileNameOnly;

	RResourceArchive resourceArchive;
	resourceArchive.OpenL(TheFs, KEComSpiTestFilePathAndName);
	CleanupClosePushL(resourceArchive);

	// check SPI file type
	TUid type = resourceArchive.Type();
	test(type == KEcomSpiFileTypeUid);

	// there is only 1 resource file
	while(!resourceArchive.End())
		{
		CPluginBase* entryToFill = NULL;
		TRAPD(err, iStateAccessor->ValidateEntryL(*iDiscoverer,resourceArchive,entryToFill));
		CleanupStack::PushL(entryToFill);

		TEST_OOM_ERR;
		test(err == KErrNone);
		test(entryToFill->iDllThirdUid == TestEntry.iType[2]);

		TFileName name1(KEComSpiTestFileDllPathAndName);
		TFileName name2(*(entryToFill->iDllName));
		name1.LowerCase();
		name2.LowerCase();
		TParse dllparse;
		dllparse.Set(name1,NULL,NULL);
		test(dllparse.NameAndExt()== name2);

		CleanupStack::PopAndDestroy(entryToFill); // resourceFile, resourceName, entryToFill
		entryToFill = NULL;
		}
	CleanupStack::PopAndDestroy(&resourceArchive);
	}

/**
@SYMTestCaseID		SYSLIB-ECOM-CT-0093
@SYMTestCaseDesc 	Check that there is DLL for each resource in SPI file
@SYMTestPriority 	High
@SYMTestActions  	Ensure ecom.spi contents i.e, rsc, actually exist on drive
@SYMTestExpectedResults The test must not fail.
@SYMREQ REQ3655
*/
void CDiscovererTest::ValidateSpiPluginsTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0093 "));
	__UHEAP_MARK;

	TEntry spiEntry;
	TBool err = TheFs.Entry(KEComSPIFilePathAndName, spiEntry);
	// It is possible for ecom.spi file not to exist. If it does not then no testing can be done.
	if(err != KErrNone)
		return;

	TParse spiPath;
	spiPath.Set(KEComSPIFilePathAndName, NULL, NULL);

	//To read the SPI file
	RResourceArchive resourceArchive;
	resourceArchive.OpenL(TheFs, KEComSPIFilePathAndName);
	CleanupClosePushL(resourceArchive);
	CRegistryData::CDriveData* driveData = NULL;
	//Check spi file type
	TUid spiType = resourceArchive.Type();
	test(spiType == KEcomSpiFileTypeUid);

	while(!resourceArchive.End())
		{
		CPluginBase* entryToFill = NULL;
		TRAPD(err, iStateAccessor->ValidateEntryL(*iDiscoverer,resourceArchive,entryToFill));
		CleanupStack::PushL(entryToFill);

		TEST_OOM_ERR;
		test(err == KErrNone);

		CRegistryData::CDllData * dllData=CRegistryData::CDllData::NewLC(*(entryToFill->iDllName),entryToFill->iDllModifiedTime,entryToFill->iDllSecondUid, entryToFill->iDllThirdUid,driveData);

		TBool successful=dllData->ProcessSecurityCheckL();
		if(!successful)
		{
			_LIT(KMessage,"ERROR: Plugin SID Mismatch ERROR for %S.");
			RDebug::Print(KMessage, entryToFill->iDllName);
		}
		test(successful);

		CleanupStack::PopAndDestroy(dllData);
		CleanupStack::PopAndDestroy(entryToFill);
		entryToFill=NULL;
		}

		CleanupStack::PopAndDestroy(&resourceArchive);
	__UHEAP_MARKEND;
	}


/**
Scans plugin directories and verifies successfull completion

@SYMTestCaseID          SYSLIB-ECOM-CT-0720
@SYMTestCaseDesc	    Tests for scanning plugin directories and verifies successfull completion
@SYMTestPriority 	    High
@SYMTestActions  	    Scans registered plugin directories from A to Z drive
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
void CDiscovererTest::ScanDirectoryIncrementTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0720 "));
	TInt err;
	// Scans registered plugin directories from A to Z drive
	TEComCachedDriveInfoIterator iter(*iCachedDriveInfo);
	for(iter.Last(); iter.InRange(); iter.Prev())
		{
		TRAP(err, iStateAccessor->ScanDirectoryL(*iDiscoverer,iter.DriveNumber()));
		TEST_OOM_ERR;
		test(err == KErrNone);
		}
	// After successful completion of ScanDirectoryL, DiscovererObserver is updated
	// with DiscoveriesComplete successful
	// DiscovererObserver is a stub class used in place of CRegistrar. Flags are used for the
	// successfull execution of API
	test(iDiscovererObserver->IsDiscoveriesCompleteSuccessfully());
	}

/**
Stops scaning of plugin directories

@SYMTestCaseID          SYSLIB-ECOM-CT-0722
@SYMTestCaseDesc	    Tests for stopping of scanning plugin directories
@SYMTestPriority 	    High
@SYMTestActions  	    Stops scaning of plugin directories. Check for OOM error.
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
void CDiscovererTest::ScanDirectoryCancelTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0722 "));
	TRAPD(err, iStateAccessor->ScanDirectoryCancel(*iDiscoverer));
	TEST_OOM_ERR;
	test(err == KErrNone);
	test(iStateAccessor->IsDirectoryScanCancelled(*iDiscoverer));
	}

/**
Scaning of plugin directories in Z: drive and C:drive, check these two drives is in drive list

@SYMTestCaseID          SYSLIB-ECOM-UT-1859
@SYMTestCaseDesc	    Tests for scanning plugin directories in specific drives.
@SYMTestPriority 	    High
@SYMTestActions  	    scaning of plugin directories. Check for OOM error.
@SYMTestExpectedResults The test must not fail.
@SYMDEF                 DEF088454
*/

void CDiscovererTest::ScanDirectoryTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-1859 "));
	EComPerformance::ResetEComPerfTimeRecords();

	// Do scan on specific drive
	TRAPD(err, iStateAccessor->ScanDriveL(*iDiscoverer, EDriveZ, ETrue));
	TEST_OOM_ERR;
	test(err == KErrNone);

	TRAP(err, iStateAccessor->ScanDriveL(*iDiscoverer, EDriveC, EFalse));
	TEST_OOM_ERR;
	test(err == KErrNone);

	// Test record information correct
	test(EComPerformance::iEComPerfTimeRecordCount == 4);
	test(EComPerformance::iEComPerfTimeRecords[0].iType == ECDiscovererRediscoveryScanDirectoryL);
	test(EComPerformance::iEComPerfTimeRecords[0].iInfo == EDriveZ);
	test(EComPerformance::iEComPerfTimeRecords[1].iType == ECDiscovererRediscoveryScanDirectoryL);
	test(EComPerformance::iEComPerfTimeRecords[1].iInfo == EDriveZ);

	test(EComPerformance::iEComPerfTimeRecords[2].iType == ECDiscovererRediscoveryScanDirectoryL);
	test(EComPerformance::iEComPerfTimeRecords[2].iInfo == EDriveC);
	test(EComPerformance::iEComPerfTimeRecords[3].iType == ECDiscovererRediscoveryScanDirectoryL);
	test(EComPerformance::iEComPerfTimeRecords[3].iInfo == EDriveC);
	}

/**
@SYMTestCaseID		SYSLIB-ECOM-CT-0185
@SYMTestCaseDesc 	Check that SSA related states transition as expected when discovery is staged
@SYMTestPriority 	High
@SYMTestActions  	Use CDiscoverer::ProcessSSAEventL to start discovery in stages i.e. rom only
then non rom only. Check that the
CDiscoverer state is transitioning correctly at every step.
@SYMTestExpectedResults The test must not fail.
@SYMREQ REQ3655
*/
void CDiscovererTest::StagedDiscoveryStateTransitionTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0185 "));
	//After construction check that:
	//- current state is EDisc_NoPluginsDisc
	//- registry is empty. i.e. no plugins discovered
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_NoPluginsDisc);

	//Call ProcessSSAEvent with state set to various states that will
	//not cause a transition. Check that:
	//- current state has not changed
	iDiscoverer->ProcessSSAEventL(EStartupStateUndefined);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_NoPluginsDisc);

	//Call ProcessSSAEventL with EStartupStateCriticalStatic state.
	//Check that
	//- current state is EDisc_CriticalPluginsDisc
	//- discoverer observer has processed RO plugins
	iDiscoverer->ProcessSSAEventL(EStartupStateCriticalStatic);
	test(iStateAccessor->GetDiscovererObserverState(*iDiscoverer) == CObserverStub::OSS_CriticalPlugins);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_CriticalPluginsDisc);

	//Call ProcessSSAEvent with state set to various states that will
	//not cause a transition. Check that:
	//- current state has not changed
	iDiscoverer->ProcessSSAEventL(EStartupStateUndefined);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_CriticalPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateCriticalStatic);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_CriticalPluginsDisc);

	//Call ProcessSSAEventL with EStartupStateNonCritical state. Check that
	//- current state is EDisc_AllPluginsDisc
	//- discoverer observer has processed non-RO plugins
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);
	test(iStateAccessor->GetDiscovererObserverState(*iDiscoverer) == CObserverStub::OSS_AllPlugins);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);

	//Call ProcessSSAEvent with state set to various states that will
	//not cause a transition. Check that:
	//- current state has not changed
	iDiscoverer->ProcessSSAEventL(EStartupStateUndefined);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateCriticalStatic);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateCriticalDynamic);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);

	//Call ProcessDNEventL to indicate that current set of plugins is dirty.
	//Check that:
	//- current state is EDisc_PluginsDirty
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveC);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_PluginsDirty);

	//Call ProcessDNEventL to indicate that a rediscovery should take place.
	//Check that:
	//- current state is EDisc_AllPluginsDisc
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveC);
	iStateAccessor->CompleteNotificationProcessing(*iDiscoverer);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	}

/**
@SYMTestCaseID		SYSLIB-ECOM-CT-0186
@SYMTestCaseDesc 	Check that SSA related states transition as expected when discovery is all at once
@SYMTestPriority 	High
@SYMTestActions  	Use CDiscoverer::ProcessSSAEventL to start discovery all at once. Check that the
CDiscoverer state is transitioning correctly at every step.
@SYMTestExpectedResults The test must not fail.
@SYMREQ REQ3655
*/
void CDiscovererTest::AllAtOnceDiscoveryStateTransitionTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0186 "));
	//After construction check that:
	//- current state is EDisc_NoPluginsDisc
	//- registry is empty. i.e. no plugins discovered
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_NoPluginsDisc);

	//Call ProcessSSAEvent with state set to various states that will
	//not cause a transition. Check that:
	//- current state has not changed
	iDiscoverer->ProcessSSAEventL(EStartupStateUndefined);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_NoPluginsDisc);

	//Call ProcessSSAEventL with EStartupStateNonCritical state. Check that
	//- current state is EDisc_AllPluginsDisc
	//- discoverer observer has processed non-RO plugins
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);
	test(iStateAccessor->GetDiscovererObserverState(*iDiscoverer) == CObserverStub::OSS_AllPlugins);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);

	//Call ProcessSSAEvent with state set to various states that will
	//not cause a transition. Check that:
	//- current state has not changed
	iDiscoverer->ProcessSSAEventL(EStartupStateUndefined);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateCriticalStatic);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateCriticalDynamic);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);

	//Call ProcessDNEventL to indicate that current set of plugins is dirty.
	//Check that:
	//- current state is EDisc_PluginsDirty
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveC);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_PluginsDirty);

	//Call ProcessDNEventL to indicate that a rediscovery should take place.
	//Check that:
	//- current state is EDisc_AllPluginsDisc
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveC);
	iStateAccessor->CompleteNotificationProcessing(*iDiscoverer);
	test(iStateAccessor->State(*iDiscoverer) == CDiscoverer::EDisc_AllPluginsDisc);
	}

/**
@SYMTestCaseID          SYSLIB-ECOM-UT-1796
@SYMTestCaseDesc	    Tests multiple notification processing for
						"INC087110: ECOM rescanning code could miss a drive?" and
						"DEF088454: [PCB] ECOM CDiscoverer::CIdleScanningTimer::RunL() Performs Unnecessary Tasks"
@SYMTestPriority 	    High
@SYMTestActions  	    Create multiple notification request on both single drive and multiple drives.
						Check if the notifications are ONLY processed on corresponding drive(s) by timer.
						Check the notifications are processed properly by timer.
						Check the state of discoverer was set correctly on completion.
@SYMTestExpectedResults The test must not fail.
@SYMDEF                 INC087110, DEF088454
*/
void CDiscovererTest::MultipleNotificationProcessingTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-1796 "));
	TBool pending = EFalse;

	// Multiple notification on single drive:
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);
	// Raise multiple notification on C: drive
	for(TInt num = 0; num < 10; ++num)
		{
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveC);
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveC);
		}

	// Check only one pending drive in the list.
	test(iStateAccessor->PendingDriveListCount(*iDiscoverer) == 1);
	// Check the pending drive is C: drive
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveC);
	test(pending);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check if notifications have been processed on all drives.
	test(iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	// Multiple notification on multiple drives:
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);
	// Raise multiple notification on C: drive
	for(TInt num = 0; num < 10; ++num)
		{
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveC);
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveC);
		}
#if defined(__WINSCW__) // X: drive on emulator
	// Raise multiple notification on X: drive
	for(TInt num = 0; num < 10; ++num)
		{
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveX);
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveX);
		}

#else // E: drive on HW
	// Raise multiple notification on E: drive
	for(TInt num = 0; num < 10; ++num)
		{
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveE);
		iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveE);
		}
#endif	// __WINSCW__

	// Check only one pending drive in the list.
	test(iStateAccessor->PendingDriveListCount(*iDiscoverer) == 2);

	// Check the pending drive are C: and X: on emulator, or C: and E: on hardware.
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveC);
	test(pending);
#if defined(__WINSCW__) // X: drive on emulator
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveX);
	test(pending);
#else // E: drive on HW
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveE);
	test(pending);
#endif	// __WINSCW__

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check if notifications have been processed on all drives.
	test(iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));
	}

/**
@SYMTestCaseID          SYSLIB-ECOM-UT-3519
@SYMTestCaseDesc	    Tests notification processing during SWI for
						PDEF110201: Undesireable interaction between ECOM and SWI
@SYMTestActions  	    Create notification request on  drives.
						Check the notifications are not processed by timer if SWI in progress.
						Check that timer processes pending notifications after SWI completes
@SYMTestExpectedResults The test must not fail.
@SYMDEF                 PDEF110201
*/
void CDiscovererTest::SWINotificationProcessingTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-3519 "));

	//Begin SWI
	iStateAccessor->SwiChangeNotificationL(*iDiscoverer,ESASwisInstall);

	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);

	// Raise a notification on C: drive
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveC);
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveC);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check that notifications have NOT been processed as SWI is in progress
	test(!iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	//complete SWI
	iStateAccessor->SwiChangeNotificationL(*iDiscoverer,ESASwisUninstall);


#if defined(__WINSCW__) // X: drive on emulator
	// Raise  notification on X: drive
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveX);
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveX);
#else // E: drive on HW
	// Raise notification on E: drive
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified, EDriveE);
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover, EDriveE);
#endif	// __WINSCW__

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check that notifications have NOT been processed as SWI is not finished
	test(!iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	//finalise SWI
	iStateAccessor->SwiChangeNotificationL(*iDiscoverer,ESASwisNone);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check that notifications have been processed on all drives
	test(iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	//Begin SWI
	iStateAccessor->SwiChangeNotificationL(*iDiscoverer,ESASwisInstall);

	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);

	// Raise a notification
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsModified,EDriveC);
	iDiscoverer->ProcessDNEventL(CDiscoverer::EPluginsRediscover,EDriveC);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check that notifications have NOT been processed as SWI is in progress
	test(!iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	//Simulate an error in reading the P&S Variable - This should reset the
	//SWI state to ESASwisNone in the same way as completing SWI
	iStateAccessor->SwiChangeNotifierRunError(*iDiscoverer,KErrNotFound);

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check that notifications have been processed on all drives
	test(iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));
	}

/**
Call the TDiscoverer_StateAccessor::IdleScanningTimerRunErrorL funtion
passing in a reference to the CDiscoverer object and the error code
to be passed to the CIdleScanningTimer::RunError function
*/
void CDiscovererTest::IdleScanningTimerRunErrorL()
	{
	iStateAccessor->IdleScanningTimerRunErrorL(*iDiscoverer, EEComPanic_CDiscoverer_CIdleScanningTimer_RunError);
	}

/**
Call the TDiscoverer_StateAccessor::IdleScanningTimerRunErrorL funtion
passing in a reference to the CDiscoverer object and the error code
to be passed to the CDirChangeNotifier::RunError function
*/
void CDiscovererTest::DirChangeNotifierRunErrorL()
	{
	iStateAccessor->DirChangeNotifierRunErrorL(*iDiscoverer, EEComPanic_CDiscoverer_CDirChangeNotifier_RunError);
	}

/**
Call the TDiscoverer_StateAccessor::IdleScanningTimerRunErrorL funtion
passing in a reference to the CDiscoverer object and the error code
to be passed to the CSwiChangeNotifier::RunError function
*/
void CDiscovererTest::SwiChangeNotifierRunError()
	{
	iStateAccessor->SwiChangeNotifierRunError(*iDiscoverer, KErrNoMemory);
	}
/**
@SYMTestCaseID          SYSLIB-ECOM-UT-3172
@SYMTestCaseDesc	    Tests language switch notification processing for
						"CR0902: Enable Dynamic Language Switching in APPARC, ECOM and EIKSTD"
@SYMTestPriority 	    High
@SYMTestActions  	    Call ProcessSSAEventL with EStartupStateNonCritical state.
						Call DriveMountedL to build up drives in system.
						Call LanguageChangedL to raise multiple notification on all drives in system.
						Check if the notifications are processed on all drive(s) by timer.
						Check the notifications are processed properly by timer.
						Check the state of discoverer was set correctly on completion.
@SYMTestExpectedResults The test must not fail.
@SYMDEF                 CR0902
*/
void CDiscovererTest::LanguageChangedNotificationTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-3172 "));
	TBool pending = EFalse;

	//Call ProcessSSAEventL with EStartupStateNonCritical state
	iDiscoverer->ProcessSSAEventL(EStartupStateNonCritical);

	if(iStateAccessor->IsDriveMounted(*iDiscoverer, EDriveK))
		{
		TRAPD(err, iStateAccessor->DriveUnmountedL(*iDiscoverer, EDriveK));
		TEST_OOM_ERR;
		test(err == KErrNone);
		}

	// Mount drives on system
	TRAPD(err, iStateAccessor->DriveMountedL(*iDiscoverer, EDriveZ));
	TEST_OOM_ERR;
	test(err == KErrNone);

	TRAP(err, iStateAccessor->DriveMountedL(*iDiscoverer, EDriveC));
	TEST_OOM_ERR;
	test(err == KErrNone);

#if defined(__WINSCW__) // X: drive on emulator
	TRAP(err, iStateAccessor->DriveMountedL(*iDiscoverer, EDriveX));
	TEST_OOM_ERR;
	test(err == KErrNone);
#else // E: drive on HW
	TRAP(err, iStateAccessor->DriveMountedL(*iDiscoverer, EDriveE));
	TEST_OOM_ERR;
	test(err == KErrNone);
#endif

	// Multiple notification on all drives:
	iStateAccessor->LanguageChangedL(*iDiscoverer);

	// Check three pending drive in the list.
	test(iStateAccessor->PendingDriveListCount(*iDiscoverer) == 3);
	// Check the pending drive is Z: drive
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveZ);
	test(pending);

	// Check the pending drive is C: drive
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveC);
	test(pending);

#if defined(__WINSCW__) // X: drive on emulator
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveX);
	test(pending);
#else // E: drive on HW
	pending = iStateAccessor->IsScanDirectoryPending(*iDiscoverer, EDriveE);
	test(pending);
#endif	// __WINSCW__

	// Start Active Scheduler and shut it down in 3 secs, it will launch RunL of timer to process
	// all pending notification.
	iShutdown.StartAfter(KOneSecond * 3);
	CActiveScheduler::Start();

	// Check if notifications have been processed on all drives.
	test(iStateAccessor->IsScanDirectoryComplete(*iDiscoverer));

	}

/**
@SYMTestCaseID          SYSLIB-ECOM-CT-0723
@SYMTestCaseDesc	    Tests the creation and deletion of CDiscoverer
@SYMTestPriority 	    High
@SYMTestActions  	    Create and delete CDiscoverer object,checks for open handles
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
LOCAL_C void CreateDeleteTestL()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0723 CreateDeleteTestL "));
	//
	// Tests the Creating and deletion of CDiscoverer
	// ------------------------------------------------------------------
	//
	// Set up for heap leak checking
	__UHEAP_MARK;

	//Check Thread handles leak
	TInt startProcessHandleCount = 0;
	TInt startThreadHandleCount = 0;
	TInt endProcessHandleCount = 0;
	TInt endThreadHandleCount = 0;

	RThread rThread;
	rThread.HandleCount(startProcessHandleCount, startThreadHandleCount);

	//START CREATE DELETE TEST//

	CDiscovererTest* discTest = CDiscovererTest::NewL();

	test(discTest != NULL);

	delete discTest;

	//END CREATE DELETE TEST//

	// Check for open handles
	rThread.HandleCount(endProcessHandleCount, endThreadHandleCount);
	test(startThreadHandleCount == endThreadHandleCount);

	//Test ends
	__UHEAP_MARKEND;
	}

/**
@SYMTestCaseID          SYSLIB-ECOM-CT-0724
@SYMTestCaseDesc	    OOM test for create and delete of CDiscoverer.
@SYMTestPriority 	    High
@SYMTestActions  	    Create and delete CDiscoverer object,checks for any memory leak.
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
LOCAL_C void OOMCreateDeleteTest()
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0724 OOM CreateDeleteTest "));
	TInt err;
	TInt failAt = 1;
	__UNUSED_VAR(failAt);

	CDiscovererTest* discTest = NULL;

	do
		{
		__UHEAP_MARK;
  		// find out the number of open handles
		TInt startProcessHandleCount;
		TInt startThreadHandleCount;
		RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);

		__UHEAP_SETFAIL(RHeap::EDeterministic, failAt++);

		TRAP(err, discTest = CDiscovererTest::NewL());

		__UHEAP_SETFAIL(RHeap::ENone, 0);

		delete discTest;
		discTest = NULL;

		// check that no handles have leaked
		TInt endProcessHandleCount;
		TInt endThreadHandleCount;
		RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);

		test(startProcessHandleCount == endProcessHandleCount);
		test(startThreadHandleCount  == endThreadHandleCount);

		__UHEAP_MARKEND;
		}
	while(err == KErrNoMemory);

	test.Printf(_L("- Succeeded at heap failure rate of %i\n"), failAt);
	test(err == KErrNone);
	}

// Type definition for pointer to member function.
// Used in calling the CDiscovererTest member function for testing.
typedef void (CDiscovererTest::*ClassFuncPtrL) (void);

/**
@SYMTestCaseID          SYSLIB-ECOM-CT-0725
@SYMTestCaseDesc	    Function to call all test functions
@SYMTestPriority 	    High
@SYMTestActions  	    Calls up test function of CDiscovererTest.
@SYMTestExpectedResults The test must not fail.
@SYMREQ                 REQ0000
*/
/**
Wrapper function to call all test functions

@param		testFunc pointer to test function
@param		aTestDesc test function name
*/
LOCAL_C void DoBasicTestL(ClassFuncPtrL testFuncL, const TDesC& aTestDesc)
	{
	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-0725 "));
	test.Next(aTestDesc);

	__UHEAP_MARK;
  	// find out the number of open handles
	TInt startProcessHandleCount;
	TInt startThreadHandleCount;
	RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);

	CDiscovererTest* discTest = CDiscovererTest::NewL();
	CleanupStack::PushL(discTest);

	(discTest->*testFuncL)();

	CleanupStack::PopAndDestroy(discTest);

	// check that no handles have leaked
	TInt endProcessHandleCount;
	TInt endThreadHandleCount;
	RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);

	test(startProcessHandleCount == endProcessHandleCount);
	test(startThreadHandleCount  == endThreadHandleCount);

	__UHEAP_MARKEND;
	}

/**
Utility function to continually invoke a test function and cause memory allocation failures

@param		testFuncL pointer to OOM test function
@param	 	tryCount specifies what value to start memory allocation failures at
@param		increment how much to increase the point at which memory allocation will fail on each test attempt
@param		stopCount the value of memory allocation failure to stop testing at
*/
TInt RunTestUnderOOMCondition(ClassFuncPtrL testFuncL, TInt tryCount, TInt increment, TInt stopCount)
{
	TInt err = KErrNone;

	do
		{

		__UHEAP_MARK;
  		// find out the number of open handles
		TInt startProcessHandleCount;
		TInt startThreadHandleCount;
		RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);

		CDiscovererTest* discTest = CDiscovererTest::NewL();
		CleanupStack::PushL(discTest);


		__UHEAP_SETFAIL(RHeap::EDeterministic, tryCount);
		TRAP(err, (discTest->*testFuncL)());
		__UHEAP_SETFAIL(RHeap::ENone, 0);


		CleanupStack::PopAndDestroy(discTest);
		discTest = NULL;

		// check that no handles have leaked
		TInt endProcessHandleCount;
		TInt endThreadHandleCount;
		RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);

		test(startProcessHandleCount == endProcessHandleCount);
		test(startThreadHandleCount  == endThreadHandleCount);

		__UHEAP_MARKEND;

	 	tryCount = tryCount + increment;
		} while((err == KErrNoMemory) && (tryCount != stopCount));

		tryCount = tryCount - increment;


		if (err == KErrNoMemory)
		{
			// test has not yet been able to pass due to memory allocation failures.
			return -1;
		}

		test(err == KErrNone);

	 	// If enough memory has finally been allocated for the test to pass then return
		// the memory allocation counter value.
		test.Printf(_L("- server succeeded at heap failure rate of %i\n"), tryCount);
		return tryCount;
}

/**
Wrapper function to call all OOM test functions

@param		testFuncL pointer to OOM test function
@param		aTestDesc test function name
*/
LOCAL_C void DoOOMTestL(ClassFuncPtrL testFuncL, const TDesC& aTestDesc)
	{
	test.Next(aTestDesc);

	TInt startCount = 1;
	TInt increment = 1;
	TInt successRate = -1;
	TInt stopCount = 256;

 	successRate = RunTestUnderOOMCondition(testFuncL, startCount, increment, stopCount);

 	// (INC115057)
 	// When method CDiscoverer::CDirScanner::DoScanDriveL is encountered in a test hundreds
 	// of plug-in files will be scanned. It takes in the order of 3-4000 memory allocation failure
 	// loops (in techview context) before the scan is finished and the test can complete successfully.
 	// This will take over an hour. Instead determine the approximate failure point by
 	// testing with large increments between failures. Once a failure rate interval is found test
 	// for OOM conditions running up to it.
 	// This in effect means that we are checking OOM at the start and end of tests but skipping
 	// the scanning of each and every plugin in the middle of the test.
 	// (Note that CDiscoverer::CDirScanner::DoScanDriveL may return without leaving when it
 	// can't allocate TFileName. In this case it seems to this function that the test is
 	// successful. Therefore even if the successRate above indicates a pass the test is still
 	// re-run below with larger memory allocation failure valued to make sure that the test does
 	// in fact run to completion.

 		startCount = 256;
 		increment = 256;
 		stopCount = -1;
 		successRate = RunTestUnderOOMCondition(testFuncL, startCount, increment, stopCount);
 		test(successRate > 0);

 		if (successRate > 256)
 		{
 			startCount = successRate - 256;
 			increment = 1;
 			stopCount = -1;
 			successRate = RunTestUnderOOMCondition(testFuncL, startCount, increment, stopCount);
 		}

 	test(successRate > 0);
	}

/**
Creates and installs active scheduler for this thread and calls
CDiscovererTest::IdleScanningTimerRunErrorL

@param		aDiscTest The CDiscovererTest object used to carry out the test
*/
LOCAL_C	void DoIdleScanningTimerRunErrorTestL(CDiscovererTest* aDiscTest)
	{

	// create and install the active scheduler we need
	CActiveScheduler* scheduler=new(ELeave) CActiveScheduler;
	CleanupStack::PushL(scheduler);

	CActiveScheduler::Install(scheduler);

	aDiscTest->IdleScanningTimerRunErrorL();

	// Cleanup CDiscovererTest, TheFs and scheduler
	CleanupStack::PopAndDestroy(scheduler);

	}
/**
Thread entry point for the test thread.  Creates a CTrapCleanup and
calls  DoIdleScanningTimerRunErrorTestL to carry out the test

@param		aDiscTest The CDiscovererTest object used to carry out the test
*/
LOCAL_C TInt IdleScanningTimerRunErrorThreadEntry(TAny* aDiscTest)
	{

	CTrapCleanup* tc = CTrapCleanup::New();

	CDiscovererTest *discTest = static_cast<CDiscovererTest*>(aDiscTest);

	TRAPD(err,DoIdleScanningTimerRunErrorTestL(discTest));

	delete tc;

	return err;

	}


/**
@SYMTestCaseID		SYSLIB-ECOM-CT-3165
@SYMTestCaseDesc 	Check that the CIdleScanningTimer::RunError() works correctly.
@SYMTestPriority 	High
@SYMTestActions  	Create a new thread which will call RunError.  Wait for the
					thread to exit and check the thread exit type and reason
					to verify behaviour
@SYMTestExpectedResults The test must not fail.
@SYMDEF DEF094675
*/
LOCAL_C void IdleScanningTimer_RunErrorTest()
	{
	__UHEAP_MARK;

	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-3165 CIdleScanningTimer RunError test "));

	_LIT(KStartThreadName,"CIdleScanningTimer RunError Thread");

	//Disable JIT so that the Panic doesn't bring up a dialog
	//and stop the test
	TBool jitEnabled = User::JustInTime();
	User::SetJustInTime(EFalse);

	//Create a CDiscovererTest object to pass into the test thread
	CDiscovererTest* discTest = CDiscovererTest::NewL();
	CleanupStack::PushL(discTest);

	//Create a new thread to run the test
	RThread testThread;
	testThread.Create(KStartThreadName, IdleScanningTimerRunErrorThreadEntry,
					KDefaultStackSize,KMinHeapSize,KMinHeapSize,discTest);
	TRequestStatus status;
	testThread.Logon(status);


	testThread.Resume();

	//Wait for the thread to exit
	User::WaitForRequest(status);

	//Obtain exit type and reason for test thread
	TExitType exitType = testThread.ExitType();
	TInt exitReason = testThread.ExitReason();

	//close the thread handle
	testThread.Close();

	CleanupStack::PopAndDestroy(discTest);

	//Set JIT back to original state
	User::SetJustInTime(jitEnabled);

	//Verify the exit reason and exit code
	test(exitType == EExitPanic);
	test(exitReason == EEComPanic_CDiscoverer_CIdleScanningTimer_RunError);

	__UHEAP_MARKEND;
	}

/**
Creates and installs active scheduler for this thread and calls
CDiscovererTest::DirChangeNotifierRunErrorL

@param		aDiscTest The CDiscovererTest object used to carry out the test
*/
LOCAL_C void DoDirChangeNotifierRunErrorTestL(CDiscovererTest* aDiscTest)
	{

	// create and install the active scheduler we need
	CActiveScheduler* scheduler=new(ELeave) CActiveScheduler;
	CleanupStack::PushL(scheduler);

	CActiveScheduler::Install(scheduler);

	//call the RunErrorL method which should panic
	aDiscTest->DirChangeNotifierRunErrorL();

	// Cleanup CDiscovererTest, TheFs and scheduler
	CleanupStack::PopAndDestroy(scheduler);

	}

/**
Thread entry point for the test thread.  Creates a CTrapCleanup and
calls  DoDirChangeNotifierRunErrorTestL to carry out the test

@param		aDiscTest The CDiscovererTest object used to carry out the test
*/
LOCAL_C TInt DirChangeNotifierRunErrorThreadEntry(TAny* aDiscTest)
	{

	CTrapCleanup* tc = CTrapCleanup::New();

	CDiscovererTest *discTest = static_cast<CDiscovererTest*>(aDiscTest);

	TRAPD(err,DoDirChangeNotifierRunErrorTestL(discTest));

	delete tc;

	return err;

	}

/**
@SYMTestCaseID		SYSLIB-ECOM-CT-3166
@SYMTestCaseDesc 	Check that the CDirChangeNotifier::RunError() works correctly.
@SYMTestPriority 	High
@SYMTestActions  	Create a new thread which will call RunError.  Wait for the
					thread to exit and check the thread exit type and reason
					to verify behaviour
@SYMTestExpectedResults The test must not fail.
@SYMDEF DEF094675
*/
LOCAL_C void DirChangeNotifier_RunErrorTest()
	{
	__UHEAP_MARK;

	test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-3166 CDirChangeNotifier RunError test "));

	_LIT(KStartThreadName,"CDirChangeNotifier RunError Thread");

	//Disable JIT so that the Panic doesn't bring up a dialog
	//and stop the test
	TBool jitEnabled = User::JustInTime();
	User::SetJustInTime(EFalse);

	//Create a CDiscovererTest object to pass into the test thread
	CDiscovererTest* discTest = CDiscovererTest::NewL();
	CleanupStack::PushL(discTest);

	//Create a new thread to run the test
	RThread testThread;
	testThread.Create(KStartThreadName, DirChangeNotifierRunErrorThreadEntry,
					KDefaultStackSize,KMinHeapSize,KMinHeapSize,discTest);
	TRequestStatus status;
	testThread.Logon(status);
	testThread.Resume();

	//Wait for the thread to exit
	User::WaitForRequest(status);

	//Obtain exit type and reason for test thread
	TExitType exitType = testThread.ExitType();
	TInt exitReason = testThread.ExitReason();

	//close the thread handle
	testThread.Close();

	CleanupStack::PopAndDestroy(discTest);

	//Set JIT back to original state
	User::SetJustInTime(jitEnabled);

	//Verify the exit reason and exit code
	test(exitType == EExitPanic);
	test(exitReason == EEComPanic_CDiscoverer_CDirChangeNotifier_RunError);

	__UHEAP_MARKEND;
	}

TInt DoTestsL()
	{
	__UHEAP_MARK;

	// Basic tests
	CreateDeleteTestL();
	DoBasicTestL(&CDiscovererTest::ResumeSuspendTestL, _L("ResumeSuspendTestL"));
	DoBasicTestL(&CDiscovererTest::DriveMountUnmountTestL, _L("DriveMountUnmountTestL"));
	DoBasicTestL(&CDiscovererTest::ProcessEntryTestL, _L("ProcessEntryTestL"));
	DoBasicTestL(&CDiscovererTest::ValidateEntryTestL, _L("ValidateEntryTestL"));
	DoBasicTestL(&CDiscovererTest::ProcessSpiEntryTestL, _L("ProcessSpiEntryTestL"));
	DoBasicTestL(&CDiscovererTest::ValidateSpiEntryTestL, _L("ValidateSpiEntryTestL"));
	DoBasicTestL(&CDiscovererTest::ProcessEntryPlugIn3TestL, _L("ProcessEntryPlugIn3TestL"));
	DoBasicTestL(&CDiscovererTest::ValidateEntryPlugIn3TestL, _L("ValidateEntryPlugIn3TestL"));
	DoBasicTestL(&CDiscovererTest::ProcessSpiEntryPlugIn3TestL, _L("ProcessSpiEntryPlugIn3TestL"));
	DoBasicTestL(&CDiscovererTest::ValidateSpiEntryPlugIn3TestL, _L("ValidateSpiEntryPlugIn3TestL"));
	DoBasicTestL(&CDiscovererTest::ValidateSpiPluginsTestL, _L("ValidateSpiPluginsTestL"));
	DoBasicTestL(&CDiscovererTest::ScanDirectoryIncrementTestL, _L("ScanDirectoryIncrementTestL"));
	DoBasicTestL(&CDiscovererTest::StagedDiscoveryStateTransitionTestL, _L("StagedDiscoveryStateTransitionTestL"));
	DoBasicTestL(&CDiscovererTest::AllAtOnceDiscoveryStateTransitionTestL, _L("AllAtOnceDiscoveryStateTransitionTestL"));
	DoBasicTestL(&CDiscovererTest::ScanDirectoryTestL, _L("ScanDirectoryTestL"));
	DoBasicTestL(&CDiscovererTest::MultipleNotificationProcessingTestL, _L("MultipleNotificationProcessingTestL"));
	DoBasicTestL(&CDiscovererTest::LanguageChangedNotificationTestL, _L("MLanguageChangedNotificationTestL"));
	DoBasicTestL(&CDiscovererTest::SWINotificationProcessingTestL, _L("SWINotificationProcessingTestL"));

	//RunError tests
	IdleScanningTimer_RunErrorTest();
	DirChangeNotifier_RunErrorTest();

	// OOM tests
	OOMCreateDeleteTest();
	// This test is not performed because the error from the final memory allocation failures are not
	// propagated back to the calling function and cannot be dealt with. Therefore
	// this test does not complete. However the normal test is performed above.
	//DoOOMTestL(&CDiscovererTest::ResumeSuspendTestL, _L("OOM ResumeSuspendTestL"));
	DoOOMTestL(&CDiscovererTest::DriveMountUnmountTestL, _L("OOM DriveMountUnmountTestL"));
	DoOOMTestL(&CDiscovererTest::ProcessEntryTestL, _L("OOM ProcessEntryTestL"));
	DoOOMTestL(&CDiscovererTest::ProcessSpiEntryTestL, _L("OOM ProcessSpiEntryTestL"));
	DoOOMTestL(&CDiscovererTest::ValidateSpiEntryTestL, _L("OOM ValidateSpiEntryTestL"));
	DoOOMTestL(&CDiscovererTest::ValidateEntryTestL, _L("OOM ValidateEntryTestL"));
	DoOOMTestL(&CDiscovererTest::ProcessEntryPlugIn3TestL, _L("OOM ProcessEntryPlugIn3TestL"));
	DoOOMTestL(&CDiscovererTest::ProcessSpiEntryPlugIn3TestL, _L("OOM ProcessSpiEntryPlugIn3TestL"));
	DoOOMTestL(&CDiscovererTest::ValidateSpiEntryPlugIn3TestL, _L("OOM ValidateSpiEntryPlugIn3TestL"));
	DoOOMTestL(&CDiscovererTest::ValidateEntryPlugIn3TestL, _L("OOM ValidateEntryPlugIn3TestL"));
	DoOOMTestL(&CDiscovererTest::ScanDirectoryIncrementTestL, _L("OOM ScanDirectoryIncrementTestL"));
	DoOOMTestL(&CDiscovererTest::StagedDiscoveryStateTransitionTestL, _L("StagedDiscoveryStateTransitionTestL"));
	DoOOMTestL(&CDiscovererTest::AllAtOnceDiscoveryStateTransitionTestL, _L("AllAtOnceDiscoveryStateTransitionTestL"));
	DoOOMTestL(&CDiscovererTest::ScanDirectoryTestL, _L("OOM ScanDirectoryTestL"));
	// This test is not performed because the error from the final memory allocation failures are not
	// propagated back to the calling function and cannot be dealt with. Therefore
	// this test does not complete. However the normal test is performed above.
	//DoOOMTestL(&CDiscovererTest::MultipleNotificationProcessingTestL, _L("MultipleNotificationProcessingTestL"));
	// This test is not performed because the error from the final memory allocation failures are not
	// propagated back to the calling function and cannot be dealt with. Therefore
	// this test does not complete. However the normal test is performed above.
	//DoOOMTestL(&CDiscovererTest::SWINotificationProcessingTestL, _L("OOM SWINotificationProcessingTestL"));

	__UHEAP_MARKEND;
	return KErrNone;
	}

// Copy the Plugins to specific folder for testing purpose
LOCAL_C void CopyPlugins()
	{
	TInt err=KErrNone;
	TRAP(err, EComTestUtils::FileManCopyFileL(KNewResourceFileNameOnZ, KNewResourceFileName));
	test(err==KErrNone);
	TRAP(err, EComTestUtils::FileManCopyFileL(KNewExampleDllFileNameOnZ, KNewExampleDllFileName));
	test(err==KErrNone);
	TRAP(err, EComTestUtils::FileManCopyFileL(KPlugIn3ResourceFileNameOnZ, KPlugIn3ResourceFileName));
	test(err==KErrNone);
	TRAP(err, EComTestUtils::FileManCopyFileL(KPlugIn3ExampleDllFileNameOnZ, KPlugIn3ExampleDllFileName));
	test(err==KErrNone);
	}

// Deleting plugin from the RAM for cleanup purpose
inline LOCAL_C void DeleteTestPlugin()
	{
	TInt err=KErrNone;
	TRAP(err, EComTestUtils::FileManDeleteFileL(KNewResourceFileName));
	TRAP(err, EComTestUtils::FileManDeleteFileL(KNewExampleDllFileName));
	TRAP(err, EComTestUtils::FileManDeleteFileL(KPlugIn3ResourceFileName));
	TRAP(err, EComTestUtils::FileManDeleteFileL(KPlugIn3ExampleDllFileName));
	}

//
//Initialise the Active Scheduler
//
LOCAL_C void SetupL()
	{
	// Construct and install the Active Scheduler. The Active Schedular is needed
	// by components used by this test as they are ActiveObjects.
	TheActiveScheduler = new(ELeave)CActiveScheduler;
	CActiveScheduler::Install(TheActiveScheduler);
	}

GLDEF_C TInt E32Main()
	{
	__UHEAP_MARK;

	test.Printf(_L("\n"));
	test.Title();
	test.Start(_L("Discoverer Tests."));

	TheTrapCleanup = CTrapCleanup::New();

	TRAPD(err, SetupL());
	test(err == KErrNone);

	// Connect the file server instance
	User::LeaveIfError(TheFs.Connect());

	CopyPlugins();

	// The reason for the folowing delay is:
	// ECOM server could be already started. It means that when we copy some
	// ECOM plugins from Z: to C: drive - ECOM server should look for and
	// find the new ECOM plugins. The ECOM server uses for that an active object,
	// which scans plugin directories. So the discovering service is asynchronous.
	// We have to wait some time until it finishes.
	// Otherwise ListImplementationsL could fail to find requested implementations.
	User::After(KOneSecond * 3);


	// Call the main tests
	TRAP(err, DoTestsL());
	test(err == KErrNone);

	// Cleanup files. If the cleanup fails that is no problem,
	// as any subsequent tests will replace them. The only downside
	// would be the disk not being tidied
	DeleteTestPlugin();

	TheFs.Close();

	delete TheActiveScheduler;
	delete TheTrapCleanup;

	test.End();
	test.Close();

	__UHEAP_MARKEND;
	return (KErrNone);
	}