tzservices/tzserver/test/component/tz_userdata.cpp
changeset 0 2e3d3ce01487
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tzservices/tzserver/test/component/tz_userdata.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1799 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+#include <e32test.h>
+#include <tz.h>
+#include <vtzrules.h>
+#include <e32math.h>
+#include <tzconverter.h>
+#include "testserver.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <tzusernames.h>
+#include <tzuserdefineddata.h>
+#endif
+#include <tzlocalizedcityrecord.h>
+#include <tzlocalizedtimezonerecord.h>
+#include "tzidinternal.h"
+
+
+_LIT(KTzUserDataDb, "c:\\private\\1020383e\\SQLite__tzuserdata.db");
+
+const TInt KPrintFreq=500;
+
+static RPIMTestServer Serv;
+// Forward class references.	
+class CTzUserDataTest;
+
+
+_LIT(KTestName,"User-Defined TZ Data Test Suite");
+RTest test(KTestName);
+
+
+_LIT8(KTzLondon, "Europe/London");
+
+
+typedef void (CTzUserDataTest::*OOMTestFunction)();
+
+
+class CTzUserDataTest : public CBase
+	{
+public:
+	enum TOOMTest  
+		{
+		EClientOOM,
+		EServerOOM 
+		};
+	
+	enum TTest
+		{
+		ETimeConversion,
+		EDayLightSave,
+		EDeleteCurrentUserRule,
+		EUpdateCachedTz,
+		EDeleteCachedTz,
+		EPersistence
+		};
+	
+    static CTzUserDataTest* NewLC();
+	~CTzUserDataTest();
+	
+	// Basic test - client operations on user-defined time zones.
+	void TestBasicUserDataL();
+	void TestOutOfMemoryBehaviourL(TOOMTest aOOMTest);
+	void TestTimeZoneRulesL(TTest aWhatToTest);	
+	void TestServerResponseToChangesL();
+	void TestReadIdsL(RTz& aRTz);
+	void TestIdsL(RTz& aRTz);
+	void TestTimeConversionL();
+	void TestDaylightSaveL();
+	void TestDeleteCurrentTimeZoneL(RTz& aTz);
+	void TestCurrentTimeZonePersistenceL(RTz& aTz);
+	void TestUpdateCachedUserTimeZoneL(RTz& aTz);
+	void TestDeletedCachedUserTimeZoneL(RTz& aTz);
+	void BoundaryTestL();
+	void TestTzIdReusabilityL();
+	void NullTestL();
+	void TestShortTzId(RTz& aRTz);
+
+private:
+	CTzUserDataTest();
+
+	// Basic operations.
+	void TestCreateUserDefinedTzL();
+	void TestUpdateUserDefinedTzL();
+	void TestDeleteUserDefinedTzL();
+	void ReadIdsAndTestL(RTz& aRTz, TBool aCheckId);
+
+	// Create user-defined time zone.
+	void CreateTzAndCheckL(TInt aOldOffset, TInt aNewOffset, RTz& aRTz, TTest aWhatToTest);	
+	CTzId* CreateUserDefinedTzL(TInt16 aStandardOffset,TInt16 aDSTOffset, TBool aCheck);
+	void CreateUserTzBasedOnLondonRuleL(RTz& aRTz, TTest aWhatToTest);
+	void CreateUserTzBasedOnShanghaiRuleL(RTz& aRTz, TTest aWhatToTest);
+	CTzUserNames* CreateUserDefinedTzNamesLC();
+	CTzRules* CreateUserDefinedTzLC(TInt16 aStandardOffset,TInt16 aDSTOffset);
+	
+	// OOM tests.
+	void CreateOOML();
+	void ReadOOML();
+	void GetIdsOOML();
+	void UpdateOOML();
+	void DeleteOOML();
+	void OOMTestL(OOMTestFunction aFunction, TOOMTest  aOOMTest);
+
+	// TZ Server response to changes.
+	void DeleteCurrentTzL(RTz& aTz);
+	void UpdateCurrentTzL(RTz& aTz,TInt aOldOffSet, TInt aNewOffSet);
+	void DeleteCurrentUserTzL(RTz& aTz, TTest aWhatToTest);
+	void UpdateCurrentUserTzL(RTz& aTz);
+	void CreateUserTzAndSetCurrentTimeToL(RTz& aTz, TInt aStandardOffSet, TInt aDSTOffset);
+	void CachedUserTimeZoneL(RTz& aRTz, TTest aWhatToTest);
+
+	// Utility methods.
+	void CreateString(TDes& aString);
+	TBool CompareArray(const RPointerArray<CTzId>& aIds1, const RPointerArray<CTzId>& aIds2);
+	TBool CompareNames(const CTzUserNames& aName1, const CTzUserNames& aNames);
+	void TestDaylightSavingStateL(CTzId& aTzId, const RArray<TTime>& times, TBool aIsOn, RTz& aRTz);
+	void TestUtcOffsetL(CTzId& aTzId,const CTzRules& rules, const RArray<TTime>& times, TInt aOffset, RTz& aRTz);
+	void CheckTimeZoneL(const CTzId& aId, const CTzRules& aRules, const CTzUserNames& aNames);
+
+	void ResetTzUserDataL();
+	
+private:
+	RPointerArray<CTzId> 	iTzIds;	//Used for transfering time zone IDs in delete and update test.
+	CTzUserData*			iUserData;
+	TInt64					iSeed;
+	};
+
+
+CTzUserDataTest* CTzUserDataTest::NewLC()
+	{
+	CTzUserDataTest* self = new (ELeave) CTzUserDataTest();
+	CleanupStack::PushL(self);
+	return (self);
+	}
+
+
+CTzUserDataTest::CTzUserDataTest()
+	:iSeed(100)
+	{
+	}	
+
+
+CTzUserDataTest::~CTzUserDataTest()	
+	{
+	TRAP_IGNORE(ResetTzUserDataL());
+	delete iUserData;
+	}
+
+
+LOCAL_D void ResetTimeZoneToLondonL()
+	{
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	
+	CTzId* id = CTzId::NewL(KTzLondon);
+	CleanupStack::PushL(id);
+	tz.SetTimeZoneL(*id);
+	CleanupStack::PopAndDestroy(2, &tz);
+	}
+
+
+LOCAL_D void ResetAndDestroyTzIdArray(TAny* aPtr)
+	{
+	RPointerArray<CTzId>* ids = static_cast<RPointerArray<CTzId>*>(aPtr);
+	if (ids)
+		{
+		ids->ResetAndDestroy();
+		}
+	}
+
+		
+void CTzUserDataTest::CreateString(TDes& aString)
+	{
+	for (TInt i(0) ; i < 10 ; ++i)
+		{
+		// Add random upper and lower case letters
+		aString.Append( 'A' + (Math::Rand(iSeed) % 26) );
+		}
+	}
+
+
+TBool CTzUserDataTest::CompareArray(const RPointerArray<CTzId>& aIds1, const RPointerArray<CTzId>& aIds2)
+	{
+	TInt count1 = aIds1.Count();
+	TInt count2 = aIds2.Count();
+	test(count1 == count2);
+	
+	TBool isEqual = ETrue;
+	TInt ii=0;
+	
+	while(ii<count1 && isEqual)
+		{
+		isEqual = EFalse;
+		for (TInt jj=0; jj<count2; ++jj)
+			{
+			if(aIds1[ii]==aIds2[jj])
+				{
+				isEqual = ETrue;
+				break;	
+				}
+			}
+		++ii;
+		}
+	return isEqual;
+	}
+
+
+TBool CTzUserDataTest::CompareNames(const CTzUserNames& aNames1, const CTzUserNames& aNames2)
+	{
+	if (aNames1.StandardName() !=  aNames2.StandardName())
+		return EFalse; 
+	if (aNames1.ShortStandardName() != aNames2.ShortStandardName())
+		return EFalse;
+	if (aNames1.DaylightSaveName() != aNames2.DaylightSaveName())
+		return EFalse;
+	if (aNames1.ShortDaylightSaveName() != aNames2.ShortDaylightSaveName())
+		return EFalse;
+	if (aNames1.CityName() != aNames2.CityName())
+		return EFalse;
+	if (aNames1.RegionName() != aNames2.RegionName())
+		return EFalse;
+	
+	return ETrue;
+	}
+
+	
+void CTzUserDataTest::TestUtcOffsetL(CTzId& aTzId, const CTzRules& rules, const RArray<TTime>& times, TInt aOffset, RTz& aRTz )
+	{
+	aRTz.SetTimeZoneL(aTzId);
+
+	TInt count = times.Count();
+	
+	for(TInt ii=0; ii<count; ++ii)
+		{
+		test (aOffset == rules.GetOffsetL(times[ii], ETzUtcTimeReference));	
+		TTime utc = times[ii];
+		aRTz.ConvertToUniversalTime(utc);
+		TTimeIntervalMinutes minutes;
+		times[ii].MinutesFrom(utc, minutes);
+		test (minutes == TTimeIntervalMinutes(aOffset));	
+		}
+	}
+
+
+void CTzUserDataTest::TestDaylightSavingStateL(CTzId& aTzId, const RArray<TTime>& times, TBool aIsOn, RTz& aRTz)
+	{
+	aRTz.SetTimeZoneL(aTzId);
+	TInt count = times.Count();
+	for(TInt ii=0; ii<count; ++ii)
+		{
+		test (aIsOn == aRTz.IsDaylightSavingOnL(aTzId, times[ii]));
+		}
+	}
+
+
+void CTzUserDataTest::ResetTzUserDataL()
+	{
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	CTzUserData* userdata = CTzUserData::NewL(tz);
+	CleanupStack::PushL(userdata);
+	userdata->GetTzIdsL(iTzIds);
+	TInt count = iTzIds.Count();
+	for (TInt ii=0; ii<count; ++ii)
+		{
+		if(ii%KPrintFreq == 0)
+			{
+			test.Printf(_L("Deleted %d time zones in the database\n"), ii);
+			}
+		
+		userdata->DeleteL(*iTzIds[ii]);	
+		}
+	CleanupStack::PopAndDestroy(2, &tz);
+	
+	iTzIds.ResetAndDestroy();
+	}
+	
+
+CTzId* CTzUserDataTest::CreateUserDefinedTzL(TInt16 aStandardOffset,TInt16 aDSTOffset, TBool aCheck)
+	{
+	CTzRules* rules = CreateUserDefinedTzLC(aStandardOffset, aDSTOffset);
+	CTzUserNames* names = CreateUserDefinedTzNamesLC();
+	CTzId* id = iUserData->CreateL(*rules, *names);
+	CleanupStack::PushL(id);
+	if(aCheck)
+		{
+		CheckTimeZoneL(*id, *rules, *names);
+		}
+	CleanupStack::Pop(id);
+	CleanupStack::PopAndDestroy(2, rules);
+	return id;
+	}
+
+	
+void CTzUserDataTest::CheckTimeZoneL(const CTzId& aId, const CTzRules& aRules, const CTzUserNames& aNames)
+	{
+	CTzRules* rulesGet = iUserData->ReadRulesL(aId);
+	CleanupStack::PushL(rulesGet);
+	test(aRules.IsEqualTo(*rulesGet));
+	CleanupStack::PopAndDestroy(rulesGet);
+		
+	CTzUserNames* namesGet = iUserData->ReadNamesL(aId);
+	CleanupStack::PushL(namesGet);
+	test (CompareNames(aNames, *namesGet));
+	CleanupStack::PopAndDestroy(namesGet);
+	}
+
+	
+void CTzUserDataTest::CreateUserTzBasedOnLondonRuleL(RTz& aRTz, TTest aWhatToTest)
+	{
+	test.Next(_L("Test Creation user-defined time zone based on London rules"));
+	//create a new rule which doesn't have DST saving.
+	TTime start (TDateTime(2010, ESeptember, 0, 0, 0, 0, 0));
+	TInt year = start.DateTime().Year();
+	TMonth month = start.DateTime().Month();
+	TInt day = start.DateTime().Day();
+	TTzRule newrule(year, 9999, 0, 0, month,  ETzFixedDate, day,  0, ETzWallTimeReference, 120);
+
+	//Get the existing london rule
+	_LIT8(KTimeNone, "Europe/London");
+	
+	CTzId* londonId = CTzId::NewL(KTimeNone());
+	CleanupStack::PushL(londonId);
+	CTzRules* userrule = aRTz.GetTimeZoneRulesL(*londonId, 0, 9999, ETzUtcTimeReference);
+	CleanupStack::PopAndDestroy(londonId); 
+
+	//Use London rule to create a new user-defined rule
+	TInt count = userrule->Count();
+
+	//Since the last two rules (TTzRule objects one for summer rule one for winter rule) in existing database covers the years in which a new rule starts.
+	//The client has to amend the ending years of those two rules before adding a new rule.
+	//We set the ending year for last two rules to 2009 since the new rule starts on 2010
+
+	TTzRule lastRule = (*userrule)[count-1];
+	TDateTime dateTimeLast = lastRule.iTo.iTime.DateTime();
+	dateTimeLast.SetYear(2009);
+	lastRule.iTo.iTime = dateTimeLast;
+
+	TTzRule lastSecondRule = (*userrule)[count-2];
+	TDateTime dateTimeLastSecond = lastSecondRule.iTo.iTime.DateTime();
+	dateTimeLastSecond.SetYear(2009);
+	lastSecondRule.iTo.iTime = dateTimeLastSecond;
+		
+	CleanupStack::PushL(userrule);
+	//Remove last two existing rules
+	userrule->RemoveRule(count-1);
+	userrule->RemoveRule(count-2);
+	
+	//Add two rules whoes ending years have been amended
+	userrule->AddRuleL(lastRule);
+	userrule->AddRuleL(lastSecondRule);
+	
+	//Add the new rule
+	userrule->AddRuleL(newrule);
+	//userrule->AddRuleL(newrule);//add the new rule which doesn't have DST
+	
+	CTzUserNames* newRuleNames = CreateUserDefinedTzNamesLC();
+	CTzId* id = iUserData->CreateL(*userrule, *newRuleNames);
+	CleanupStack::PushL(id);
+	iTzIds.AppendL(id);
+	CleanupStack::Pop(id);
+	CheckTimeZoneL(*id, *userrule, *newRuleNames);
+	CleanupStack::PopAndDestroy(newRuleNames);
+		
+	RArray<TTime> timesOn;
+	CleanupClosePushL(timesOn);
+	RArray<TTime> timesOff;
+	CleanupClosePushL(timesOff);
+	
+	// Check UTC offset and DST.
+	TTime check = TDateTime(1998, ESeptember, 0, 0, 0, 0, 0); 
+	timesOn.AppendL(check);
+	check = TDateTime(2005, ESeptember, 0, 0, 0, 0, 0);
+	timesOn.AppendL(check);	
+	check = TDateTime(2009, ESeptember, 0, 0, 0, 0, 0);
+	timesOn.AppendL(check);
+
+	check = TDateTime(2010, ESeptember, 0, 3, 0, 0, 0); 
+	timesOff.AppendL(check);
+	check = TDateTime(2015, ESeptember, 0, 3, 0, 0, 0);
+	timesOff.AppendL(check);	
+	check = TDateTime(2020, ESeptember, 0, 3, 0, 0, 0);
+	timesOff.AppendL(check);
+
+	if(aWhatToTest==ETimeConversion)
+		{
+		TestUtcOffsetL(*id,*userrule, timesOn, 60, aRTz);
+		TestUtcOffsetL(*id,*userrule, timesOff, 0, aRTz);
+		}
+	else if(aWhatToTest==EDayLightSave)
+		{
+		TestDaylightSavingStateL(*id, timesOn, ETrue, aRTz);
+		TestDaylightSavingStateL(*id, timesOff, EFalse, aRTz);
+		}
+	
+	CleanupStack::PopAndDestroy(3, userrule);	
+	}
+
+
+void CTzUserDataTest::CreateUserTzBasedOnShanghaiRuleL(RTz& aRTz, TTest aWhatToTest)
+	{
+	_LIT8(KTimeNone, "Asia/Shanghai");
+	
+	CTzId* shanghaiId = CTzId::NewL(KTimeNone());
+	CleanupStack::PushL(shanghaiId);
+
+	CTzRules* shanghaiRule = aRTz.GetTimeZoneRulesL(*shanghaiId, 0, 9999, ETzUtcTimeReference);
+	CleanupStack::PopAndDestroy(shanghaiId); 
+	
+	// Last rule: 00:00:000 Date:1/01/1987  Time: 23:59:59:000 Date:31/12/1991  Old=480 New=540 Ch=0  
+	TTime dston (TDateTime(2010, EMarch, 0, 0, 0, 0, 0)); 
+	TTime dstoff (TDateTime(2010, ESeptember, 0, 0, 0, 0, 0));
+	TMonth monthOn = dston.DateTime().Month();
+	TInt dayOn = dston.DateTime().Day();
+	TMonth monthOff = dstoff.DateTime().Month();
+	TInt dayOff = dstoff.DateTime().Day();
+	 
+	test.Next(_L("Test Creation user-defined time zone based on Shanghai rules"));
+	
+	TTzRule dstOn(2010, 9999, 480, 540, monthOn,  ETzFixedDate, dayOn,  0, ETzWallTimeReference, 120);
+	TTzRule dstOff (2010, 9999, 540, 480, monthOff, ETzFixedDate, dayOff, 0, ETzWallTimeReference, 120);
+	
+	CleanupStack::PushL(shanghaiRule);
+	shanghaiRule->AddRuleL(dstOff);//add the new rule which have DST
+	shanghaiRule->AddRuleL(dstOn);
+	CTzUserNames* newRuleNames = CreateUserDefinedTzNamesLC();
+
+	CTzId* id = iUserData->CreateL(*shanghaiRule, *newRuleNames);
+	CleanupStack::PushL(id);
+	iTzIds.AppendL(id);
+	CleanupStack::Pop(id);
+	
+	CheckTimeZoneL(*id, *shanghaiRule, *newRuleNames);
+	
+	// Check UTC offset and DST.
+	RArray<TTime> timesOn;
+	CleanupClosePushL(timesOn);
+	RArray<TTime> timesOff;
+	CleanupClosePushL(timesOff);
+
+	TTime check = TDateTime(1998, ESeptember, 0, 3, 0, 0, 0); 
+	timesOff.AppendL(check);
+	check = TDateTime(2005, ESeptember, 0, 3, 0, 0, 0);
+	timesOff.AppendL(check);	
+	check = TDateTime(2020, ESeptember, 0, 3, 0, 0, 0);
+	timesOff.AppendL(check);
+
+	check = TDateTime(2011, EAugust, 0, 0, 0, 0, 0); 
+	timesOn.AppendL(check);
+	check = TDateTime(2015, EAugust, 0, 0, 0, 0, 0);
+	timesOn.AppendL(check);	
+	check = TDateTime(2020, EAugust, 0, 0, 0, 0, 0);
+	timesOn.AppendL(check);
+
+	if(aWhatToTest==ETimeConversion)
+		{
+		TestUtcOffsetL(*id,*shanghaiRule, timesOn, 540, aRTz);
+		TestUtcOffsetL(*id,*shanghaiRule, timesOff, 480, aRTz);
+		}
+	else if(aWhatToTest==EDayLightSave)
+		{
+		TestDaylightSavingStateL(*id, timesOn, ETrue, aRTz);
+		TestDaylightSavingStateL(*id, timesOff, EFalse, aRTz);
+		}
+	
+	CleanupStack::PopAndDestroy(4, shanghaiRule);
+	}	
+
+
+CTzRules* CTzUserDataTest::CreateUserDefinedTzLC(TInt16 aStandardOffset,TInt16 aDSTOffset)
+	{
+	TTime dston (TDateTime(2005, EMarch, 0, 0, 0, 0, 0)); 
+	TTime dstoff (TDateTime(2005, ESeptember, 0, 0, 0, 0, 0));
+	TMonth monthOn = dston.DateTime().Month();
+	TInt dayOn = dston.DateTime().Day();
+	TMonth monthOff = dstoff.DateTime().Month();
+	TInt dayOff = dstoff.DateTime().Day();
+
+	TTzRule dstOff(0, 9999, aStandardOffset, aDSTOffset, monthOn,  ETzFixedDate, dayOn,  0, ETzWallTimeReference, 120);
+	TTzRule dstOn (0, 9999, aDSTOffset, aStandardOffset, monthOff, ETzFixedDate, dayOff, 0, ETzWallTimeReference, 120);
+
+	CTzRules* rules = CTzRules::NewL(0, 9999);
+	CleanupStack::PushL(rules);
+	rules->AddRuleL(dstOff);
+	rules->AddRuleL(dstOn);
+	return rules;
+	}
+
+
+CTzUserNames* CTzUserDataTest::CreateUserDefinedTzNamesLC()
+	{
+	TBuf<10> standardName;
+	CreateString(standardName);
+	
+	TBuf<10> shortStandardName;
+	CreateString(shortStandardName);
+	
+	TBuf<10> dayLightSaveName;
+	CreateString(dayLightSaveName);
+	
+	TBuf<10> shortDayLightSaveName;
+	CreateString(shortDayLightSaveName);
+		
+	TBuf<10> cityName;
+	CreateString(cityName);
+	
+	TBuf<10> regionName;
+	CreateString(regionName);
+	
+	return CTzUserNames::NewLC(standardName, shortStandardName, dayLightSaveName, shortDayLightSaveName, cityName, regionName);
+	}
+
+	
+void CTzUserDataTest::CreateTzAndCheckL(TInt aOldOffset, TInt aNewOffset, RTz& aRTz, TTest aWhatToTest)	
+	{
+/* On the day:
+ 
+	TTime dston (TDateTime(2005, EMarch, 0, 0, 0, 0, 0)); 
+	TTime dstoff (TDateTime(2005, ESeptember, 0, 0, 0, 0, 0));
+
+After two hours DST changes which should be repeated every year
+*/
+	RArray<TTime> timesOn;
+	CleanupClosePushL(timesOn);
+	RArray<TTime> timesOff;
+	CleanupClosePushL(timesOff);
+	
+	TTime check = TDateTime(1920, EMarch, 0, 0, 0, 0, 0); 
+	timesOff.AppendL(check);
+	check = TDateTime(2005, EMarch, 0, 0, 0, 0, 0);
+	timesOff.AppendL(check);	
+	check = TDateTime(2020, EMarch, 0, 0, 0, 0, 0);
+	timesOff.AppendL(check);
+	
+	check = TDateTime(1920, EMarch, 0, 3, 0, 0, 0); 
+	timesOn.AppendL(check);
+	check = TDateTime(2005, EMarch, 0, 3, 0, 0, 0);
+	timesOn.AppendL(check);	
+	check = TDateTime(2020, EMarch, 0, 3, 0, 0, 0);
+	timesOn.AppendL(check);
+	
+	CTzId* id = CreateUserDefinedTzL(aOldOffset, aNewOffset, ETrue);
+	CleanupStack::PushL(id);
+	CTzRules* rules = iUserData->ReadRulesL(*id);
+	CleanupStack::PushL(rules);
+	
+	if (aWhatToTest==ETimeConversion)
+		{
+		TestUtcOffsetL(*id,*rules, timesOn, aNewOffset, aRTz);
+		TestUtcOffsetL(*id,*rules, timesOff, aOldOffset, aRTz);
+		}
+	else if (aWhatToTest==EDayLightSave)
+		{
+		TBool isDSTon = aOldOffset != aNewOffset;
+		TestDaylightSavingStateL(*id, timesOn, isDSTon, aRTz);
+		TestDaylightSavingStateL(*id, timesOff, EFalse, aRTz);
+		}
+
+	CleanupStack::PopAndDestroy(4, &timesOn);
+	}
+		
+
+void CTzUserDataTest::CreateOOML()
+	{
+	CTzId* id = CreateUserDefinedTzL(60, 60, EFalse);
+	delete id;
+	}
+
+
+void CTzUserDataTest::ReadOOML()
+	{
+	CTzRules* rule = iUserData->ReadRulesL(*iTzIds[0]);
+	CleanupStack::PushL(rule);
+	CTzUserNames* newNames = iUserData->ReadNamesL(*iTzIds[0]);
+	CleanupStack::PopAndDestroy(rule);
+	delete newNames;
+	}
+
+	
+void CTzUserDataTest::GetIdsOOML()
+	{
+	RPointerArray<CTzId> ids;
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyTzIdArray, &ids));
+	iUserData->GetTzIdsL(ids);
+	CleanupStack::PopAndDestroy(&ids);	
+	}
+
+
+void CTzUserDataTest::UpdateOOML()
+	{
+	CTzRules* rules = CreateUserDefinedTzLC(0, 0);
+	CTzUserNames* newNames = CreateUserDefinedTzNamesLC();
+	iUserData->UpdateL(*(iTzIds[0]), *rules, *newNames);
+	CleanupStack::PopAndDestroy(2, rules);
+	}	
+
+
+void CTzUserDataTest::DeleteOOML()
+	{
+	for(TInt ii=iTzIds.Count()-1; ii>=0; --ii)
+		{
+		//Delete the user-defined time zone as the last element in the array.
+		iUserData->DeleteL(*(iTzIds[ii]));
+		}
+	}
+
+
+void CTzUserDataTest::OOMTestL(OOMTestFunction aFunction, TOOMTest  aOOMTest)
+	{
+	TInt tryCount = 1;
+	
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	iUserData = CTzUserData::NewL(tz);
+
+	TInt cellsBefore = 0;
+			
+	for (;;)
+		{
+		test.Printf(_L("Heap memory allocation set to fail at allocation #%d.\n"),
+			tryCount);
+
+		if(aOOMTest == EClientOOM)
+			{
+			__UHEAP_SETFAIL(RAllocator::EDeterministic, tryCount);
+			__UHEAP_MARK;
+			}
+		else
+			{
+			TInt heapSize = 0;
+			tz.__dbgSetHeapFailL(RAllocator::EDeterministic, tryCount);
+			cellsBefore = tz.__dbgRequestAllocatedCellsL(heapSize);
+			}
+		
+		TRAPD(err, (this->*aFunction)());
+
+		if(err == KErrNone)
+   			{
+   			test.Printf(_L("OOM test complete.\n"));
+   			break;
+   			}
+		
+		test(err == KErrNoMemory);
+		
+		if(aOOMTest == EClientOOM)
+			{
+			__UHEAP_MARKEND;	
+			}
+		else
+			{
+			tz.__dbgResetHeapL();
+			TInt heapSize = 0;
+			TInt cellsAfter = tz.__dbgRequestAllocatedCellsL(heapSize);
+			if(cellsBefore != cellsAfter)
+				{
+				test.Printf(_L("ERROR: Memory leak.  Heap cells: %d before, %d after.\n"),
+					cellsBefore, cellsAfter);
+				test(EFalse);
+				}
+			}
+  	
+		tryCount++;
+		}
+	
+	__UHEAP_RESET;
+	tz.__dbgResetHeapL();
+	
+	delete iUserData;
+	iUserData = NULL;
+	
+	CleanupStack::PopAndDestroy(&tz);	
+	}
+
+	
+/**
+Create and read user-defined time zones.
+
+@SYMTestCaseID 	PIM-APPSERV-TZS-CO-0001
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that user-defined time zone rules and
+	names can be created and read back.
+
+@SYMTestActions    
+	1.	Create a few user-defined time zone with different offset.
+	2.	Read the rules and names for the user-defined time zone created in action
+		1. 
+
+@SYMTestExpectedResults
+	The following information is the same as the information used to created
+	the user-defined time zone in action 1:
+	
+	- Time zone rules
+	- Standard time name
+	- Daylight saving time name 
+	- Short standard time name
+	- Short daylight saving time name
+	- City name
+	- Region name
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+
+
+void CTzUserDataTest::TestCreateUserDefinedTzL()
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-CO-0001 Create user-defined Time Zone"));
+
+	// Offset 60 There is no DST 
+	test.Printf(_L("Offset 60 There is no DST\n"));
+
+	CTzId* id = CreateUserDefinedTzL(60, 60, ETrue);
+	CleanupStack::PushL(id);
+	iTzIds.AppendL(id);
+	CleanupStack::Pop(id);
+
+	// Offset - 60 There is no DST
+	test.Printf(_L("Offset -60 There is no DST\n"));
+	id = CreateUserDefinedTzL(-60, -60, ETrue);
+	CleanupStack::PushL(id);
+	iTzIds.AppendL(id);
+	CleanupStack::Pop(id);
+	
+	// Offset 60 There is DST of 60
+	id = CreateUserDefinedTzL(60, 120, ETrue);
+	CleanupStack::PushL(id);
+	iTzIds.AppendL(id);
+	CleanupStack::Pop(id);
+
+	// Offset - 60 There is DST of 60
+	test.Printf(_L("Offset - 60 There is DST of 60\n"));
+	id = CreateUserDefinedTzL(-60, 0, ETrue);
+	CleanupStack::PushL(id);
+	iTzIds.AppendL(id);
+	CleanupStack::Pop(id);
+	}
+
+
+/**
+Update user-defined time zone.
+
+@SYMTestCaseID 	PIM-APPSERV-TZS-CO-0002
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that user-defined time zone time rules
+	and names can be updated.
+
+@SYMTestActions    
+	1.	Create a user-defined time zone (rules and names).
+	2.	Get all existing user-defined time zones and update them with the rules
+		and names created in action 1.
+	3.	Read the new user-defined time zone rules and names updated in action 2. 
+
+@SYMTestExpectedResults
+	The following information is the same as the information used to update the
+	user-defined time zone in action 3:
+	
+	- Time zone rules
+	- Standard time name
+	- Daylight saving time name 
+	- Short standard time name
+	- Short daylight saving time name
+	- City name
+	- Region name
+
+@SYMTestType
+	CT
+	
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestUpdateUserDefinedTzL()
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-CO-0002 "));
+	CTzRules* newRule = CreateUserDefinedTzLC(0,0);
+	CTzUserNames* newNames = CreateUserDefinedTzNamesLC();
+	
+	for(TInt ii=0; ii<iTzIds.Count(); ++ii)
+		{
+		iUserData->UpdateL(*(iTzIds[ii]), *newRule, *newNames);
+	
+		//Get and Compare
+		CTzRules* userRuleGet = iUserData->ReadRulesL(*(iTzIds[ii]));
+		test (userRuleGet->IsEqualTo(*newRule));
+		delete userRuleGet;
+
+		CTzUserNames* userNamesGet = iUserData->ReadNamesL(*(iTzIds[ii]));
+		test(CompareNames(*userNamesGet, *newNames));
+		delete userNamesGet;
+		}
+	
+	CleanupStack::PopAndDestroy(2, newRule);
+	}
+
+
+/**
+Delete user-defined time zones.
+
+@SYMTestCaseID 	PIM-APPSERV-TZS-CO-0003
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that user-defined time zones can be
+	deleted.
+
+@SYMTestActions  
+	1.	Get all existing user-defined time zones.
+	2.	Delete the user-defined time zone as the last element in the array one
+		by one.
+	3.	Try to read the user-defined time zone deleted in action 2.
+
+@SYMTestExpectedResults
+	The user-defined time zone does not exist.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestDeleteUserDefinedTzL()	
+	{
+	test.Next(_L("@SYMTestCaseID  PIM-APPSERV-TZS-CO-0003"));
+	RPointerArray<CTzId> ids;
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyTzIdArray, &ids));
+
+	for(TInt ii=iTzIds.Count()-1; ii>=0; --ii)
+		{
+		iUserData->GetTzIdsL(ids);
+		
+		// The array obtained should be same as expected who elements is deleted
+		// one by one in each loop.
+		CompareArray(ids,iTzIds);
+		ids.ResetAndDestroy();
+		
+		// Delete the user-defined time zone as the last element in the array.
+		iUserData->DeleteL(*(iTzIds[ii]));
+		
+		// The rule and names of the last element in the array should not be
+		// found since it has been deleted.
+		TRAPD(err, iUserData->ReadRulesL(*(iTzIds[ii])));
+		test(err == KErrNotFound);
+		TRAP(err, iUserData->ReadNamesL(*(iTzIds[ii])));
+		test(err == KErrNotFound);
+
+		delete iTzIds[ii];
+		iTzIds.Remove(ii);
+		}
+
+	CleanupStack::PopAndDestroy(&ids);
+	}
+
+
+/**
+All user-defined time zone identifiers.
+
+@SYMTestCaseID PIM-APPSERV-TZS-CO-0004 
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that time zone identifiers for user-
+	defined time zones can be queried.
+
+@SYMTestActions    
+	1.	Get all existing user-defined time zones.
+
+@SYMTestExpectedResults
+	The time zone identifiers obtained should be same as those existing ones.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/	
+
+
+void CTzUserDataTest::TestReadIdsL(RTz& aRTz)
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-CO-0004  Read time zone IDs"));
+	ReadIdsAndTestL(aRTz, EFalse);
+	}
+
+
+/**
+Check time zone identifier is a user-defined time zone identifier.
+	
+@SYMTestCaseID 	PIM-APPSERV-TZS-CO-0005
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that a time zone identifier is or is
+	not a user-defined time zone identifier.
+
+@SYMTestActions 
+	1.	Get all existing user-defined time zones.
+	2.	Obtain a time zone identifier for a non-user-defined time zone
+
+@SYMTestExpectedResults     
+	  - Check that the time zone identifier is a user-defined time zone
+		identifier.
+	  - Check that the time zone identifier is not a user-defined time zone 
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/	
+
+
+void CTzUserDataTest::TestIdsL(RTz& aRTz)
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-CO-0005 Check time zone IDs"));
+	ReadIdsAndTestL(aRTz, ETrue);
+	}
+
+	
+void CTzUserDataTest::TestShortTzId(RTz& aRTz)
+	{
+	test.Next(_L("test short TzId behaviour"));
+	TInt KGreaterThanExpectedVal = 65536; //a value greater than 0xffff i.e. 16 bits
+	TUint8 groupId = 8; //make up some random value
+	TUint resourceId = 123; //make up some random value
+	TRAPD(err, aRTz.LocalizationWriteCityL(_L("myCity"), KGreaterThanExpectedVal, groupId, resourceId));
+	test(err == KErrArgument);
+	TRAPD(err1, aRTz.LocalizationDeleteCityL(_L("myCity"), KGreaterThanExpectedVal));
+	test(err1 == KErrArgument);
+	
+	TRAPD(err2, aRTz.LocalizationDeleteCityL(_L("myCity"), KGreaterThanExpectedVal - 1));
+	test(err2 == KErrNotFound);
+	
+	TRAPD(err3, CTzLocalizedTimeZoneRecord::NewLC(KGreaterThanExpectedVal, _L("standardName"), _L("daylightName"), _L("shortStandardName"), _L("shortDaylighName"), 0));
+	test(err3 == KErrArgument);
+	
+	TRAPD(err4, CTzLocalizedCityRecord::NewLC(_L("aCity"), 0, 0, KGreaterThanExpectedVal, 0));
+	test(err4 == KErrArgument);
+	}
+
+	
+	
+void CTzUserDataTest::ReadIdsAndTestL(RTz& aRTz, TBool aCheckId)
+	{
+	test.Next(_L("Read time zone IDs"));
+	RPointerArray<CTzId> ids;
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyTzIdArray, &ids));
+	iUserData->GetTzIdsL(ids);
+	test(iTzIds.Count() == ids.Count());
+	if(aCheckId)
+		{
+		TInt count = ids.Count();
+		for(TInt ii = 0; ii<count; ++ii)
+			{
+			test(ids[ii]->IsUserTzId());	
+			}
+		//Current time zone is default time zone Europe/London which is not the user-defined time zone.
+		CTzId* currentId = aRTz.GetTimeZoneIdL();
+		test (!currentId->IsUserTzId());
+		delete currentId;
+		}
+	
+	CleanupStack::PopAndDestroy(&ids);
+	}
+
+	
+void CTzUserDataTest::TestBasicUserDataL()
+	{
+	ResetTzUserDataL();
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	iUserData = CTzUserData::NewL(tz);
+	TestCreateUserDefinedTzL();
+	TestReadIdsL(tz);
+	TestIdsL(tz);
+	TestUpdateUserDefinedTzL();
+	TestDeleteUserDefinedTzL();	
+	TestShortTzId(tz);
+	delete iUserData;
+	iUserData = NULL;
+	CleanupStack::PopAndDestroy(&tz);
+	}
+
+	
+/**
+Out of memory behaviour.
+
+@SYMTestCaseID PIM-APPSERV-TZS-CO-0006
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that user-defined time zone operations
+	are robust and result in no memory leaks under OOM conditions.
+	
+@SYMTestActions
+	Create, Read, Update and Delete a user-defined time zone rule under OOM
+	conditions.
+
+@SYMTestExpectedResults
+	Each operation leaves with KErrNoMemory until eventually the operation
+	completes successfully.  Once the operation completes successfully the
+	client process (for client-side OOM testing) or TZ Server process (for
+	server-side OOM testing) is terminated and does not report a memory leak.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestOutOfMemoryBehaviourL(TOOMTest aOOMTest)
+	{
+	ResetTzUserDataL();
+
+	
+	test.Start(_L("@SYMTestCaseID PIM-APPSERV-TZS-CO-0006 Test Create User-Defined Time Zone OOM"));
+	OOMTestL(&CreateOOML,aOOMTest);
+	
+	// Ensure that a tz ID is saved in iTzIds which is used to fetch a time zone
+	// in ReadOOML().
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	iUserData = CTzUserData::NewL(tz);
+	iUserData->GetTzIdsL(iTzIds);
+	delete iUserData;
+	iUserData = NULL;
+	CleanupStack::PopAndDestroy(&tz);
+	
+	test.Next(_L("Test Read User-Defined Time Zone OOM"));
+	OOMTestL(&ReadOOML,aOOMTest);
+
+	test.Next(_L("Test Get User-Defined Time Zone IDs OOM"));
+	OOMTestL(&GetIdsOOML,aOOMTest);
+
+	test.Next(_L("Test Update User-Defined Time Zone OOM"));
+	OOMTestL(&UpdateOOML,aOOMTest);
+
+	test.Next(_L("Test Delete User-Defined Time Zone OOM"));
+	OOMTestL(&DeleteOOML,aOOMTest);
+	
+	test.End();
+
+	ResetTzUserDataL();
+	}
+ 
+ 
+/**
+Boundary tests.
+ 
+@SYMTestCaseID PIM-APPSERV-TZUSERDATA-0013
+ 	
+@SYMTestCaseDesc
+	The purpose of this test is to test behaviour under various boundary
+	conditions.
+
+@SYMTestActions     
+	1.  Get TZ Ids of  user-defined time zone when the database is empty.
+	2.  Get the user-defined rule for a valid TZ Id when the database is empty.
+	3.  Get the user-defined rule names when the database is empty.
+	4.  Create a user time zone with all named KNullDesC
+	5.  Get rules, names and try to update and delete using a non-user-defined
+		TZID.
+
+@SYMTestExpectedResults
+	Array obtained in action 1 has 0 count.  Leaving code KErrNotFound is
+	expected in action 2 and 3.  A user time zone with all named KNullDesC
+	should be allowed.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/	
+
+void CTzUserDataTest::BoundaryTestL()
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZUSERDATA-0013 Boundary Test"));
+	ResetTzUserDataL();
+	
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	iUserData = CTzUserData::NewL(tz); 
+
+	// Empty user time zone database.
+	iUserData->GetTzIdsL(iTzIds);
+	test (iTzIds.Count() == 0);
+	
+	CTzId * id = CTzId::NewL(KUserTzIdMin);
+	CleanupStack::PushL(id);
+	CTzRules* rulesGet = NULL;
+	TRAPD(err, rulesGet = iUserData->ReadRulesL(*id));
+	test (!rulesGet);
+	test (err==KErrNotFound);
+
+	CTzUserNames* namesGet = NULL;
+	TRAP(err, namesGet = iUserData->ReadNamesL(*id));
+	test (!namesGet);
+	test (err==KErrNotFound);
+	iUserData->DeleteL(*id);
+	CleanupStack::PopAndDestroy(id);
+
+	// Create a user time zone with all named KNullDesC.
+	CTzRules*  rules = CreateUserDefinedTzLC(0, 0);
+	CTzUserNames* names = CTzUserNames::NewLC(KNullDesC , KNullDesC, KNullDesC, KNullDesC, KNullDesC, KNullDesC);
+	id = iUserData->CreateL(*rules, *names);
+	CleanupStack::PushL(id);
+	CheckTimeZoneL(*id, *rules, *names);
+
+	// Create a non-user-defined TZID object and reuse it in the following
+	// tests.
+	CTzId* nonUserDefinedTzId = CTzId::NewL(KUserTzIdMin - 1);
+	CleanupStack::PushL(nonUserDefinedTzId);
+
+	// Attempt to update user-defined TZ data using a TZID which is not a user-
+	// defined TZID.
+	TRAP(err, iUserData->UpdateL(*nonUserDefinedTzId, *rules, *names));
+	test(err == KErrArgument);
+
+	// Attempt to read rules from user-defined TZ data using a TZID which is
+	// not a user-defined TZID.
+	TRAP(err, rulesGet = iUserData->ReadRulesL(*nonUserDefinedTzId));
+	test(err == KErrArgument);
+		
+	// Attempt to read names from user-defined TZ data using a TZID which is
+	// not a user-defined TZID.
+	TRAP(err, namesGet = iUserData->ReadNamesL(*nonUserDefinedTzId));
+	test(err == KErrArgument);
+	
+	// Attempt to delete from user-defined TZ data using a TZID which is not
+	// a user-defined TZID.
+	TRAP(err, iUserData->DeleteL(*nonUserDefinedTzId));
+	test(err == KErrArgument);
+
+	CleanupStack::PopAndDestroy(4, rules);
+
+	delete iUserData;
+	CleanupStack::PopAndDestroy(&tz);
+	ResetTzUserDataL();
+	}
+
+
+/**
+Convert time using user-defined time zone.
+
+@SYMTestCaseID PIM-APPSERV-TZS-TZR-0001
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify the behaviour of time conversion using
+	a user-defined time zone.
+
+@SYMTestActions 
+	1.	Create a few user-defined time zone with different UTC offsets and store
+		them in the database.
+	2.	Get the UTC offset of each time zone created.
+	3.	Set the current time zone to each user-defined time zone created in
+		action 1.
+	4.	Convert the system time from UTC to local.
+	5. 	Verify the UTC offset for each user-defined time zone.
+
+@SYMTestExpectedResults
+	The UTC offset for the given time zone created is correct.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestTimeConversionL()
+	{
+	TestTimeZoneRulesL(ETimeConversion);
+	}
+
+
+/**
+Daylight saving observation using user-defined time zone.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-TZR-0002
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify the behaviour of daylight saving time
+	zone rules for a user-defined time zone.
+
+@SYMTestActions 
+	1.	Create a user-defined time zone.
+	2.	Set the current time zone to the user-defined time zone created in
+		action 1.
+	3.	Check if the daylight saving is on to a time that is inside the time
+		interval during which DST is observed. [1]
+	4.	Check if the daylight saving is on to a time that is outside the time
+		interval during which DST is not observed. [2]
+
+@SYMTestExpectedResults     
+	[1]	The system indicates that DST is currently being observed.
+	[2]	The system indicates that DST is not currently being observed.
+
+@SYMTestType
+	CT
+	
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestDaylightSaveL()
+	{
+	TestTimeZoneRulesL(EDayLightSave);
+	}
+
+
+/**
+Check that CTzUserData can work with creating a CTzUserData with KUserTzIdMin
+id and with a KNullDesC8 name as expected.
+*/
+void CTzUserDataTest::NullTestL()
+	{
+	CTzId* minId = CTzId::NewL(KUserTzIdMin);
+	test (minId->IsUserTzId());
+	delete minId;
+	
+	CTzId* nullId = CTzId::NewL(KNullDesC8());
+	test (nullId->IsUserTzId() == EFalse);
+	delete nullId;
+	}
+
+void CTzUserDataTest::TestTimeZoneRulesL(TTest aWhatToTest)
+	{
+	ResetTzUserDataL();
+	
+	test.Next(_L("Time Zone Rules"));
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+	tz.SetAutoUpdateBehaviorL(RTz::ETZAutoDSTUpdateOn);
+	iUserData = CTzUserData::NewL(tz);
+
+	test.Next(_L("Create user-defined Time Zone"));
+
+	// Offset 60 There is no DST 
+	test.Printf(_L("Offset 60 There is no DST\n"));
+	CreateTzAndCheckL(60, 60, tz, aWhatToTest);
+
+	// Offset - 60 There is no DST
+	test.Printf(_L("Offset -60 There is no DST\n"));
+	CreateTzAndCheckL(-60, -60, tz, aWhatToTest);
+	
+	// Offset 60 There is DST of 60
+	CreateTzAndCheckL(60, 120, tz, aWhatToTest);
+
+	// Offset - 60 There is DST of 60
+	test.Printf(_L("Offset - 60 There is DST of 60\n"));
+	CreateTzAndCheckL(-60, 0, tz, aWhatToTest);
+
+	// Create user time zone based on London TZ rules 
+	test.Printf(_L("Create User Tz Based On London Rule\n"));
+	CreateUserTzBasedOnLondonRuleL(tz, aWhatToTest);
+	
+	// Create user time zone based on Shanghai TZ rules
+	test.Printf(_L("Create User Tz Based On Shanghai Rule\n"));
+	CreateUserTzBasedOnShanghaiRuleL(tz, aWhatToTest);
+	
+	delete iUserData;
+	iUserData= NULL;
+	CleanupStack::PopAndDestroy(&tz);
+	ResetTzUserDataL();
+	}
+
+
+void CTzUserDataTest::UpdateCurrentTzL(RTz& aTz,TInt aOldOffSet, TInt aNewOffSet )
+	{
+	CTzRules*  newrules = CreateUserDefinedTzLC(aOldOffSet, aNewOffSet);
+	CTzUserNames* newnames = CreateUserDefinedTzNamesLC();
+	CTzId* currentTzid = aTz.GetTimeZoneIdL();
+	CleanupStack::PushL(currentTzid);
+	iUserData->UpdateL(*currentTzid,*newrules, *newnames);
+	CleanupStack::PopAndDestroy(currentTzid);
+	CTzRules* currentRules = aTz.GetTimeZoneRulesL(0, 9999,ETzUtcTimeReference );
+	CleanupStack::PushL(currentRules);
+	test(newrules->IsEqualTo(*currentRules));
+	CleanupStack::PopAndDestroy(3, newrules);
+	}
+
+
+void CTzUserDataTest::DeleteCurrentTzL(RTz& aTz)
+	{
+	CTzId* currentTzid = aTz.GetTimeZoneIdL();
+	CleanupStack::PushL(currentTzid);
+	iUserData->DeleteL(*currentTzid);
+	CleanupStack::PopAndDestroy(currentTzid);
+	CTzId* tzGot = aTz.GetTimeZoneIdL();
+	test(KTzLondon()==tzGot->TimeZoneNameID());
+	delete tzGot;
+	}
+
+
+/**
+User-defined time zone is current time zone.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-RC-0001  
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that the current time zone can be set
+	to a user-defined time zone.
+
+@SYMTestActions 
+	1.	Create a user-defined time zone and store the returned time zone
+		identifier.
+	2.	Set the current time zone using the time zone identifier stored in
+		action 1.
+	3.	Get the time zone identifier for the current time zone.
+
+@SYMTestExpectedResults
+	The time zone identifier obtained in action 1 is the same as the time zone
+	identifier obtained in action 3.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+
+
+void CTzUserDataTest::CreateUserTzAndSetCurrentTimeToL(RTz& aTz, TInt aStandardOffSet, TInt aDSTOffset)
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-RC-0001 Test user-defined time zone is current time zone"));
+	CTzId* usertzid = CreateUserDefinedTzL(aStandardOffSet, aDSTOffset, ETrue);
+	CleanupStack::PushL(usertzid);
+	aTz.SetTimeZoneL(*usertzid);
+	CTzId* tzGot = aTz.GetTimeZoneIdL();
+	test (*tzGot == *usertzid);
+	delete tzGot;
+	CleanupStack::PopAndDestroy(usertzid);
+	}
+
+
+/**
+Update user-defined time zone whose rules are being cached by TZ Server in the
+current time zone rules cache.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-RC-0002 
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that expected behaviour when a time
+	zone rule for a user-defined time zone, which is also the current time zone,
+	is updated.
+
+@SYMTestActions 
+	1.	Create a user-defined time zone.
+	2.	Set the current time zone to the user-defined time zone created in
+		action 1.
+	3.	Update the first time zone rule for the user-defined zone created in
+		action 1.
+	4.	Get the first time zone rule for the current time zone.
+
+@SYMTestExpectedResults
+	The rule used to update the user-defined time zone in action 2 is the same
+	as the rule obtained in action 4, implying that the current time zone rules
+	cache in the TZ Server has been updated.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+
+
+void CTzUserDataTest::UpdateCurrentUserTzL(RTz& aTz)
+	{
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-RC-0002 Update Current TZ rules - Server Response to Changes"));
+	TInt standardOffset = 60;
+	TInt dstOffset = 60;
+	CreateUserTzAndSetCurrentTimeToL(aTz,standardOffset,dstOffset); 
+	standardOffset = 120;
+	dstOffset = 120;
+	UpdateCurrentTzL(aTz,standardOffset, dstOffset);
+	}
+
+
+/**
+Delete user-defined time zone whose rules are being cached by TZ Server in the
+current time zone rules cache.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-RC-0003
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify the expected behaviour when a user-
+	defined time zone, which is also the current time zone, is deleted.
+
+@SYMTestActions 
+	1.	Set the current time zone to the default time zone for the system TZ
+		database.
+	2.	Get the time zone identifier for the current time zone.
+	3.	Create a user-defined time zone.
+	4.	Set the current time zone to the user-defined time zone created in
+		action 3.
+	5.	Delete the user-defined time zone created in action 3.
+	6.	Get the time zone identifier for the current time zone.
+
+@SYMTestExpectedResults
+	The time zone identifier obtained in action 2 is the same as the time zone
+	identifier obtained in action 6, implying that the current time zone has
+	reverted to the default time zone for the system TZ database.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestDeleteCurrentTimeZoneL(RTz& aTz)
+	{
+	DeleteCurrentUserTzL(aTz, EDeleteCurrentUserRule);
+	}
+
+
+void CTzUserDataTest::DeleteCurrentUserTzL(RTz& aTz, TTest aWhatToTest)
+	{
+	test.Next(_L("Delete Current TZ rules - Server Response to Changes"));
+
+	// Set system to default time zone
+	ResetTimeZoneToLondonL();
+	CTzId* defaulteTzid = aTz.GetTimeZoneIdL();
+	test(KTzLondon()==defaulteTzid->TimeZoneNameID());
+	delete defaulteTzid;
+	
+	// Set system to a newly created user time zone
+	const TInt KStandardOffset = 60;
+	const TInt KDSTOffset = 120;
+	CreateUserTzAndSetCurrentTimeToL(aTz,KStandardOffset,KDSTOffset); 
+	
+	//Delete the user time zone
+	DeleteCurrentTzL(aTz);
+	
+	if(aWhatToTest == EPersistence)
+		{
+		aTz.Close();	
+		User::After(1000000);
+		User::LeaveIfError(aTz.Connect());
+		}
+	CTzId* tzGot = aTz.GetTimeZoneIdL();
+	test(KTzLondon()==tzGot->TimeZoneNameID());
+	delete tzGot;
+	}
+
+
+/**
+Current time zone persistence.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-RC-0006
+
+@SYMTestCaseDesc
+	The purpose of this test is to ensure the home time zone identifier in the
+	Central Repository is not defined when it is deleted.
+
+@SYMTestActions 
+	1.	Set the current time zone to the default time zone for the system TZ
+		database.
+	2.	Get the time zone identifier for the current time zone.
+	3.	Create a user-defined time zone.
+	4.	Set the current time zone to the user-defined time zone created in
+		action 3.
+	5.	Delete the user-defined time zone created in action 3.
+	6.	Get the time zone identifier for the current time zone.
+	7.	Close session with TZ Server so that TZ Server process is terminated.
+	8.	Get the time zone identifier for the current time zone.
+	9.	The expected result is same as 8.
+
+@SYMTestExpectedResults
+	The time zone identifier obtained in action 2 is the same as the time zone
+	identifier obtained in action 8, implying that the current time zone has
+	been established by the TZ Server when the server is started using the
+	current time zone value persisted to the Central Repository.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestCurrentTimeZonePersistenceL(RTz& aTz)
+	{
+	DeleteCurrentUserTzL(aTz, EPersistence);
+	}
+
+
+/**
+Update user-defined time zone whose rules are being cached by TZ Server in the
+foreign time zone rules cache.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-RC-0004 
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that time conversion to/from a foreign
+	(i.e. not current) time zone behaves correctly when the time zone rules
+	cached by the TZ Server for the foreign time zone are time zone rules from a
+	user-defined time zone that is subsequently updated.
+
+@SYMTestActions 
+	1.	Create a user-defined time zone.
+	2.	Convert a given time from UTC to local time using the user-defined time
+		zone. 
+	3.	Update the user-defined time zone created in action 1.
+	4.	Convert a given time from UTC to local time using an existing time zone. 
+
+@SYMTestExpectedResults
+	The local time is correctly converted, implying that the foreign time zone
+	rules cache in the TZ Server is invalidated and recreated.
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestUpdateCachedUserTimeZoneL(RTz& aRTz)
+	{
+	CachedUserTimeZoneL(aRTz, EUpdateCachedTz);
+	}
+
+
+/**
+Delete user-defined time zone whose rules are being cached by TZ Server in the
+foreign time zone rules cache.
+
+@SYMTestCaseID	PIM-APPSERV-TZS-RC-0005
+
+@SYMTestCaseDesc
+	The purpose of this test is to verify that time conversion to/from a foreign
+	(i.e. not current) time zone behaves correctly when the time zone rules
+	cached by the TZ Server for the foreign time zone are time zone rules from a
+	user-defined time zone that is subsequently deleted.
+
+@SYMTestActions 
+	1.	Create a user-defined time zone.
+	2.	Convert a given time from UTC to local time using the user-defined time
+		zone.
+	3.	Delete the user-defined time zone created in action 1.
+	4.	Convert a given time from UTC to local time using an existing time zone.
+
+@SYMTestExpectedResults
+	The local time is correctly converted, implying that the foreign time zone
+	rules cache in the TZ Server is invalidated and recreated. 
+
+@SYMTestType
+	CT
+
+@SYMTestPriority
+	1
+*/
+void CTzUserDataTest::TestDeletedCachedUserTimeZoneL(RTz& aRTz)
+	{
+	CachedUserTimeZoneL(aRTz, EDeleteCachedTz);
+	}
+
+
+void CTzUserDataTest::CachedUserTimeZoneL(RTz& aRTz, TTest aWhatToTest)
+	{
+	test.Next(_L("Conver times - Server Response to Changes"));
+	TInt offset = 60;
+	TTime utctime (TDateTime(2000, EMay, 0, 0, 0, 0, 0));
+	
+	//Convert a given time from UTC to local time using the user-defined time zone
+	TTime localtime = utctime ;
+	CreateUserTzAndSetCurrentTimeToL(aRTz, offset, offset);
+	aRTz.ConvertToLocalTime(localtime);
+	TTimeIntervalMinutes minutes;
+	localtime.MinutesFrom(utctime, minutes);
+	test (minutes == TTimeIntervalMinutes(offset));
+	
+	localtime = utctime;
+
+	//Convert a given time from UTC to local time when the corrent tz rule is updated 
+	if(aWhatToTest==EUpdateCachedTz)
+		{
+		offset = 120;
+		UpdateCurrentTzL(aRTz, offset, offset);
+		}
+	else if(aWhatToTest==EDeleteCachedTz)
+		{
+		//Delete the current tz rule which result in system time reverting to the default time zone. 
+		DeleteCurrentTzL(aRTz);
+		//Convert a given time from UTC to local time using an existing time zone which is the defaut time zone.
+		CTzRules* currentRules = aRTz.GetTimeZoneRulesL(0, 9999,ETzUtcTimeReference );
+		CleanupStack::PushL(currentRules);
+		offset = currentRules->GetOffsetL(utctime, ETzUtcTimeReference);
+		CleanupStack::PopAndDestroy(currentRules);
+		}
+	
+	aRTz.ConvertToLocalTime(localtime);
+	localtime.MinutesFrom(utctime, minutes);
+	test (minutes == TTimeIntervalMinutes(offset));
+	}
+
+
+/**
+The purpose of the following test cases is to verify the behaviour of the TZ
+Server component’s response to changes in user-defined time zones, specifically
+the rules associated with user-defined time zones.
+
+The TZ Server maintains a cache of certain time zone rules data and persists the
+time zone identifier for the current time zone.
+
+If either this cache or the persisted setting relates to user-defined time zones
+and those time zones are modified then the TZ Server must respond to the change
+appropriately.
+*/
+
+// @SYMTestCaseID PIM-APPSERV-TZS-RC-0003-TO-0006
+
+void CTzUserDataTest::TestServerResponseToChangesL()
+	{
+	ResetTzUserDataL();
+
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-RC-0003-TO-0006 Server Response To Changes"));
+
+	RTz tz;
+	User::LeaveIfError(tz.Connect());
+	CleanupClosePushL(tz);
+
+	iUserData = CTzUserData::NewL(tz);
+
+	const TInt KStandardOffset = 60;
+	const TInt KDSTOffset = 60;
+	CreateUserTzAndSetCurrentTimeToL(tz,KStandardOffset,KDSTOffset); 
+
+	UpdateCurrentUserTzL(tz);
+
+	TestUpdateCachedUserTimeZoneL(tz);
+	TestDeletedCachedUserTimeZoneL(tz);
+	TestDeleteCurrentTimeZoneL(tz);
+	TestCurrentTimeZonePersistenceL(tz);
+	
+	delete iUserData;
+	iUserData= NULL;
+
+	CleanupStack::PopAndDestroy(&tz);
+	}
+
+	
+/**
+The purpose of the follwing test case is to verify the behaviour of 
+reuse of Tz Ids in case all the 4095 ids have been used.
+*/	
+void CTzUserDataTest::TestTzIdReusabilityL()
+	{
+	ResetTzUserDataL();
+	RTz tz;
+	CleanupClosePushL(tz);
+	User::LeaveIfError(tz.Connect());
+	iUserData = CTzUserData::NewL(tz);
+	const TInt maxTzIds = 4095;
+	for(TInt i=0; i<= maxTzIds; i++)
+		{
+		CTzId* tzid = NULL;
+		TRAPD(err, tzid = CreateUserDefinedTzL(0,0, EFalse));
+		if(i%KPrintFreq == 0 || i == maxTzIds)
+			{
+			test.Printf(_L("Added %d rules to the database\n"), i);
+			}
+			
+		if(err != KErrNone)
+			{
+			test.Printf(_L("Error while creating rules. Error is %d\n"), err);	
+			}
+		delete tzid;
+		}
+	const TUint KFirstReusedTzId = 16400;
+	CTzId* tzId = CTzId::NewL(KFirstReusedTzId);
+	CleanupStack::PushL(tzId);
+	iUserData->DeleteL(*tzId);
+	CleanupStack::PopAndDestroy(tzId);
+	
+	const TUint KSecondReusedTzId = 16500;
+	CTzId* tzId1 = CTzId::NewL(KSecondReusedTzId);
+	CleanupStack::PushL(tzId1);
+	iUserData->DeleteL(*tzId1);
+	CleanupStack::PopAndDestroy(tzId1);	
+		
+	CTzId* reusedId = CreateUserDefinedTzL(0, 0, EFalse);
+	test(reusedId->TimeZoneNumericID() == KFirstReusedTzId);
+	test.Printf(_L("The first re-used id is %d\n"), reusedId->TimeZoneNumericID());
+	delete reusedId;
+	
+	CTzId* secondReusedId = CreateUserDefinedTzL(0, 0, EFalse);
+	test(secondReusedId->TimeZoneNumericID() == KSecondReusedTzId);
+	test.Printf(_L("The second re-used id is %d\n"), secondReusedId->TimeZoneNumericID());
+	delete secondReusedId;
+	
+	TRAPD(err, CreateUserDefinedTzL(0, 0, EFalse));
+	test(err == KErrOverflow);
+	
+	delete iUserData;
+	iUserData = NULL;
+	CleanupStack::PopAndDestroy(&tz);
+	}
+	
+static void DoTestsL()
+	{
+	User::LeaveIfError(Serv.Connect());
+		
+	test.Title();
+
+	ResetTimeZoneToLondonL();
+
+	CTzUserDataTest* userDataTest = CTzUserDataTest::NewLC();
+
+	test.Start(_L("Test Basic User Data"));
+	userDataTest->TestBasicUserDataL();
+
+	test.Next(_L("Test Out Of Memory Behaviour (Client)"));
+	userDataTest->TestOutOfMemoryBehaviourL(CTzUserDataTest::EClientOOM);
+
+	test.Next(_L("Test Out Of Memory Behaviour (Server)"));
+	userDataTest->TestOutOfMemoryBehaviourL(CTzUserDataTest::EServerOOM );
+	
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-TZR-0001 Test Time Conversion"));
+	userDataTest->TestTimeConversionL();
+
+	test.Next(_L("@SYMTestCaseID PIM-APPSERV-TZS-TZR-0002 Test Daylight Save"));
+	userDataTest->TestDaylightSaveL();
+
+	test.Next(_L("Test Boundary Test"));
+	userDataTest->BoundaryTestL();
+
+	test.Next(_L("Test Server Response To Changes"));
+	userDataTest->TestServerResponseToChangesL();
+	
+	// Delete the user-defined TZ database before the next test case.
+	Serv.CloseTzSession();
+	Serv.DeleteFileL(KTzUserDataDb);
+
+	test.Next(_L("Test Reusability Of TZ IDs"));
+	userDataTest->TestTzIdReusabilityL();
+
+	// Delete the user defined TZ database.
+	Serv.CloseTzSession();
+	Serv.DeleteFileL(KTzUserDataDb);	
+
+	test.Next(_L("Null Test"));
+	userDataTest->NullTestL();
+
+	ResetTimeZoneToLondonL();
+
+	CleanupStack::PopAndDestroy(userDataTest);
+
+	test.End();
+
+	Serv.Close();
+	}
+
+
+TInt E32Main()
+    {
+	__UHEAP_MARK;
+
+	CTrapCleanup* trapCleanup = CTrapCleanup::New();
+	if(!trapCleanup)
+		{
+		return KErrNoMemory;
+		}
+
+	CActiveScheduler* scheduler = new CActiveScheduler;
+	if(!scheduler)
+		{
+		return KErrNoMemory;
+		}
+	CActiveScheduler::Install(scheduler);	
+	
+	TRAPD(ret, DoTestsL());
+	test.Printf(_L("Trapped return value from DoTestsL(): %d\n"), ret);
+	test(ret == KErrNone);
+
+	test.Close();
+		
+	delete scheduler;
+	delete trapCleanup;	
+
+	__UHEAP_MARKEND;
+
+	return (KErrNone);
+    }