pimprotocols/phonebooksync/Test/TE_cntsync/te_cntsyncview.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimprotocols/phonebooksync/Test/TE_cntsync/te_cntsyncview.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,551 @@
+// Copyright (c) 2003-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:
+// Tests that PhBkSync adds contacts from USIM address books to the contacts database,
+// and that they appear correctly in the Contacts Model local view.
+// 
+//
+
+#include <e32test.h>
+#include "te_cntsyncbase.h"
+#include "te_cntsyncview.h"
+#include <cntview.h>
+
+// Values for User::After()
+const TInt	K1SecondWait(1000000);
+const TInt	K5SecondWait(5*K1SecondWait);
+const TInt	K20SecondWait(20*K1SecondWait);
+
+// Test config numbers...
+const TInt  KNormalSIMTestConfig(0);
+const TInt  KLockedSIMTestConfig(8);
+
+// Number of contacts on SIM cards
+const TInt	KNumContactsNormalSIM(5);
+const TInt	KNumContactsLockedSIM(25);
+
+class TViewCleanup
+	{
+	public:
+		TViewCleanup(CContactLocalView* aLocalView, CContactViewEventWait* aViewWaitEvent)
+			{
+			iLocalView = aLocalView;
+			iViewWaitEvent = aViewWaitEvent;
+			}
+		CContactViewEventWait* iViewWaitEvent;
+		CContactLocalView* iLocalView;
+	};
+
+static void ViewCleanup(TAny* aPointer)
+	{
+	TViewCleanup* cleanup = static_cast<TViewCleanup*> (aPointer);
+	CContactLocalView* iLocalView = cleanup->iLocalView;
+	CContactViewEventWait* iViewWaitEvent = cleanup->iViewWaitEvent;
+	iLocalView->Close(*iViewWaitEvent);
+	delete iViewWaitEvent;
+	}
+
+/** 
+ * Factory construction method.
+ * @return Pointer to CPhbkViewICCSyncTest object
+ */
+CPhbkViewICCSyncTest* CPhbkViewICCSyncTest::NewL()
+	{
+	CPhbkViewICCSyncTest* self = new(ELeave) CPhbkViewICCSyncTest();
+	return self;
+	}
+
+/**
+ *  Default constructor.  Each test step initialises it's own name.
+ */
+CPhbkViewICCSyncTest::CPhbkViewICCSyncTest()
+	{
+	SetTestStepName(_L("ViewICCSyncTest"));
+	}
+
+/**
+ * Synchronisation of normal, unlocked, ICC.  Creates a Contacts View
+ * with ICC entries only.
+ */
+enum TVerdict CPhbkViewICCSyncTest::doTestStepL()
+	{
+	SetSimTsyTestNumberL(0);
+	DoSyncL();
+	
+	// all View tests use Manual Sync mode
+	User::LeaveIfError(iSession.SetSyncMode(RPhoneBookSession::EManual)); // Set mode to manual to avoid getting KErrInUse
+	CheckSyncModeL(RPhoneBookSession::EManual);
+	
+	// ICC unlocked
+	SetSimTsyTestNumberL(KNormalSIMTestConfig);
+	CleanupClosePushL(iViewSortOrder);
+
+	// A sort order (only Family Name is present in ADN phonebooks)
+    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
+    iViewSortOrder.AppendL(KUidContactFieldGivenName);
+    iViewSortOrder.AppendL(KUidContactFieldCompanyName);
+
+	// Helper class that gives timed wait for View events
+	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
+	CleanupStack::PushL(viewEventWait);
+
+	// View with just ICC entries
+	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesOnly);
+
+	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
+	TViewCleanup cleanup(iIccView, viewEventWait);
+	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));
+
+	INFO_PRINTF1(_L("  Manual Sync"));
+	// do manual synchronisation
+	DoSyncL();
+	WaitForSyncToCompleteL();
+
+	// let view catch up, waits 2s
+	INFO_PRINTF1(_L("  Wait for ICC view to become ready"));
+	// Wait 30s for View Event: EReady or ESortOrderChanged only
+	TBool eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
+	// check that event was received
+	TESTCHECKCONDITIONL(eventReceived);
+	TESTCHECKL(iEvent.iEventType, TContactViewEvent::EReady);
+
+	INFO_PRINTF1(_L("  Check all PhoneBook entries are in view"));
+	TInt count = iIccView->CountL();
+	if (count != KNumContactsNormalSIM)
+		{
+		INFO_PRINTF3(_L("  Expecting %d entries in View but found %d:"),
+			KNumContactsNormalSIM, count);
+		DumpICCViewL();
+		}
+	TESTCHECK(count, KNumContactsNormalSIM);
+
+	User::After(K5SecondWait);
+	CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
+
+	return TestStepResult();
+	}
+	
+	
+/** 
+ * Factory construction method.
+ * @return Pointer to CPhbkViewICCLockedICCTest object
+ */
+CPhbkViewICCLockedICCTest* CPhbkViewICCLockedICCTest::NewL()
+	{
+	CPhbkViewICCLockedICCTest* self = new(ELeave) CPhbkViewICCLockedICCTest();
+	return self;
+	}
+
+/**
+ *  Default constructor.  Each test step initialises it's own name.
+ */
+CPhbkViewICCLockedICCTest::CPhbkViewICCLockedICCTest()
+	{
+	SetTestStepName(_L("ViewICCLockedICCTest"));
+	}
+
+/**
+ * Synchronisation when ICC is locked.  Creates a Contacts View of ICC entries
+ * only.
+ *
+ * Synchroniser is initially unable to perform synchronisation because ICC is locked. The
+ * Local View class recognises that the ICC is locked, and creates an empty View.
+ *
+ * When ICC becomes unlocked the synchronisation completes successfully. The Contacts Local 
+ * View sees this, and re-sorts itself making the ICC entries appear in the View.
+ */
+enum TVerdict CPhbkViewICCLockedICCTest::doTestStepL()
+	{
+	// ICC locked, so initial Synchronisation is not carried out 
+	SetSimTsyTestNumberL(KLockedSIMTestConfig);
+	CleanupClosePushL(iViewSortOrder);
+	// A sort order (only Family Name is present in ADN phonebooks)
+    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
+    iViewSortOrder.AppendL(KUidContactFieldGivenName);
+    iViewSortOrder.AppendL(KUidContactFieldCompanyName);
+
+	// Helper class that gives timed wait for View events
+	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
+	CleanupStack::PushL(viewEventWait);
+
+	// View with just ICC entries
+	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesOnly);
+	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
+	TViewCleanup cleanup(iIccView, viewEventWait);
+	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));
+
+	INFO_PRINTF1(_L("  Initial Sync Failure"));
+	// check that ICC is locked
+	TRAPD(err, DoSyncFailL());
+	if(err == KErrGeneral)
+		{
+		INFO_PRINTF1(_L("The view has already been created before we attempt to sync, so sync won't fail. We should finsh test here"));
+		SetTestStepResult(EPass);
+		CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
+		return TestStepResult(); 
+		}
+	TESTCHECKL(err, KErrNone);
+	User::After(K1SecondWait);
+
+	RPhoneBookSession::TSyncState state;
+	iSession.GetPhoneBookCacheState(state);
+
+	TESTCHECKL(state, RPhoneBookSession::EErrorDuringSync); // Cache not in valid state 
+
+	iSession.GetLastSyncError(err);
+	TESTCHECKL(err, KErrAccessDenied); // ICC locked
+
+	// initially ready with no entries as ICC (SIM) card is not ready, waits 2s
+	INFO_PRINTF1(_L("  Check View becomes ready with no entries"));
+	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
+	TBool eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
+	// check that event was received
+	TESTCHECKCONDITIONL(eventReceived);
+
+	TESTCHECKL(iEvent.iEventType, TContactViewEvent::EReady);
+	TESTCHECKL(iIccView->CountL(), 0); // view should be empty
+
+	// wait for ICC to become unlocked
+	INFO_PRINTF1(_L("  Start Sync when ICC becomes unlocked"));
+	User::After(K20SecondWait); // ICC should become unlocked now 
+	DoSyncL();
+	WaitForSyncToCompleteL();
+
+	// let the view catch up, waits 2s
+	INFO_PRINTF1(_L("  Wait for View to Re-Sort with ICC entries"));
+	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
+	eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
+	// check that event was received
+	TESTCHECKCONDITIONL(eventReceived);
+
+	INFO_PRINTF1(_L("  Contacts View should be resorted"));
+	TESTCHECKL(iEvent.iEventType, TContactViewEvent::ESortOrderChanged);
+
+	INFO_PRINTF1(_L("  Check all PhoneBook entries are in view"));
+	TInt count = iIccView->CountL();
+	if (count != KNumContactsLockedSIM)
+		{
+		INFO_PRINTF3(_L("  Expecting %d entries in View but found %d:"),
+			KNumContactsLockedSIM, count);
+		DumpICCViewL();
+		}
+	TESTCHECK(count, KNumContactsLockedSIM);
+
+	User::After(K5SecondWait);
+	CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
+
+	return TestStepResult();
+	}
+	
+	
+/** 
+ * Factory construction method.
+ * @return Pointer to CPhbkViewICCLockedMixedTest object
+ */
+CPhbkViewICCLockedMixedTest* CPhbkViewICCLockedMixedTest::NewL()
+	{
+	CPhbkViewICCLockedMixedTest* self = new(ELeave) CPhbkViewICCLockedMixedTest();
+	return self;
+	}
+
+/**
+ *  Default constructor.  Each test step initialises it's own name.
+ */
+CPhbkViewICCLockedMixedTest::CPhbkViewICCLockedMixedTest()
+	{
+	SetTestStepName(_L("ViewICCLockedMixedTest"));
+	}
+
+/**
+ * Synchronisation when ICC is locked.  Creates a Contacts View of Contacts
+ * and ICC entries.  This is similar to the ICC entries only test, but timing
+ * and behaviour of Contacts model is different.
+ *
+ * Synchroniser is initially unable to perform synchronisation because ICC is locked. The
+ * Local View class recognises that the ICC is locked, and creates a View without ICC entries.
+ *
+ * When ICC becomes unlocked the synchronisation completes successfully. The Contacts Local 
+ * View sees this, and re-sorts itself making the ICC entries appear in the View.
+ */
+enum TVerdict CPhbkViewICCLockedMixedTest::doTestStepL()
+	{
+	// ICC locked, so initial Synchronisation is not carried out
+	SetSimTsyTestNumberL(KLockedSIMTestConfig);
+	CleanupClosePushL(iViewSortOrder);
+
+	// A sort order (only Family Name is present in ADN phonebooks)
+    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
+    iViewSortOrder.AppendL(KUidContactFieldGivenName);
+    iViewSortOrder.AppendL(KUidContactFieldCompanyName);
+
+	// Helper class that gives timed wait for View events
+	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
+	CleanupStack::PushL(viewEventWait);
+
+	// View with ICC entries and contacts
+	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesAndContacts);
+	
+	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
+	TViewCleanup cleanup(iIccView, viewEventWait);
+	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));
+
+	INFO_PRINTF1(_L("  Initial Sync Failure"));
+	// check that ICC is locked
+	TRAPD(err, DoSyncFailL());
+	if(err == KErrGeneral)
+		{
+		INFO_PRINTF1(_L("The view has already been created before we attempt to sync, so sync won't fail. We should finsh test here"));		
+		SetTestStepResult(EPass);
+		CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
+		return TestStepResult(); 
+		}
+	TESTCHECKL(err, KErrNone);
+	User::After(K1SecondWait);
+
+	RPhoneBookSession::TSyncState state;
+	iSession.GetPhoneBookCacheState(state);
+
+	TESTCHECKL(state, RPhoneBookSession::EErrorDuringSync); // Cache not in valid state 
+
+	iSession.GetLastSyncError(err);
+	TESTCHECKL(err, KErrAccessDenied); // ICC locked
+
+	// initially ready with no entries as ICC (SIM) card is not ready, waits 2s
+	INFO_PRINTF1(_L("  Check View becomes ready without ICC entries"));
+	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
+	TBool eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
+	// check that event was received
+	TESTCHECKCONDITIONL(eventReceived);
+
+	TESTCHECKL(iEvent.iEventType, TContactViewEvent::EReady);
+	TESTCHECKL(iIccView->CountL(), 0); // view should be empty
+
+	// wait for ICC to become unlocked
+	INFO_PRINTF1(_L("  Start Sync when ICC becomes unlocked"));
+	User::After(K20SecondWait); // ICC should become unlocked now 
+	DoSyncL();
+	WaitForSyncToCompleteL();
+
+	// let the view catch up, waits 2s
+	INFO_PRINTF1(_L("  Wait for View to Re-Sort with ICC entries"));
+	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
+	eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
+	// check that event was received
+	TESTCHECKCONDITIONL(eventReceived);
+
+	INFO_PRINTF1(_L("  Contacts View should be resorted"));
+	TESTCHECKL(iEvent.iEventType, TContactViewEvent::ESortOrderChanged);
+
+	INFO_PRINTF1(_L("  Check all PhoneBook entries are in view"));
+	TInt count = iIccView->CountL();
+	if (count != KNumContactsLockedSIM)
+		{
+		INFO_PRINTF3(_L("  Expecting %d entries in View but found %d:"),
+			KNumContactsLockedSIM, count);
+		DumpICCViewL();
+		}
+	TESTCHECK(count, KNumContactsLockedSIM);
+
+	User::After(K5SecondWait);
+	CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
+	return TestStepResult();
+	}
+
+
+/**
+ *  Synchronisation and create a view when just one phonebook exists. Previously
+ *  a defect existed which would fail if no FDN phonebook was defined.
+ */
+enum TVerdict CPhbkViewICCSinglePhonebookTest::doTestStepL()
+	{
+	SetSimTsyTestNumberL(30);
+
+	//
+	// Setup a sort order (only Family Name is present in ADN phonebooks)
+    //
+	INFO_PRINTF1(_L("Setup a sort order (only Family Name is present in ADN phonebooks)"));
+	CleanupClosePushL(iViewSortOrder);
+    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
+    iViewSortOrder.AppendL(KUidContactFieldGivenName);
+    iViewSortOrder.AppendL(KUidContactFieldCompanyName);
+	
+	//
+    // Helper class that gives timed wait for View events
+	//
+	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
+	CleanupStack::PushL(viewEventWait);
+
+	//
+	// Create a view with ICC entries and contacts
+	//
+	INFO_PRINTF1(_L("Create a view with ICC entries and contacts"));
+	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesAndContacts);
+	
+	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
+	TViewCleanup cleanup(iIccView, viewEventWait);
+	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));	
+
+	//
+	// Sync ADN phonebook...
+	//
+	INFO_PRINTF1(_L(" Sync ADN phonebook..."));
+	TRequestStatus  status; 
+
+	iSession.DoSynchronisation(status, KUidIccGlobalAdnPhonebook);
+	User::WaitForRequest(status);
+	TESTCHECKL(status.Int(), KErrNone);
+
+	//
+	// Close view and clean up...
+	//
+	INFO_PRINTF1(_L(" Close view and clean up..."));
+	CleanupStack::PopAndDestroy(2);
+
+	return TestStepResult();
+	} // CPhbkViewICCSinglePhonebookTest::doTestStepL
+
+
+void CPhbkSyncViewIntegrationTestBase::DumpICCViewL()
+	{
+	const TInt count = iIccView->CountL();
+
+	if (count == 0)
+		{
+		INFO_PRINTF1(_L("  No contacts to list."));
+		return;
+		}
+
+	CContactItem* contact = NULL;
+	TInt  index;
+
+	for (index = 0;  index < count;  index++)
+		{
+		const CViewContact&  viewContact = iIccView->ContactAtL(index);
+		const TInt  id = viewContact.Id();
+		
+		// get actual Contact from DB
+		contact = iDb->ReadMinimalContactLC(id);
+
+		// Get & print Contact's phone number
+		CContactItemFieldSet& fieldset = contact->CardFields();
+		// look for Phone Number field in record
+		const TInt pos = fieldset.Find(KUidContactFieldPhoneNumber);	
+		User::LeaveIfError(pos);	// field must be present
+		CContactItemField& field = fieldset[pos];
+		CContactTextField* textfield = field.TextStorage();
+
+		TBuf<128>  outputString;
+		outputString.AppendFormat(_L("    [%04i]  Id=%04i Name=\""), index+1, id);
+		outputString.Append(viewContact.Field(0));
+		outputString.AppendFormat(_L("\" Number=\""));
+		outputString.Append(textfield->Text());
+		outputString.AppendFormat(_L("\""));
+		INFO_PRINTF1(outputString);
+
+		CleanupStack::PopAndDestroy(contact);
+		contact = NULL;
+		}
+	}
+
+// support class implementation, timed wait for View Event; (based on CContactViewEventQueue)
+
+CContactViewEventWait* CContactViewEventWait::NewL()
+    {
+    CContactViewEventWait* self = new(ELeave) CContactViewEventWait;
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+
+CContactViewEventWait::~CContactViewEventWait()
+    {
+    CTimer::Cancel();
+    if (iView) iView->Close(*this);
+    }
+
+
+/**
+ *  Waits for an event from the database.
+ *
+ *  @param aView        Contact view to listen for events.
+ *  @param aTimeOut     Max time to wait for an event.
+ *  @param aEvent       The received event, undefined if this function returns false.
+ *  @param aWaitForAny  ETrue if wait is for any event, EFalse for view ready events only
+ *
+ *  @return true if an event was received, false if timeout expired first.
+ */
+TBool CContactViewEventWait::WaitForViewEvent(CContactViewBase* aView,
+											  TTimeIntervalSeconds aTimeOut, 
+											  TContactViewEvent& aEvent, 
+											  TBool aWaitForAny)
+    {
+	iView = aView;
+	iWaitForAny = aWaitForAny;
+	iTimedOut = EFalse;
+    CTimer::After(aTimeOut.Int() * 1000000);
+
+	// wait for timer to finish or desired View event
+    CActiveScheduler::Start();
+
+    if (!iTimedOut)
+        {
+        aEvent = iEvent;
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+
+void CContactViewEventWait::RunL()
+    {
+    // Timer expired
+	iTimedOut = ETrue;
+    CActiveScheduler::Stop();
+    }
+
+
+void CContactViewEventWait::HandleContactViewEvent(const CContactViewBase& aView,
+												   const TContactViewEvent& aEvent)
+    {
+	__ASSERT_ALWAYS(iView == &aView, User::Invariant());
+
+	// either waiting for Any event, or Ready or Ready after Re-sort
+	if(iWaitForAny || aEvent.iEventType == TContactViewEvent::EReady || 
+			aEvent.iEventType == TContactViewEvent::ESortOrderChanged)
+		{
+		iEvent = aEvent;
+
+	    CTimer::Cancel();
+	    CActiveScheduler::Stop();
+		}
+    }
+
+
+CContactViewEventWait::CContactViewEventWait()
+    : CTimer(CActive::EPriorityStandard)
+    {
+    }
+
+
+void CContactViewEventWait::ConstructL()
+    {
+    CTimer::ConstructL();
+    CActiveScheduler::Add(this);
+	iView = NULL;
+    }
+