// Copyright (c) 2008-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:
// t_msv_cache_indextableentry_step.cpp
//

#include "t_msv_cache_indextableentry_step.h"
#include <msvids.h>
#include <flogger.h>
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
#include "msvconsts.h"
#endif

#define MY_ASSERT_TRUE(a)  \
		INFO_PRINTF1(KFunction);   \
		ASSERT_TRUE(a);
#define MY_ASSERT_FALSE(a)  \
		INFO_PRINTF1(KFunction);   \
		ASSERT_FALSE(a);
#define MY_ASSERT_EQUALS(a,b)  \
		INFO_PRINTF1(KFunction);   \
		ASSERT_EQUALS(a,b);

		
_LIT(KSTDMSGINI, "C:\\private\\1000484b\\msgcache.ini");
_LIT(KMSGINI_2, "C:\\private\\1000484b\\msgcache2.ini");


CTestIndexTableEntry::CTestIndexTableEntry()
	{
	}

CTestIndexTableEntry::~CTestIndexTableEntry()
	{
	
	}

void CTestIndexTableEntry::SetupL()
	{
	_LIT(KFunction, "SetupL");
	INFO_PRINTF1(KFunction);
	
	//__UHEAP_MARK;
	
	TInt err =	iFileHandle.Connect();
	MY_ASSERT_EQUALS(err, KErrNone);
	//err = iFileHandle.Replace(KMSGINI_2, KSTDMSGINI);
	CFileMan* file = CFileMan::NewL(iFileHandle);
	err = file->Copy(KMSGINI_2, KSTDMSGINI);
	MY_ASSERT_EQUALS(err, KErrNone);
	delete file;

	//Create entry free pool.
	TDblQue<CMsvCacheVisibleFolder> iEntryCache;
	iMsvEntryFreePool = CMsvEntryFreePool::CreateL(&iEntryCache);
	
	//create index table entry
	iIndexTableEntry = CMsvCacheIndexTableEntry::NewL();
	iEntryPointer = new(ELeave) RPointerArray<CMsvCacheEntry>;

	}

void CTestIndexTableEntry::TearDownL()
	{
	_LIT(KFunction, "TearDownL");
	INFO_PRINTF1(KFunction);
	
	//destroy the index table entry
	delete iIndexTableEntry;
	if(iEntryPointer)
		{
		iEntryPointer->Close();
		delete iEntryPointer;
		iEntryPointer = NULL;
		}
	
	//iFileHandle.Replace(KSTDMSGINI, KMSGINI_2);
	iFileHandle.Close();
	
	// Delete entry free pool.
#ifdef _DEBUG
	CMsvEntryFreePool::Destroy(iMsvEntryFreePool);
	iMsvEntryFreePool = NULL;
#else
	delete iMsvEntryFreePool;
	iMsvEntryFreePool = NULL;
#endif
	
	//__UHEAP_MARKEND;
	}

void CTestIndexTableEntry::TestConstructorL()
	{
	_LIT(KFunction, "TestConstructorL");
	INFO_PRINTF1(KFunction);
	
	//Test whether a Index table entry is created correctly.
	CMsvCacheIndexTableEntry* tempTableEntry = NULL;
	TRAPD(err, tempTableEntry = new(ELeave) CMsvCacheIndexTableEntry);
	MY_ASSERT_EQUALS(KErrNone, err);
	MY_ASSERT_TRUE(tempTableEntry->BlockPtr() == NULL);
	MY_ASSERT_TRUE(tempTableEntry->GetMaxMsvIdRange() == 0);
	MY_ASSERT_TRUE(tempTableEntry->GetMinMsvIdRange() == 0);
	MY_ASSERT_FALSE(tempTableEntry->IsGrandChildPresent());
	MY_ASSERT_FALSE(tempTableEntry->IsDirty());
	delete tempTableEntry;

	//Test the same using NewL
	TRAP(err, tempTableEntry = CMsvCacheIndexTableEntry::NewL());
	MY_ASSERT_EQUALS(KErrNone, err);
	MY_ASSERT_TRUE(tempTableEntry->BlockPtr() == NULL);
	MY_ASSERT_TRUE(tempTableEntry->GetMaxMsvIdRange() == 0);
	MY_ASSERT_TRUE(tempTableEntry->GetMinMsvIdRange() == 0);
	MY_ASSERT_FALSE(tempTableEntry->IsGrandChildPresent());
	MY_ASSERT_FALSE(tempTableEntry->IsDirty());
	delete tempTableEntry;

	//Test creation with addition of one cache entry
	CMsvCacheEntry* entry = NULL;
	TRAP(err, entry = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entry->Entry().SetId((TMsvId)50);
	entry->Entry().SetParent((TMsvId)25);
	TRAP(err, tempTableEntry = CMsvCacheIndexTableEntry::NewL(entry));
	MY_ASSERT_EQUALS(KErrNone, err);
	MY_ASSERT_TRUE(tempTableEntry->BlockPtr() != NULL);
	MY_ASSERT_TRUE(tempTableEntry->GetMaxMsvIdRange() == 50);
	MY_ASSERT_TRUE(tempTableEntry->GetMinMsvIdRange() == 50);
	MY_ASSERT_FALSE(tempTableEntry->IsGrandChildPresent());
	MY_ASSERT_FALSE(tempTableEntry->IsDirty());
	MY_ASSERT_TRUE(tempTableEntry->GetEntry((TMsvId)50, entry));
	delete tempTableEntry;

	//Test the same using NewLC
	TRAP(err, entry = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entry->Entry().SetId((TMsvId)50);
	entry->Entry().SetParent((TMsvId)25);
	tempTableEntry = CMsvCacheIndexTableEntry::NewLC(entry);
	MY_ASSERT_TRUE(tempTableEntry->BlockPtr() != NULL);
	MY_ASSERT_TRUE(tempTableEntry->GetMaxMsvIdRange() == 50);
	MY_ASSERT_TRUE(tempTableEntry->GetMinMsvIdRange() == 50);
	MY_ASSERT_FALSE(tempTableEntry->IsGrandChildPresent());
	MY_ASSERT_FALSE(tempTableEntry->IsDirty());
	MY_ASSERT_TRUE(tempTableEntry->GetEntry((TMsvId)50, entry));
	CleanupStack::Pop(); //tempTableEntry
	delete tempTableEntry;

	//Test creation with addition of list of entries
	RPointerArray<CMsvCacheEntry> addList;
	for(TInt index = 0; index < 10; ++index)
		{
		TRAP(err, entry = CMsvEntryFreePool::Instance()->EntryL());
		MY_ASSERT_EQUALS(KErrNone, err);
		entry->Entry().SetId((TMsvId)50+index);
		entry->Entry().SetParent((TMsvId)25);
		TRAP(err, addList.AppendL(entry));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	TRAP(err, tempTableEntry = CMsvCacheIndexTableEntry::NewL(addList));
	MY_ASSERT_EQUALS(KErrNone, err);
	MY_ASSERT_TRUE(tempTableEntry->BlockPtr() != NULL);
	MY_ASSERT_TRUE(tempTableEntry->Size() == 10);
	delete tempTableEntry;

	//Test the same using NewLC
	addList.Reset();
	for(TInt index = 0; index < 10; ++index)
		{
		TRAP(err, entry = CMsvEntryFreePool::Instance()->EntryL());
		MY_ASSERT_EQUALS(KErrNone, err);
		entry->Entry().SetId((TMsvId)50+index);
		entry->Entry().SetParent((TMsvId)25);
		TRAP(err, addList.AppendL(entry));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	tempTableEntry = CMsvCacheIndexTableEntry::NewLC(addList);
	MY_ASSERT_TRUE(tempTableEntry->BlockPtr() != NULL);
	MY_ASSERT_TRUE(tempTableEntry->Size() == 10);
	CleanupStack::Pop(); //tempTableEntry
	delete tempTableEntry;
	addList.Close();
	}
	
void CTestIndexTableEntry::TestAddEntry()
	{

	_LIT(KFunction, "TestAddEntry");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt bulkCount = 100;
	
	TMsvId msvId = KFirstFreeEntryId;
	
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	
	// t1. add single entry to empty block
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
	TRAP(err, entryA = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryA->Entry().SetId(++msvId);
	++msvId;
	TTime timeBefore = iIndexTableEntry->AccessTime();
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryA->GetId()));
	User::After(1000);
	TTime timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), entryA->GetId());
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entryA->GetId());
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	
	
	// t2. add entry to non-empty block
	TRAP(err, entryB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryB->Entry().SetId(++msvId);
	++msvId;
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryB->GetId()));
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entryB->GetId());
	
	
	// t3. add duplicate entry
	//---3.1 older entry has details to be preserved
	TInt sizeBefore = iIndexTableEntry->Size();
	CMsvCacheEntry *dupB = NULL;
	TRAP(err, dupB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	dupB->Entry().SetId(entryB->GetId());
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntryL(dupB)); //replace older entry = EFalse (default)
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryB->GetId()));
	RPointerArray<CMsvCacheEntry>* blockPtr = iIndexTableEntry->BlockPtr();
	for(TInt index = 0; index < sizeBefore; ++index) //entries have different address
		{
		if( (*blockPtr)[index]->GetId() == entryB->GetId() )
			{
			MY_ASSERT_TRUE( &(*blockPtr)[index] != &dupB );
			}
		}
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore == timeAfter);
	TInt sizeAfter = iIndexTableEntry->Size();
	MY_ASSERT_EQUALS(sizeBefore, sizeAfter);
	//---3.2 newer entry has more recent details
	TRAP(err, entryD = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryD->Entry().SetId(++msvId);
	++msvId;
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntryL(entryD));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter); 
	CMsvCacheEntry *dupD = NULL;
	TRAP(err, dupD = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	dupD->Entry().SetId(entryD->GetId());
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntryL(dupD, ETrue)); //replace older entry = ETrue
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(dupD->GetId()));
	for(TInt index = 0; index < sizeBefore; ++index) //entries have different address
		{
		if( (*blockPtr)[index]->GetId() == dupD->GetId() )
			{
			MY_ASSERT_TRUE( (*blockPtr)[index] != entryD );
			}
		}
	MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(entryD->GetId()));
	timeAfter = iIndexTableEntry->AccessTime();
	//MY_ASSERT_TRUE(timeBefore != timeAfter);
	
	
	// t4. add entry with TMsvId < iMinMsvId
	TMsvId minId = iIndexTableEntry->GetMinMsvIdRange();
	TRAP(err, entryC = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryC->Entry().SetId(minId - 1);
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), entryC->GetId());
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	
	
	// t5. add entry with TMsvId > iMaxMsvId
	TMsvId maxId = iIndexTableEntry->GetMaxMsvIdRange();
	TRAP(err, entryD = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryD->Entry().SetId(maxId + 1);
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntryL(entryD));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entryD->GetId());
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
		
	
	// t6. add large amount of entries
	TMsvId id = msvId + 10;
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		timeBefore = iIndexTableEntry->AccessTime();
		User::After(1000);
		TRAP(err, iIndexTableEntry->AddEntryL((entries[index])));
		ASSERT_EQUALS(err, KErrNone);
		timeAfter = iIndexTableEntry->AccessTime();
		ASSERT_TRUE(timeBefore != timeAfter);
		}
	for(TInt index = 0; index < bulkCount; ++index)
		{
		ASSERT_TRUE(iIndexTableEntry->EntryExists(tmsvEntries[index].Id()));
		}
	
	tmsvEntries.Close();
	entries.Close();
	}

void CTestIndexTableEntry::TestAddEntrySet()
	{
	_LIT(KFunction, "TestAddEntrySet");
	INFO_PRINTF1(KFunction);
	
	TInt err, index;
	TInt bulkCount = 5; //100;
	TTime timeBefore, timeAfter;
	
	TMsvId msvId = KFirstFreeEntryId;
	
	TMsvId id = msvId + 500;
	RPointerArray<CMsvCacheEntry> oEntries;
		
	// T1:	block is NULL. add only non-immediate children.
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
		
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count()));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	for(index = 0; index < bulkCount; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entries[index]->GetId()));
		}
		
	//---add entries less than those in aEntries
	iIndexTableEntry->ReleaseBlock(ETrue);
	iEntryPointer->Reset();
	entries.Reset();
	tmsvEntries.Reset();
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TInt aCount = 3;
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, aCount));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	for(index = 0; index < aCount; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entries[index]->GetId()));
		}
	MY_ASSERT_EQUALS(iIndexTableEntry->Size(), aCount);
	for(index = aCount; index < bulkCount; ++index) //manually release remaining entries
		{
		CMsvEntryFreePool::Instance()->ReleaseEntry(entries[index]);
		}
	
	//---aCount > aEntries.Count()
	iIndexTableEntry->ReleaseBlock(ETrue);
	iEntryPointer->Reset();
	entries.Reset();
	tmsvEntries.Reset();
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	 aCount = bulkCount + 10;
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, aCount));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	for(index = 0; index < bulkCount; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entries[index]->GetId()));
		}
	MY_ASSERT_EQUALS(iIndexTableEntry->Size(), bulkCount);
	
	//---[aInitIndex..aCount] < [0..bulkCount]
	iIndexTableEntry->ReleaseBlock(ETrue);
	iEntryPointer->Reset();
	entries.Reset();
	tmsvEntries.Reset();
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TInt aInitIndex = 1;
	aCount = 3;
	//entries added are entries[1] to entries[3]. 0 and 4 are left out.
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, aInitIndex, aCount));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	for(index = aInitIndex; index < aCount+aInitIndex; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entries[index]->GetId()));
		}
	MY_ASSERT_EQUALS(iIndexTableEntry->Size(), aCount);
	CMsvEntryFreePool::Instance()->ReleaseEntry(entries[0]);
	CMsvEntryFreePool::Instance()->ReleaseEntry(entries[4]);
		
	//---out of bounds index
	iIndexTableEntry->ReleaseBlock(ETrue);
	iEntryPointer->Reset();
	entries.Reset();
	tmsvEntries.Reset();
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	aInitIndex = -1;
	aCount = 3;
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, aInitIndex, aCount));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore == timeAfter);
	for(index = 0; index < bulkCount; ++index)
		{
		MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(entries[index]->GetId()));
		}
	MY_ASSERT_EQUALS(iIndexTableEntry->Size(), 0);
	for(index = 0; index < bulkCount; ++index)
		{
		CMsvEntryFreePool::Instance()->ReleaseEntry(entries[index]);
		}
		

	
	// T2:	block is NULL. add only immediate children.
	// start afresh.
	iIndexTableEntry->ReleaseBlock(ETrue);
	msvId = KFirstFreeEntryId;
	TRAP(err, parent = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	parent->Entry().SetId(++msvId);
	++msvId;
	TRAP(err, entryA = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryA->Entry().SetId(++msvId);
	++msvId;
	TRAP(err, entryB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryB->Entry().SetId(++msvId);
	++msvId;
	TRAP(err, entryC = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryC->Entry().SetId(++msvId);
	++msvId;
	iEntryPointer->Reset();
	entries.Reset();
	tmsvEntries.Reset();
	
	TRAP(err, iEntryPointer->AppendL(parent));
	MY_ASSERT_EQUALS(KErrNone, err);
	entryA->Entry().SetParent(parent->GetId());
	TRAP(err, iEntryPointer->AppendL(entryA));
	MY_ASSERT_EQUALS(KErrNone, err);
	entryB->Entry().SetParent(parent->GetId());
	TRAP(err, iEntryPointer->AppendL(entryB));
	MY_ASSERT_EQUALS(KErrNone, err);
	entryC->Entry().SetParent(parent->GetId());
	TRAP(err, iEntryPointer->AppendL(entryC));
	MY_ASSERT_EQUALS(KErrNone, err);
	
	id = msvId;
	
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		entries[index]->Entry().SetParent(parent->GetId());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count()));
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	oEntries.Reset();
	TRAP(err, iIndexTableEntry->GetChildrenL(parent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(oEntries.Count(), bulkCount + 4); 
	for(index = 0; index < bulkCount; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(tmsvEntries[index].Id()));
		}
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryA->GetId()));
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryB->GetId()));
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryC->GetId()));
	
	
	// T3:	block is not NULL. add only non-immediate children. there are immediate 
	//		children present in the old block.
	//start fresh
	iIndexTableEntry->ReleaseBlock(ETrue);
	iEntryPointer->Reset();
	entries.Reset();
	tmsvEntries.Reset();
	
	
	TRAP(err, parent = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	parent->Entry().SetId(++id);
	++id;
	TRAP(err, entryA = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, entryB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryB->Entry().SetId(++id);
	++id;
	
	
	TRAP(err, iIndexTableEntry->AddEntryL(parent));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone); //A and B are non-immediate children
	
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		entries[index]->Entry().SetParent(parent->GetId());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count())); //add some children
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	for(index = 0; index < bulkCount; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(tmsvEntries[index].Id()));
		}
	MY_ASSERT_EQUALS(iIndexTableEntry->Size(), 3 + bulkCount);
	
	entries.Reset();
	tmsvEntries.Reset();
	iEntryPointer->Reset();
	CMsvCacheEntry *dupA = NULL;
	TRAP(err, dupA = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	dupA->Entry().SetId(entryA->GetId());
	CMsvCacheEntry *dupB = NULL;
	TRAP(err, dupB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	dupB->Entry().SetId(entryB->GetId());
	TMsvId entryAId = entryA->GetId();
	TMsvId entryBId = entryB->GetId();
	TRAP(err, iEntryPointer->AppendL(dupA));
	MY_ASSERT_EQUALS(KErrNone, err);
	TRAP(err, iEntryPointer->AppendL(dupB)); //A and B are duplicates in the new list
	MY_ASSERT_EQUALS(KErrNone, err);
	for(index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count())); //add some non-immediate children
	MY_ASSERT_EQUALS(err, KErrNone);
	iIndexTableEntry->SetGrandChildPresent();
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeBefore != timeAfter);
	//MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryAId));
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryBId));
	//MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entries[entries.Count() - 1]->GetId());
	for(index = 0; index < bulkCount; ++index)
		{
		MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(tmsvEntries[index].Id()));
		}
	oEntries.Reset();
	TRAP(err, iIndexTableEntry->GetChildrenL(parent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(oEntries.Count(), bulkCount);
	MY_ASSERT_EQUALS(iIndexTableEntry->Size(), 3 + bulkCount + bulkCount);
	
	iIndexTableEntry->ReleaseBlock(ETrue);
	
	oEntries.Reset();
	
	entries.Reset();
	entries.Close();
	tmsvEntries.Reset();
	tmsvEntries.Close();
	iEntryPointer->Reset();
	}

void CTestIndexTableEntry::TestGetEntry()
	{
	_LIT(KFunction, "TestGetEntry");
	INFO_PRINTF1(KFunction);
	
	CMsvCacheEntry *oEntry = NULL;
	TBool ret;
	TInt err;
	TInt bulkCount = 100;
	TMsvId msvId = KFirstFreeEntryId;
	TMsvId id = msvId;
	TTime timeBefore, timeAfter;
	
	
	// t1. GetEntry from an empty block 
	ret = iIndexTableEntry->GetEntry(id, oEntry); //pass some arbitrary TMsvId for this
	MY_ASSERT_TRUE(oEntry == NULL);
	MY_ASSERT_FALSE(ret);
	
	
	// t2. get entry from non-empty block
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count())); //add some entries
	MY_ASSERT_EQUALS(err, KErrNone);
	for(TInt index = 0; index < bulkCount; ++index)
		{
		ASSERT_TRUE(iIndexTableEntry->EntryExists(tmsvEntries[index].Id()));
		}
	TRAP(err, entryA = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, entryB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryB->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryA->GetId()));
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryB->GetId()));
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	ret = iIndexTableEntry->GetEntry(entryA->GetId(), oEntry);
	MY_ASSERT_EQUALS(oEntry->GetId(), entryA->GetId());
	MY_ASSERT_TRUE(ret);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeAfter != timeBefore);
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	ret = iIndexTableEntry->GetEntry(entryB->GetId(), oEntry);
	MY_ASSERT_EQUALS(oEntry->GetId(), entryB->GetId());
	MY_ASSERT_TRUE(ret);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeAfter != timeBefore);
	
	for(TInt index = 0; index < bulkCount; ++index)
		{
		timeBefore = iIndexTableEntry->AccessTime();
		User::After(1000);
		ret = iIndexTableEntry->GetEntry(tmsvEntries[index].Id(), oEntry);
		ASSERT_TRUE(ret);
		ASSERT_EQUALS(oEntry->GetId(), tmsvEntries[index].Id());
		timeAfter = iIndexTableEntry->AccessTime();
		ASSERT_TRUE(timeAfter != timeBefore);
		}
	
	
	// t3. getentry - non-existing entry
	ret = iIndexTableEntry->GetEntry((TMsvId)50, oEntry); //50 has not been added
	MY_ASSERT_FALSE(ret);
	tmsvEntries.Reset();
	for(TInt index = 0 ; index < bulkCount; ++index)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(++id);
		}
	for(TInt index = 0; index < bulkCount; ++index)
		{
		timeBefore = iIndexTableEntry->AccessTime();
		ret = iIndexTableEntry->GetEntry(tmsvEntries[index].Id(), oEntry);
		ASSERT_FALSE(ret);
		timeAfter = iIndexTableEntry->AccessTime();
		//MY_ASSERT_FALSE(timeAfter == timeBefore);
		}
		
	entries.Reset();
	entries.Close();
	tmsvEntries.Reset();
	tmsvEntries.Close();
	
	}


void CTestIndexTableEntry::TestGetChildren()
	{
	_LIT(KFunction, "TestGetChildren");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt size;
	TInt bulkCount = 10;
	TMsvId msvId = KFirstFreeEntryId;
	TMsvId id = msvId + 50;
	TTime timeBefore, timeAfter;
	
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	
	RPointerArray<CMsvCacheEntry> oEntries; 
	CMsvCacheEntry* nonimmediateParent = NULL;
	TRAP(err, nonimmediateParent = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	nonimmediateParent->Entry().SetId(++id);
	TMsvId parentId;
	
	
	// t1. block is NULL, perform GetChildren
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->GetChildrenL(id + 200, oEntries)); //non-existent parent
	MY_ASSERT_EQUALS(err, KErrNone);
	timeAfter = iIndexTableEntry->AccessTime();
	MY_ASSERT_TRUE(timeAfter != timeBefore);
	
	
	// t2. when grandchildren are present in the block.
	TRAP(err, parent = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	parent->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(parent));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, entryA = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryA->Entry().SetId(++id);
	++id;
	entryA->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
			
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id + 1);
		TRAP(err, entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		MY_ASSERT_EQUALS(KErrNone, err);
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		entries[index]->Entry().SetParent(parent->GetId());
		TRAP(err, iEntryPointer->AppendL(entries[index]));
		MY_ASSERT_EQUALS(KErrNone, err);
		}
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count())); //immediate children
	MY_ASSERT_EQUALS(err, KErrNone);
	size = iIndexTableEntry->Size();
	
	TRAP(err, entryB = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	entryB->Entry().SetId(++id);
	++id;
	entryB->Entry().SetParent(nonimmediateParent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(entryB)); //B is non-immediate child
	MY_ASSERT_EQUALS(err, KErrNone);
	iIndexTableEntry->SetGrandChildPresent();
	size = iIndexTableEntry->Size();
	
//	entries.Reset(); // add non-immediate children
//	tmsvEntries.Reset();
//	iEntryPointer->Reset();
//	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
//		{
//		tmsvEntries.Append(TMsvEntry());
//		tmsvEntries[index].SetId(id);
//		entries.Append(CMsvEntryFreePool::Instance()->EntryL());
//		entries[index]->Entry().SetId(tmsvEntries[index].Id());
//		entries[index]->Entry().SetParent(parentEntry2->Id());
//		iEntryPointer->AppendL(entries[index]);
//		}
//	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0)); //add some non-immediate children
//	MY_ASSERT_EQUALS(err, KErrNone);
	
	TRAP(err, iIndexTableEntry->GetChildrenL(parent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(oEntries.Count(), 11); //entryA + 10 others
	
	oEntries.Reset();
	TRAP(err, iIndexTableEntry->GetChildrenL(nonimmediateParent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(oEntries.Count(), 1); //entryB
	
	
	// t3. when grandchildren are not present in the block.
	entryB->LockEntry();
	TRAP(err, iIndexTableEntry->DeleteEntryL(entryB->GetId(), parentId));
	MY_ASSERT_EQUALS(err, KErrNone);
	oEntries.Reset();
	TRAP_IGNORE(iIndexTableEntry->GetChildrenL(parent->GetId(), oEntries));
	MY_ASSERT_EQUALS(oEntries.Count(), 11); //entryA + 10 others
	CMsvEntryFreePool::Instance()->ReleaseEntry(nonimmediateParent);
	
	
	// t4. only grandchildren are present in the block
	iIndexTableEntry->ReleaseBlock(ETrue);
	entries.Reset(); 
	tmsvEntries.Reset();
	iEntryPointer->Reset();
	
	TRAP(err, nonimmediateParent = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	nonimmediateParent->Entry().SetId(++id);
	++id;
	
	TRAP(err, parent = CMsvEntryFreePool::Instance()->EntryL());
	MY_ASSERT_EQUALS(KErrNone, err);
	parent->Entry().SetId(++id);
	++id;
	
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP_IGNORE(entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		entries[index]->Entry().SetParent(nonimmediateParent->GetId());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count())); //add some non-immediate children
	MY_ASSERT_EQUALS(err, KErrNone);
	
	oEntries.Reset();
	TRAP(err, iIndexTableEntry->GetChildrenL(nonimmediateParent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(oEntries.Count(), 10);
	
	oEntries.Reset();
	TRAP(err, iIndexTableEntry->GetChildrenL(parent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(oEntries.Count(), 0);
	
	CMsvEntryFreePool::Instance()->ReleaseEntry(nonimmediateParent);
	CMsvEntryFreePool::Instance()->ReleaseEntry(parent);
	oEntries.Close();
	tmsvEntries.Close();
	entries.Close();	
	}


void CTestIndexTableEntry::TestDeleteEntry()
	{
	_LIT(KFunction, "TestDeleteEntry");
	INFO_PRINTF1(KFunction);
	TInt err;
	
	TMsvId parentId;
	TMsvId msvId = KFirstFreeEntryId;
	TMsvId id = msvId + 50;
	TMsvId temp;
	TTime timeBefore, timeAfter;
	TInt bulkCount = 100;
	
	// t1. delete entry from NULL block.
	TRAP(err, iIndexTableEntry->DeleteEntryL(id, parentId));
	MY_ASSERT_EQUALS(err, KErrNotFound);
		
	
	// t2. remove unlocked existing entry
	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	entryA->Entry().SetParent(parent->GetId());
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	entryB->Entry().SetParent(parent->GetId());
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP(err, iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
	MY_ASSERT_EQUALS(err, KErrAccessDenied);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryA->GetId()));
	timeAfter = iIndexTableEntry->AccessTime();
 	MY_ASSERT_TRUE(timeAfter == timeBefore);
 		
	
	// t3. remove locked existing entry
	entryA->LockEntry();
	timeBefore = iIndexTableEntry->AccessTime();
	User::After(1000);
	temp = entryA->GetId();
 	TRAP(err, iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
 	MY_ASSERT_EQUALS(err, KErrNone);
 	MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(temp)); 
 	MY_ASSERT_EQUALS(parentId, parent->GetId());
 	timeAfter = iIndexTableEntry->AccessTime();
 	MY_ASSERT_TRUE(timeAfter != timeBefore);
 	
 	
 	// t4. remove last entry in the block
 	entryB->LockEntry();
 	timeBefore = iIndexTableEntry->AccessTime();
 	User::After(1000);
 	temp = entryB->GetId();
 	TRAP(err, iIndexTableEntry->DeleteEntryL(entryB->GetId(), parentId));
 	MY_ASSERT_EQUALS(err, KErrNone);
 	MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(temp)); 
 	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
 	MY_ASSERT_EQUALS(parentId, parent->GetId());
 	timeAfter = iIndexTableEntry->AccessTime();
 	MY_ASSERT_TRUE(timeAfter != timeBefore);
 	
 	
 	// t5. remove non-existing entries
 	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	entryA->Entry().SetParent(parent->GetId());
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	entryB->Entry().SetParent(parent->GetId());
	++id;
 	TRAP(err, iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
 	MY_ASSERT_EQUALS(err, KErrNotFound);
 	
 	entryA->LockEntry();
 	TRAP(err, iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
 	MY_ASSERT_EQUALS(err, KErrNotFound);
 	
 	CMsvEntryFreePool::Instance()->ReleaseEntry(parent);
 	CMsvEntryFreePool::Instance()->ReleaseEntry(entryA);
 	CMsvEntryFreePool::Instance()->ReleaseEntry(entryB);
 	
 	
 	// t6. bulk additions and deletions
 	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
 	
 	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
 	
 	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP_IGNORE(entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		entries[index]->Entry().SetParent(parent->GetId());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count()));
	MY_ASSERT_EQUALS(err, KErrNone);
	
	for(TInt index = 0; index < bulkCount; ++index)
		{
		entries[index]->LockEntry();
		timeBefore = iIndexTableEntry->AccessTime();
		User::After(1000);
		temp = entries[index]->GetId();
		TRAP(err, iIndexTableEntry->DeleteEntryL(entries[index]->GetId(), parentId));
		ASSERT_EQUALS(err, KErrNone);
		ASSERT_FALSE(iIndexTableEntry->EntryExists(temp));
		ASSERT_EQUALS(parentId, parent->GetId());
		timeAfter = iIndexTableEntry->AccessTime();
 		ASSERT_TRUE(timeAfter != timeBefore);
		}
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
	
	CMsvEntryFreePool::Instance()->ReleaseEntry(parent);
	tmsvEntries.Close();
	entries.Close();
	}


void CTestIndexTableEntry::TestSortBlock()
	{
	_LIT(KFunction, "TestSortBlock");
	INFO_PRINTF1(KFunction);
	
	TInt err;
	TMsvId id = KFirstFreeEntryId;
	RPointerArray<CMsvCacheEntry> oEntries;
	
	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
	
	/* Basic idea:
	 *  - append 3 entries with unsorted TMsvIds (descending order of Ids is used here)
	 *  - call SortBlock
	 *  - now when we pick any 2 successive (need not be adjacent) entries,
	 * 	  if the difference between their TMsvIds is -ve then block has been sorted
	 */
	TRAP_IGNORE(entryC = CMsvEntryFreePool::Instance()->EntryL());
	entryC->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	
	entryC->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_EQUALS(err, KErrNone);
	
	entryB->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	
	entryA->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	
	iIndexTableEntry->SortBlock();
	//atleast 3 entries have been added, so test with the first three entries.
	TRAP(err, iIndexTableEntry->GetChildrenL(parent->GetId(), oEntries));
	MY_ASSERT_EQUALS(err, KErrNone);
	err = oEntries[0]->GetId() - oEntries[2]->GetId(); //successive entries
	MY_ASSERT_TRUE(err < 0);
	err = oEntries[1]->GetId() - oEntries[2]->GetId(); //successive entries
	MY_ASSERT_TRUE(err < 0);
	err = oEntries[0]->GetId() - oEntries[1]->GetId(); //successive entries
	MY_ASSERT_TRUE(err < 0);
	
	CMsvEntryFreePool::Instance()->ReleaseEntry(parent);
	oEntries.Close();
	}


void CTestIndexTableEntry::TestReleaseBlock()
	{
	_LIT(KFunction, "TestReleaseBlock");
	INFO_PRINTF1(KFunction);
	
	TInt err;
	TBool ret;
	TInt size;
	TMsvId msvId = KFirstFreeEntryId;
	TMsvId id = msvId + 50;
	
	// t1. release NULL block
	ret = iIndexTableEntry->ReleaseBlock();
	MY_ASSERT_TRUE(ret);
	ret = iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(ret);
	
	
	// t2. release block with all entries locked
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryC = CMsvEntryFreePool::Instance()->EntryL());
	entryC->Entry().SetId(++id);
	++id;
	entryA->LockEntry();
	entryB->LockEntry();
	entryC->LockEntry();
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_EQUALS(err, KErrNone);
	size = iIndexTableEntry->Size();
	ret = iIndexTableEntry->ReleaseBlock(EFalse);
	MY_ASSERT_FALSE(ret);
	MY_ASSERT_EQUALS(size, iIndexTableEntry->Size());
	
	// t3. release block with only 1 entry unswappable
	entryB->ReleaseEntry();
	entryC->ReleaseEntry();
	entryA->IncStoreReaderCount();
	size = iIndexTableEntry->Size();
	ret = iIndexTableEntry->ReleaseBlock(EFalse);
	MY_ASSERT_FALSE(ret);
	MY_ASSERT_EQUALS(size, iIndexTableEntry->Size());
	
	
	// t4. release block with no entries unswappable
	entryA->ReleaseEntry();
	entryA->DecStoreReaderCount();
	ret = iIndexTableEntry->ReleaseBlock(EFalse);
	MY_ASSERT_TRUE(ret);
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
	MY_ASSERT_TRUE(iIndexTableEntry->IsDirty());
	
	
	// t5. forcibly release a block even if entries are unswappable
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryC = CMsvEntryFreePool::Instance()->EntryL());
	entryC->Entry().SetId(++id);
	++id;
	entryA->LockEntry();
	entryB->LockEntry();
	entryC->LockEntry();
	entryA->IncStoreReaderCount();
	entryC->IncStoreReaderCount();
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_EQUALS(err, KErrNone);
	ret = iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(ret);
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
	
	
	// t6. forcibly release block when no entries are unswappable
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryC = CMsvEntryFreePool::Instance()->EntryL());
	entryC->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_EQUALS(err, KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_EQUALS(err, KErrNone);
	ret = iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(ret);
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() ==  NULL);
	
	}


void CTestIndexTableEntry::TestIsInRange()
	{
	_LIT(KFunction, "TestIsInRange");
	INFO_PRINTF1(KFunction);
	
	TMsvId id = KFirstFreeEntryId;
	
	//find max and min MsvIds.
	//test should fail for TMsvIds outside the boundaries. (the first 2 tests)
	//test should pass otherwise.
			
	iIndexTableEntry->SetMinMsvIdRange(id + 10);
	iIndexTableEntry->SetMaxMsvIdRange(id + 50);
			
	TBool ret;
	TMsvId maxId = iIndexTableEntry->GetMaxMsvIdRange();
	TMsvId minId = iIndexTableEntry->GetMinMsvIdRange();
	
	ret = iIndexTableEntry->IsInRange((TMsvId)(maxId + 1));
	MY_ASSERT_FALSE(ret);
	ret = iIndexTableEntry->IsInRange((TMsvId)(minId - 1));
	MY_ASSERT_FALSE(ret);
	ret = iIndexTableEntry->IsInRange((TMsvId)(maxId - 1));
	MY_ASSERT_TRUE(ret);	
	ret = iIndexTableEntry->IsInRange((TMsvId)(minId + 1));
	MY_ASSERT_TRUE(ret);
	}


void CTestIndexTableEntry::TestEntryExists()
	{
	_LIT(KFunction, "TestEntryExists");
	INFO_PRINTF1(KFunction);
	TInt err;
	TMsvId parentId;
	TMsvId id = KFirstFreeEntryId;
	TInt bulkCount = 100;
	
	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	
	
	// t1. no entries in the cache
	MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(entryA->GetId()));
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
	
	
	// t2. delete added entry and check
	entryA->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(parent));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryA->GetId()));
		//cannot delete entry not locked in cache
	TRAP(err, iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
	MY_ASSERT_EQUALS(err, KErrAccessDenied);
	MY_ASSERT_TRUE(iIndexTableEntry->EntryExists(entryA->GetId()));
	entryA->LockEntry(); //can only delete entry locked in cache
	TMsvId entryAId = entryA->GetId();
	TRAP(err, iIndexTableEntry->DeleteEntryL(entryAId, parentId));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(entryAId));
	MY_ASSERT_EQUALS(parentId, parent->GetId());
	
	
	// t3. bulk operations
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP_IGNORE(entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count()));
	MY_ASSERT_EQUALS(err, KErrNone);
	for(TInt index = 0; index < bulkCount; ++index)
		{
		ASSERT_TRUE(iIndexTableEntry->EntryExists(entries[index]->GetId()));
		}
		
	tmsvEntries.Reset();
	++id;
	for(TInt index = 0; index < bulkCount; ++index, ++id) 
		{
		tmsvEntries.Append(TMsvEntry());  //non-existent entries
		tmsvEntries[index].SetId(id);
		ASSERT_FALSE(iIndexTableEntry->EntryExists(tmsvEntries[index].Id()));
		}
 	entries.Close();
 	tmsvEntries.Close();
 	}


void CTestIndexTableEntry::TestIsDirty()
	{
	_LIT(KFunction, "TestIsDirty");
	INFO_PRINTF1(KFunction);
	TBool err;
	TInt bulkCount = 100;
	TMsvId id = KFirstFreeEntryId;
	
		
	// t1. test using setting and resetting of the dirty flag
	iIndexTableEntry->SetDirty();
	err = iIndexTableEntry->IsDirty();
	MY_ASSERT_TRUE(err);
	
	iIndexTableEntry->ClearDirty();
	err = iIndexTableEntry->IsDirty();
	MY_ASSERT_FALSE(err);
	
	
	// t2. test using ClearFlags
	iIndexTableEntry->ClearFlags();
	err = iIndexTableEntry->IsDirty();
	MY_ASSERT_FALSE(err);
	
	
	// t3. releasing the block sets dirty flag
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	err = iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(err);
	MY_ASSERT_TRUE(iIndexTableEntry->IsDirty());
	}


void CTestIndexTableEntry::TestSetDirty()
	{
	_LIT(KFunction, "TestSetDirty");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt bulkCount = 100;
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test using setting and resetting of dirty flag
	iIndexTableEntry->SetDirty();
	TBool ret = iIndexTableEntry->IsDirty();
	MY_ASSERT_TRUE(ret);
	
	iIndexTableEntry->ClearFlags();
	ret = iIndexTableEntry->IsDirty();
	MY_ASSERT_FALSE(ret);
	
	iIndexTableEntry->ClearDirty();
	ret = iIndexTableEntry->IsDirty();
	MY_ASSERT_FALSE(ret);
	
	iIndexTableEntry->SetDirty();
	ret = iIndexTableEntry->IsDirty();
	MY_ASSERT_TRUE(ret);
	iIndexTableEntry->ClearDirty();
	
	
	// t2. Releasing a block to free pool causes setting of dirty bit 
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	err = iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(err);
	MY_ASSERT_TRUE(iIndexTableEntry->IsDirty());
	
	}

void CTestIndexTableEntry::TestClearDirty()
	{
	_LIT(KFunction, "TestClearDirty");
	INFO_PRINTF1(KFunction);
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test using setting and resetting of dirty flag
	TInt err;
	iIndexTableEntry->ClearDirty();
	err = iIndexTableEntry->IsDirty();
	MY_ASSERT_FALSE(err);
	
	iIndexTableEntry->SetDirty();
	err = iIndexTableEntry->IsDirty();
	MY_ASSERT_TRUE(err);
	
	iIndexTableEntry->ClearDirty();
	err = iIndexTableEntry->IsDirty();
	MY_ASSERT_FALSE(err);
	
	}

void CTestIndexTableEntry::TestGetMaxMsvIdRange()
	{
	_LIT(KFunction, "TestGetMaxMsvIdRange");
	INFO_PRINTF1(KFunction);
	TInt err;
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test by setting manually
	iIndexTableEntry->SetMaxMsvIdRange(id);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), id);
	
	
	// t2. AddEntryL to a NULL block
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entryA->GetId());
	
	
	// t3. AddEntryL to last block (assuming this block is the last one)
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entryB->GetId());
	
	}


void CTestIndexTableEntry::TestGetMinMsvIdRange()
	{
	_LIT(KFunction, "TestGetMinMsvIdRange");
	INFO_PRINTF1(KFunction);
	TInt err;
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test by setting manually
	iIndexTableEntry->SetMinMsvIdRange(id + 50);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), id + 50);
	
	
	// t2. AddEntryL to a NULL block
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(id + 20);
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), entryA->GetId());
	
	
	// t3. AddEntryL to folder with no indextable created
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(id + 10);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), entryB->GetId());
	
	}

void CTestIndexTableEntry::TestSetMaxMsvIdRange()
	{
	_LIT(KFunction, "TestSetMaxMsvIdRange");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt id = KFirstFreeEntryId + 10;
	
	// t1. testing by setting iMaxMsvId and getting it.
	TMsvId aId= id - 5;
	iIndexTableEntry->SetMaxMsvIdRange(aId);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), aId);
		
	
	// t2. AddEntryL on a NULL block results in setting of iMaxMsvId
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMaxMsvIdRange(), entryA->GetId());
	
	}


void CTestIndexTableEntry::TestSetMinMsvIdRange()
	{
	_LIT(KFunction, "TestSetMinMsvIdRange");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt id = KFirstFreeEntryId;
	
	// t1. testing by setting iMinMsvId and getting it.
	TMsvId aId= id + 10;
	iIndexTableEntry->SetMinMsvIdRange(aId);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), aId);
	
		
	// t2. AddEntryL on a NULL block results in setting of iMaxMsvId
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(id + 8);
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	MY_ASSERT_EQUALS(iIndexTableEntry->GetMinMsvIdRange(), entryA->GetId());
	
	}


void CTestIndexTableEntry::TestSize()
	{
	_LIT(KFunction, "TestSize");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt bulkCount = 50;
	TMsvId id = KFirstFreeEntryId;
	
	// t1. perform Size() on NULL block
	TInt ret = iIndexTableEntry->Size();
	MY_ASSERT_TRUE(ret == 0); 
	
	
	// t2. add a single entry
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_EQUALS(err, KErrNone);
	ret = iIndexTableEntry->Size();
	MY_ASSERT_TRUE(ret == 1);
			
	
	// t3. add large number of entries and check
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP_IGNORE(entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	TRAP(err, iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count()));
	MY_ASSERT_EQUALS(err, KErrNone);
	ret = iIndexTableEntry->Size();
	MY_ASSERT_EQUALS(ret, bulkCount + 1);
	entries.Close();
	tmsvEntries.Close();
	}

void CTestIndexTableEntry::TestUpdateChildMsvIds()
	{
	_LIT(KFunction, "TestUpdateChildMsvIds");
	INFO_PRINTF1(KFunction);
	TInt err;
	TInt bulkCount = 100;
	TMsvId id = KFirstFreeEntryId;
	RArray<TMsvId> *childArray;
	
		
	// t1. Updating iChildIdArray with many child entries.
	TBool flag = ETrue;
	TInt index = 0;
	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryC = CMsvEntryFreePool::Instance()->EntryL());
	entryC->Entry().SetId(++id);
	++id;
	entryA->Entry().SetParent(parent->GetId());
	entryB->Entry().SetParent(parent->GetId());
	entryC->Entry().SetParent(parent->GetId());
	TRAP_IGNORE(iEntryPointer->AppendL(entryA));
	TRAP_IGNORE(iEntryPointer->AppendL(entryB));
	
	// when iBlockPtr is NULL. ------------------
	MY_ASSERT_TRUE(iIndexTableEntry->Size() == 0);
	
	// when iBlockPtr is not NULL. --------------
	// ---update on parent on whom GetChildren has not been performed
	TRAP(err, iIndexTableEntry->AddEntryL(parent));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(*iEntryPointer));
	MY_ASSERT_TRUE(err == KErrNone);
	childArray = parent->ChildIdArray();
	MY_ASSERT_EQUALS(childArray->Count(), 2); // entryA and entryB
	// ---update on parent on whom GetChildren has been performed => array is reset and assigned
	TRAP_IGNORE(iEntryPointer->AppendL(entryC));
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(*iEntryPointer));
	MY_ASSERT_TRUE(err == KErrNone);
	childArray = parent->ChildIdArray();
	MY_ASSERT_EQUALS(childArray->Count(), 3); // entryA, entryB and now entryC		
	
	// t2. Updating iChildIdArray of a parent with a single child entry.
	// when iBlockPtr is NULL. ------------------
	iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(iIndexTableEntry->Size() == NULL);
	
	// when iBlockPtr is not NULL. --------------
	// ---iChildIdArray != NULL, and addition is being performed
	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryB = CMsvEntryFreePool::Instance()->EntryL());
	entryB->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(entryC = CMsvEntryFreePool::Instance()->EntryL());
	entryC->Entry().SetId(++id);
	++id;
	entryA->Entry().SetParent(parent->GetId());
	entryB->Entry().SetParent(parent->GetId());
	entryC->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(parent));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryB));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->AddEntryL(entryC));
	MY_ASSERT_TRUE(err == KErrNone);
	
	RArray<TMsvId> *childArray1 = NULL;
	TRAP_IGNORE(childArray1 = new(ELeave) RArray<TMsvId>);
	TRAP_IGNORE(childArray1->AppendL(entryA->GetId()));
	TRAP_IGNORE(childArray1->AppendL(entryB->GetId()));
	TRAP_IGNORE(childArray1->AppendL(entryC->GetId()));
	parent->SetChildIdArray(childArray1);
	TRAP_IGNORE(entryD = CMsvEntryFreePool::Instance()->EntryL()); // new child
	entryD->Entry().SetId(++id);
	++id;
	entryD->Entry().SetParent(parent->GetId());
	TRAP(err, iIndexTableEntry->AddEntryL(entryD));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(parent->GetId(), entryD->GetId())); //addition
	MY_ASSERT_TRUE(err == KErrNone);	
	childArray1 = parent->ChildIdArray();
	MY_ASSERT_EQUALS(childArray1->Count(), 4); // A, B, C and now D
	
	// ---deletion of child entry from iChildIdArray
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(parent->GetId(), entryD->GetId(), EFalse));
	MY_ASSERT_TRUE(err == KErrNone);
	childArray1 = parent->ChildIdArray();
	MY_ASSERT_EQUALS(childArray1->Count(), 3); // A, B and C. D has now been deleted
	
	// ---delete all children from child array
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(parent->GetId(), entryA->GetId(), EFalse));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(parent->GetId(), entryB->GetId(), EFalse));
	MY_ASSERT_TRUE(err == KErrNone);
	TRAP(err, iIndexTableEntry->UpdateChildMsvIdsL(parent->GetId(), entryC->GetId(), EFalse));
	MY_ASSERT_TRUE(err == KErrNone);
	childArray1 = parent->ChildIdArray();
	MY_ASSERT_EQUALS(childArray1->Count(), 0); // all children have been deleted	
	}

void CTestIndexTableEntry::TestSetGrandChildPresent()
	{
	_LIT(KFunction, "TestSetGrandChildPresent");
	INFO_PRINTF1(KFunction);
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test by setting and clearing of the flag(s)
	iIndexTableEntry->SetGrandChildPresent();
	MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	iIndexTableEntry->ClearFlags();
	MY_ASSERT_FALSE(iIndexTableEntry->IsGrandChildPresent());	
	iIndexTableEntry->SetGrandChildPresent();
	MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	iIndexTableEntry->ClearGrandChildPresent();
	MY_ASSERT_FALSE(iIndexTableEntry->IsGrandChildPresent());	
	
	}

void CTestIndexTableEntry::TestClearGrandChildPresent()
	{
	_LIT(KFunction, "TestClearGrandChildPresent");
	INFO_PRINTF1(KFunction);
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test by setting and clearing of the flag(s)
	iIndexTableEntry->SetGrandChildPresent();
	MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	iIndexTableEntry->ClearGrandChildPresent();
	MY_ASSERT_FALSE(iIndexTableEntry->IsGrandChildPresent());		
	iIndexTableEntry->SetGrandChildPresent();
	MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	iIndexTableEntry->ClearFlags();
	MY_ASSERT_FALSE(iIndexTableEntry->IsGrandChildPresent());	
	
	}

void CTestIndexTableEntry::TestIsGrandChildPresent()
	{
	_LIT(KFunction, "TestIsGrandChildPresent");
	INFO_PRINTF1(KFunction);
	TMsvId id = KFirstFreeEntryId;
	
	// t1. test by setting and clearing of the flag(s)
	iIndexTableEntry->SetGrandChildPresent();
	MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	iIndexTableEntry->ClearGrandChildPresent();
	MY_ASSERT_FALSE(iIndexTableEntry->IsGrandChildPresent());		
	iIndexTableEntry->SetGrandChildPresent();
	MY_ASSERT_TRUE(iIndexTableEntry->IsGrandChildPresent());
	iIndexTableEntry->ClearFlags();
	MY_ASSERT_FALSE(iIndexTableEntry->IsGrandChildPresent());	
	
	}

void CTestIndexTableEntry::TestBlockPtr()
	{
	_LIT(KFunction, "TestBlockPtr");
	INFO_PRINTF1(KFunction);
	TInt err;
	TMsvId id = KFirstFreeEntryId, parentId;
	
	
	// t1. call the function when block is NULL. it should return NULL
	MY_ASSERT_TRUE(iIndexTableEntry->BlockPtr() == NULL);
	
	
	// t2. add something to the block, and attempt to get the iBlockPtr.
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE(iIndexTableEntry->iBlockPtr == iIndexTableEntry->BlockPtr());
	
	
	// t3. release block makes iBlockPtr NULL
	err = iIndexTableEntry->ReleaseBlock(ETrue);
	MY_ASSERT_TRUE(err);
	MY_ASSERT_TRUE(NULL == iIndexTableEntry->BlockPtr());
	
	
	// t4. deleting last entry in the block
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(iIndexTableEntry->AddEntryL(entryA));
	entryA->LockEntry();
	TRAP_IGNORE(iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
	MY_ASSERT_TRUE(NULL == iIndexTableEntry->BlockPtr());
	
	}

void CTestIndexTableEntry::TestAccessTime()
	{ 
	_LIT(KFunction, "AccessTime");
	INFO_PRINTF1(KFunction);
	TInt err;
	TMsvId id = KFirstFreeEntryId, parentId;
	TInt bulkCount = 50;
	
	// t1. access time is changed on AddEntryL
	TTime tempTime = iIndexTableEntry->AccessTime();
	TRAP_IGNORE(entryA = CMsvEntryFreePool::Instance()->EntryL());
	entryA->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(iIndexTableEntry->AddEntryL(entryA));
	MY_ASSERT_TRUE( tempTime != iIndexTableEntry->AccessTime());
	
	
	// t2. access time is changed on AddEntrySetL
	tempTime = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP_IGNORE(parent = CMsvEntryFreePool::Instance()->EntryL());
	parent->Entry().SetId(++id);
	++id;
	TRAP_IGNORE(iIndexTableEntry->AddEntryL(parent));
	RArray<CMsvCacheEntry*> entries;
	RArray<TMsvEntry> tmsvEntries;
	for(TInt index = 0 ; index < bulkCount; ++index, ++id)
		{
		tmsvEntries.Append(TMsvEntry());
		tmsvEntries[index].SetId(id);
		TRAP_IGNORE(entries.Append(CMsvEntryFreePool::Instance()->EntryL()));
		entries[index]->Entry().SetId(tmsvEntries[index].Id());
		entries[index]->Entry().SetParent(parent->GetId());
		TRAP_IGNORE(iEntryPointer->AppendL(entries[index]));
		}
	TRAP_IGNORE(iIndexTableEntry->AddEntrySetL(*iEntryPointer, 0, iEntryPointer->Count()));
	MY_ASSERT_TRUE( tempTime != iIndexTableEntry->AccessTime()); 
	entries.Close();
	tmsvEntries.Close();
	//*/
	
	// t3. access time is changed on GetEntryL hit
	tempTime = iIndexTableEntry->AccessTime();
	User::After(1000);
	CMsvCacheEntry *dummy;
	iIndexTableEntry->GetEntry(entryA->GetId(), dummy);
	MY_ASSERT_TRUE( tempTime != iIndexTableEntry->AccessTime());
	
	
	// t4. when entry is deleted
	tempTime = iIndexTableEntry->AccessTime();
	User::After(1000);
	entryA->LockEntry();
	TMsvId entryAId = entryA->GetId();
	TRAP(err, iIndexTableEntry->DeleteEntryL(entryA->GetId(), parentId));
	MY_ASSERT_TRUE(err == KErrNone);
	MY_ASSERT_FALSE(iIndexTableEntry->EntryExists(entryAId));
	MY_ASSERT_TRUE( tempTime != iIndexTableEntry->AccessTime());
	
	
	// t5. when GetChildren is performed
	iIndexTableEntry->ClearGrandChildPresent();
	iEntryPointer->Reset();
	tempTime = iIndexTableEntry->AccessTime();
	User::After(1000);
	TRAP_IGNORE(iIndexTableEntry->GetChildrenL(parent->GetId(), *iEntryPointer));
	MY_ASSERT_TRUE( tempTime != iIndexTableEntry->AccessTime());
	//*/
	}



#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
/*
void Print(CMsvCacheIndexTableEntry *aIndexTable)
	{
	RFileLogger logger;
	if (logger.Connect() == KErrNone)
		{
		logger.CreateLog(_L("msgs"), _L("Cache.txt"), EFileLoggingModeOverwrite);
		logger.Write(_L(""));
	
		aIndexTable->Print(logger);
		logger.CloseLog();
		}
	logger.Close();		
	}
*/



#endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)


CTestSuite* CTestIndexTableEntry::CreateSuiteL(const TDesC& aName)
// static
	{
	SUB_SUITE;
	ADD_ASYNC_TEST_STEP(TestConstructorL);
	ADD_ASYNC_TEST_STEP(TestAddEntry);
	ADD_ASYNC_TEST_STEP(TestAddEntrySet);
	ADD_ASYNC_TEST_STEP(TestGetEntry);
	ADD_ASYNC_TEST_STEP(TestGetChildren);
	ADD_ASYNC_TEST_STEP(TestDeleteEntry);
	ADD_ASYNC_TEST_STEP(TestSortBlock);
	ADD_ASYNC_TEST_STEP(TestReleaseBlock);
	ADD_ASYNC_TEST_STEP(TestIsInRange);
	ADD_ASYNC_TEST_STEP(TestEntryExists);
	ADD_ASYNC_TEST_STEP(TestIsDirty);
	ADD_ASYNC_TEST_STEP(TestSetDirty);
	ADD_ASYNC_TEST_STEP(TestClearDirty);
	ADD_ASYNC_TEST_STEP(TestSetMaxMsvIdRange);
	ADD_ASYNC_TEST_STEP(TestSetMinMsvIdRange);
	ADD_ASYNC_TEST_STEP(TestGetMaxMsvIdRange);
	ADD_ASYNC_TEST_STEP(TestGetMinMsvIdRange);
	ADD_ASYNC_TEST_STEP(TestUpdateChildMsvIds);
	ADD_ASYNC_TEST_STEP(TestSize);
	ADD_ASYNC_TEST_STEP(TestSetGrandChildPresent);
	ADD_ASYNC_TEST_STEP(TestClearGrandChildPresent);
	ADD_ASYNC_TEST_STEP(TestIsGrandChildPresent);
	ADD_ASYNC_TEST_STEP(TestBlockPtr);
	ADD_ASYNC_TEST_STEP(TestAccessTime);

	END_SUITE;
	}
