phonebookengines_old/contactsmodel/tsrc/T_ViewSortPlugin.cpp
changeset 40 b46a585f6909
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines_old/contactsmodel/tsrc/T_ViewSortPlugin.cpp	Fri Jun 11 13:29:23 2010 +0300
@@ -0,0 +1,784 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <s32file.h>
+#include <e32math.h>
+#include <cntdb.h>
+#include <cntitem.h>
+#include <cntfldst.h>
+#include <cntview.h>
+#include <coreappstest/testserver.h>
+
+_LIT(KTestName, "T_ViewSortPlugin");
+#include "testhelpers.h" //Defines RTest test;
+#include "T_ViewSortPlugin.h"
+
+LOCAL_D	RFs theFs;
+
+_LIT8(KReverseSortPlugin, "application.vnd.symbian.com/contacts-reverse-sort"); //SimpleSortPlugin DLL Unique name
+
+LOCAL_C void CopyFileL(const TDesC& aFile1, const TDesC& aFile2)
+	{
+    RPIMTestServer serv;
+    User::LeaveIfError(serv.Connect());
+    serv.DeleteFileL(aFile2);
+    serv.CopyFileL(aFile1, aFile2);
+    serv.Close();
+	}
+
+// This test harness uses special framework for asynchronous function testing
+// The test contains of steps. Every step is presented by a function with a name
+// starting with "Step". Predefined step "StepDone" shut the framework down and
+// must always be in the end of the Step list
+
+// Step list is the function pointers array:
+// All of the steps will be called consiquenlty from RunL() function of framework
+void (CTestMachine::*StepFunc[])(void)= 
+	{
+	&CTestMachine::StepRestoreDatabaseL,
+	&CTestMachine::StepNamedRemoteViewsL,
+	&CTestMachine::StepFindViewsL,
+	&CTestMachine::StepDone
+	}; 
+
+_LIT(KTestFile,"c:T_ViewSortPlugin.test");
+_LIT(KTestFileBase,"c:T_ViewSortPlugin.base");
+
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+_LIT(KTestFileBaseFullPath,"C:\\private\\10003A73\\T_ViewSortPlugin.base");
+_LIT(KTestFileFullPath,"C:\\private\\10003A73\\T_ViewSortPlugin.test");
+#else
+_LIT(KTestFileBaseFullPath,"C:\\private\\10003A73\\SQLite__T_ViewSortPlugin.base");
+_LIT(KTestFileFullPath,"C:\\private\\10003A73\\SQLite__T_ViewSortPlugin.test");
+#endif
+
+const TInt64 KRandomSeed=648;
+
+
+CTestMachine::CTestMachine() 
+	: CTimer(EPriorityStandard), iSeed(KRandomSeed), iStep(-1), iSubStep(0), 
+	 iNumOfEvents(0)
+	{
+	};
+
+void CTestMachine::RunL()
+	{
+	(this->*StepFunc[iStep])();
+	}
+
+TInt CTestMachine::RunError(TInt aErrNum)
+	{
+	test.Printf(_L("RunError called with %d...\n"), aErrNum);
+	return KErrNone;
+	}
+
+void CTestMachine::StepRestoreDatabaseL()
+	{
+	test.Printf(_L("Restoring Database..."));
+	delete iDb; iDb = NULL; //Close
+
+	TESTTRAPL(CopyFileL(KTestFileBaseFullPath, KTestFileFullPath));
+	//Open
+	test.Printf(_L("Opening cntmodel..."));
+	iDb=CContactDatabase::OpenL(KTestFile);
+	
+	NextStep();
+	//User::After(1000000);
+	test.Printf(_L("done!\n"));
+	}
+
+
+// Macros for asynchronous operations //
+// These macros is the main part of the framework
+// Every step consists of several substeps. Between the steps active object
+// is idle and waiting for request to be completed, allowing other object to do their work
+// To provide this functionality framework puts hidden switch statement in the RunL 
+// fuction of its active object. The switch is actually hidden by these macros:
+
+// Don't be afraid of the macros, use them like this:
+// void CTestMachine::StepMy()
+//		{
+//		BEGIN_ASYNC_TEST
+//		WAIT_EVENT(1)
+//		WAIT_EVENT(2)
+//		...
+//		WAIT_EVENT(n)
+//		END_ASYNC_TEST
+//		}
+// and you gonna be alright!
+
+#define BEGIN_ASYNC_TEST	\
+	switch(iSubStep)		\
+	{						\
+	case 0:					\
+		{					
+
+#define WAIT_EVENT(num)		\
+		iNumOfEvents = 1;	\
+		}					\
+	break;					\
+	case num:				\
+		{	
+
+#define WAIT_EVENTS(num,numOfEv)\
+		iNumOfEvents = numOfEv;	\
+		}					\
+	break;					\
+	case num:				\
+		{	
+
+
+
+#define WAIT_TIMER(num,time)\
+		iNumOfEvents = 0;   \
+		this->After(time);	\
+		++iSubStep;			\
+		}					\
+	break;					\
+	case num:				\
+		{	
+
+#define END_ASYNC_TEST	\
+		NextStep();		\
+		}				\
+	break;				\
+	default:			\
+		test.Printf(_L("Test step %d doesn't contain substep %d"), iStep, iSubStep);	\
+		User::Leave(KErrAbort);	}
+
+//
+// STEPS //
+
+void CTestMachine::StepFindViewsL()
+	{
+	const TContactViewPreferences viewPrefs = TContactViewPreferences(EUnSortedAtEnd | EContactsOnly);
+	_LIT(KMansell, 	"Mansell");	
+
+	BEGIN_ASYNC_TEST
+		
+		//
+		//Actions:	Create a local view with reverse sort plugin
+		TESTTRAP(iLocalView = CContactLocalView::NewL(*this, *iDb, iSurnNameSortOrder, viewPrefs, KReverseSortPlugin));
+	WAIT_EVENT(1)
+
+		//Expected Result:	Check the order of entries in the view - it must be reverse.
+		test.Printf(_L("Local View created:\n"));
+		CheckViewOrderL(iLocalView);
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Create a remote view with reverse sort plugin
+		TESTTRAP(iRemoteViewReverse = CContactRemoteView::NewL(*this, *iDb, iSurnNameSortOrder, viewPrefs, KReverseSortPlugin));
+	WAIT_EVENT(2)
+
+		//Expected Result:	Check the order of entries in the view - it must be reverse.
+		test.Printf(_L("Remote View created:\n"));
+		CheckViewOrderL(iRemoteViewReverse);
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Create a remote view with default sorting behaviour
+		TESTTRAP(iRemoteViewForward = CContactRemoteView::NewL(*this, *iDb, iSurnNameSortOrder, viewPrefs));
+	WAIT_EVENT(3)
+
+		//Expected Result:	Check the order of entries in the view - it must be forward
+		test.Printf(_L("Remote View created:\n"));
+		CheckViewOrderL(iRemoteViewForward, EFalse, EFalse); //do not Print, forward order
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Create a Find view on top of the local view, using "Ma" search string 
+		iFindDesArray =new(ELeave)CPtrC16Array(1);
+		_LIT(KMa,"Ma");
+		iFindDesArray->AppendL(TPtrC(KMa));
+
+		iLocalFindView= CContactFindView::NewL(*iDb,*iLocalView,*this,iFindDesArray);
+	WAIT_EVENT(4)
+
+		//Expected Result:	Check the order of entries in the find view - it must be reverse
+		test.Printf(_L("LocalFind View created:\n"));
+		CheckViewOrderL(iLocalFindView);
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Create a Find view on top of the reverse remote view, using "el" search string 
+		iFindDesArray->Reset();
+		_LIT(Kel,"el");
+		iFindDesArray->AppendL(TPtrC(Kel));
+		iRemoteFindView = CContactFindView::NewL(*iDb,*iRemoteViewReverse,*this,iFindDesArray);
+	WAIT_EVENT(5)
+		
+		//Expected Result:	Check the order of entries in the find view - it must be reverse
+		test.Printf(_L("RemoteFind View created:\n"));
+		CheckViewOrderL(iRemoteFindView);
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Add a new contact to the database, it must have "ma" and "el" substrings in it 
+		//          to appear in either find view. Check the sorting in every view.		
+		_LIT8(KIrvVCard, "BEGIN:VCARD\r\nVERSION:2.1\r\nN:Mansell;Nigel;11\r\nPensioner\r\nEND:VCARD");
+		RDesReadStream stream(KIrvVCard);
+		stream.PushL();
+		  TBool success(EFalse);
+		  CArrayPtr<CContactItem>* contactItems=iDb->ImportContactsL(TUid::Uid(KUidVCardConvDefaultImpl), stream, success, NULL);
+		CleanupStack::PopAndDestroy(); // stream
+		
+		PUSH(contactItems);
+		  TESTTRUE(success);
+		  test.Printf(_L("%d entry was added created\n"), contactItems->Count());
+		  contactItems->ResetAndDestroy(); //Potential memory leak - must be pushed onto the stack with ResetAndDestroy
+		POPD(contactItems);
+
+	WAIT_EVENTS(6,5) //Waiting for 5 events to arrive (one from each view) 
+		//Note, that if all 5 events won't arrive the code will stuck here
+		//It can be solved with another "timeout" active object, but not yet implemented
+		
+		//Expected Result:	Every view must send an event (5 events in total). 
+		//Sort order for all the views except for RemoteForward view must be reverse. 
+		//New entry must be inserted in every view.
+		test.Printf(_L("Local View:\n"));
+		CheckViewOrderL(iLocalView);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Remote View Reverse:\n"));
+		CheckViewOrderL(iRemoteViewReverse);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Remote View Forward:\n"));
+		CheckViewOrderL(iRemoteViewForward, EFalse, EFalse); //do not Print, forward order
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Local Find View:\n"));
+		CheckViewOrderL(iLocalFindView);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Remote Find View:\n"));
+		CheckViewOrderL(iRemoteFindView);
+		test.Printf(_L("\n\n"));
+		
+		//Searching for Mansell in the DB.
+		TContactItemId manselId = SearchInViewL(iLocalFindView, KMansell);
+		TESTTRUEL(manselId != 0); //Have we found it?
+
+		//Actions:	Change a newly added contact from "Nigel Mansell" to "Ayrton Senna". 
+		CContactItem* mansContact = iDb->OpenContactLX(manselId);
+		PUSH(mansContact);
+		  CContactItemFieldSet& fieldSet      = mansContact->CardFields();
+		  
+		  CContactItemField&    givenNameField = fieldSet[fieldSet.Find(KUidContactFieldGivenName)];
+		  givenNameField.TextStorage()->SetTextL(_L("Ayrton"));
+
+		  CContactItemField&    familyNameField = fieldSet[fieldSet.Find(KUidContactFieldFamilyName)];
+		  familyNameField.TextStorage()->SetTextL(_L("Senna"));
+
+		  CContactItemField&    ordinalNumField = fieldSet[fieldSet.Find(KUidContactFieldAdditionalName)];
+		  ordinalNumField.TextStorage()->SetTextL(_L("20")); //Number is used for sorting checking
+
+		iDb->CommitContactL(*mansContact);
+		POPD(mansContact);
+		CleanupStack::PopAndDestroy(); //record lock
+
+	WAIT_EVENTS(7,10) //Waiting for 10 events to arrive (delele and insert event from each view)
+		//Actions:	Check the sorting in every view.
+	
+		//Expected Result:	10 events should arrive - 5 deletes and 5 inserts. 
+		//Sort order for all the views except for RemoteForward view must be reverse. 
+		//The entry must be updated in local and remote views and should disappear 
+		//from Find views because it doesn't contain substrings "Ma" or "el" anymore.
+		test.Printf(_L("Local View:\n"));
+		CheckViewOrderL(iLocalView, ETrue);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Remote View Reverse:\n"));
+		CheckViewOrderL(iRemoteViewReverse, ETrue);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Remote View Forward:\n"));
+		CheckViewOrderL(iRemoteViewForward, EFalse, EFalse); //do not Print, forward order
+		test.Printf(_L("\n\n"));
+		
+		test.Printf(_L("Local Find View:\n"));
+		CheckViewOrderL(iLocalFindView, ETrue);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Remote Find View:\n"));
+		CheckViewOrderL(iRemoteFindView, ETrue);
+		test.Printf(_L("\n\n"));
+
+		//We changed Mansell to Senna - the entry shouldn't appear in either find views
+		TContactItemId manselId = SearchInViewL(iLocalFindView, KMansell);
+		TESTTRUE(manselId == 0);
+		manselId = SearchInViewL(iRemoteFindView, KMansell);
+		TESTTRUE(manselId == 0);
+
+	CloseView(iLocalFindView);
+	CloseView(iLocalView);
+	CloseView(iRemoteFindView);
+	CloseView(iRemoteViewReverse);
+	CloseView(iRemoteViewForward);
+
+	iFindDesArray->Reset();
+	delete iFindDesArray; iFindDesArray = NULL;
+
+	END_ASYNC_TEST
+	}
+
+
+void CTestMachine::StepNamedRemoteViewsL()
+	{
+	const TContactViewPreferences viewPrefs = TContactViewPreferences(EUnSortedAtEnd | EContactsOnly);
+	_LIT(KNamedRemoteView, "NamedRemoteView");
+
+	RContactViewSortOrder theNameSurnSortOrder;
+	theNameSurnSortOrder.AppendL(KUidContactFieldGivenName);
+	theNameSurnSortOrder.AppendL(KUidContactFieldFamilyName);
+	theNameSurnSortOrder.AppendL(KUidContactFieldPrefixName); //Contains order numbers for given name
+
+	BEGIN_ASYNC_TEST
+		//Actions:	Create named remote view a reverse sorting plugin. Check sorting order.
+		iNamedRemoteView = CContactNamedRemoteView::NewL(*this, KNamedRemoteView, *iDb,iSurnNameSortOrder,viewPrefs, KReverseSortPlugin);
+
+	WAIT_EVENT(1)
+		//Expected Result:	Named remote view must be created - sorting order must be reverse.
+		test.Printf(_L("Named Remote View:\n"));
+		CheckViewOrderL(iNamedRemoteView, ETrue);
+		test.Printf(_L("\n\n"));
+
+		//Actions:	Create another instance of the named remote view with the same name, 
+		//			but without a sorting plugin this time. Check sorting order.
+		TESTTRAP(iNamedRemoteView2 = CContactNamedRemoteView::NewL(*this, KNamedRemoteView, *iDb, iSurnNameSortOrder,viewPrefs));
+	WAIT_EVENT(2)
+
+		//Expected Result:	When we create another named remote view with the name of existing view 
+		// - another copy of the view will not be created, instead will receive the handle 
+		//to existing view. That is why sort order should be as first time - reverse.
+		test.Printf(_L("Another Copy of Named Remote View:\n"));
+		CheckViewOrderL(iNamedRemoteView2, ETrue);
+		test.Printf(_L("\n\n"));
+
+		//Actions:	Change the sort order of the named remote view to sort on 
+		//	Name and then Surname of the contacts. Check sorting for both handles of the view.
+		iNamedRemoteView2->ChangeSortOrderL(theNameSurnSortOrder);
+	WAIT_EVENTS(3,4) //2 EUnavailable and 2 EOrderChanged
+
+		//Expected Result:	Both instances of the view must be sorted in reverse order on 
+		//Names and Surnames of the contacts.
+		test.Printf(_L("First Copy of Named Remote View:\n"));
+		CheckViewOrderL(iNamedRemoteView, ETrue);
+		test.Printf(_L("\n\n"));
+
+		test.Printf(_L("Another Copy of Named Remote View:\n"));
+		CheckViewOrderL(iNamedRemoteView2, ETrue);
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Create a Find view on top of the first instance of named remote view, 
+		//using "Ma" search string 
+		iFindDesArray =new(ELeave)CPtrC16Array(1);
+		_LIT(KMa,"Ma");
+		iFindDesArray->AppendL(TPtrC(KMa));
+
+		iNamedRemoteFindView= CContactFindView::NewL(*iDb,*iNamedRemoteView,*this,iFindDesArray);
+	WAIT_EVENT(4)
+
+		//Expected Result:	Check the order of entries in the find view - it must be reverse,
+		// sorting on Names and Surnames
+		test.Printf(_L("NamedRemoteFind View created:\n"));
+		CheckViewOrderL(iNamedRemoteFindView, ETrue);
+		test.Printf(_L("\n\n"));
+
+		//
+		//Actions:	Create a Find view on top of the second instance of named remote view, 
+		// using "el" search string 
+		iFindDesArray->Reset();
+		_LIT(Kel,"el");
+		iFindDesArray->AppendL(TPtrC(Kel));
+		iNamedRemoteFindView2 = CContactFindView::NewL(*iDb,*iNamedRemoteView2,*this,iFindDesArray);
+	WAIT_EVENT(5)
+
+		//Expected Result:	Check the order of entries in the find view - it must be reverse, 
+		//sorting on Names and Surnames
+		test.Printf(_L("NamedRemoteFind View 2 created:\n"));
+		CheckViewOrderL(iNamedRemoteFindView2, ETrue);
+		test.Printf(_L("\n\n"));
+		
+		CloseView(iNamedRemoteFindView);
+		CloseView(iNamedRemoteFindView2);
+		CloseView(iNamedRemoteView);
+		CloseView(iNamedRemoteView2);
+
+		iFindDesArray->Reset();
+		delete iFindDesArray; iFindDesArray = NULL;
+
+	END_ASYNC_TEST
+
+	theNameSurnSortOrder.Close();
+	}
+
+/** Searches the view for a contact with particular surname */
+TContactItemId CTestMachine::SearchInViewL(CContactViewBase* aView, const TDesC& aSurname)
+	{		
+	//Searching for aSurname in the DB.
+	for (TInt i=aView->CountL() - 1; i >= 0; --i)
+		{
+		const CViewContact& theContact = aView->ContactAtL(i);
+		const TPtrC& surn = theContact.Field(0);
+		if (surn == aSurname)
+			return theContact.Id();
+		}
+	return NULL;
+	}
+
+
+void CTestMachine::CheckViewOrderL(const CContactViewBase* aView, TBool aPrint, TBool aReverseOrder)
+	{
+	ASSERT(aView);
+	const TInt numOfCont = aView->CountL();
+	TInt prevOrder = aReverseOrder ? 99 : -1; //used for first comparison
+	//99 - More than items in database, -1 less than an index of first item
+
+	for (TInt i=0; i < numOfCont; ++i)
+		{
+		const CViewContact& theContact = aView->ContactAtL(i);
+		const TPtrC& theNum = theContact.Field(2);
+		
+		const TPtrC& theFamilyName = theContact.Field(0);
+		if (aPrint)
+			{ //Print only if we asked to
+			const TPtrC& theGivenName = theContact.Field(1);
+			test.Printf(_L("%S %S, %S\n"), &theNum, &theFamilyName, &theGivenName);
+			}
+
+		//Order checking 
+		//The number of contact in alphabetically sorted list is given in MiddleName field
+		TLex16 strOrder(theNum);
+		TInt   currOrder; 
+		TESTNOERRL(strOrder.Val(currOrder)) //Convert string to integer
+
+		if (aReverseOrder)
+			TESTTRUE(prevOrder > currOrder) //Descending order for reverse sorting
+		else
+			TESTTRUE(prevOrder < currOrder) //Ascending order for forward sorting
+
+		prevOrder = currOrder;
+		}
+	}
+
+
+void CTestMachine::StepOOML()
+	{
+	//TInt allocCells(0);
+
+	BEGIN_ASYNC_TEST
+		if (iOOMCounter % 100 == 0)
+			test.Printf(_L("Step: %d...\n"), iOOMCounter);
+		++iOOMCounter;
+
+		//__SRVHEAP_SETFAIL(iOOMCounter);
+		//allocCells = iAgnServ->_DebugRequestAllocatedCellsL();				//__UHEAP_MARK;
+		
+		int ret=0;
+		//TRAP(ret, DoSomething); 
+		
+		if (ret == KErrNoMemory)
+			{
+			//iAgnServ->_DebugSetHeapFail(RHeap::ENone,1);					  //__UHEAP_RESET; 
+			//TESTVALUEL(iAgnServ->_DebugRequestAllocatedCellsL(), allocCells); //__UHEAP_MARKEND; 
+
+			--iSubStep; //Stay in the same step
+			//Completed(KErrNone);
+			}
+		else if (ret != KErrNone)
+			{
+			//__SRVHEAP_RESET;
+			TESTNOERRL(ret); //Bad leaving code
+			}
+		
+		iError = NULL;
+
+	WAIT_EVENT(1);
+		if (iError == KErrNoMemory)
+			{//__UHEAP_MARKEND; //Cannot test, because agenda stores Category in long-living object
+			iSubStep -=2; //One steps back
+			//__SRVHEAP_RESET;
+			}
+		else if (iError != KErrNone)
+			{
+			TESTNOERRL(iError); //Bad leaving code
+			}
+		
+		__UHEAP_RESET;
+		//Completed(KErrNone);
+
+	WAIT_EVENT(2);
+
+		test.Printf(_L("OOM test finished successfully on step: %d...\n"), iOOMCounter);
+
+	END_ASYNC_TEST
+	}
+
+
+void CTestMachine::StepDone()
+	{
+	test.Printf(_L("Shutting down\n"));
+	User::After(1000000); // Wait for any server side processes to release the file
+    TRAP_IGNORE(CContactDatabase::DeleteDatabaseL(KTestFileBase));
+    TRAP_IGNORE(CContactDatabase::DeleteDatabaseL(KTestFile));
+	CActiveScheduler::Stop();
+	}
+
+
+void CTestMachine::HandleContactViewEvent(const CContactViewBase& aView,
+										  const TContactViewEvent& aEvent)
+	{
+	//Indentifying the view
+	TPtrC viewName(KNullDesC);
+	_LIT(KLocalView, "LocalView");
+	_LIT(KRemoteViewReverse, "RemoteViewReverse");
+	_LIT(KRemoteViewForward, "RemoteViewForward");
+	_LIT(KNamedRemoteView, "NamedRemoteView");
+	_LIT(KNamedRemoteView2, "NamedRemoteView2");
+	_LIT(KLocalFindView, "LocalFindView");
+	_LIT(KRemoteFindView, "RemoteFindView");
+	_LIT(KNamedRemoteFindView, "NamedRemoteFindView");
+	_LIT(KNamedRemoteFindView2, "NamedRemoteFindView2");
+
+	if (&aView == iLocalView)
+		viewName.Set(KLocalView);
+	else if (&aView == iRemoteViewReverse)
+		viewName.Set(KRemoteViewReverse);
+	else if (&aView == iRemoteViewForward)
+		viewName.Set(KRemoteViewForward);
+	else if (&aView == iLocalFindView)
+		viewName.Set(KLocalFindView);
+	else if (&aView == iRemoteFindView)
+		viewName.Set(KRemoteFindView);
+	else if (&aView == iNamedRemoteView)
+		viewName.Set(KNamedRemoteView);
+	else if (&aView == iNamedRemoteView2)
+		viewName.Set(KNamedRemoteView2);
+	else if (&aView == iNamedRemoteFindView)
+		viewName.Set(KNamedRemoteFindView);
+	else if (&aView == iNamedRemoteFindView2)
+		viewName.Set(KNamedRemoteFindView2);
+
+
+	TPtrC eventName(KNullDesC);
+	_LIT(KEventUnavailable, "Unavailable");
+	_LIT(KEventReady, "Ready");
+	_LIT(KEventSortOrderChanged, "Sort Order Changed");
+	_LIT(KEventSortError, "Sort Error");
+	_LIT(KEventServerError, "Server Error");
+	_LIT(KEventIndexingError, "Indexing Error");
+	_LIT(KEventItemAdded, "Item Added");
+	_LIT(KEventItemRemoved, "Item Removed");
+	_LIT(KEventGroupChanged, "Group Changed");
+	_LIT(KEventUnknown, "unknown ??");
+
+	
+	switch (aEvent.iEventType)
+		{
+	case TContactViewEvent::EUnavailable:
+		eventName.Set(KEventUnavailable);
+		break;
+	case TContactViewEvent::EReady:
+		eventName.Set(KEventReady);
+		break;
+	case TContactViewEvent::ESortOrderChanged:
+		eventName.Set(KEventSortOrderChanged);
+		break;
+	case TContactViewEvent::ESortError:
+		eventName.Set(KEventSortError);
+		break;
+	case TContactViewEvent::EServerError:
+		eventName.Set(KEventServerError);
+		break;
+	case TContactViewEvent::EIndexingError:
+		eventName.Set(KEventIndexingError);
+		break;
+	case TContactViewEvent::EItemAdded:
+		eventName.Set(KEventItemAdded);
+		break;
+	case TContactViewEvent::EItemRemoved:
+		eventName.Set(KEventItemRemoved);
+		break;
+	case TContactViewEvent::EGroupChanged:
+		eventName.Set(KEventGroupChanged);
+		break;
+	default:
+		eventName.Set(KEventUnknown);
+		break;
+		}
+
+	test.Printf(_L("=> %S has sent an event: %S\n"), &viewName, &eventName);
+
+//	iError = aError;
+
+	
+	if (--iNumOfEvents == 0) 
+		{ //We have received all planned events
+		++iSubStep;
+
+		TRequestStatus *pS=&iStatus;
+		User::RequestComplete(pS,KErrNone);
+		SetActive();
+		}
+	else if (iNumOfEvents < 0)
+		{
+		TESTTRUE(EFalse);  //Too many events
+		}
+	}
+
+
+CTestMachine* CTestMachine::NewLC()
+	{
+	CTestMachine* self = new (ELeave) CTestMachine;
+	PUSH(self);
+	self->ConstructL();
+	CActiveScheduler::Add(self);
+	self->NextStep();
+	return self;
+	}
+
+void CTestMachine::ConstructL()
+	{
+	CTimer::ConstructL();
+
+	TESTTRAP(iDb=CContactDatabase::ReplaceL(KTestFileBase));
+
+	RFileReadStream vcard;
+	CleanupClosePushL(vcard);
+	TESTNOERR(vcard.Open(theFs, _L("z:\\cntvcard\\T_ViewSortPlugin.vcf"), EFileRead));
+
+	TBool success=EFalse;
+	CArrayPtr<CContactItem>* contactItems=iDb->ImportContactsL(TUid::Uid(KUidVCardConvDefaultImpl), vcard, success, NULL);
+	CleanupStack::PopAndDestroy(); //read stream vcard
+
+	TESTTRUEL(success);
+
+	test.Printf(_L("Sample Database with %d entries created\n"), contactItems->Count());
+
+	contactItems->ResetAndDestroy();
+	delete contactItems;
+
+	//Prepare sort order for the views
+	iSurnNameSortOrder.AppendL(KUidContactFieldFamilyName);
+	iSurnNameSortOrder.AppendL(KUidContactFieldGivenName);
+	iSurnNameSortOrder.AppendL(KUidContactFieldAdditionalName); //Contains order number for family name
+	}
+
+CTestMachine::~CTestMachine()
+	{
+	iSurnNameSortOrder.Close();
+	//iRemoteSortOrder.Close();
+
+	delete iDb;
+	}
+
+void CTestMachine::CloseView(CContactViewBase* aView)
+	{
+	if (aView)
+		aView->Close(*this);
+	aView = NULL;
+	}
+
+
+void CTestMachine::NextStep()
+	{
+	iError = KErrNone; //reset callback error variable
+	++iStep;
+	iSubStep = 0;
+
+	TRequestStatus *pS=&iStatus;
+	User::RequestComplete(pS,KErrNone);
+	SetActive();
+	}
+
+LOCAL_C void doMainL()
+	{
+	TESTNOERR(theFs.Connect());
+	CleanupClosePushL(theFs);
+	CTestMachine* tm = CTestMachine::NewLC();
+	CActiveScheduler::Start();
+	CleanupStack::PopAndDestroy(tm);
+	CleanupStack::PopAndDestroy(); // Close FS
+	}
+
+
+/**
+
+@SYMTestCaseID     PIM-T-VIEWSORTPLUGIN-0001
+
+*/
+
+GLDEF_C TInt E32Main()
+	{
+	__UHEAP_MARK;
+	test.Title();
+	test.Start(_L("@SYMTESTCaseID:PIM-T-VIEWSORTPLUGIN-0001 T_ViewSortPlugin"));
+
+	CActiveScheduler* scheduler=new CActiveScheduler;
+	test(scheduler != NULL);
+	CActiveScheduler::Install(scheduler);
+	CTrapCleanup* theCleanup=CTrapCleanup::New();
+	TRAPD(ret,doMainL());	
+	test(ret==KErrNone);
+	test(__NB_failures == 0); //There were failures before.
+	delete theCleanup;	
+	delete scheduler;
+	test.End();
+	test.Close();
+	__UHEAP_MARKEND;
+	return(KErrNone);
+	}
+
+
+
+
+// Helpers //
+void RandomText(TDes& aText,TInt64& aSeed)
+{
+	TInt numChar=Math::Rand(aSeed)%aText.MaxLength();
+	if(Math::Rand(aSeed)%2)
+		{
+		for (TInt i=0;i<numChar;++i)
+			{
+			TInt c=Math::Rand(aSeed)%6;
+			c= (c==0)? ' ' : ((Math::Rand(aSeed)%26)+    ((c==2)? 'A' : 'a'));
+			aText.Append(c);
+			}
+		}
+	else
+		aText=KNullDesC;
+}
+
+
+//Export routine
+//static void ExportContactAsVCardL(CContactDatabase& aDatabase, TContactItemId aId, RFs& aFsSession, const TDesC& aVCardFileName)
+/*	CContactIdArray* idArray = CContactIdArray::NewLC();
+	idArray->AddL(id);
+	//
+	RFile outfile;
+	User::LeaveIfError(outfile.Replace(theFs, theFamilyName, EFileWrite));
+	CleanupClosePushL(outfile);
+	//
+	RFileWriteStream writeStream(outfile);
+	CleanupClosePushL(writeStream);
+	//	
+	const TUid KVersitVCardUid = { KUidVCardConvDefaultImpl };
+	iDb->ExportSelectedContactsL(KVersitVCardUid, *idArray, writeStream, CContactDatabase::EDefault);
+	writeStream.CommitL();
+	CleanupStack::PopAndDestroy(3, idArray); // writeStream, outfile, idArray*/
+