phonebookengines_old/contactsmodel/tsrc/t_iccmultiplephonebook.cpp
changeset 40 b46a585f6909
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines_old/contactsmodel/tsrc/t_iccmultiplephonebook.cpp	Fri Jun 11 13:29:23 2010 +0300
@@ -0,0 +1,983 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <e32test.h>
+#include <cntdb.h>
+#include <cntitem.h>
+#include <cntfield.h>
+#include <cntfldst.h>
+#include <phbksync.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "cntsyncecom.h"
+#endif
+
+// include templates for CleanupResetAndDestroyPushL(T)
+#include "cntviewprivate.h"
+
+#include "T_UTILS.H"
+#include "cntsyncchecker.h"
+
+_LIT(KTestName,"CContactICCEntry tests with multiple phonebooks");
+_LIT(KDatabaseFileName,"C:T_ICCMULTIPLEPHONEBOOK");
+_LIT(KGivenEditName,"edited name");
+_LIT(KIccName,"icc entry name");
+_LIT(KNonIccName,"non-icc name");
+_LIT(KIccNumber,"020 794 60123");
+_LIT(KNonIccNumber,"020 794 60060");
+
+_LIT(KPluginName,"phone book synchronizer Implementation");
+_LIT(KTestPluginName,"Test phone book synchronizer Implementation");
+
+CCntTest* CntTest=NULL;
+LOCAL_D RTest test(KTestName);
+
+LOCAL_D CContactSyncChecker* syncChecker;
+
+//===============================================================================================
+// SETUP & UTILITIES
+//===============================================================================================
+class TFieldEntry
+	{
+	public:
+		TFieldEntry(TFieldType aField);
+		TFieldEntry(TFieldType aField,TUid aFieldType);
+	public:
+		TFieldType iField;
+		TUid iFieldType;
+	};
+
+TFieldEntry::TFieldEntry(TFieldType aField)
+:iField(aField)
+,iFieldType(KUidIccPhonebookNotFound)
+	{}
+
+TFieldEntry::TFieldEntry(TFieldType aField,TUid aFieldType)
+:iField(aField)
+,iFieldType(aFieldType)
+	{}
+
+/**
+ * Create a new template and add it to the database
+ * @param aDb Contact database
+ * @param aTemplateName Name for the template
+ * @param aFieldSet Array of fields which should are added to the template
+ * @return TContactItemId Id of the newly created template
+ */
+TContactItemId CreatePhonebookTemplateL(CContactDatabase& aDb, const TDesC& aTemplateName, RArray<TFieldEntry>& aFieldSet)
+	{
+	CContactItem* temp = aDb.CreateContactCardTemplateLC(aTemplateName);
+	TContactItemId templateId = temp->Id();
+	CleanupStack::PopAndDestroy(temp);
+	temp=NULL;
+
+	//Remove all the unnecessary fields
+	temp = aDb.OpenContactLX(templateId);
+	CleanupStack::PushL(temp);	
+	const TInt fieldCount = temp->CardFields().Count();
+	for(TInt i=fieldCount-1;i>=0;i--)
+		temp->RemoveField(i);
+
+	// Add each of the required fields to the template
+	for (TInt j=0; j<aFieldSet.Count(); ++j)
+		{
+		TFieldEntry fieldEntry=aFieldSet[j];
+
+		CContactItemField* field = CContactItemField::NewLC(KStorageTypeText,fieldEntry.iField);
+		if (fieldEntry.iFieldType!=KNullUid)
+			field->AddFieldTypeL(fieldEntry.iFieldType);
+		temp->AddFieldL(*field);
+		CleanupStack::Pop(field);
+		}
+
+	aDb.CommitContactL(*temp);
+	CleanupStack::PopAndDestroy(2); // temp, close template
+	
+	return templateId;
+	}
+
+/**
+ * Return an array of fields for the phonebook specified
+ * @param aPhonebookUid The phonebook uid
+ * @return RArray<TFieldEntry> Field set for this specific phonebook.  Any contact item
+ * which belongs to this phonebook should contain these fields
+ */
+RArray<TFieldEntry> fieldSetForPhonebook(TUid aPhonebookUid)
+	{
+	RArray<TFieldEntry> entries;
+	entries.Append(TFieldEntry(KUidContactFieldFamilyName));
+	entries.Append(TFieldEntry(KUidContactFieldGivenName));
+	entries.Append(TFieldEntry(KUidContactFieldPhoneNumber,KUidContactFieldVCardMapHOME));
+	entries.Append(TFieldEntry(KUidContactFieldICCPhonebook));
+	
+	if (aPhonebookUid==KUidUsimAppAdnPhonebook)
+		{
+		entries.Append(TFieldEntry(KUidContactFieldEMail,KUidContactFieldVCardMapHOME));
+		entries.Append(TFieldEntry(KUidContactFieldEMail,KUidContactFieldVCardMapWORK));
+		entries.Append(TFieldEntry(KUidContactFieldPhoneNumber,KUidContactFieldVCardMapHOME));
+		entries.Append(TFieldEntry(KUidContactFieldPhoneNumber,KUidContactFieldVCardMapWORK));
+		entries.Append(TFieldEntry(KUidContactFieldPhoneNumber,KUidContactFieldVCardMapCELL));
+		entries.Append(TFieldEntry(KUidContactFieldPhoneNumber,KUidContactFieldVCardMapPAGER));
+		}
+
+	return entries;
+	}
+
+void SetUpIccPhonebooksL(CContactDatabase& aDb)
+	{
+	test.Next(_L("Set up phonebooks"));
+	RArray<TUid>	phbkList;
+	CleanupClosePushL(phbkList);
+
+	phbkList.AppendL(KUidIccGlobalAdnPhonebook);
+	phbkList.AppendL(KUidIccGlobalSdnPhonebook);
+	phbkList.AppendL(KUidIccGlobalLndPhonebook);
+	phbkList.AppendL(KUidUsimAppAdnPhonebook);
+	// tell phonebook sync simulator what phonebooks to use
+	test(syncChecker->SetPhonebookListL(phbkList) == KErrNone);
+
+	// simulate synchronisation - includes creating/finding template & group
+	// also defaults all validate responses to KErrNone
+	test(syncChecker->SynchroniseIccAllPhonebooksL(aDb, KErrNone, KErrNone) == KErrNone);
+	
+	CleanupStack::PopAndDestroy(); // phbkList
+	}
+
+/**
+ * Check the content of the phonebook field in the contact item
+ * @param aContactItem Contact item
+ * @param aPhonebookUid The phonebook uid
+ * @param aFieldIsSet EFalse if the phonebook field should not contain a value, else ETrue
+ */
+void CheckPhonebookField(CContactItem& aContactItem,TUid aPhonebookUid,TBool aFieldIsSet)
+	{
+	const CContactItemFieldSet& fieldset = aContactItem.CardFields();
+	const TInt pos = fieldset.Find(KUidContactFieldICCPhonebook);
+	test(pos!=KErrNotFound);
+	TPtrC phonebookField=fieldset[pos].TextStorage()->Text();
+
+	if(aFieldIsSet)
+		{
+		TLex input(phonebookField);
+		TInt phonebookFieldVal;
+		/*TInt ignore  = */ input.Val(phonebookFieldVal);
+		TUid phonebookFieldUid;
+		phonebookFieldUid.iUid=phonebookFieldVal;
+		test(phonebookFieldUid==aPhonebookUid);
+		}
+	else
+		test(phonebookField==KNullDesC);
+	}
+
+/**
+ * Verify that the template id returned by CContactDatabase::ICCTemplateIdL is the
+ * same as that returned directly from the plugin
+ * @param aDb Contact database
+ */
+void VerifyPhonebookTemplateIdsL(CContactDatabase& aDb)
+	{
+	test.Next(_L("Verify template ids"));
+	syncChecker->ResetMethodCallCountsL();
+	test(aDb.ICCTemplateIdL() == syncChecker->ICCTemplateIdL(KUidIccGlobalAdnPhonebook));
+	test(aDb.ICCTemplateIdL(KUidIccGlobalAdnPhonebook) == syncChecker->ICCTemplateIdL(KUidIccGlobalAdnPhonebook));
+	test(aDb.ICCTemplateIdL(KUidIccGlobalSdnPhonebook) == syncChecker->ICCTemplateIdL(KUidIccGlobalSdnPhonebook));
+	test(aDb.ICCTemplateIdL(KUidIccGlobalLndPhonebook) == syncChecker->ICCTemplateIdL(KUidIccGlobalLndPhonebook));
+	test(aDb.ICCTemplateIdL(KUidUsimAppAdnPhonebook) == syncChecker->ICCTemplateIdL(KUidUsimAppAdnPhonebook));
+	test(aDb.ICCTemplateIdL(KNullUid) == KNullContactId);
+	test(syncChecker->ValidateMethodCallCountL() == 6);
+	}
+
+/**
+ * Set the name field of the contact with id aId to contain the name aName
+ * @param aDb Contact database
+ * @param aId Contact item id
+ * @param aName A name
+ */
+void SetNameField(CContactDatabase& aDb,TContactItemId aId,const TDesC& aName)
+	{
+	syncChecker->ResetMethodCallCountsL();
+	CContactItem* item = aDb.OpenContactLX(aId);
+	CleanupStack::PushL(item);
+	if (item->Type() == KUidContactICCEntry)
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 2);
+		}
+	else
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 0);
+		}
+	CContactItemFieldSet& fieldset = item->CardFields();
+	TInt pos = fieldset.Find(KUidContactFieldFamilyName);
+	test(pos!=KErrNotFound);
+	CContactItemField& field = fieldset[pos];
+	CContactTextField* textfield = field.TextStorage();
+	textfield->SetTextL(aName);
+
+	syncChecker->ResetMethodCallCountsL();
+	aDb.CommitContactL(*item);
+	if (item->Type() == KUidContactICCEntry)
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 2);
+		}
+	else
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 0);
+		}
+	CleanupStack::PopAndDestroy(2); // item, lock record
+	}
+
+/**
+ * Set the phone number field of the contact with id aId to contain the number aNumber
+ * @param aDb Contact database
+ * @param aId Contact item id
+ * @param aNumber A telephone number
+ */
+void SetPhoneNumberField(CContactDatabase& aDb,TContactItemId aId,const TDesC& aNumber)
+	{
+	syncChecker->ResetMethodCallCountsL();
+	CContactItem* item = aDb.OpenContactLX(aId);
+	CleanupStack::PushL(item);
+	if (item->Type() == KUidContactICCEntry)
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 2);
+		}
+	else
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 0);
+		}
+	CContactItemFieldSet& fieldset = item->CardFields();
+	TInt pos = fieldset.Find(KUidContactFieldPhoneNumber);
+	test(pos!=KErrNotFound);
+	
+	CContactItemField& field = fieldset[pos];
+	CContactTextField* textfield = field.TextStorage();
+	textfield->SetTextL(aNumber);
+
+	syncChecker->ResetMethodCallCountsL();
+	aDb.CommitContactL(*item);
+	if (item->Type() == KUidContactICCEntry)
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 2);
+		}
+	else
+		{
+		test(syncChecker->ValidateMethodCallCountL() == 0);
+		}
+	CleanupStack::PopAndDestroy(2); // item, lock record
+	}
+
+//===============================================================================================
+// ADDING entries
+//===============================================================================================
+/**
+ * Create an entry based on the template for this specific phonebook, and add
+ * the entry to the contact database
+ * @param aDb Contact database
+ * @param aPhonebookUid The phonebook uid
+ * @return TContactItemId Id of the newly created icc entry
+ */
+TContactItemId doAddIccEntryL(CContactDatabase& aDb,TUid aPhonebookUid)
+	{
+	syncChecker->ResetMethodCallCountsL();
+	TContactItemId templateId = aDb.ICCTemplateIdL(aPhonebookUid);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	CContactItem* iccTemplate = aDb.ReadContactLC(templateId);
+	CContactICCEntry* entry = CContactICCEntry::NewL(*iccTemplate);
+	CleanupStack::PopAndDestroy(iccTemplate);
+	CleanupStack::PushL(entry);
+	// Add to the database
+	CheckPhonebookField(*entry,aPhonebookUid, EFalse);
+	syncChecker->ResetMethodCallCountsL();
+	TContactItemId id = aDb.AddNewContactL(*entry); 
+	test(syncChecker->ValidateMethodCallCountL() == 3);
+	CleanupStack::PopAndDestroy(entry);
+	test(id!=KNullContactId);
+	// Check group membership
+	syncChecker->ResetMethodCallCountsL();
+	CContactICCEntry* fetchedItem = static_cast<CContactICCEntry*>(aDb.ReadContactL(id));
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	CleanupStack::PushL(fetchedItem);	
+	const CContactIdArray* owned = fetchedItem->GroupsJoined();
+	test(owned!=NULL && owned->Count() == 1);
+	test((*owned)[0]==syncChecker->GroupIdL(aPhonebookUid));
+	test(fetchedItem->Type() == KUidContactICCEntry);
+	// Verify that the phonebook field has been set
+	CheckPhonebookField(*fetchedItem,aPhonebookUid, ETrue);
+	CleanupStack::PopAndDestroy(fetchedItem);	
+
+	return id;
+	}
+
+TContactItemId AddIccEntryL(CContactDatabase& aDb,TUid aPhonebookUid)
+	{
+	syncChecker->SetValidateWriteResponseL(KErrNone);
+	return doAddIccEntryL(aDb, aPhonebookUid);
+	}
+
+void UnsuccessfulAddIccEntryL(CContactDatabase& aDb,TUid aPhonebookUid, TInt aReason)
+	{
+	syncChecker->SetValidateWriteResponseL(aReason);
+	TRAPD(err,doAddIccEntryL(aDb, aPhonebookUid));
+	test(err==aReason);
+	}
+
+void AddEntriesBasedOnEachOfTheTemplatesL(CContactDatabase& aDb)
+	{
+	test.Next(_L("Test successful adding"));
+	TInt numberOfAdnEntries=3;
+	TInt numberOfSdnEntries=2;
+	TInt numberOfLdnEntries=1;
+	TInt numberOfUsimEntries=4;
+	TInt iter=0;
+	for (iter=0; iter<numberOfAdnEntries; ++iter)
+		{
+		TContactItemId id=AddIccEntryL(aDb,KUidIccGlobalAdnPhonebook);
+		CContactGroup* group=static_cast<CContactGroup*>(aDb.ReadContactLC(syncChecker->GroupIdL(KUidIccGlobalAdnPhonebook)));
+		CContactIdArray* entries=group->ItemsContainedLC();
+		test(entries->Count() == iter+1);
+		CleanupStack::PopAndDestroy(entries);
+		test(group->ContainsItem(id));
+		CleanupStack::PopAndDestroy(group);
+		}
+	for (iter=0; iter<numberOfSdnEntries; ++iter)
+		{
+		TContactItemId id=AddIccEntryL(aDb,KUidIccGlobalSdnPhonebook);
+		CContactGroup* group=static_cast<CContactGroup*>(aDb.ReadContactLC(syncChecker->GroupIdL(KUidIccGlobalSdnPhonebook)));
+		CContactIdArray* entries=group->ItemsContainedLC();
+		test(entries->Count() == iter+1);
+		CleanupStack::PopAndDestroy(entries);
+		test(group->ContainsItem(id));
+		CleanupStack::PopAndDestroy(group);
+		}
+	for (iter=0; iter<numberOfLdnEntries; ++iter)
+		{
+		TContactItemId id=AddIccEntryL(aDb, KUidIccGlobalLndPhonebook);
+		CContactGroup* group=static_cast<CContactGroup*>(aDb.ReadContactLC(syncChecker->GroupIdL(KUidIccGlobalLndPhonebook)));
+		CContactIdArray* entries=group->ItemsContainedLC();
+		test(entries->Count() == iter+1);
+		CleanupStack::PopAndDestroy(entries);
+		test(group->ContainsItem(id));
+		CleanupStack::PopAndDestroy(group);
+		}
+	for (iter=0; iter<numberOfUsimEntries; ++iter)
+		{
+		TContactItemId id=AddIccEntryL(aDb,KUidUsimAppAdnPhonebook);
+		CContactGroup* group=static_cast<CContactGroup*>(aDb.ReadContactLC(syncChecker->GroupIdL(KUidUsimAppAdnPhonebook)));
+		CContactIdArray* entries=group->ItemsContainedLC();
+		test(entries->Count() == iter+1);
+		CleanupStack::PopAndDestroy(entries);
+		test(group->ContainsItem(id));
+		CleanupStack::PopAndDestroy(group);
+		}
+	// Add an ICC entry based on the system template, not one of the ICC templates
+	TContactItemId templateId=aDb.TemplateId();
+	CContactItem* systemTemplate = aDb.ReadContactLC(templateId);
+	CContactICCEntry* entry = CContactICCEntry::NewL(*systemTemplate);
+	CleanupStack::PopAndDestroy(systemTemplate);
+	CleanupStack::PushL(entry);
+	syncChecker->ResetMethodCallCountsL();
+	TContactItemId id = aDb.AddNewContactL(*entry); 
+	test(syncChecker->ValidateMethodCallCountL() == 3);
+
+	syncChecker->ResetMethodCallCountsL();
+	CContactItem* item=aDb.ReadContactLC(id);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	// check the entry hasn't been added to any group
+	CContactIdArray* array=static_cast<CContactICCEntry*>(item)->GroupsJoinedLC();
+	test(array->Count() == 0);
+	CleanupStack::PopAndDestroy(3); // array, close item, item
+	}
+
+void TestUnsuccessfulAddL(CContactDatabase& aDb)
+	{
+	// Test adding entries to each of the phonebooks when the ICC is locked, unaccessible or corrupt
+	test.Next(_L("Test unsuccessful adding"));
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalAdnPhonebook,KErrLocked);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalAdnPhonebook,KErrAccessDenied);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalAdnPhonebook,KErrCorrupt);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalSdnPhonebook,KErrLocked);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalSdnPhonebook,KErrAccessDenied);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalSdnPhonebook,KErrCorrupt);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalLndPhonebook,KErrLocked);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalLndPhonebook,KErrAccessDenied);
+	UnsuccessfulAddIccEntryL(aDb,KUidIccGlobalLndPhonebook,KErrCorrupt);
+	UnsuccessfulAddIccEntryL(aDb,KUidUsimAppAdnPhonebook,KErrLocked);
+	UnsuccessfulAddIccEntryL(aDb,KUidUsimAppAdnPhonebook,KErrAccessDenied);
+	UnsuccessfulAddIccEntryL(aDb,KUidUsimAppAdnPhonebook,KErrCorrupt);
+	}
+
+/** 
+ * Verify that adding contact cards doesn't call the synchroniser interface
+ * @param aDb Contact database
+ */
+TContactItemId AddContactCardL(CContactDatabase& aDb)
+	{
+	_LIT(KTemplateName,"contact card template");
+	RArray<TFieldEntry> entries=fieldSetForPhonebook(KUidIccGlobalAdnPhonebook);
+	TContactItemId templateId=CreatePhonebookTemplateL(aDb,KTemplateName,entries);
+	entries.Close();
+	CContactItem* iccTemplate = aDb.ReadContactLC(templateId);
+	CContactCard* card = CContactCard::NewLC(iccTemplate);
+	syncChecker->ResetMethodCallCountsL();
+	TContactItemId id=aDb.AddNewContactL(*card);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	CleanupStack::PopAndDestroy(2,iccTemplate);
+	return id;
+	}
+//===============================================================================================
+// DELETING entries
+//===============================================================================================
+/**
+ * Verify that the synchroniser is called when deleting an icc entry, and that the 
+ * deletion of an icc entry fails if the icc is locked.
+ * @param aDb Contact database
+ */
+void TestDeleteL(CContactDatabase& aDb)
+	{
+	test.Next(_L("Test delete when ICC locked"));
+	syncChecker->SetDeleteContactResponseL(KErrLocked);
+	TContactItemId iccId=AddIccEntryL(aDb,KUidIccGlobalAdnPhonebook);
+	syncChecker->ResetMethodCallCountsL();
+	TRAPD(err,aDb.DeleteContactL(iccId));
+	test(err==KErrLocked);
+	test(syncChecker->ValidateMethodCallCountL() == 2);
+	syncChecker->ResetMethodCallCountsL();
+	CContactItem* item=aDb.ReadContactLC(iccId);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(item!=NULL);
+	CleanupStack::PopAndDestroy(item);
+	item=NULL;
+
+	test.Next(_L("Test successful delete of non-icc entry when ICC locked"));
+	TContactItemId nonIccId=AddContactCardL(aDb);
+	syncChecker->ResetMethodCallCountsL();
+	TRAP(err,aDb.DeleteContactL(nonIccId));
+	test(err==KErrNone);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+
+	test.Next(_L("Test successful delete"));
+	syncChecker->SetDeleteContactResponseL(KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	TRAP(err,aDb.DeleteContactL(iccId));
+	test(syncChecker->ValidateMethodCallCountL() == 2);
+	test(err==KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	TRAP(err,aDb.ReadContactLC(iccId));
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(err==KErrNotFound);
+	}
+
+//===============================================================================================
+// READING entries
+//===============================================================================================
+void TestReadMinimalContactL(CContactDatabase& aDb, TContactItemId aIccId, TContactItemId aNonIccId)
+	{
+	test.Next(_L("Test ReadMinimalContactL"));
+	// Successful read of icc entry
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	CContactItem* item=aDb.ReadMinimalContactLC(aIccId);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(item!=NULL);
+	CleanupStack::PopAndDestroy(item);
+	item=NULL;
+
+	// Unsuccessful read of icc entry because icc locked
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrAccessDenied);
+	syncChecker->ResetMethodCallCountsL();
+	TRAPD(err,item=aDb.ReadMinimalContactLC(aIccId));
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(item==NULL);
+	test(err==KErrAccessDenied);
+	
+	// successful read of non-icc entry, even though icc locked
+	syncChecker->ResetMethodCallCountsL();
+	item=aDb.ReadMinimalContactLC(aNonIccId);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(item!=NULL);
+	CleanupStack::PopAndDestroy(item);
+	item=NULL;
+	}
+
+void TestReadContactL(CContactDatabase& aDb, TContactItemId aIccId, TContactItemId aNonIccId)
+	{
+	test.Next(_L("Test ReadContactL"));
+	// Successful read of icc entry
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	test(syncChecker->ValidateMethodCallCountL() == 0);	
+	CContactItem* item=aDb.ReadContactLC(aIccId);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(item!=NULL);
+	CleanupStack::PopAndDestroy(item);
+	item=NULL;
+
+	// Unsuccessful read of icc entry because icc locked
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrAccessDenied);
+	syncChecker->ResetMethodCallCountsL();
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	TRAPD(err,item=aDb.ReadContactL(aIccId));
+	test(item==NULL);
+	test(err==KErrAccessDenied);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	
+	// successful read of non-icc entry, even though icc locked
+	syncChecker->ResetMethodCallCountsL();
+	test(syncChecker->ValidateMethodCallCountL() == 0);	
+	item=aDb.ReadContactLC(aNonIccId);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(item!=NULL);
+	CleanupStack::PopAndDestroy(item);
+	item=NULL;
+	}
+
+void TestReadTextDefinitionL(CContactDatabase& aDb, TContactItemId aIccId, TContactItemId aNonIccId)
+	{
+	test.Next(_L("Test ReadTextDefinitionL"));
+	// Successful read of icc entry
+	CContactTextDef* textDef=CContactTextDef::NewLC();
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName));
+	TBuf<64> result;
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	aDb.ReadContactTextDefL(aIccId,result,textDef);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(result==KIccName);
+	result.Zero();
+
+	// Unsuccessful read of icc entry because icc locked
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrAccessDenied);
+	syncChecker->ResetMethodCallCountsL();
+	TRAPD(err, aDb.ReadContactTextDefL(aIccId,result,textDef));
+	test(err==KErrAccessDenied);
+	test(result.Length() == 0);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+
+	// successful read of non-icc entry, even though icc locked
+	syncChecker->ResetMethodCallCountsL();
+	TRAP(err, aDb.ReadContactTextDefL(aNonIccId,result,textDef));
+	test(err==KErrNone);
+	test(result==KNonIccName);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	CleanupStack::PopAndDestroy(textDef);
+	}
+
+/**
+ * Verify that the synchroniser is called when reading an icc entry
+ * @param aDb Contact database
+ */
+void TestReadL(CContactDatabase& aDb)
+	{
+	TContactItemId iccId=AddIccEntryL(aDb,KUidIccGlobalAdnPhonebook);
+	SetNameField(aDb,iccId,KIccName);
+	TContactItemId nonIccId = AddContactCardL(aDb);
+	SetNameField(aDb,nonIccId,KNonIccName);
+	TestReadMinimalContactL(aDb,iccId,nonIccId);
+	TestReadContactL(aDb,iccId,nonIccId);
+	TestReadTextDefinitionL(aDb,iccId,nonIccId);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	aDb.DeleteContactL(iccId);
+	aDb.DeleteContactL(nonIccId);
+	test(syncChecker->ValidateMethodCallCountL() == 2);
+	}
+
+//===============================================================================================
+// EDITING entries
+//===============================================================================================
+/**
+ * Verify that edit validation is being done for ICC entries
+ * and write validation is done when Commit is called.
+ * @param aDb Contact database
+ * @param aId Item Id to edit
+ */
+void TestSuccessfulIccEditL(CContactDatabase& aDb, TContactItemId aId)
+	{
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::EEdit, KErrNone);
+	syncChecker->SetValidateWriteResponseL(KErrNone);
+	syncChecker->ResetMethodCallCountsL();
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	CContactItem* item = aDb.OpenContactLX(aId);
+	CleanupStack::PushL(item);
+	test(syncChecker->ValidateMethodCallCountL() == 2);	
+
+	CContactItemFieldSet& fieldset = item->CardFields();
+	const TInt pos = fieldset.Find(KUidContactFieldFamilyName);	
+	CContactItemField& field = fieldset[pos];
+	CContactTextField* textfield = field.TextStorage();
+	textfield->SetTextL(KGivenEditName);
+
+	aDb.CommitContactL(*item);
+	test(syncChecker->ValidateMethodCallCountL() == 4);	
+	CleanupStack::PopAndDestroy(2); //item, lock record
+	}
+
+/**
+ * Verify that edit of non-icc entries is successful when the icc is
+ * locked, and that the synchroniser is not called
+ * @param aDb Contact database
+ * @param aId Item Id to edit
+ */
+void TestSuccessfulNonIccEditL(CContactDatabase& aDb, TContactItemId aId)
+	{
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrLocked);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::EEdit, KErrLocked);
+	syncChecker->SetValidateWriteResponseL(KErrLocked);
+	syncChecker->ResetMethodCallCountsL();
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	CContactItem* item = aDb.OpenContactLX(aId);
+	CleanupStack::PushL(item);
+	test(syncChecker->ValidateMethodCallCountL() == 0);	
+
+	CContactItemFieldSet& fieldset = item->CardFields();
+	const TInt pos = fieldset.Find(KUidContactFieldFamilyName);	
+	CContactItemField& field = fieldset[pos];
+	CContactTextField* textfield = field.TextStorage();
+	textfield->SetTextL(KGivenEditName);
+
+	aDb.CommitContactL(*item);
+	test(syncChecker->ValidateMethodCallCountL() == 0);	
+	CleanupStack::PopAndDestroy(2); //item, lock record
+	}
+
+/**
+ * Unsuccessful edit. Fail the edit validation request
+ * @param aDb Contact database
+ * @param aId Item Id to edit
+ */
+void FailEditValidationL(CContactDatabase& aDb, TContactItemId aId)
+	{
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::EEdit, KErrAccessDenied);
+	syncChecker->ResetMethodCallCountsL();
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	TRAPD(err, aDb.OpenContactL(aId));
+	test(syncChecker->ValidateMethodCallCountL() == 2);	
+	test(err==KErrAccessDenied);
+	}
+
+/**
+ * Unsuccessful edit. Fail the write validation request
+ * @param aDb Contact database
+ * @param aId Item Id to edit
+ */
+void FailWriteValidationL(CContactDatabase& aDb, TContactItemId aId)
+	{
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::EEdit, KErrNone);
+	syncChecker->SetValidateWriteResponseL(KErrAccessDenied);
+	syncChecker->ResetMethodCallCountsL();
+
+	CContactItem* item = aDb.OpenContactLX(aId);
+	CleanupStack::PushL(item);
+	CContactItemFieldSet& fieldset = item->CardFields();
+	const TInt pos = fieldset.Find(KUidContactFieldFamilyName);	
+	CContactItemField& field = fieldset[pos];
+	CContactTextField* textfield = field.TextStorage();
+	textfield->SetTextL(KGivenEditName);
+
+	TRAPD(err, aDb.CommitContactL(*item));
+	test(syncChecker->ValidateMethodCallCountL() == 4);	
+	test(err==KErrAccessDenied);
+	CleanupStack::PopAndDestroy(2); //item, lock record
+	}
+
+/**
+ * Verify that edit validation is being done for ICC entries
+ * and write validation is done when Commit is called.
+ * @param aDb Contact database
+ */
+void TestEditL(CContactDatabase& aDb)
+	{
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	TContactItemId iccId = AddIccEntryL(aDb,KUidIccGlobalAdnPhonebook);
+	TContactItemId nonIccId = AddContactCardL(aDb);
+	test.Next(_L("Test successful edit"));
+	TestSuccessfulIccEditL(aDb,iccId);
+	TestSuccessfulNonIccEditL(aDb,nonIccId);
+	test.Next(_L("Test unsuccessful edit - fail edit"));
+	FailEditValidationL(aDb,iccId);
+	test.Next(_L("Test unsuccessful edit - fail write"));
+	FailWriteValidationL(aDb,iccId);
+	}
+//===============================================================================================
+// SEARCHING entries
+//===============================================================================================
+void TestFindLC(CContactDatabase& aDb, TContactItemId aIccId, TContactItemId aNonIccId)
+	{
+	test.Next(_L("Test FindLC"));
+	// Successful find of icc entry
+	CContactItemFieldDef* fieldDef=new(ELeave) CContactItemFieldDef;
+	CleanupStack::PushL(fieldDef);
+	fieldDef->AppendL(KUidContactFieldFamilyName);
+	syncChecker->ResetMethodCallCountsL();
+	CContactIdArray* array = aDb.FindLC(KIccName,fieldDef);
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aIccId);
+	CleanupStack::PopAndDestroy(array);
+	array=NULL;
+
+	test.Next(_L("Test searching when ICC locked"));
+	// Unsuccessful find of icc entry because icc locked
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ESearch,KErrLocked);
+	syncChecker->ResetMethodCallCountsL();
+	TRAPD(err,array = aDb.FindLC(KIccName,fieldDef));
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(err==KErrLocked);
+	test(array==NULL);
+
+	// successful find of non-icc entry, even though icc locked
+	syncChecker->ResetMethodCallCountsL();
+	array = aDb.FindLC(KNonIccName,fieldDef);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aNonIccId);
+	CleanupStack::PopAndDestroy(2,fieldDef); // array, fieldDef
+	}
+
+TInt findWordSplitterL(TAny *aParams)
+	{
+	SFindInTextDefWordParser *parser=(SFindInTextDefWordParser *)aParams;
+	parser->iWordArray->AppendL(*parser->iSearchString);
+	return(KErrNone);
+	}
+
+void TestFindInTextDefLC(CContactDatabase& aDb, TContactItemId aIccId, TContactItemId aNonIccId)
+	{
+	test.Next(_L("Test FindInTextDefLC"));
+	// Successful find of icc entry
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ESearch,KErrNone);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+
+	TCallBack callBack(findWordSplitterL);
+	CContactTextDef* textDef=CContactTextDef::NewLC();
+	textDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName));
+	CDesCArray* desArray = new(ELeave) CDesCArrayFlat(5);
+	desArray->AppendL(_L("icc"));
+	syncChecker->ResetMethodCallCountsL();
+	CContactIdArray* array = aDb.FindInTextDefLC(*desArray,textDef,callBack);
+	//test(syncChecker->ValidateMethodCallCountL() == 3);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aIccId);
+	CleanupStack::PopAndDestroy(array);
+	array=NULL;
+
+	test.Next(_L("Test searching when ICC locked"));
+	// Unsuccessful find of icc entry because icc locked
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ESearch,KErrLocked);
+	syncChecker->ResetMethodCallCountsL();
+	TRAPD(err,array = aDb.FindInTextDefLC(*desArray,textDef,callBack));
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(err==KErrLocked);
+	test(array==NULL);
+	desArray->Delete(0);
+	delete desArray;
+
+	// successful find of non-icc entry, even though icc locked
+	CDesCArray* desArray2 = new(ELeave) CDesCArrayFlat(5);
+	desArray2->AppendL(_L("non-icc"));
+	syncChecker->ResetMethodCallCountsL();
+	array = aDb.FindInTextDefLC(*desArray2,textDef,callBack);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aNonIccId);
+
+	// both the icc and non-icc entry should match the search criteria, but only the
+	// non-icc entry should be returned since icc is locked
+	SetNameField(aDb,aIccId,KNonIccName);
+	syncChecker->ResetMethodCallCountsL();
+	TRAP(err,array = aDb.FindInTextDefLC(*desArray2,textDef,callBack));
+	test(syncChecker->ValidateMethodCallCountL() == 1);
+	test(err==KErrLocked);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aNonIccId);
+	desArray2->Delete(0);
+	delete desArray2;
+	SetNameField(aDb,aIccId,KIccName);
+	CleanupStack::PopAndDestroy(2,textDef); // array, textDef
+	}
+
+void TestMatchPhoneNumberL(CContactDatabase& aDb, TContactItemId aIccId, TContactItemId aNonIccId)
+	{
+	// The synchroniser is not called to validate the IDs at for this method because 
+	// phone number resolution needs to be as quick as possible. 
+	// Instead, validation is done when the client attempts to read the items.
+	test.Next(_L("Test MatchPhoneNumberL"));
+	// Successful find of icc entry phone number
+	syncChecker->ResetMethodCallCountsL();
+	CContactIdArray* array = aDb.MatchPhoneNumberL(KIccNumber,KMaxPhoneMatchLength);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aIccId);
+	delete array;
+	array=NULL;
+
+	test.Next(_L("Test searching when ICC locked"));
+	// successful find when icc locked - validation done when entry read
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ESearch,KErrLocked);
+	syncChecker->ResetMethodCallCountsL();
+	TRAPD(err,array = aDb.MatchPhoneNumberL(KIccNumber,KMaxPhoneMatchLength));
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(array!=NULL);
+	test(err==KErrNone);
+	test((*array)[0]==aIccId);
+	delete array;
+	array=NULL;
+	syncChecker->ResetMethodCallCountsL();
+	array = aDb.MatchPhoneNumberL(KNonIccNumber,KMaxPhoneMatchLength);
+	test(syncChecker->ValidateMethodCallCountL() == 0);
+	test(array!=NULL);
+	test(array->Count() == 1);
+	test((*array)[0]==aNonIccId);
+	delete array;
+	array=NULL;
+	}
+
+void TestSearchL(CContactDatabase& aDb)
+	{
+	test.Next(_L("Test searching"));
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ERead,KErrNone);
+	syncChecker->SetValidateResponseL(MContactSynchroniser::ESearch,KErrNone);
+	TContactItemId iccId = AddIccEntryL(aDb,KUidIccGlobalAdnPhonebook);
+	SetNameField(aDb,iccId,KIccName);
+	SetPhoneNumberField(aDb,iccId,KIccNumber);
+	TContactItemId nonIccId = AddContactCardL(aDb);
+	SetNameField(aDb,nonIccId,KNonIccName);
+	SetPhoneNumberField(aDb,nonIccId,KNonIccNumber);
+
+	TestFindLC(aDb,iccId,nonIccId);
+	TestFindInTextDefLC(aDb,iccId,nonIccId);
+	TestMatchPhoneNumberL(aDb,iccId,nonIccId);
+	}
+
+
+void CheckForPhbkSyncPluginL()
+	{
+	test.Next(_L("Check for PhbkSync test plug-in"));
+
+	RImplInfoPtrArray	implInfoArray;
+	CleanupResetAndDestroyPushL(implInfoArray);
+	REComSession::ListImplementationsL(KUidEcomCntPhBkSyncInterface, implInfoArray);
+	//Find implementations of KUidEcomCntPhBkSyncInterface
+	TInt availCount = implInfoArray.Count(); 
+	TInt count;
+	for(count = 0; count < availCount; count++)
+		{
+		const TUid firstImplementationFound = implInfoArray[count]->ImplementationUid();
+		CImplementationInformation *info = implInfoArray[count];
+		test.Printf(_L("\n"));
+		test.Printf(_L("PhbkSync plugin #%i, Implementation UID 0x%08X version %i\n"),
+			count + 1, info->ImplementationUid(), info->Version());
+		test.Printf(_L("Plugin name = \"%S\"\n"), &(info->DisplayName()));
+		}
+
+	// is telephony's plug-in in the list?
+	for(count = 0; count < availCount; count++)
+		{
+		const TUid firstImplementationFound = implInfoArray[count]->ImplementationUid();
+		CImplementationInformation *info = implInfoArray[count];
+		if(info->DisplayName() == KTestPluginName)
+			{
+			test.Printf(_L("\n"));
+			test.Printf(_L("This test has now loaded the test plugin"));
+			test.Printf(_L("\n"));
+			availCount = 1;
+			break;
+			}		
+		
+		if(info->DisplayName() == KPluginName)
+			{
+			test.Printf(_L("\n"));
+			test.Printf(_L("This test only works with Contacts the test plugin and not the original phonebooksync plugin."));
+			test.Printf(_L("Depending on the build to removed the plugin in different ways:"));
+			test.Printf(_L("hardware - delete the line \"ECOM_PLUGIN(phbksyncplugin.dll,1020428C.rsc)\" from phbksync.iby"));
+			test.Printf(_L("winscw - delete phbksyncplugin.dll from %epocroot%/epoc32/release/winscw/udeb or similarly named directory"));
+			test.Printf(_L("\n"));
+			test(0);  // stop
+			break;
+			}
+		}
+
+	// only continue test if there is exactly one plug-in present
+	test(availCount == 1);	
+
+	CleanupStack::PopAndDestroy(&implInfoArray);
+	}
+
+	
+//===============================================================================================
+
+/** Lists tests to execute */
+
+/**
+
+@SYMTestCaseID     PIM-T-ICCMULTIPLEPHONEBOOK-0001
+
+*/
+void DoTestsL()
+    {
+	test.Start(_L("@SYMTestCaseID:PIM-T-ICCMULTIPLEPHONEBOOK-0001 CContactICCEntry tests with multiple phonebooks"));
+
+	CheckForPhbkSyncPluginL();
+
+	CntTest->CreateDatabaseL();	
+	CntTest->OpenDatabaseL();
+	CContactDatabase& db= *CntTest->Db();
+
+	syncChecker = CContactSyncChecker::NewL();
+	syncChecker->ResetEverythingL();
+
+	SetUpIccPhonebooksL(db);
+	VerifyPhonebookTemplateIdsL(db);
+	AddEntriesBasedOnEachOfTheTemplatesL(db);
+	TestUnsuccessfulAddL(db);
+	TestDeleteL(db);
+	TestReadL(db);
+	TestEditL(db);
+	TestSearchL(db);
+	syncChecker->ResetMethodCallCountsL();
+
+	CntTest->CloseDatabase();
+	CntTest->DeleteDatabaseL();
+
+
+	delete syncChecker;
+	syncChecker = NULL;
+    }
+
+
+/** Standard E32Main method */
+GLDEF_C TInt E32Main()
+	{
+    CntTest=new(ELeave) CCntTest;
+	CntTest->ConstructL(test,KDatabaseFileName);
+    TRAPD(err,DoTestsL());
+	if (syncChecker)
+		{
+		delete syncChecker;
+		syncChecker = NULL;
+		}
+	CntTest->EndTestLib(err);
+	return KErrNone;
+    }
+