1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/dbms/tdbms/t_dbstrcmp.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,485 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Testing DBMS ordering and searching functionality when the key field is unicode string.
1.18 +// The idea is to verify that collation level 0 is used when doing string based searching
1.19 +// and collation level > 0 is used when doing string based ordering.
1.20 +//
1.21 +//
1.22 +
1.23 +#include <e32test.h>
1.24 +#include <f32file.h>
1.25 +#include <d32dbms.h>
1.26 +
1.27 +/////////////////////////////////////////////////////////////////
1.28 +//Globals
1.29 +
1.30 +_LIT( KTestDatabase, "C:\\DBMS-TST\\T_DbmsStrComp.DB");
1.31 +
1.32 +static RTest TheTest(_L("t_dbstrcmp"));
1.33 +static RFs TheFs;
1.34 +static RDbNamedDatabase TheDb;
1.35 +static RDbs TheDbSession;
1.36 +
1.37 +//Test table defs
1.38 +_LIT(KTestTableName1, "TABLE1");//EDbColText16 key field
1.39 +_LIT(KTestTableName2, "TABLE2");//EDbColLongText16 key field
1.40 +
1.41 +struct TColDef
1.42 + {
1.43 + const TText* iName;
1.44 + TDbColType iType;
1.45 + TInt iAttributes;
1.46 + };
1.47 +static TColDef const KColDefs1[]=
1.48 + {
1.49 + {_S("ID"), EDbColText16, 0},
1.50 + {_S("DATA"), EDbColUint32, 0},
1.51 + {0}
1.52 + };
1.53 +static TColDef const KColDefs2[]=
1.54 + {
1.55 + {_S("ID"), EDbColLongText16, 0},
1.56 + {_S("DATA"), EDbColUint32, 0},
1.57 + {0}
1.58 + };
1.59 +
1.60 +//Test strings
1.61 +const TInt KTestStrLen = 3; //The length of test strings
1.62 +typedef TBuf16<KTestStrLen> TNameBuf;
1.63 +//Test strings array - using upper and lower case - which will force the DBMS server to make
1.64 +//different decisions depending on what is the current case: ordering or searching.
1.65 +const TNameBuf KTestStr[] =
1.66 + {
1.67 + _L16("aaa"),
1.68 + _L16("aAa"),
1.69 + _L16("bbB"),
1.70 + _L16("BbB")
1.71 + };
1.72 +const TInt KTestStrCnt = sizeof(KTestStr) / sizeof(KTestStr[0]);
1.73 +
1.74 +///////////////////////////////////////////////////////////////////////////////////////
1.75 +///////////////////////////////////////////////////////////////////////////////////////
1.76 +//Destroy test environment - global functions
1.77 +
1.78 +//Deletes "aFullName" file.
1.79 +static TInt DeleteDataFile(const TDesC& aFullName)
1.80 + {
1.81 + RFs fsSession;
1.82 + TInt err = fsSession.Connect();
1.83 + if(err == KErrNone)
1.84 + {
1.85 + TEntry entry;
1.86 + err = fsSession.Entry(aFullName, entry);
1.87 + if(err == KErrNone)
1.88 + {
1.89 + RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
1.90 + err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
1.91 + if(err != KErrNone)
1.92 + {
1.93 + RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
1.94 + }
1.95 + err = fsSession.Delete(aFullName);
1.96 + if(err != KErrNone)
1.97 + {
1.98 + RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
1.99 + }
1.100 + }
1.101 + fsSession.Close();
1.102 + }
1.103 + else
1.104 + {
1.105 + RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
1.106 + }
1.107 + return err;
1.108 + }
1.109 +
1.110 +///////////////////////////////////////////////////////////////////////////////////////
1.111 +///////////////////////////////////////////////////////////////////////////////////////
1.112 +//Tests macros and functions.
1.113 +//If (!aValue) then the test will be panicked, the test data files will be deleted.
1.114 +static void Check(TInt aValue, TInt aLine)
1.115 + {
1.116 + if(!aValue)
1.117 + {
1.118 + ::DeleteDataFile(KTestDatabase);
1.119 + TheTest(EFalse, aLine);
1.120 + }
1.121 + }
1.122 +//If (aValue != aExpected) then the test will be panicked, the test data files will be deleted.
1.123 +static void Check(TInt aValue, TInt aExpected, TInt aLine)
1.124 + {
1.125 + if(aValue != aExpected)
1.126 + {
1.127 + RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
1.128 + ::DeleteDataFile(KTestDatabase);
1.129 + TheTest(EFalse, aLine);
1.130 + }
1.131 + }
1.132 +//Use these to test conditions.
1.133 +#define TEST(arg) ::Check((arg), __LINE__)
1.134 +#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
1.135 +
1.136 +///////////////////////////////////////////////////////////////////////////////////////
1.137 +///////////////////////////////////////////////////////////////////////////////////////
1.138 +//Global functions
1.139 +
1.140 +//Prepares the test directory.
1.141 +//TheFs.Connect() has to be called already.
1.142 +static void SetupTestDirectory()
1.143 + {
1.144 + TInt err = TheFs.MkDir(KTestDatabase);
1.145 + TEST(err == KErrNone || err == KErrAlreadyExists);
1.146 + }
1.147 +
1.148 +//Leaves with info message printed out
1.149 +static void LeaveL(TInt aError, TInt aLine)
1.150 + {
1.151 + RDebug::Print(_L("*** Leave. Error: %d, Line: %d\r\n"), aError, aLine);
1.152 + User::Leave(aError);
1.153 + }
1.154 +
1.155 +//Leaves if aError < 0 with info message printed out
1.156 +static void LeaveIfErrorL(TInt aError, TInt aLine)
1.157 + {
1.158 + if(aError < KErrNone)
1.159 + {
1.160 + LeaveL(aError, aLine);
1.161 + }
1.162 + }
1.163 +
1.164 +//Use LEAVE() macro instead of User::Leave() and LEAVE_IF_ERROR() macro instead of
1.165 +//User::LeaveIfError(). They will print the line number, where the "leave" was called.
1.166 +#define LEAVE(aError) ::LeaveL(aError, __LINE__)
1.167 +#define LEAVE_IF_ERROR(aError) ::LeaveIfErrorL(aError, __LINE__)
1.168 +
1.169 +//Creates the test DBMS session
1.170 +static void CreateTestDbSession()
1.171 + {
1.172 + RDebug::Print(_L("Create DBMS session\n"));
1.173 + TInt err = TheDbSession.Connect();
1.174 + TEST2(err, KErrNone);
1.175 + }
1.176 +
1.177 +
1.178 +//Creates the test database
1.179 +//TheDbSession instance has to be connected already.
1.180 +//TheFs.Connect() has to be called already.
1.181 +static void CreateTestDatabase(RDbs& aDbs, RDbNamedDatabase& aDb)
1.182 + {
1.183 + RDebug::Print(_L("Create test database\n"));
1.184 + TInt err = aDb.Replace(TheFs, KTestDatabase);
1.185 + TEST2(err, KErrNone);
1.186 + TheDb.Close();
1.187 + err = aDb.Open(aDbs, KTestDatabase);
1.188 + TEST2(err, KErrNone);
1.189 + }
1.190 +
1.191 +//Creates test table
1.192 +static void DoCreateTestTableL(RDbNamedDatabase& aDb, const TDesC& aTblName, const TColDef aColDefs[])
1.193 + {
1.194 + CDbColSet* colSet = CDbColSet::NewLC();
1.195 + for(const TColDef* colDef=aColDefs;colDef->iName;++colDef)
1.196 + {
1.197 + TDbCol col(TPtrC(colDef->iName), colDef->iType);
1.198 + col.iAttributes = colDef->iAttributes;
1.199 + colSet->AddL(col);
1.200 + }
1.201 + TEST2(aDb.CreateTable(aTblName, *colSet), KErrNone);
1.202 + CleanupStack::PopAndDestroy(colSet);
1.203 + }
1.204 +
1.205 +//Creates test tables
1.206 +static void CreateTestTablesL(RDbNamedDatabase& aDb)
1.207 + {
1.208 + RDebug::Print(_L("Create test tables\n"));
1.209 + ::DoCreateTestTableL(aDb, KTestTableName1, KColDefs1);
1.210 + ::DoCreateTestTableL(aDb, KTestTableName2, KColDefs2);
1.211 + }
1.212 +
1.213 +//Gets the value of the string field, which type may be EDbColText16 or EDbColLongText16
1.214 +void GetStrFieldValueL(RDbRowSet& aTbl, const TDesC& aTblName, TDes& aStrFldVal)
1.215 + {
1.216 + if(aTblName.CompareF(KTestTableName1) == 0)
1.217 + {
1.218 + aStrFldVal = aTbl.ColDes16(1);
1.219 + }
1.220 + else
1.221 + {
1.222 + RDbColReadStream blob;
1.223 + blob.OpenLC(aTbl, 1);
1.224 + blob.ReadL(aStrFldVal, aTbl.ColLength(1));
1.225 + CleanupStack::PopAndDestroy();
1.226 + }
1.227 + }
1.228 +
1.229 +//Prints all table records
1.230 +static TInt PrintRecordsL(RDbRowSet& aTbl, const TDesC& aTblName)
1.231 + {
1.232 + RDebug::Print(_L("Table: %S\n"), &aTblName);
1.233 + aTbl.FirstL();
1.234 + TInt rec = 0;
1.235 + while(aTbl.AtRow())
1.236 + {
1.237 + aTbl.GetL();
1.238 + TNameBuf strFldVal;
1.239 + GetStrFieldValueL(aTbl, aTblName, strFldVal);
1.240 + TUint32 v = aTbl.ColUint32(2);
1.241 + RDebug::Print(_L(" Record %d, Str: %S, Val: %d\n"), ++rec, &strFldVal, v);
1.242 + aTbl.NextL();
1.243 + }
1.244 + return rec;
1.245 + }
1.246 +
1.247 +//Checks if the records order (based on a string key field comparison) matches the order of the
1.248 +//strings in aTestStrArray
1.249 +static void AssertRecordsOrderL(RDbRowSet& aTbl, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
1.250 + {
1.251 + aTbl.FirstL();
1.252 + TInt rec = 0;
1.253 + while(aTbl.AtRow())
1.254 + {
1.255 + aTbl.GetL();
1.256 + TNameBuf strFldVal;
1.257 + GetStrFieldValueL(aTbl, aTblName, strFldVal);
1.258 + TEST(aTestStrArray[rec] == strFldVal);
1.259 + ++rec;
1.260 + aTbl.NextL();
1.261 + }
1.262 + }
1.263 +
1.264 +//Adds test data to the specified table. Make sure that the records are not in
1.265 +//order (assuming that the first field will be the key).
1.266 +static void AddTestDataL(RDbNamedDatabase& aDb, const TDesC& aTblName)
1.267 + {
1.268 + RDbTable tbl;
1.269 + CleanupClosePushL(tbl);
1.270 + TEST2(tbl.Open(aDb, aTblName, RDbRowSet::EUpdatable), KErrNone);
1.271 + for(TInt i=0;i<KTestStrCnt;++i)
1.272 + {
1.273 + tbl.InsertL();
1.274 + tbl.SetColL(1, KTestStr[KTestStrCnt - i - 1]);
1.275 + tbl.SetColL(2, i + 1);
1.276 + tbl.PutL();
1.277 + }
1.278 + TEST(tbl.CountL() == KTestStrCnt);
1.279 + (void)::PrintRecordsL(tbl, aTblName);
1.280 + CleanupStack::PopAndDestroy(&tbl);
1.281 + }
1.282 +
1.283 +//Adds the test data to test tables
1.284 +static void AddTestDataL(RDbNamedDatabase& aDb)
1.285 + {
1.286 + RDebug::Print(_L("Add data to test tables\n"));
1.287 + ::AddTestDataL(aDb, KTestTableName1);
1.288 + ::AddTestDataL(aDb, KTestTableName2);
1.289 + }
1.290 +
1.291 +//Init test environment
1.292 +static void InitEnvL()
1.293 + {
1.294 + ::CreateTestDbSession();
1.295 + //Create test database and tables. Add some test data to them.
1.296 + ::CreateTestDatabase(TheDbSession, TheDb);
1.297 + ::CreateTestTablesL(TheDb);
1.298 + ::AddTestDataL(TheDb);
1.299 + }
1.300 +
1.301 +//String comparison function, used in FillStrArraySorted() function.
1.302 +static TInt CompareC(const TNameBuf& aName1, const TNameBuf& aName2)
1.303 + {
1.304 + return aName1.CompareC(aName2);
1.305 + }
1.306 +
1.307 +//Inserts all test string into an ordered array - aTestStrArray
1.308 +static void FillStrArraySortedL(RArray<TNameBuf>& aTestStrArray)
1.309 + {
1.310 + for(TInt i=0;i<KTestStrCnt;++i)
1.311 + {
1.312 + User::LeaveIfError(aTestStrArray.InsertInOrder(KTestStr[i], TLinearOrder<TNameBuf>(CompareC)));
1.313 + }
1.314 + }
1.315 +
1.316 +static void CreateIndexL(RDbNamedDatabase& aDb, const TDesC& aTblName, const TDesC& aColumnName)
1.317 + {
1.318 + RDebug::Print(_L("Create index. Table: %S, column: %S\n"), &aTblName, &aColumnName);
1.319 + CDbKey* key = CDbKey::NewLC();
1.320 + key->AddL(aColumnName);
1.321 + key->MakeUnique();
1.322 + key->SetComparison(EDbCompareCollated);
1.323 + LEAVE_IF_ERROR(aDb.CreateIndex(aColumnName, aTblName, *key));
1.324 + CleanupStack::PopAndDestroy(key);
1.325 + }
1.326 +
1.327 +///////////////////////////////////////////////////////////////////////////////////////
1.328 +///////////////////////////////////////////////////////////////////////////////////////
1.329 +//Test cases
1.330 +
1.331 +//Test case 1. Check SELECT statement with ORDER BY clause when the key field is a string.
1.332 +static void OrderByTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
1.333 + {
1.334 + RDbView view;
1.335 + CleanupClosePushL(view);
1.336 +
1.337 + TBuf<128> sqlStmt;
1.338 + sqlStmt.Append(_L("SELECT ID, DATA FROM "));
1.339 + sqlStmt.Append(aTblName);
1.340 + sqlStmt.Append(_L(" ORDER BY ID"));
1.341 + User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited));
1.342 + User::LeaveIfError(view.EvaluateAll());
1.343 +
1.344 + (void)::PrintRecordsL(view, aTblName);
1.345 + AssertRecordsOrderL(view, aTblName, aTestStrArray);
1.346 +
1.347 + CleanupStack::PopAndDestroy(&view);
1.348 + }
1.349 +
1.350 +//Test case 2. Check SELECT statement with LIKE keyword when the key field is a string.
1.351 +static void LikeTestL(RDbNamedDatabase& aDb, const TDesC& aTblName)
1.352 + {
1.353 + RDbView view;
1.354 + CleanupClosePushL(view);
1.355 +
1.356 + TBuf<128> sqlStmt;
1.357 + sqlStmt.Append(_L("SELECT ID, DATA FROM "));
1.358 + sqlStmt.Append(aTblName);
1.359 + sqlStmt.Append(_L(" WHERE ID LIKE 'B*'"));
1.360 + User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited));
1.361 + User::LeaveIfError(view.EvaluateAll());
1.362 +
1.363 + TInt cnt = ::PrintRecordsL(view, aTblName);
1.364 + TEST(cnt == 2);
1.365 +
1.366 + CleanupStack::PopAndDestroy(&view);
1.367 + }
1.368 +
1.369 +//Test case 3. Check SELECT statement with LIKE & ORDER BY keywords when the key field is a string.
1.370 +static void LikeOrderTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
1.371 + {
1.372 + RDbView view;
1.373 + CleanupClosePushL(view);
1.374 +
1.375 + TBuf<128> sqlStmt;
1.376 + sqlStmt.Append(_L("SELECT ID, DATA FROM "));
1.377 + sqlStmt.Append(aTblName);
1.378 + sqlStmt.Append(_L(" WHERE ID LIKE 'B*' ORDER BY ID"));
1.379 + User::LeaveIfError(view.Prepare(aDb, TDbQuery(sqlStmt, EDbCompareCollated), TDbWindow::EUnlimited));
1.380 + User::LeaveIfError(view.EvaluateAll());
1.381 +
1.382 + TInt cnt = ::PrintRecordsL(view, aTblName);
1.383 + TEST(cnt == 2);
1.384 + AssertRecordsOrderL(view, aTblName, aTestStrArray);
1.385 +
1.386 + CleanupStack::PopAndDestroy(&view);
1.387 + }
1.388 +
1.389 +//Test case 4. Indexed table. The index is a string field.
1.390 +static void IndexTestL(RDbNamedDatabase& aDb, const TDesC& aTblName, const RArray<TNameBuf>& aTestStrArray)
1.391 + {
1.392 + _LIT(KIdxName, "ID");
1.393 + ::CreateIndexL(aDb, aTblName, KIdxName);
1.394 +
1.395 + RDbTable tbl;
1.396 + CleanupClosePushL(tbl);
1.397 + TEST2(tbl.Open(aDb, aTblName, RDbRowSet::EReadOnly), KErrNone);
1.398 + TEST2(tbl.SetIndex(KIdxName), KErrNone);
1.399 +
1.400 + (void)::PrintRecordsL(tbl, aTblName);
1.401 + AssertRecordsOrderL(tbl, aTblName, aTestStrArray);
1.402 +
1.403 + CleanupStack::PopAndDestroy(&tbl);
1.404 + }
1.405 +
1.406 +///////////////////////////////////////////////////////////////////////////////////////
1.407 +///////////////////////////////////////////////////////////////////////////////////////
1.408 +//The main test function.
1.409 +//Call your new test functions from here
1.410 +static void RunTestsL()
1.411 + {
1.412 + TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-LEGACY-DBMSSTRCOMP-0001 Init test environment "));
1.413 + ::InitEnvL();
1.414 +
1.415 + RArray<TNameBuf> testStrArray;
1.416 + CleanupClosePushL(testStrArray);
1.417 + ::FillStrArraySortedL(testStrArray);
1.418 +
1.419 + TheTest.Next(_L("SELECT, ORDER BY, EDbColText16"));
1.420 + ::OrderByTestL(TheDb, KTestTableName1, testStrArray);
1.421 +
1.422 + TheTest.Next(_L("SELECT, ORDER BY, EDbColLongText16"));
1.423 + ::OrderByTestL(TheDb, KTestTableName2, testStrArray);
1.424 +
1.425 + TheTest.Next(_L("SELECT, LIKE, EDbColText16"));
1.426 + ::LikeTestL(TheDb, KTestTableName1);
1.427 +
1.428 + TheTest.Next(_L("SELECT, LIKE, EDbColLongText16"));
1.429 + ::LikeTestL(TheDb, KTestTableName2);
1.430 +
1.431 + RArray<TNameBuf> testStrArray2;
1.432 + CleanupClosePushL(testStrArray2);
1.433 + testStrArray2.AppendL(testStrArray[2]);//"bbB"
1.434 + testStrArray2.AppendL(testStrArray[3]);//"BbB"
1.435 +
1.436 + TheTest.Next(_L("SELECT, LIKE, ORDER BY, EDbColText16"));
1.437 + ::LikeOrderTestL(TheDb, KTestTableName1, testStrArray2);
1.438 +
1.439 + TheTest.Next(_L("SELECT, LIKE, ORDER BY, EDbColLongText16"));
1.440 + ::LikeOrderTestL(TheDb, KTestTableName2, testStrArray2);
1.441 +
1.442 + TheTest.Next(_L("Index, EDbColText16"));
1.443 + ::IndexTestL(TheDb, KTestTableName1, testStrArray);
1.444 +
1.445 +// Not possible to create a key with EDbColLongText16
1.446 +// TheTest.Next(_L("Index, EDbColLongText16"));
1.447 +// ::IndexTestL(TheDb, KTestTableName2, testStrArray);
1.448 +
1.449 + //Add tests here!
1.450 +
1.451 + CleanupStack::PopAndDestroy(&testStrArray2);
1.452 + CleanupStack::PopAndDestroy(&testStrArray);
1.453 + }
1.454 +
1.455 +TInt E32Main()
1.456 + {
1.457 + TheTest.Title();
1.458 +
1.459 + __UHEAP_MARK;
1.460 +
1.461 + CTrapCleanup* trapCleanup = CTrapCleanup::New();
1.462 + TEST(trapCleanup != NULL);
1.463 +
1.464 + TInt err = TheFs.Connect();
1.465 + TEST2(err, KErrNone);
1.466 + ::SetupTestDirectory();
1.467 +
1.468 + ::DeleteDataFile(KTestDatabase);
1.469 +
1.470 + TRAP(err, ::RunTestsL());
1.471 + TheDb.Close();
1.472 + TheDbSession.Close();
1.473 + TheFs.Close();
1.474 + TEST2(err, KErrNone);
1.475 +
1.476 + ::DeleteDataFile(KTestDatabase);
1.477 +
1.478 + TheTest.End();
1.479 + TheTest.Close();
1.480 +
1.481 + delete trapCleanup;
1.482 +
1.483 + __UHEAP_MARKEND;
1.484 +
1.485 + return 0;
1.486 + }
1.487 +
1.488 +