pimappservices/calendar/tsrc/tcal_observer_modifier.cpp
changeset 0 f979ecb2b13e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/tsrc/tcal_observer_modifier.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,1060 @@
+// Copyright (c) 2005-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 "tcal_observer_modifier.h"
+
+void ResetAndDestroyCalEntryArray(TAny*);
+
+LOCAL_D const TInt KNumberBulkEntries(50);
+LOCAL_D const TInt KNumberBulkEntriesToOverflowNotificationBuffer(51);
+
+_LIT8(KGuid1, "guid");
+_LIT8(KEntryGuid, "A_DUMMY_GUID");
+_LIT(KSummary1, "Reminder Parent entry");
+_LIT(KDescription1, "Source entry");
+_LIT(KSummary2, "Reminder child entry with repeat rule");
+_LIT(KDescription2, "Updating the Parent entry");
+
+CTestAppModifier* CTestAppModifier::NewL()
+	{
+	CTestAppModifier* self = new(ELeave) CTestAppModifier;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CTestAppModifier::ConstructL()
+	{
+	CTestApp::ConstructL();
+	iCalTestLibrary = CCalTestLibrary::NewL();
+	iCalTestLibrary->OpenFileL(KCalendarFile());
+	
+	iChunk.OpenGlobal(KChunkName(), EFalse);
+	iNumExpectedChanges = reinterpret_cast<TInt*>(iChunk.Base());
+	(*iNumExpectedChanges) = 0;
+	iExpectedChanges = sizeof(TInt) + reinterpret_cast<TCalChangeEntry*>(iChunk.Base());
+	}
+
+CTestAppModifier::~CTestAppModifier()
+	{
+	delete iCalTestLibrary;
+	}
+	
+void CTestAppModifier::ClearEntryL()
+	{
+	// this function deletes all entries with the UID used in this test harness
+	for (TInt i(0) ; i < iNumEntriesToDelete ; ++i)
+		{
+		iExpectedChanges[i].iChangeType = MCalChangeCallBack2::EChangeDelete;
+		}
+	iNumEntriesToDelete = 0;
+	
+	iCalTestLibrary->AsynCGetEntryViewL().DeleteL(*iUidArray);
+	
+	delete iUidArray;
+	iUidArray = NULL;
+	}
+
+CCalEntry* CTestAppModifier::CreateEntryLC(CCalEntry::TType aType, TTime aTimeLocal)
+	{
+	// create a new unique guid every time we create an entry   
+	TBuf8<255> buf; // 255 is the Maximum guid length;
+	buf.Num(iGuidNum++);
+	HBufC8* guid = buf.AllocLC();
+	
+	if (!iUidArray)
+		{
+		iUidArray = new (ELeave) CDesC8ArraySeg(1000);
+		}
+	
+	iUidArray->AppendL(*guid);
+	
+	CCalEntry* entry = CCalEntry::NewL(aType, guid, CCalEntry::EMethodNone, 0);
+	CleanupStack::Pop(guid);
+	CleanupStack::PushL(entry);
+	
+	// Set the start and end time as passed to us
+	TCalTime calTime1;
+	TCalTime calTime2;
+	calTime1.SetTimeLocalL(aTimeLocal);
+	
+	//for undated todo, both start and end time shud be NULL
+	if(aTimeLocal != Time::NullTTime())
+		{
+		calTime2.SetTimeLocalL(aTimeLocal + TTimeIntervalHours(1));
+		}
+	else
+		{
+		calTime2.SetTimeLocalL(aTimeLocal);
+		}
+
+	entry->SetStartAndEndTimeL(calTime1, calTime2);
+	return entry;
+	}
+	
+void CTestAppModifier::UpdateEntriesL(TBool aInRange)
+	{
+	// update every entry the we have added to the store so far
+	const TInt KUidCount(iUidArray->Count());
+	for (TInt j(0) ; j < KUidCount ; ++j)
+		{
+		RPointerArray<CCalEntry> calEntries;
+		CleanupResetAndDestroyPushL(calEntries);
+		iCalTestLibrary->SynCGetEntryViewL().FetchL((*iUidArray)[j], calEntries);
+		
+		const TInt KEntryCount(calEntries.Count());
+		for (TInt i(0) ; i < KEntryCount ; ++i)
+			{
+			calEntries[i]->SetLastModifiedDateL();
+			if (aInRange)
+				{
+				iExpectedChanges[*iNumExpectedChanges].iChangeType = MCalChangeCallBack2::EChangeModify;
+				iExpectedChanges[*iNumExpectedChanges].iEntryId = calEntries[i]->LocalUidL();
+				++(*iNumExpectedChanges);	
+				}
+			}
+			
+		TInt numSucsessful;
+		iCalTestLibrary->AsynCGetEntryViewL().UpdateL(calEntries, numSucsessful);
+		
+		CleanupStack::PopAndDestroy(); //calEntries.ResetAndDestroy();
+		}	
+
+	if(KUidCount>20)
+		{//bulk operation
+		*iNumExpectedChanges = 1;
+		}
+
+	}
+	
+void CTestAppModifier::StoreEntryLD(CCalEntry* aEntry, TBool aInRange)
+	{
+	StoreEntryLC(aEntry, aInRange);
+	CleanupStack::PopAndDestroy(aEntry);
+	}
+	
+void CTestAppModifier::StoreEntryLC(CCalEntry* aEntry, TBool aInRange)
+	{
+	CleanupStack::PushL(aEntry);
+	
+	RPointerArray<CCalEntry> entriesToAdd;
+	CleanupClosePushL(entriesToAdd);
+	
+	entriesToAdd.AppendL(aEntry);
+	
+	if (aInRange)
+		{
+		iExpectedChanges[*iNumExpectedChanges].iChangeType = MCalChangeCallBack2::EChangeAdd;
+		if (aEntry->EntryTypeL() == CCalEntry::ETodo)
+			{
+			iExpectedChanges[*iNumExpectedChanges].iEntryType = MCalChangeCallBack2::EChangeEntryTodo;
+			}
+		else
+			{
+			iExpectedChanges[*iNumExpectedChanges].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;	
+			}
+		iExpectedChanges[*iNumExpectedChanges].iEntryId = 0;
+		++(*iNumExpectedChanges);
+		++iNumEntriesToDelete;
+		}
+	
+	TInt successfulAdd(0);
+	iCalTestLibrary->SynCGetEntryViewL().StoreL(entriesToAdd, successfulAdd);
+	
+	CleanupStack::PopAndDestroy(); // entriesToAdd.Close()
+	}
+
+void CTestAppModifier::RunTestL()
+	{
+	while (*iTestCase < EAmount)
+		{
+		NextTestL();         // Prepare the test case
+		iSemaphore.Signal(); // Done preparing: Report to the manager thread that it can continue now
+		RThread().Suspend(); // Rest here until the manager thread has finished this test case
+		}
+	}
+
+	
+void CTestAppModifier::NextTestL()
+	{		
+	// Create some variables for use in the test cases
+	TCalTime startBoundaryStartTime;
+	startBoundaryStartTime.SetTimeLocalL(KRangeStartTime - TTimeIntervalDays(1));
+	TCalTime startBoundaryEndTime;
+	startBoundaryEndTime.SetTimeLocalL(KRangeStartTime - TTimeIntervalDays(1) + TTimeIntervalHours(1));
+
+	TCalTime endBoundaryStartTime;
+	endBoundaryStartTime.SetTimeLocalL(KRangeEndTime - TTimeIntervalDays(1));
+	TCalTime endBoundaryEndTime;
+	endBoundaryStartTime.SetTimeLocalL(KRangeEndTime - TTimeIntervalDays(1) + TTimeIntervalHours(1));
+	
+	TCalTime outsideStartTime;
+	outsideStartTime.SetTimeLocalL(KRangeEndTime + TTimeIntervalDays(1));
+	TCalTime outsideEndTime;
+	outsideEndTime.SetTimeLocalL(KRangeEndTime + TTimeIntervalDays(1) + TTimeIntervalHours(1));
+	
+	TCalRRule rRuleStartBoundary(TCalRRule::EDaily);
+	rRuleStartBoundary.SetDtStart(startBoundaryStartTime);
+	rRuleStartBoundary.SetCount(5);
+	rRuleStartBoundary.SetInterval(1);
+	
+	TCalRRule rRuleEndBoundary(TCalRRule::EDaily);
+	rRuleEndBoundary.SetDtStart(endBoundaryStartTime);
+	rRuleEndBoundary.SetCount(5);
+	rRuleEndBoundary.SetInterval(1);
+	
+	TCalRRule rRuleOutside(TCalRRule::EDaily);
+	rRuleOutside.SetDtStart(outsideStartTime);
+	rRuleOutside.SetInterval(1);
+	rRuleOutside.SetCount(5);
+			
+	TInt numSucsess;
+	
+	switch (*iTestCase)
+		{
+		case EEntryOutOfRange:
+			{
+			HBufC8* guid = KEntryGuid().AllocLC();
+			CCalEntry* entry = CCalEntry::NewL(CCalEntry::EReminder, guid, CCalEntry::EMethodNone, 0);
+			CleanupStack::Pop(guid);
+			CleanupStack::PushL(entry);	
+		 
+			TTime startTime(TDateTime(1984, EJune, 9, 10, 0, 0, 0)); // 10 June 1984 10am
+			TCalTime calTime1;
+			calTime1.SetTimeLocalFloatingL(startTime);
+			entry->SetStartAndEndTimeL(calTime1, calTime1); // end time is ignored for for reminder
+			entry->SetSummaryL(KSummary1());
+			entry->SetDescriptionL(KDescription1());
+
+			TCalRRule rule(TCalRRule::EDaily);
+			rule.SetDtStart(calTime1);
+			rule.SetInterval(1);
+			rule.SetCount(5);
+			entry->SetRRuleL(rule);
+
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry,ETrue); // store the entry which is out of range
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EEntryOutOfRange1:
+			{
+			HBufC8* guid2 = KEntryGuid().AllocLC();
+
+			TTime recurId(TDateTime(1984, EJune, 11, 10, 0, 0, 0)); // 12 June 1984 10am
+			TCalTime calRecurId;
+			calRecurId.SetTimeLocalFloatingL(recurId);
+
+			CCalEntry* childEntry = CCalEntry::NewL(CCalEntry::EReminder, guid2, CCalEntry::EMethodNone, 0, calRecurId, CalCommon::EThisAndFuture);
+			
+			CleanupStack::Pop(guid2);
+			CleanupStack::PushL(childEntry);	
+
+			TTime startTime2(TDateTime(1984, EJune, 15, 15, 0, 0, 0)); // 16 June 1984 3pm
+			TTime endTime2(TDateTime(1984, EJune, 15, 16, 0, 0, 0)); // 16 June 1984 4pm
+			
+			TCalTime calStartTime2;
+			calStartTime2.SetTimeLocalFloatingL(startTime2);
+			TCalTime calEndTime2;
+			calEndTime2.SetTimeLocalFloatingL(endTime2);
+			childEntry->SetStartAndEndTimeL(calStartTime2, calEndTime2);
+			
+			childEntry->SetSummaryL(KSummary2);
+			childEntry->SetDescriptionL(KDescription2);
+
+			TCalRRule rule2(TCalRRule::EDaily);
+			rule2.SetDtStart(calStartTime2);
+			rule2.SetInterval(1);
+			rule2.SetCount(5);
+			childEntry->SetRRuleL(rule2);
+
+			CleanupStack::Pop(childEntry);
+			StoreEntryLD(childEntry, ETrue); // store the entry which is out of range
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EApptInsideRange1:
+			{
+			// Add an appointment inside the range
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, ETrue);
+			}
+			break;
+		case EApptInsideRange2:
+			{
+			UpdateEntriesL(ETrue);
+			}
+			break;
+		case EApptInsideRange3:
+			{
+			*iNumExpectedChanges = 1;
+			ClearEntryL();
+			}
+			break;	
+		case EApptOutsideRange1:
+			{
+			// add appt outside time range
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime - TTimeIntervalMonths(3));
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;
+		case EApptOutsideRange2:
+			{
+			UpdateEntriesL(EFalse);
+			}
+			break;
+		case EApptOutsideRange3:
+			{
+			ClearEntryL();
+			}
+			break;
+
+		case ENotifyNonResponsive:
+			{
+			// Disable notification then add a ToDo.
+			iCalTestLibrary->GetSession().DisableChangeBroadcast();
+			CCalEntry* entry = CreateEntryLC(CCalEntry::ETodo, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			
+			/* this client will be non responsive */
+ 			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeUndefined;
+ 			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryAll;
+ 			iExpectedChanges[0].iEntryId = 0;
+//The timer which enbles the broadcast added in 9.3 is not implemented here
+ 			*iNumExpectedChanges = 0;
+ 			//*iNumExpectedChanges = 1;
+//
+			}
+			break;
+		case ENotifyNonResponsive1:
+			{
+//The timer which enbles the broadcast added in 9.3 is not implemented here
+			*iNumExpectedChanges = 0;
+			iNumEntriesToDelete = 0;
+			//*iNumExpectedChanges = 1;
+			//iNumEntriesToDelete = 1;
+//			
+			ClearEntryL();
+			/* notification is still not enabled */
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeUndefined;				
+			}
+			break;
+
+		case ETodoInsideRange1:
+			{
+			// Add a todo within the time range, but disable notification
+			iCalTestLibrary->GetSession().DisableChangeBroadcast();
+			CCalEntry* entry = CreateEntryLC(CCalEntry::ETodo, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;
+		case ETodoInsideRange2:
+			{
+			// re-enable notification and set up the expected values 
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeUndefined;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryAll;
+			iExpectedChanges[0].iEntryId = 0;
+			*iNumExpectedChanges = 1;
+			iCalTestLibrary->GetSession().EnableChangeBroadcast();
+			}
+			break;
+		case ETodoInsideRange3:
+			{
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryTodo;
+			UpdateEntriesL(ETrue);
+			}
+			break;
+		case ETodoInsideRange4:
+			{
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			ClearEntryL();
+			}
+			break;
+		case ETodoOutsideRange1:
+			{
+			// Add a todo outside of the time range
+			CCalEntry* entry = CreateEntryLC(CCalEntry::ETodo, KRangeEndTime + TTimeIntervalHours(4));
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;
+		case ETodoOutsideRange2:
+			{
+			UpdateEntriesL(EFalse);
+			}
+			break;
+			
+		case ETodoOutsideRange3:
+			{
+			ClearEntryL();
+			}
+			break;
+		case EAddUndatedTodo:
+			{
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeAdd;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryTodo;
+			iExpectedChanges[0].iEntryId = 0;
+			*iNumExpectedChanges = 0;
+
+			CCalEntry* entry = CreateEntryLC(CCalEntry::ETodo, Time::NullTTime());
+			entry->SetSummaryL(_L("original todo"));
+			CleanupStack::Pop(entry);
+			StoreEntryLC(entry, ETrue);
+			iExpectedChanges[0].iEntryId = entry->LocalUidL();
+			CleanupStack::PopAndDestroy(entry);
+			}
+			break;
+		case EUpdateUndatedTodo:
+			{
+			//Create a modified todo with new GUID.
+			CCalEntry* newEntry = CreateEntryLC(CCalEntry::ETodo, Time::NullTTime());
+			iUidArray->Delete(0);
+			newEntry->SetSummaryL(_L("Modified todo"));
+			
+			CCalEntry* entry = iCalTestLibrary->SynCGetEntryViewL().FetchL(iExpectedChanges[0].iEntryId);
+			CleanupStack::PushL(entry);
+			entry->CopyFromL(*newEntry);
+			entry->SetLocalUidL(iExpectedChanges[0].iEntryId);
+			CleanupStack::Pop(entry);
+			CleanupStack::PopAndDestroy(newEntry);
+			
+			*iNumExpectedChanges = 1;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryTodo;
+			StoreEntryLD(entry, EFalse);
+			--iNumEntriesToDelete;
+			}
+			break;
+		case EClearUndatedTodo:
+			{	
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			ClearEntryL();
+			}
+			break;
+		case EMultipleInAndOutside1:
+			{
+			// Add multiple entries in and outside range
+			CCalEntry* todoOutRange = CreateEntryLC(CCalEntry::ETodo, KRangeEndTime + TTimeIntervalHours(4));
+			CleanupStack::Pop(todoOutRange);
+			StoreEntryLD(todoOutRange, EFalse);
+			CCalEntry* apptOutOfRange = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime - TTimeIntervalMonths(3));
+			CleanupStack::Pop(apptOutOfRange);
+			StoreEntryLD(apptOutOfRange, EFalse);
+			CCalEntry* apptInRange = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(apptInRange);
+			StoreEntryLD(apptInRange);
+			CCalEntry* todoInRange = CreateEntryLC(CCalEntry::ETodo, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(todoInRange);
+			StoreEntryLD(todoInRange);
+			}
+			break;
+		case EMultipleInAndOutside2:
+			{	
+			*iNumExpectedChanges = 2;
+			ClearEntryL();
+			}
+			break;
+		case EBulkAdd:
+			{
+			// add a lot of entries quickly to see if the notification can keep up
+			for (TInt i(0) ; i < KNumberBulkEntries; ++i)
+				{
+				CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime + TTimeIntervalDays(5));
+				CleanupStack::Pop(entry);
+				StoreEntryLD(entry);
+				}
+			}
+			break;
+		case EBulkDelete:
+			{
+			// Delete all the entries in the bulk add
+			*iNumExpectedChanges = 1;//bulk operation
+			ClearEntryL();
+			}
+			break;
+		case EBulkAddToOverflowNotificationBuffer:
+			{
+			// Add a lot of entries and wait for 5 seconds (in the manager) and overflow the notification buffer
+			for (TInt i(0) ; i < KNumberBulkEntriesToOverflowNotificationBuffer; ++i)
+				{
+				CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime + TTimeIntervalDays(5));
+				CleanupStack::Pop(entry);
+				StoreEntryLD(entry);
+				}
+				
+			// set up expected data
+			*iNumExpectedChanges = 1;
+			// Expecting one Undefined Change
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryAll;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeUndefined;
+			iExpectedChanges[0].iEntryId = 0;
+			}
+			break;
+		case EBulkDeleteToOverflowNotificationBuffer:
+			{
+			// Delete all the entries in the bulk add
+			*iNumExpectedChanges = 1;
+			iNumEntriesToDelete = KNumberBulkEntriesToOverflowNotificationBuffer;
+			ClearEntryL();
+			// Expecting one Undefined Change
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeUndefined;
+			}
+			break;
+		case ERepeatingEitherSideOfRange1:
+			{
+			// Create an entry that has instances before and after the observation range
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime - TTimeIntervalDays(1));
+			TCalRRule rRule(TCalRRule::EYearly);
+			TCalTime calTime;
+			calTime.SetTimeLocalL(KRangeStartTime - TTimeIntervalDays(1));
+			rRule.SetDtStart(calTime);
+			rRule.SetCount(2);
+			rRule.SetInterval(2);
+			entry->SetRRuleL(rRule);
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;	
+		case ERepeatingEitherSideOfRange2:
+			{
+			UpdateEntriesL(EFalse);
+			}
+			break;
+		case ERepeatingEitherSideOfRange3:
+			{
+			ClearEntryL();
+			}
+			break;
+		case ERepeatingAcrossStartBoundary1:
+			{
+			// Create a repeating entry starting outside and finishing inside
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime - TTimeIntervalDays(1));
+			entry->SetRRuleL(rRuleStartBoundary);
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry);
+			}
+			break;
+		case ERepeatingAcrossStartBoundary2:
+			{
+			RPointerArray<CCalEntry> calEntryArray;
+			CleanupResetAndDestroyPushL(calEntryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL((*iUidArray)[iUidArray->Count() - 1], calEntryArray);
+			// Move the repeating entry to outside the range
+			calEntryArray[0]->SetStartAndEndTimeL(outsideStartTime, outsideEndTime);
+			calEntryArray[0]->SetRRuleL(rRuleOutside);
+	
+			// set up expected data
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = calEntryArray[0]->LocalUidL();
+			
+			iCalTestLibrary->SynCGetEntryViewL().UpdateL(calEntryArray, numSucsess);
+			CleanupStack::PopAndDestroy();//calEntryArray.ResetAndDestroy();
+			}
+			break;
+		case ERepeatingAcrossStartBoundary3:
+			{
+			ClearEntryL();
+			}
+			break;
+		case ERepeatingAcrossStartBoundary4:
+			{
+			// Create a repeating entry outside time range
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeEndTime + TTimeIntervalDays(5));
+			entry->SetRRuleL(rRuleOutside);
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;
+		case ERepeatingAcrossStartBoundary5:
+			{
+			// get the entry
+			RPointerArray<CCalEntry> calEntryArray;
+			CleanupResetAndDestroyPushL(calEntryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL((*iUidArray)[iUidArray->Count() - 1], calEntryArray);
+			// Move the repeating entry to inside the time range
+			calEntryArray[0]->SetStartAndEndTimeL(startBoundaryStartTime, startBoundaryEndTime);
+			calEntryArray[0]->SetRRuleL(rRuleStartBoundary);
+	
+			// set up expected data
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = calEntryArray[0]->LocalUidL();
+	
+			iCalTestLibrary->SynCGetEntryViewL().UpdateL(calEntryArray, numSucsess);
+			CleanupStack::PopAndDestroy(); //calEntryArray.ResetAndDestroy();
+			}
+			break;
+		case ERepeatingAcrossStartBoundary6:
+			{
+			*iNumExpectedChanges = 1;
+			ClearEntryL();
+			}
+			break;
+		case ERepeatingAcrossEndBoundary1:
+			{
+			// Create a repeating across the end boundary
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeEndTime - TTimeIntervalDays(1));
+			entry->SetRRuleL(rRuleEndBoundary);
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry);
+			}
+			break;
+		case ERepeatingAcrossEndBoundary2:
+			{
+			// get the entry
+			RPointerArray<CCalEntry> calEntryArray;
+			CleanupResetAndDestroyPushL(calEntryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL((*iUidArray)[iUidArray->Count() - 1], calEntryArray);
+
+			// Move the repeating entry to outside the time range
+			calEntryArray[0]->SetStartAndEndTimeL(outsideStartTime, outsideEndTime);
+			calEntryArray[0]->SetRRuleL(rRuleOutside);
+	
+			// set up expected data
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = calEntryArray[0]->LocalUidL();
+	
+			iCalTestLibrary->SynCGetEntryViewL().UpdateL(calEntryArray, numSucsess);
+			CleanupStack::PopAndDestroy(); //calEntryArray.ResetAndDestroy();
+			}
+			break;
+		case ERepeatingAcrossEndBoundary3:
+			{
+			*iNumExpectedChanges = 0;
+			ClearEntryL();
+			}
+			break;
+		case ERepeatingAcrossEndBoundary4:
+			{
+			// Create a repeating entry outside the time range
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeEndTime + TTimeIntervalDays(5));
+			entry->SetRRuleL(rRuleOutside);
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;	
+		case ERepeatingAcrossEndBoundary5:
+			{
+			RPointerArray<CCalEntry> calEntryArray;
+			CleanupResetAndDestroyPushL(calEntryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL((*iUidArray)[iUidArray->Count() - 1], calEntryArray);
+			
+			// Move the repeating entry to across the end boundary
+			calEntryArray[0]->SetStartAndEndTimeL(endBoundaryStartTime, endBoundaryEndTime);
+			calEntryArray[0]->SetRRuleL(rRuleEndBoundary);
+	
+			// set up expected data
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = calEntryArray[0]->LocalUidL();
+
+			iCalTestLibrary->SynCGetEntryViewL().UpdateL(calEntryArray, numSucsess);
+			CleanupStack::PopAndDestroy(); //calEntryArray.ResetAndDestroy();
+			}
+			break;
+		case ERepeatingAcrossEndBoundary6:
+			{
+			*iNumExpectedChanges = 1;
+			ClearEntryL();
+			}
+			break;
+		case EFilterOnlyEventEntries1:
+			{
+			// do nothing, filter is changing
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EFilterOnlyEventEntries2:
+			{
+			// Add todo entry, should not be notified
+			CCalEntry* entryTodo = CreateEntryLC(CCalEntry::ETodo, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entryTodo);
+			StoreEntryLD(entryTodo, EFalse);
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EFilterOnlyEventEntries3:
+			{
+			// Add event entry, should be notified
+			CCalEntry* entryAppt = CreateEntryLC(CCalEntry::EEvent, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entryAppt);
+			StoreEntryLD(entryAppt, ETrue);	
+			*iNumExpectedChanges = 1;
+			}
+			break;
+		case EFilterOnlyEventEntries4:
+			{
+			*iNumExpectedChanges = 1;
+			ClearEntryL();
+			}
+			break;
+		case EFilterOnlyTodoEntries1:
+			{
+			// do nothing, filter is changing
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EFilterOnlyTodoEntries2:
+			{
+			// Add todo entry, should be notified
+			CCalEntry* entryTodo = CreateEntryLC(CCalEntry::ETodo, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entryTodo);
+			StoreEntryLD(entryTodo, ETrue);
+			*iNumExpectedChanges = 1;
+			}
+			break;
+		case EFilterOnlyTodoEntries3:
+			{	
+			// Add event entry, should not be notified
+			CCalEntry* entryAppt = CreateEntryLC(CCalEntry::EEvent, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entryAppt);
+			StoreEntryLD(entryAppt, EFalse);	
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EFilterOnlyTodoEntries4:
+			{
+			*iNumExpectedChanges = 1;
+			ClearEntryL();
+			}
+			break;
+		case EFilterOnlyTodoEntries5:
+			{
+			// do nothing, filter is changing
+			*iNumExpectedChanges = 0;
+			}
+			break;
+		case EAddAndUpdateParentAndChild1:
+			{
+			// add a parent entry
+			HBufC8* guid = KGuid1().AllocL();
+			CCalEntry* entryAppt = iCalTestLibrary->CreateCalEntryL(CCalEntry::EAppt, guid);
+			CleanupStack::PushL(entryAppt);
+			iCalTestLibrary->SetEntryStartAndEndTimeL(entryAppt, KRangeStartTime + TTimeIntervalDays(5), KRangeStartTime + TTimeIntervalDays(5) + TTimeIntervalHours(1));
+			
+			TCalRRule rRule(TCalRRule::EDaily);
+			TCalTime rRuleDtStart;
+			rRuleDtStart.SetTimeLocalL(KRangeStartTime + TTimeIntervalDays(5));
+			rRule.SetDtStart(rRuleDtStart);
+			rRule.SetInterval(1);
+			rRule.SetCount(5);
+			
+			entryAppt->SetRRuleL(rRule);
+			
+			CleanupStack::Pop(entryAppt);
+			StoreEntryLD(entryAppt, ETrue);
+			}
+			break;
+		case EAddAndUpdateParentAndChild2:
+			{
+			//update the parent entry
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KGuid1, entryArray);
+			if (entryArray.Count() == 0)
+				{
+				RDebug::Print(_L("entry not found"));
+				User::Leave(KErrNotFound);
+				}
+			entryArray[0]->SetSummaryL(_L("modified parent"));
+			TInt numSuc;
+			
+			// we are expecting an update on the parent
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = entryArray[0]->LocalUidL();
+			
+			iCalTestLibrary->SynCGetEntryViewL().UpdateL(entryArray, numSuc);
+			
+			CleanupStack::PopAndDestroy(&entryArray);
+			}
+			break;
+		case EAddAndUpdateParentAndChild3:
+			{
+			// add a child entry
+			HBufC8* guid = KGuid1().AllocL();
+			TCalTime recId;
+			recId.SetTimeLocalL(KRangeStartTime + TTimeIntervalDays(5) + TTimeIntervalDays(4));
+			CCalEntry* childEntry = CCalEntry::NewL(CCalEntry::EAppt, guid, CCalEntry::EMethodNone, 0, recId, CalCommon::EThisOnly);
+			childEntry->SetStartAndEndTimeL(recId, recId);
+			
+			// we are expecting an update on the parent
+			// and an add for the child
+			*iNumExpectedChanges = iNumEntriesToDelete = 2;
+			iExpectedChanges[1].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[1].iChangeType = MCalChangeCallBack2::EChangeAdd;
+			iExpectedChanges[1].iEntryId = childEntry->LocalUidL();
+			
+			StoreEntryLC(childEntry, EFalse);
+			iExpectedChanges[1].iEntryId = childEntry->LocalUidL();
+			CleanupStack::PopAndDestroy(childEntry);
+			}
+			break;
+		case EAddAndUpdateParentAndChild4:
+			{
+			// update the child entry
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KGuid1, entryArray);
+			
+			// we are expecting only a modification on the child
+			*iNumExpectedChanges = iNumEntriesToDelete = 1;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = entryArray[1]->LocalUidL();
+			
+			delete entryArray[0];
+			entryArray.Remove(0);
+			
+			entryArray[0]->SetSummaryL(_L("modified child"));
+			
+			StoreEntryLD(entryArray[0], EFalse);
+			
+			entryArray.Remove(0);
+			
+			CleanupStack::PopAndDestroy(&entryArray);
+			}
+			break;
+		case EAddAndUpdateParentAndChild5:
+			{
+			// store the parent again
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KGuid1, entryArray);
+			
+			// we are expecting a modification on the parent
+			// and a delete on the child
+			*iNumExpectedChanges = iNumEntriesToDelete = 2;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = entryArray[0]->LocalUidL();
+			iExpectedChanges[1].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[1].iChangeType = MCalChangeCallBack2::EChangeDelete;
+			iExpectedChanges[1].iEntryId = entryArray[1]->LocalUidL();
+			
+			delete entryArray[1];
+			entryArray.Remove(1);
+			
+			TInt numSuc;
+			
+			entryArray[0]->SetSummaryL(_L("modified parent"));
+			
+			
+			iCalTestLibrary->SynCGetEntryViewL().StoreL(entryArray, numSuc);
+			
+			CleanupStack::PopAndDestroy(&entryArray);
+			}
+			break;
+		case EAddAndUpdateParentAndChild6:
+			{
+			// add another child
+			HBufC8* guid = KGuid1().AllocL();
+			TCalTime recId;
+			recId.SetTimeLocalL(KRangeStartTime + TTimeIntervalDays(5) + TTimeIntervalDays(4));
+			CCalEntry* childEntry = CCalEntry::NewL(CCalEntry::EAppt, guid, CCalEntry::EMethodNone, 0, recId, CalCommon::EThisOnly);
+			childEntry->SetStartAndEndTimeL(recId, recId);
+			
+			// we are expecting an add notification for the child
+			// and an update for the parent
+			*iNumExpectedChanges = iNumEntriesToDelete = 2;
+			iExpectedChanges[1].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[1].iChangeType = MCalChangeCallBack2::EChangeAdd;
+			
+			StoreEntryLC(childEntry, EFalse);
+			
+			iExpectedChanges[1].iEntryId = childEntry->LocalUidL();
+			CleanupStack::PopAndDestroy(childEntry);
+			}
+			break;
+		case EAddAndUpdateParentAndChild7:
+			{
+			// delete the child
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KGuid1, entryArray);
+			
+			// we are expecting only a delete notification for the child
+			*iNumExpectedChanges = iNumEntriesToDelete = 2;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = entryArray[0]->LocalUidL();			
+			iExpectedChanges[1].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[1].iChangeType = MCalChangeCallBack2::EChangeDelete;
+			iExpectedChanges[1].iEntryId = entryArray[1]->LocalUidL();
+				
+			iCalTestLibrary->SynCGetEntryViewL().DeleteL(*entryArray[1]);
+			
+			CleanupStack::PopAndDestroy(&entryArray);
+			}
+			break;
+		case EAddAndUpdateParentAndChild8:
+			{
+			// add another child
+			HBufC8* guid = KGuid1().AllocL();
+			TCalTime recId;
+			recId.SetTimeLocalL(KRangeStartTime + TTimeIntervalDays(5) + TTimeIntervalDays(4));
+			CCalEntry* childEntry = CCalEntry::NewL(CCalEntry::EAppt, guid, CCalEntry::EMethodNone, 0, recId, CalCommon::EThisOnly);
+			childEntry->SetStartAndEndTimeL(recId, recId);
+			
+			// fetch the parent so we can get the local uid
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KGuid1, entryArray);
+			
+			// we are expecting an add notification for the child
+			// and an update for the parent
+			*iNumExpectedChanges = iNumEntriesToDelete = 2;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeModify;
+			iExpectedChanges[0].iEntryId = entryArray[0]->LocalUidL();
+			iExpectedChanges[1].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[1].iChangeType = MCalChangeCallBack2::EChangeAdd;
+		
+			CleanupStack::PopAndDestroy(&entryArray);
+			
+			StoreEntryLC(childEntry, EFalse);
+			
+			iExpectedChanges[1].iEntryId = childEntry->LocalUidL();
+			CleanupStack::PopAndDestroy(childEntry);
+			}
+			break;
+		case EAddAndUpdateParentAndChild9:
+			{
+			// delete the parent
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KGuid1, entryArray);
+			
+			// we are expectiond a delete notification for both the parent and the child
+			*iNumExpectedChanges = iNumEntriesToDelete = 2;
+			iExpectedChanges[0].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[0].iChangeType = MCalChangeCallBack2::EChangeDelete;
+			iExpectedChanges[0].iEntryId = entryArray[0]->LocalUidL();
+			iExpectedChanges[1].iEntryType = MCalChangeCallBack2::EChangeEntryEvent;
+			iExpectedChanges[1].iChangeType = MCalChangeCallBack2::EChangeDelete;
+			iExpectedChanges[1].iEntryId = entryArray[1]->LocalUidL();
+
+			
+			iCalTestLibrary->SynCGetEntryViewL().DeleteL(*entryArray[0]);
+			
+			CleanupStack::PopAndDestroy(&entryArray);
+			}
+			break;
+
+		case EChangesToOtherFile:
+			{
+			// Make changes to another file (should not be notified)
+			iCalTestLibrary->ReplaceFileL(KCalendarFileOther);
+			iCalTestLibrary->OpenFileL(KCalendarFileOther);
+			CCalEntry* entry = CreateEntryLC(CCalEntry::EAppt, KRangeStartTime + TTimeIntervalDays(5));
+			CleanupStack::Pop(entry);
+			StoreEntryLD(entry, EFalse);
+			}
+			break;
+		case EDeleteMultipleEntriesSetup:
+			{
+			*iNumExpectedChanges =  0;
+			_LIT8(KValidGuid, "valid-guid");
+			HBufC8* guid = KValidGuid().AllocLC();
+			CCalEntry* entry = CCalEntry::NewL(CCalEntry::ETodo, guid, CCalEntry::EMethodNone, 0);
+			CleanupStack::Pop(guid);
+			StoreEntryLD(entry, ETrue);
+			}
+			break;
+		case EDeleteMultipleEntriesFail:
+			{
+			// Try to delete two entries, the second should fail and the first delete should be rolled back.
+			// No notification must be received.
+			_LIT8(KValidGuid, "valid-guid");
+			_LIT8(KNoSuchGuid, "no-such-guid");
+			CDesC8ArrayFlat* descArray = new (ELeave) CDesC8ArrayFlat(2);
+			CleanupStack::PushL(descArray);
+			descArray->AppendL(KValidGuid());
+			descArray->AppendL(KNoSuchGuid());
+			TRAPD(err, iCalTestLibrary->SynCGetEntryViewL().DeleteL(*descArray));
+			__ASSERT_ALWAYS(err == KErrNotFound, User::Invariant());
+			CleanupStack::PopAndDestroy(descArray);
+			
+			// check that the first entry has not been deleted
+			RPointerArray<CCalEntry> entryArray;
+			CleanupResetAndDestroyPushL(entryArray);
+			iCalTestLibrary->SynCGetEntryViewL().FetchL(KValidGuid(), entryArray);
+			__ASSERT_ALWAYS(entryArray.Count() == 1, User::Invariant());
+			CleanupStack::PopAndDestroy(&entryArray);
+			}
+			break;
+		default:
+			{
+			User::Panic(_L("A case statement for this test has not been added"), *iTestCase);
+			}
+			break;
+		}
+	}
+
+// modifying thread entry point
+TInt RunTestThread(TAny* /*aArgs*/)
+	{
+	TInt err;
+	CTrapCleanup* trapCleanup = CTrapCleanup::New();
+	CActiveScheduler* scheduler;
+	CTestAppModifier* modifier = NULL;
+	
+	scheduler = new CActiveScheduler;
+   	
+	if (scheduler)
+		{
+		CActiveScheduler::Install(scheduler);
+
+		// Create a semaphore
+		RSemaphore semaphore;
+		err = semaphore.CreateGlobal(KSemName(), 0);
+		if (err == KErrAlreadyExists)
+			{
+			semaphore.OpenGlobal(KSemName());
+			}
+
+	
+		TRAP(err, modifier = CTestAppModifier::NewL());
+		if (err == KErrNone)
+			{
+			TRAP(err, modifier->RunTestL());
+			}
+
+		delete modifier;
+		delete scheduler;
+		delete trapCleanup;
+
+		semaphore.Signal();
+		semaphore.Close();
+		}
+	return err;
+	}
+