sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Testing DBMS ordering and searching functionality when the key field is unicode string. sl@0: // The idea is to verify that collation level 0 is used when doing string based searching sl@0: // and collation level > 0 is used when doing string based ordering. sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "crccheck.h" sl@0: sl@0: #undef __UHEAP_MARK sl@0: #define __UHEAP_MARK sl@0: #undef __UHEAP_MARKEND sl@0: #define __UHEAP_MARKEND sl@0: sl@0: LOCAL_D TDBMS_CRCChecks TheCrcChecker; sl@0: sl@0: #ifndef __linux__ //No CRC test on LINUX sl@0: #ifdef __TOOLS2__ sl@0: const TPtrC KCrcRecord=_L("\\epoc32\\winscw\\c\\dbms-tst\\T_DBMSSTRCOMP.CRC"); sl@0: #else sl@0: const TPtrC KCrcRecord=_L("C:\\dbms-tst\\T_DBMSSTRCOMP.CRC"); sl@0: #endif sl@0: #endif sl@0: sl@0: ///////////////////////////////////////////////////////////////// sl@0: //Globals sl@0: sl@0: #ifdef __TOOLS2__ sl@0: const TPtrC KTestDatabase = _L(".\\dbms-tst\\T_DbmsStrComp.db"); sl@0: #else sl@0: const TPtrC KTestDatabase = _L("c:\\dbms-tst\\T_DbmsStrComp.db"); sl@0: #endif sl@0: sl@0: const TUint KExitDelay = 6 * 1000000;//6 seconds sl@0: sl@0: static RTest TheTest(_L("T_DbmsStrComp test")); sl@0: static RFs TheFs; sl@0: static RDbNamedDatabase TheDb; sl@0: static RDbs TheDbSession; sl@0: sl@0: //Test table defs sl@0: _LIT(KTestTableName1, "TABLE1");//EDbColText16 key field sl@0: _LIT(KTestTableName2, "TABLE2");//EDbColLongText16 key field sl@0: sl@0: struct TColDef sl@0: { sl@0: const TText* iName; sl@0: TDbColType iType; sl@0: TInt iAttributes; sl@0: }; sl@0: static TColDef const KColDefs1[]= sl@0: { sl@0: {_S("ID"), EDbColText16, 0}, sl@0: {_S("DATA"), EDbColUint32, 0}, sl@0: {0} sl@0: }; sl@0: static TColDef const KColDefs2[]= sl@0: { sl@0: {_S("ID"), EDbColLongText16, 0}, sl@0: {_S("DATA"), EDbColUint32, 0}, sl@0: {0} sl@0: }; sl@0: sl@0: //Test strings sl@0: const TInt KTestStrLen = 3; //The length of test strings sl@0: typedef TBuf16 TNameBuf; sl@0: //Test strings array - using upper and lower case - which will force the DBMS server to make sl@0: //different decisions depending on what is the current case: ordering or searching. sl@0: const TNameBuf KTestStr[] = sl@0: { sl@0: _L16("aaa"), sl@0: _L16("aAa"), sl@0: _L16("bbB"), sl@0: _L16("BbB") sl@0: }; sl@0: const TInt KTestStrCnt = sizeof(KTestStr) / sizeof(KTestStr[0]); sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: //Destroy test environment - global functions sl@0: sl@0: //Deletes "aFullName" file. sl@0: static TInt DeleteDataFile(const TDesC& aFullName) sl@0: { sl@0: RFs fsSession; sl@0: TInt err = fsSession.Connect(); sl@0: if(err == KErrNone) sl@0: { sl@0: TEntry entry; sl@0: err = fsSession.Entry(aFullName, entry); sl@0: if(err == KErrNone) sl@0: { sl@0: RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName); sl@0: err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly); sl@0: if(err != KErrNone) sl@0: { sl@0: RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName); sl@0: } sl@0: err = fsSession.Delete(aFullName); sl@0: if(err != KErrNone) sl@0: { sl@0: RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName); sl@0: } sl@0: } sl@0: fsSession.Close(); sl@0: } sl@0: else sl@0: { sl@0: RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: //Tests macros and functions. sl@0: //If (!aValue) then the test will be panicked, the test data files will be deleted. sl@0: static void Check(TInt aValue, TInt aLine) sl@0: { sl@0: if(!aValue) sl@0: { sl@0: ::DeleteDataFile(KTestDatabase); sl@0: TheTest(EFalse, aLine); sl@0: } sl@0: } sl@0: //If (aValue != aExpected) then the test will be panicked, the test data files will be deleted. sl@0: static void Check(TInt aValue, TInt aExpected, TInt aLine) sl@0: { sl@0: if(aValue != aExpected) sl@0: { sl@0: RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue); sl@0: ::DeleteDataFile(KTestDatabase); sl@0: TheTest(EFalse, aLine); sl@0: } sl@0: } sl@0: //Use these to test conditions. sl@0: #define TEST(arg) ::Check((arg), __LINE__) sl@0: #define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__) sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: //Global functions sl@0: sl@0: //Prepares the test directory. sl@0: //TheFs.Connect() has to be called already. sl@0: static void SetupTestDirectory() sl@0: { sl@0: TInt err = TheFs.MkDir(KTestDatabase); sl@0: TEST(err == KErrNone || err == KErrAlreadyExists); sl@0: } sl@0: sl@0: //Leaves with info message printed out sl@0: static void Leave(TInt aError, TInt aLine) sl@0: { sl@0: RDebug::Print(_L("*** Leave. Error: %d, Line: %d\r\n"), aError, aLine); sl@0: User::Leave(aError); sl@0: } sl@0: sl@0: //Leaves if aError < 0 with info message printed out sl@0: static void LeaveIfError(TInt aError, TInt aLine) sl@0: { sl@0: if(aError < KErrNone) sl@0: { sl@0: ::Leave(aError, aLine); sl@0: } sl@0: } sl@0: sl@0: //Use LEAVE() macro instead of User::Leave() and LEAVE_IF_ERROR() macro instead of sl@0: //User::LeaveIfError(). They will print the line number, where the "leave" was called. sl@0: #define LEAVE(aError) ::Leave(aError, __LINE__) sl@0: #define LEAVE_IF_ERROR(aError) ::LeaveIfError(aError, __LINE__) sl@0: sl@0: //Creates the test DBMS session sl@0: static void CreateTestDbSession() sl@0: { sl@0: #ifndef __TOOLS2__ sl@0: RDebug::Print(_L("Create DBMS session\n")); sl@0: TInt err = TheDbSession.Connect(); sl@0: TEST2(err, KErrNone); sl@0: #endif sl@0: } sl@0: sl@0: sl@0: //Creates the test database sl@0: //TheDbSession instance has to be connected already. sl@0: //TheFs.Connect() has to be called already. sl@0: static void CreateTestDatabase(RDbs& aDbs, RDbNamedDatabase& aDb) sl@0: { sl@0: RDebug::Print(_L("Create test database\n")); sl@0: TInt err = aDb.Replace(TheFs, KTestDatabase); sl@0: TEST2(err, KErrNone); sl@0: TheDb.Close(); sl@0: err = aDb.Open(aDbs, KTestDatabase); sl@0: TEST2(err, KErrNone); sl@0: } sl@0: sl@0: //Creates test table sl@0: static void DoCreateTestTableL(RDbNamedDatabase& aDb, const TDesC& aTblName, const TColDef aColDefs[]) sl@0: { sl@0: CDbColSet* colSet = CDbColSet::NewLC(); sl@0: for(const TColDef* colDef=aColDefs;colDef->iName;++colDef) sl@0: { sl@0: TDbCol col(TPtrC(colDef->iName), colDef->iType); sl@0: col.iAttributes = colDef->iAttributes; sl@0: colSet->AddL(col); sl@0: } sl@0: TEST2(aDb.CreateTable(aTblName, *colSet), KErrNone); sl@0: CleanupStack::PopAndDestroy(colSet); sl@0: } sl@0: sl@0: //Creates test tables sl@0: static void CreateTestTablesL(RDbNamedDatabase& aDb) sl@0: { sl@0: RDebug::Print(_L("Create test tables\n")); sl@0: ::DoCreateTestTableL(aDb, KTestTableName1, KColDefs1); sl@0: ::DoCreateTestTableL(aDb, KTestTableName2, KColDefs2); sl@0: } sl@0: sl@0: //Gets the value of the string field, which type may be EDbColText16 or EDbColLongText16 sl@0: void GetStrFieldValue(RDbRowSet& aTbl, const TDesC& aTblName, TDes& aStrFldVal) sl@0: { sl@0: if(aTblName.CompareF(KTestTableName1) == 0) sl@0: { sl@0: aStrFldVal = aTbl.ColDes16(1); sl@0: } sl@0: else sl@0: { sl@0: RDbColReadStream blob; sl@0: blob.OpenLC(aTbl, 1); sl@0: blob.ReadL(aStrFldVal, aTbl.ColLength(1)); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: } sl@0: sl@0: //Prints all table records sl@0: static TInt PrintRecordsL(RDbRowSet& aTbl, const TDesC& aTblName) sl@0: { sl@0: RDebug::Print(_L("Table: %S\n"), &aTblName); sl@0: aTbl.FirstL(); sl@0: TInt rec = 0; sl@0: while(aTbl.AtRow()) sl@0: { sl@0: aTbl.GetL(); sl@0: TNameBuf strFldVal; sl@0: ::GetStrFieldValue(aTbl, aTblName, strFldVal); sl@0: TUint32 v = aTbl.ColUint32(2); sl@0: RDebug::Print(_L(" Record %d, Str: %S, Val: %d\n"), ++rec, &strFldVal, v); sl@0: aTbl.NextL(); sl@0: } sl@0: return rec; sl@0: } sl@0: sl@0: //Checks if the records order (based on a string key field comparison) matches the order of the sl@0: //strings in aTestStrArray sl@0: static void AssertRecordsOrder(RDbRowSet& aTbl, const TDesC& aTblName, const RArray& aTestStrArray) sl@0: { sl@0: aTbl.FirstL(); sl@0: TInt rec = 0; sl@0: while(aTbl.AtRow()) sl@0: { sl@0: aTbl.GetL(); sl@0: TNameBuf strFldVal; sl@0: ::GetStrFieldValue(aTbl, aTblName, strFldVal); sl@0: TEST(aTestStrArray[rec] == strFldVal); sl@0: ++rec; sl@0: aTbl.NextL(); sl@0: } sl@0: } sl@0: sl@0: //Adds test data to the specified table. Make sure that the records are not in sl@0: //order (assuming that the first field will be the key). sl@0: static void AddTestDataL(RDbNamedDatabase& aDb, const TDesC& aTblName) sl@0: { sl@0: RDbTable tbl; sl@0: CleanupClosePushL(tbl); sl@0: TEST2(tbl.Open(aDb, aTblName, RDbRowSet::EUpdatable), KErrNone); sl@0: for(TInt i=0;i& aTestStrArray) sl@0: { sl@0: for(TInt i=0;i(CompareC))); sl@0: } sl@0: } sl@0: sl@0: static void CreateIndexL(RDbNamedDatabase& aDb, const TDesC& aTblName, const TDesC& aColumnName) sl@0: { sl@0: RDebug::Print(_L("Create index. Table: %S, column: %S\n"), &aTblName, &aColumnName); sl@0: CDbKey* key = CDbKey::NewLC(); sl@0: key->AddL(aColumnName); sl@0: key->MakeUnique(); sl@0: key->SetComparison(EDbCompareCollated); sl@0: LEAVE_IF_ERROR(aDb.CreateIndex(aColumnName, aTblName, *key)); sl@0: CleanupStack::PopAndDestroy(key); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: //Test cases sl@0: sl@0: //Test case 1. Check SELECT statement with ORDER BY clause when the key field is a string. sl@0: static void OrderByTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray& aTestStrArray) sl@0: { sl@0: RDbView view; sl@0: CleanupClosePushL(view); sl@0: sl@0: TBuf<128> sqlStmt; sl@0: sqlStmt.Append(_L("SELECT ID, DATA FROM ")); sl@0: sqlStmt.Append(aTblName); sl@0: sqlStmt.Append(_L(" ORDER BY ID")); sl@0: User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited)); sl@0: User::LeaveIfError(view.EvaluateAll()); sl@0: sl@0: (void)::PrintRecordsL(view, aTblName); sl@0: ::AssertRecordsOrder(view, aTblName, aTestStrArray); sl@0: sl@0: CleanupStack::PopAndDestroy(&view); sl@0: } sl@0: sl@0: //Test case 2. Check SELECT statement with LIKE keyword when the key field is a string. sl@0: static void LikeTestL(RDbNamedDatabase& aDb, const TDesC& aTblName) sl@0: { sl@0: RDbView view; sl@0: CleanupClosePushL(view); sl@0: sl@0: TBuf<128> sqlStmt; sl@0: sqlStmt.Append(_L("SELECT ID, DATA FROM ")); sl@0: sqlStmt.Append(aTblName); sl@0: sqlStmt.Append(_L(" WHERE ID LIKE 'B*'")); sl@0: User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited)); sl@0: User::LeaveIfError(view.EvaluateAll()); sl@0: sl@0: TInt cnt = ::PrintRecordsL(view, aTblName); sl@0: TEST(cnt == 2); sl@0: sl@0: CleanupStack::PopAndDestroy(&view); sl@0: } sl@0: sl@0: //Test case 3. Check SELECT statement with LIKE & ORDER BY keywords when the key field is a string. sl@0: static void LikeOrderTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray& aTestStrArray) sl@0: { sl@0: RDbView view; sl@0: CleanupClosePushL(view); sl@0: sl@0: TBuf<128> sqlStmt; sl@0: sqlStmt.Append(_L("SELECT ID, DATA FROM ")); sl@0: sqlStmt.Append(aTblName); sl@0: sqlStmt.Append(_L(" WHERE ID LIKE 'B*' ORDER BY ID")); sl@0: User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited)); sl@0: User::LeaveIfError(view.EvaluateAll()); sl@0: sl@0: TInt cnt = ::PrintRecordsL(view, aTblName); sl@0: TEST(cnt == 2); sl@0: ::AssertRecordsOrder(view, aTblName, aTestStrArray); sl@0: sl@0: CleanupStack::PopAndDestroy(&view); sl@0: } sl@0: sl@0: //Test case 4. Indexed table. The index is a string field. sl@0: static void IndexTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray& aTestStrArray) sl@0: { sl@0: _LIT(KIdxName, "ID"); sl@0: ::CreateIndexL(aDb, aTblName, KIdxName); sl@0: sl@0: RDbTable tbl; sl@0: CleanupClosePushL(tbl); sl@0: TEST2(tbl.Open(aDb, aTblName, RDbRowSet::EReadOnly), KErrNone); sl@0: TEST2(tbl.SetIndex(KIdxName), KErrNone); sl@0: sl@0: (void)::PrintRecordsL(tbl, aTblName); sl@0: ::AssertRecordsOrder(tbl, aTblName, aTestStrArray); sl@0: sl@0: CleanupStack::PopAndDestroy(&tbl); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////////////////////////////////////////////////////////////////// sl@0: //The main test function. sl@0: //Call your new test functions from here sl@0: static void RunTestsL() sl@0: { sl@0: TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-LEGACY-DBMSSTRCOMP-0001 Init test environment ")); sl@0: ::InitEnvL(); sl@0: sl@0: RArray testStrArray; sl@0: CleanupClosePushL(testStrArray); sl@0: ::FillStrArraySortedL(testStrArray); sl@0: sl@0: TheTest.Next(_L("SELECT, ORDER BY, EDbColText16")); sl@0: ::OrderByTestL(TheDb, KTestTableName1, testStrArray); sl@0: sl@0: TheTest.Next(_L("SELECT, ORDER BY, EDbColLongText16")); sl@0: ::OrderByTestL(TheDb, KTestTableName2, testStrArray); sl@0: sl@0: TheTest.Next(_L("SELECT, LIKE, EDbColText16")); sl@0: ::LikeTestL(TheDb, KTestTableName1); sl@0: sl@0: TheTest.Next(_L("SELECT, LIKE, EDbColLongText16")); sl@0: ::LikeTestL(TheDb, KTestTableName2); sl@0: sl@0: RArray testStrArray2; sl@0: CleanupClosePushL(testStrArray2); sl@0: testStrArray2.AppendL(testStrArray[2]);//"bbB" sl@0: testStrArray2.AppendL(testStrArray[3]);//"BbB" sl@0: sl@0: TheTest.Next(_L("SELECT, LIKE, ORDER BY, EDbColText16")); sl@0: ::LikeOrderTestL(TheDb, KTestTableName1, testStrArray2); sl@0: sl@0: TheTest.Next(_L("SELECT, LIKE, ORDER BY, EDbColLongText16")); sl@0: ::LikeOrderTestL(TheDb, KTestTableName2, testStrArray2); sl@0: sl@0: TheTest.Next(_L("Index, EDbColText16")); sl@0: ::IndexTestL(TheDb, KTestTableName1, testStrArray); sl@0: sl@0: // Not possible to create a key with EDbColLongText16 sl@0: // TheTest.Next(_L("Index, EDbColLongText16")); sl@0: // ::IndexTestL(TheDb, KTestTableName2, testStrArray); sl@0: sl@0: //Add tests here! sl@0: sl@0: CleanupStack::PopAndDestroy(&testStrArray2); sl@0: CleanupStack::PopAndDestroy(&testStrArray); sl@0: } sl@0: sl@0: TInt E32Main() sl@0: { sl@0: TheTest.Title(); sl@0: sl@0: __UHEAP_MARK; sl@0: sl@0: CTrapCleanup* trapCleanup = CTrapCleanup::New(); sl@0: TEST(trapCleanup != NULL); sl@0: sl@0: TInt err = TheFs.Connect(); sl@0: TEST2(err, KErrNone); sl@0: ::SetupTestDirectory(); sl@0: sl@0: ::DeleteDataFile(KTestDatabase); sl@0: sl@0: TRAP(err, ::RunTestsL()); sl@0: TheDb.Close(); sl@0: #ifndef __TOOLS2__ sl@0: TheDbSession.Close(); sl@0: #endif sl@0: TheFs.Close(); sl@0: TEST2(err, KErrNone); sl@0: sl@0: #ifndef __linux__ sl@0: TRAP(err, TheCrcChecker.GenerateCrcL(KTestDatabase)); sl@0: TEST(err==KErrNone); sl@0: #ifndef __TOOLS2__ sl@0: TRAPD(lc, err = TheCrcChecker.DumpCrcRecordsL(KCrcRecord)); sl@0: TEST(err==KErrNone); sl@0: TEST(lc==KErrNone); sl@0: #else sl@0: TRAPD(lc, err = TheCrcChecker.ValidateCrcRecordsL(KCrcRecord)); sl@0: TPtrC errmsg; sl@0: TheCrcChecker.ErrorReportL(err, errmsg); sl@0: RDebug::Print(errmsg); sl@0: TheTest(err==KErrNone || err==TDBMS_CRCChecks::ECrcCheckOk); sl@0: #endif sl@0: #endif sl@0: sl@0: ::DeleteDataFile(KTestDatabase); sl@0: sl@0: TheTest.Printf(_L("Wait DBMS server shutdown...\n")); sl@0: User::After(KExitDelay); sl@0: sl@0: TheTest.End(); sl@0: TheTest.Close(); sl@0: sl@0: delete trapCleanup; sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: