plugins/contacts/symbian/contactsmodel/tsrc/cntplsql/src/t_cpplpredictivesearchtable.cpp
/*
* Copyright (c) 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: Unit test class for testing 12-key predictive search table
*
*/
// INTERNAL INCLUDES
#include "t_cpplpredictivesearchtable.h"
#include "pltables.h"
#include "dbsqlconstants.h"
#include "c12keykeymap.h"
#include "c12keypredictivesearchtable.h"
#include "cqwertypredictivesearchtable.h"
#include "cpredictivesearchsettingstable.h"
#include "cpredictivesearchsynchronizer.h"
#include "t_predictivesearchtabledefs.h"
#include "predictivesearchlog.h"
// SYSTEM INCLUDES
#include <digia/eunit/eunitmacros.h>
#include <f32file.h> // CFileMan
// Used to create HbKeymapFactory singleton to get rid of resource leak
#include <QLocale>
#include <hbinputkeymapfactory.h>
// Must have same value as KMaxTokenLength in c12keypredictivesearchtable.cpp
const TInt KMaxTokenLength = 15;
const TInt KTableCount = 12;
// Must have same value as KConversionError in cpplpredictivesearchtable.cpp
const quint64 KConversionError = 0xeeeeeeeeeeeeeee;
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::NewL
// -----------------------------------------------------------------------------
//
UT_CPplPredictiveSearchTable* UT_CPplPredictiveSearchTable::NewL()
{
UT_CPplPredictiveSearchTable* self = UT_CPplPredictiveSearchTable::NewLC();
CleanupStack::Pop( self );
return self;
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::NewLC
// -----------------------------------------------------------------------------
//
UT_CPplPredictiveSearchTable* UT_CPplPredictiveSearchTable::NewLC()
{
UT_CPplPredictiveSearchTable* self = new( ELeave ) UT_CPplPredictiveSearchTable();
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::~UT_CPplPredictiveSearchTable
// -----------------------------------------------------------------------------
//
UT_CPplPredictiveSearchTable::~UT_CPplPredictiveSearchTable()
{
delete iTable;
iTable = NULL;
iDB.Close(); // Must close DB before it can be deleted
RSqlDatabase::Delete(KDBFile);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_CPplPredictiveSearchTable
// -----------------------------------------------------------------------------
//
UT_CPplPredictiveSearchTable::UT_CPplPredictiveSearchTable()
{
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::ConstructL
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::ConstructL()
{
// The ConstructL from the base class CEUnitTestSuiteClass must be called.
// It generates the test case table.
CEUnitTestSuiteClass::ConstructL();
// Create singleton outside actual test cases so that it is not treated as
// resource leak, since it can't be deleted.
HbKeymapFactory::instance();
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::SetupL
// Must start with an empty DB file for each test case
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::SetupL()
{
// Ignore error
RSqlDatabase::Delete(KDBFile);
// If this causes KErrAlreadyExists, iDB won't be fully constructed
iDB.Create(KDBFile);
iTable = C12keyPredictiveSearchTable::NewL(iDB);
iPredSearchQwertyTable = CQwertyPredictiveSearchTable::NewL(iDB);
iPredSearchSettingsTable = CPredictiveSearchSettingsTable::NewL(iDB);
// Create (empty) predictive search tables to DB
iTable->CreateTableL();
iPredSearchQwertyTable->CreateTableL();
iPredSearchSettingsTable->CreateTableL();
iPredictiveSearchSynchronizer =
CPredictiveSearchSynchronizer::NewL(iDB,
*iTable,
*iPredSearchQwertyTable,
*iPredSearchSettingsTable);
HbKeymapFactory::instance();
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::SetupSyncL
// For synchronize tables test case
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::SetupSyncL()
{
UseSpecificDbL(KDBFileWithoutPredSearch);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::SetupSyncJust12keyExistsL
// For synchronize tables test case
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::SetupSyncJust12keyExistsL()
{
UseSpecificDbL(KDBFile12keyButNoQwerty);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::SetupLanguageChangesL
// For UT_LanguageChangesL case
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::SetupLanguageChangesL()
{
UseSpecificDbL(KDBFileOtherLanguage);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UseSpecificDbL
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UseSpecificDbL(const TDesC& aDbFile)
{
// Copy an existing DB file that does not contain predictive search tables
// to a DB file that will be used in test.
RFs fs;
User::LeaveIfError(fs.Connect());
CFileMan* fm = CFileMan::NewL(fs);
CleanupStack::PushL(fm);
User::LeaveIfError(fm->Copy(aDbFile, KDBFile));
CleanupStack::PopAndDestroy(fm);
fs.Close();
User::LeaveIfError(iDB.Open(KDBFile));
iTable = C12keyPredictiveSearchTable::NewL(iDB);
iPredSearchQwertyTable = CQwertyPredictiveSearchTable::NewL(iDB);
iPredSearchSettingsTable = CPredictiveSearchSettingsTable::NewL(iDB);
iPredictiveSearchSynchronizer =
CPredictiveSearchSynchronizer::NewL(iDB,
*iTable,
*iPredSearchQwertyTable,
*iPredSearchSettingsTable);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::Teardown
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::Teardown()
{
delete iPredictiveSearchSynchronizer;
iPredictiveSearchSynchronizer = NULL;
delete iTable;
iTable = NULL;
delete iPredSearchQwertyTable;
iPredSearchQwertyTable = NULL;
delete iPredSearchSettingsTable;
iPredSearchSettingsTable = NULL;
iDB.Close(); // Must close DB before it can be deleted
RSqlDatabase::Delete(KDBFile);
}
// TEST CASES
// Dummy case to see if the first case always results a resource leak (2 heap cells)
void UT_CPplPredictiveSearchTable::UT_DummyL()
{
// The first test case that writes to tables, seems to cause resource leak
// if the DB file did not have predictive search tables already.
AddContactL(KTestFirstName, KNullDesC, KTestContactId);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_CreateInDbLL
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_CreateInDbLL()
{
CheckItemCountL(); // all empty
AddContactL(KTestFirstName, KTestLastName, KTestContactId);
CheckItemCountL(0, 1, 0, 0, 1); // Tables 1 and 4 have one entry
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_CreateInDbManyContactsL
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_CreateInDbManyContactsL()
{
AddContactL(_L(" 1 22 333 4"), _L(" 505 6768"), KTestContactId);
// Only 4 tokens are stored: first two LN and first two FN.
CheckItemCountL(0, 1, 1, 0, 0, 1, 1);
AddContactL(_L(" 1 22 333 4"), _L("777 505 6768"), KTestContactId2);
// Adds contact to tables 1 2 7 5
CheckItemCountL(0, 2, 2, 0, 0, 2, 1, 1);
AddContactL(_L(" 1 22 333 4"), _L(" 5 6"), KTestContactId3);
// Adds contact to tables 1 2 5 6
CheckItemCountL(0, 3, 3, 0, 0, 3, 2, 1);
AddContactL(_L("858585"), _L("88"), KTestContactId4);
// Adds contact to table 8
CheckItemCountL(0, 3, 3, 0, 0, 3, 2, 1, 1);
TContactItemId id = KTestContactId4;
AddContactL(KNullDesC, KNullDesC, ++id);
// Contact is not added to any table
CheckItemCountL(0, 3, 3, 0, 0, 3, 2, 1, 1);
AddContactL(_L("1 1 1 1 1 1 1"), KNullDesC, ++id);
// Adds contact to table 1
CheckItemCountL(0, 4, 3, 0, 0, 3, 2, 1, 1);
AddContactL(KNullDesC, _L(" 22 22 2 2 222222"), ++id);
// Adds contact to table 2
CheckItemCountL(0, 4, 4, 0, 0, 3, 2, 1, 1);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_CreateInDbWithHashAndStarL
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_CreateInDbWithHashAndStarL()
{
AddContactL(_L(" # * +"), _L(" +*# **"), KTestContactId);
AddContactL(_L("*"), _L("+355"), KTestContactId2);
CheckItemCountL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_UpdateLL
// Update an existing contact
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_UpdateLL()
{
_LIT(KTestUpdatedName, "0581");
// Add one contact to DB
AddContactL(KTestFirstName, KTestLastName, KTestContactId);
// Update some field
TInt id = KUidContactCardValue;
TUid uid;
uid.iUid = id;
CContactItem* contact = CContactItem::NewLC(uid);
// Only first name is changed, but also the last name must be filled to
// CContactItemField.
CContactItemField* field =
CContactItemField::NewL(KStorageTypeText, KUidContactFieldGivenName);
field->TextStorage()->SetTextL(KTestUpdatedName);
contact->AddFieldL(*field); // Takes ownership
field = NULL;
field = CContactItemField::NewL(KStorageTypeText, KUidContactFieldFamilyName);
field->TextStorage()->SetTextL(KTestLastName);
contact->AddFieldL(*field); // Takes ownership
contact->SetId(KTestContactId);
iTable->UpdateL(*contact);
CleanupStack::PopAndDestroy(contact);
CheckItemCountL(1, 0, 0, 0, 1); // tables 0 and 4 have one entry
RArray<TInt32> results = DoPredictiveSearchL(KTestUpdatedName);
CleanupClosePushL(results);
EUNIT_ASSERT_EQUALS(1, results.Count());
EUNIT_ASSERT_EQUALS(KTestContactId, results[0]);
CleanupStack::PopAndDestroy(&results);
RArray<TInt32> results2 = DoPredictiveSearchL(KTestFirstName);
CleanupClosePushL(results2);
EUNIT_ASSERT_EQUALS(0, results.Count());
CleanupStack::PopAndDestroy(&results2);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_UpdateLBothFieldsL
// Update an existing contact
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_UpdateLBothFieldsL()
{
_LIT(KTestUpdatedFirstName, "777");
_LIT(KTestUpdatedLastName, "012345");
// Add some contacts
AddContactL(KTestFirstName, KTestLastName, KTestContactId);
AddContactL(_L("9876"), _L("888"), KTestContactId2);
AddContactL(_L("5050"), _L("2"), KTestContactId3);
CheckItemCountL(0, 1, 1, 0, 1, 1, 0, 0, 1, 1);
// Update FN and LN of second contact
TInt id = KUidContactCardValue;
TUid uid;
uid.iUid = id;
CContactItem* contact = CContactItem::NewLC(uid);
// Only first name is changed, but also the last name must be filled to
// CContactItemField.
CContactItemField* field =
CContactItemField::NewL(KStorageTypeText, KUidContactFieldGivenName);
field->TextStorage()->SetTextL(KTestUpdatedFirstName);
contact->AddFieldL(*field); // Takes ownership
field = NULL;
field = CContactItemField::NewL(KStorageTypeText, KUidContactFieldFamilyName);
field->TextStorage()->SetTextL(KTestUpdatedLastName);
contact->AddFieldL(*field); // Takes ownership
contact->SetId(KTestContactId2);
iTable->UpdateL(*contact);
CleanupStack::PopAndDestroy(contact);
CheckItemCountL(1, 1, 1, 0, 1, 1, 0, 1, 0, 0);
RArray<TInt32> results = DoPredictiveSearchL(KTestUpdatedFirstName);
CleanupClosePushL(results);
EUNIT_ASSERT_EQUALS(1, results.Count());
EUNIT_ASSERT_EQUALS(KTestContactId2, results[0]);
CleanupStack::PopAndDestroy(&results);
RArray<TInt32> results2 = DoPredictiveSearchL(KTestUpdatedLastName);
CleanupClosePushL(results2);
EUNIT_ASSERT_EQUALS(1, results2.Count());
EUNIT_ASSERT_EQUALS(KTestContactId2, results2[0]);
CleanupStack::PopAndDestroy(&results2);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_SearchL
// Search contacts from the table
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_SearchL()
{
// Create some contacts
AddContactL(_L("123704"), _L("39"), KTestContactId);
AddContactL(_L("908"), KNullDesC, KTestContactId2);
AddContactL(KNullDesC, _L("967"), KTestContactId3);
// Tables 0 and 2 are empty, since company name is not used
CheckItemCountL(0, 1, 0, 1, 0, 0, 0, 0, 0, 2);
// One contact matches
RArray<TContactItemId> results = DoPredictiveSearchL(_L("1"));
CleanupClosePushL(results);
EUNIT_ASSERT_EQUALS(1, results.Count());
EUNIT_ASSERT_EQUALS(KTestContactId, results[0]);
CleanupStack::PopAndDestroy(&results);
// No matches
RArray<TContactItemId> results2 = DoPredictiveSearchL(_L("124"));
CleanupClosePushL(results2);
EUNIT_ASSERT_EQUALS(0, results2.Count());
CleanupStack::PopAndDestroy(&results2);
// Two matches
RArray<TContactItemId> results3 = DoPredictiveSearchL(_L("9"));
CleanupClosePushL(results3);
EUNIT_ASSERT_EQUALS(2, results3.Count());
EUNIT_ASSERT_EQUALS(KTestContactId2, results3[0]);
EUNIT_ASSERT_EQUALS(KTestContactId3, results3[1]);
CleanupStack::PopAndDestroy(&results3);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_SearchWithSpacesL
// Search contacts having spaces from the table
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_SearchWithSpacesL()
{
// Create some contacts
// Goes to tables 8, 4 and 0
AddContactL(_L(" 8075 4702 380"), _L(" 470 038"), KTestContactId);
// Goes to tables 0 and 4
AddContactL(_L(" 0 00"), _L(" 470 038 38"), KTestContactId2);
// Goes to table 1 and 4
AddContactL(KNullDesC, _L(" 123 47 "), KTestContactId3);
CheckItemCountL(2, 1, 0, 0, 3, 0, 0, 0, 1, 0);
// No matches
RArray<TContactItemId> results = DoPredictiveSearchL(_L("2"));
TInt count = results.Count();
results.Close();
EUNIT_ASSERT_EQUALS(0, count);
RArray<TContactItemId> results2 = DoPredictiveSearchL(_L("07"));
count = results2.Count();
results2.Close();
EUNIT_ASSERT_EQUALS(0, count);
RArray<TContactItemId> results3 = DoPredictiveSearchL(_L("1230"));
count = results3.Count();
results3.Close();
EUNIT_ASSERT_EQUALS(0, count);
RArray<TContactItemId> results4 = DoPredictiveSearchL(_L("5047"));
count = results4.Count();
results4.Close();
EUNIT_ASSERT_EQUALS(0, count);
RArray<TContactItemId> results5 = DoPredictiveSearchL(_L("4700"));
count = results5.Count();
results5.Close();
EUNIT_ASSERT_EQUALS(0, count);
// One match
RArray<TContactItemId> results6 = DoPredictiveSearchL(_L("00"));
CleanupClosePushL(results6);
EUNIT_ASSERT_EQUALS(1, results6.Count());
EUNIT_ASSERT_EQUALS(KTestContactId2, results6[0]);
CleanupStack::PopAndDestroy(&results6);
RArray<TContactItemId> results7 = DoPredictiveSearchL(_L("4702"));
CleanupClosePushL(results7);
EUNIT_ASSERT_EQUALS(1, results7.Count());
EUNIT_ASSERT_EQUALS(KTestContactId, results7[0]);
CleanupStack::PopAndDestroy(&results7);
// Two matches
RArray<TContactItemId> results8 = DoPredictiveSearchL(_L("470"));
CleanupClosePushL(results8);
EUNIT_ASSERT_EQUALS(2, results8.Count());
EUNIT_ASSERT_EQUALS(KTestContactId, results8[0]);
EUNIT_ASSERT_EQUALS(KTestContactId2, results8[1]);
CleanupStack::PopAndDestroy(&results8);
RArray<TContactItemId> results9 = DoPredictiveSearchL(_L("0"));
CleanupClosePushL(results9);
EUNIT_ASSERT_EQUALS(2, results9.Count());
EUNIT_ASSERT_EQUALS(KTestContactId, results9[0]);
EUNIT_ASSERT_EQUALS(KTestContactId2, results9[1]);
CleanupStack::PopAndDestroy(&results9);
RArray<TContactItemId> results10 = DoPredictiveSearchL(_L("038"));
CleanupClosePushL(results10);
EUNIT_ASSERT_EQUALS(2, results10.Count());
EUNIT_ASSERT_EQUALS(KTestContactId, results10[0]);
EUNIT_ASSERT_EQUALS(KTestContactId2, results10[1]);
CleanupStack::PopAndDestroy(&results10);
// Three matches
RArray<TContactItemId> results11 = DoPredictiveSearchL(_L("47"));
CleanupClosePushL(results11);
EUNIT_ASSERT_EQUALS(3, results11.Count());
CleanupStack::PopAndDestroy(&results11);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_DeleteLL
// Delete a the only contact from the table
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_DeleteLL()
{
AddContactL(KTestFirstName, KTestLastName, KTestContactId);
CheckItemCountL(0, 1, 0, 0, 1, 0, 0, 0, 0, 0);
TInt id = KUidContactCardValue;
TUid uid;
uid.iUid = id;
CContactItem* contact = CContactItem::NewLC(uid);
contact->SetId(KTestContactId);
TBool lowDiskErrorOccurred(EFalse);
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
CheckItemCountL();
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_DeleteContactsL
// Delete contacts one-by-one from the table that has multiple contacts
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_DeleteContactsL()
{
_LIT(KTestFN, "7 8 ");
_LIT(KTestLN, " 4 56 1 ");
TContactItemId contactId = KTestContactId4 + 1;
// Goes to tables 1 and 4
AddContactL(KTestFirstName, KTestLastName, KTestContactId);
// Goes to tables 1 and 4
AddContactL(KTestFirstName, KTestLastName, KTestContactId2);
// Goes to table 4
AddContactL(KNullDesC, KTestLastName, KTestContactId3);
// This contact does not go into any table
AddContactL(KNullDesC, KNullDesC, KTestContactId4);
// Goes to tables 4, 5, 7 and 8
AddContactL(KTestFN, KTestLN, contactId);
CheckItemCountL(0, 2, 0, 0, 4, 1, 0, 1, 1, 0);
TInt id = KUidContactCardValue;
TUid uid;
uid.iUid = id;
CContactItem* contact = CContactItem::NewLC(uid);
contact->SetId(KTestContactId3);
TBool lowDiskErrorOccurred(EFalse);
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
contact = NULL;
// Contact was removed from table 1
CheckItemCountL(0, 2, 0, 0, 3, 1, 0, 1, 1, 0);
contact = CContactItem::NewLC(uid);
contact->SetId(KTestContactId4);
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
contact = NULL;
// This contact was not in any table in the first place, so no changes
CheckItemCountL(0, 2, 0, 0, 3, 1, 0, 1, 1, 0);
contact = CContactItem::NewLC(uid);
contact->SetId(KTestContactId);
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
contact = NULL;
// Contact was removed from tables 1 and 4
CheckItemCountL(0, 1, 0, 0, 2, 1, 0, 1, 1, 0);
contact = CContactItem::NewLC(uid);
contact->SetId(KTestContactId2);
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
contact = NULL;
// Contact was removed from tables 1 and 4
CheckItemCountL(0, 0, 0, 0, 1, 1, 0, 1, 1, 0);
contact = CContactItem::NewLC(uid);
contact->SetId(contactId);
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
CheckItemCountL(); // all empty
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_DeleteNonexistingContactL
// Try to delete a contact that does not existing in the table
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_DeleteNonexistingContactL()
{
AddContactL(KTestFirstName, KTestLastName, KTestContactId);
CheckItemCountL(0, 1, 0, 0, 1, 0, 0, 0, 0, 0);
TInt id = KUidContactCardValue;
TUid uid;
uid.iUid = id;
CContactItem* contact = CContactItem::NewLC(uid);
contact->SetId(KTestContactId2);
TBool lowDiskErrorOccurred(EFalse);
// Note: DeleteL does not leave if the contact could not be deleted
iTable->DeleteL(*contact, lowDiskErrorOccurred);
CleanupStack::PopAndDestroy(contact);
CheckItemCountL(0, 1, 0, 0, 1, 0, 0, 0, 0, 0);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_CheckIfTableExistsL
// Predictive search table does not exist in the database.
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_CheckIfTableExistsL()
{
// Delete DB that was created in setup()
iDB.Close(); // Must close DB before it can be deleted
RSqlDatabase::Delete(KDBFile);
// Create DB, but do not create pred search table in it
iDB.Create(KDBFile);
EUNIT_ASSERT_EQUALS(EFalse,
iPredictiveSearchSynchronizer->CheckIfPredSearchTableExistsL(KSqlContactPredSearchTable0));
iDB.Close(); // Must close DB before it can be deleted
RSqlDatabase::Delete(KDBFile);
}
// -----------------------------------------------------------------------------
// UT_CPplPredictiveSearchTable::UT_CheckIfTableExists2L
// Predictive search table exists in the database.
// -----------------------------------------------------------------------------
//
void UT_CPplPredictiveSearchTable::UT_CheckIfTableExists2L()
{
EUNIT_ASSERT_EQUALS(ETrue,
iPredictiveSearchSynchronizer->CheckIfPredSearchTableExistsL(KSqlContactPredSearchTable0));
}
// IMPORTANT NOTE:
// If this case fails or a resource leak is reported on it, make sure
// KDBFileWithoutPredSearch file exists, and it does not contain the predictive
// search tables!
// If Orbit keymap is used, this test case leaks resources,
// otherwise it does not leak.
void UT_CPplPredictiveSearchTable::UT_SynchronizeTableL()
{
iPredictiveSearchSynchronizer->SynchronizeTablesL();
}
void UT_CPplPredictiveSearchTable::UT_SynchronizeTableJust12keyExistsL()
{
iPredictiveSearchSynchronizer->SynchronizeTablesL();
}
void UT_CPplPredictiveSearchTable::UT_DeleteTablesL()
{
// Delete tables
iPredictiveSearchSynchronizer->DeletePredSearchTablesL();
// Check tables have been deleted
EUNIT_ASSERT_EQUALS(EFalse,
iPredictiveSearchSynchronizer->CheckIfPredSearchTableExistsL(KSqlContactPredSearchTable0));
// Try to delete tables when they do not exist
iPredictiveSearchSynchronizer->DeletePredSearchTablesL();
}
void UT_CPplPredictiveSearchTable::UT_LanguageChangesL()
{
iPredictiveSearchSynchronizer->SynchronizeTablesL();
}
void UT_CPplPredictiveSearchTable::UT_TokenizeNamesL()
{
_LIT(KFirstNames, "99 12345 234567 987 99");
_LIT(KLastNames, "12355 987 402");
HBufC* fn = KFirstNames().AllocLC();
HBufC* ln = KLastNames().AllocLC();
QStringList emptyList;
// This constant must have same value as declared in cpplpredictivesearchtable.cpp
const TInt KMaxTokens = 4;
QStringList tokens = iTable->GetTokens(emptyList, fn, ln);
EUNIT_ASSERT_EQUALS(KMaxTokens, tokens.count());
tokens.clear();
tokens = iTable->GetTokens(emptyList, NULL, ln);
EUNIT_ASSERT_EQUALS(3, tokens.count());
tokens.clear();
tokens = iTable->GetTokens(emptyList, fn, NULL);
EUNIT_ASSERT_EQUALS(4, tokens.count());
tokens.clear();
tokens = iTable->GetTokens(emptyList, NULL, NULL);
EUNIT_ASSERT_EQUALS(0, tokens.count());
tokens.clear();
QStringList mailList;
mailList << "mail.addr1";
mailList << "mail.addr2";
tokens = iTable->GetTokens(mailList, NULL, NULL);
EUNIT_ASSERT_EQUALS(2, tokens.count());
tokens.clear();
tokens = iTable->GetTokens(mailList, fn, ln);
EUNIT_ASSERT_EQUALS(4, tokens.count());
tokens.clear();
CleanupStack::PopAndDestroy(ln);
CleanupStack::PopAndDestroy(fn);
}
// Write contacts with and without FN & LN.
void UT_CPplPredictiveSearchTable::UT_WriteToDbL()
{
const TContactItemId KTestContactId5 = 1024;
const TContactItemId KTestContactId6 = 1025;
// Just FN
AddContactL(KTestFirstName, KNullDesC, KTestContactId);
// Just LN
AddContactL(KNullDesC, KTestLastName, KTestContactId2);
// Both FN and LN
AddContactL(KTestFirstName, KTestLastName, KTestContactId3);
// Neither FN and LN
AddContactL(KNullDesC, KNullDesC, KTestContactId4);
// Long names
_LIT(KTooLongName, "abcdefghijklmnopqrstuwvxyz aabbccddeeffgghhiijjkkllmm");
AddContactL(KTooLongName, KTestLastName, KTestContactId5);
AddContactL(KTestFirstName, KTooLongName, KTestContactId6);
}
void UT_CPplPredictiveSearchTable::UT_ConvertToHexL()
{
// Basic case
EUNIT_ASSERT_EQUALS(0x4458fffffffffff, iTable->ConvertToHex("4458"));
// Long digit
EUNIT_ASSERT_EQUALS(0x123456789012345, iTable->ConvertToHex("123456789012345"));
// Trailing zeros
EUNIT_ASSERT_EQUALS(0x12345678900ffff, iTable->ConvertToHex("12345678900"));
// Leading zeros
EUNIT_ASSERT_EQUALS(0x00123456789ffff, iTable->ConvertToHex("00123456789"));
// Just zeros
EUNIT_ASSERT_EQUALS(0x00000ffffffffff, iTable->ConvertToHex("00000"));
EUNIT_ASSERT_EQUALS(0x00000000000000f, iTable->ConvertToHex("00000000000000"));
EUNIT_ASSERT_EQUALS(0x000000000000000, iTable->ConvertToHex("000000000000000"));
EUNIT_ASSERT_EQUALS(0x0ffffffffffffff, iTable->ConvertToHex("0"));
// Zeros in the middle
EUNIT_ASSERT_EQUALS(0x12300450008000f, iTable->ConvertToHex("12300450008000"));
// Empty string
EUNIT_ASSERT_EQUALS(0xfffffffffffffff, iTable->ConvertToHex(""));
// Unmapped characters
EUNIT_ASSERT_EQUALS(0x123ffffffffffff, iTable->ConvertToHex("123??45??67"));
EUNIT_ASSERT_EQUALS(0x00fffffffffffff, iTable->ConvertToHex("00?1234567"));
EUNIT_ASSERT_EQUALS(0xfffffffffffffff, iTable->ConvertToHex("?1234567"));
EUNIT_ASSERT_EQUALS(0xfffffffffffffff, iTable->ConvertToHex("???"));
// Too many digits
EUNIT_ASSERT_EQUALS(KConversionError, iTable->ConvertToHex("12345678901234567890"));
}
void UT_CPplPredictiveSearchTable::AddContactL(const TDesC& aFirstName,
const TDesC& aLastName,
TContactItemId aContactId)
{
TInt id = KUidContactCardValue; // Defined by macro, so lacks type
TUid uid;
uid.iUid = id;
CContactItem* contact = CContactItem::NewLC(uid);
// Fill contact fields before writing to DB
if (aFirstName.Length() > 0)
{
CContactItemField* field =
CContactItemField::NewL(KStorageTypeText, KUidContactFieldGivenName);
CContactTextField* textfield = field->TextStorage();
CleanupStack::PushL(field);
textfield->SetTextL(aFirstName);
contact->AddFieldL(*field); // Takes ownership
CleanupStack::Pop(field);
}
if (aLastName.Length() > 0)
{
CContactItemField* field =
CContactItemField::NewL(KStorageTypeText, KUidContactFieldFamilyName);
CleanupStack::PushL(field);
field->TextStorage()->SetTextL(aLastName);
contact->AddFieldL(*field); // Takes ownership
CleanupStack::Pop(field);
}
contact->SetId(aContactId);
iTable->CreateInDbL(*contact);
CleanupStack::PopAndDestroy(contact);
}
void UT_CPplPredictiveSearchTable::CheckItemCountL(
TInt aCountInTable0,
TInt aCountInTable1,
TInt aCountInTable2,
TInt aCountInTable3,
TInt aCountInTable4,
TInt aCountInTable5,
TInt aCountInTable6,
TInt aCountInTable7,
TInt aCountInTable8,
TInt aCountInTable9,
TInt aCountInTable10,
TInt aCountInTable11)
{
TPtrC tableNames[KTableCount] =
{
KSqlContactPredSearchTable0,
KSqlContactPredSearchTable1,
KSqlContactPredSearchTable2,
KSqlContactPredSearchTable3,
KSqlContactPredSearchTable4,
KSqlContactPredSearchTable5,
KSqlContactPredSearchTable6,
KSqlContactPredSearchTable7,
KSqlContactPredSearchTable8,
KSqlContactPredSearchTable9,
KSqlContactPredSearchTable10,
KSqlContactPredSearchTable11
};
TInt rowCounts[KTableCount] = {0};
for (TInt i = 0; i < KTableCount; ++i)
{
HBufC* s = HBufC::NewLC(KCountSelect().Length() +
// Enough space for longest table name
KSqlContactPredSearchTable11().Length());
TPtr ptr = s->Des();
ptr.Format(KCountSelect, &tableNames[i]);
TSqlScalarFullSelectQuery scalarQuery(iDB);
rowCounts[i] = scalarQuery.SelectIntL(ptr);
CleanupStack::PopAndDestroy(s);
}
EUNIT_ASSERT_EQUALS(aCountInTable0, rowCounts[0]);
EUNIT_ASSERT_EQUALS(aCountInTable1, rowCounts[1]);
EUNIT_ASSERT_EQUALS(aCountInTable2, rowCounts[2]);
EUNIT_ASSERT_EQUALS(aCountInTable3, rowCounts[3]);
EUNIT_ASSERT_EQUALS(aCountInTable4, rowCounts[4]);
EUNIT_ASSERT_EQUALS(aCountInTable5, rowCounts[5]);
EUNIT_ASSERT_EQUALS(aCountInTable6, rowCounts[6]);
EUNIT_ASSERT_EQUALS(aCountInTable7, rowCounts[7]);
EUNIT_ASSERT_EQUALS(aCountInTable8, rowCounts[8]);
EUNIT_ASSERT_EQUALS(aCountInTable9, rowCounts[9]);
EUNIT_ASSERT_EQUALS(aCountInTable10, rowCounts[10]);
EUNIT_ASSERT_EQUALS(aCountInTable11, rowCounts[11]);
}
// There is only need to search from one table (unless search string begins
// with a zero).
// E.g. if search string is "102", the results are both in tables 1 and 2
// and it does not matter to which one the search is made.
// E.g. "0102", search from table 0 (for exact match "0102",and from
// table 1 or 2 (for something that begins with 1 and 2)
RArray<TContactItemId>
UT_CPplPredictiveSearchTable::DoPredictiveSearchL(const TDesC& aSearchString)
{
RArray<TContactItemId> foundContactIds;
if (aSearchString.Length() == 0)
{
return foundContactIds;
}
const TPtrC& tableName = DetermineTableName(aSearchString);
HBufC* select(NULL);
if (aSearchString.Length() == 1)
{
// No need to use "WHERE.." or "ORDER BY first_name ASC"
_LIT(KSearchOneDigitFormat, "SELECT contact_id FROM %S");
select = HBufC::NewLC(KSearchOneDigitFormat().Length() +
KSqlContactPredSearchTable11().Length());
select->Des().AppendFormat(KSearchOneDigitFormat, &tableName);
}
else
{
// This does not yet support zero in the middle
TInt64 lowerLimit = LowerLimitL(aSearchString) - 1;
TInt64 upperLimit = UpperLimitL(aSearchString) + 1;
// Write limits as decimal numbers
_LIT(KSearchFormat, "SELECT contact_id FROM %S WHERE \
(nbr>%ld AND nbr<%ld) OR (nbr2>%ld AND nbr2<%ld) OR (nbr3>%ld AND nbr3<%ld) OR (nbr4>%ld AND nbr4<%ld);");
TInt KNbrColumns = 4;
TInt KSpaceForLimits = KNbrColumns * 2 * (KMaxTokenLength + 2); // Two extra for decimal representation of max 15 hex digits
select = HBufC::NewLC(KSearchFormat().Length() +
KSqlContactPredSearchTable11().Length() +
KSpaceForLimits);
select->Des().AppendFormat(KSearchFormat, &tableName,
lowerLimit, upperLimit,
lowerLimit, upperLimit,
lowerLimit, upperLimit,
lowerLimit, upperLimit);
}
RSqlStatement stmnt;
CleanupClosePushL(stmnt);
stmnt.PrepareL(iDB, *select);
// Fetch the list of any matching contact ids
const TInt KContactIdIndex(0);
TInt err(KErrNone);
while ((err = stmnt.Next()) == KSqlAtRow)
{
foundContactIds.AppendL(stmnt.ColumnInt(KContactIdIndex));
}
if (err != KSqlAtEnd)
{
User::Leave(err);
}
CleanupStack::PopAndDestroy(&stmnt);
CleanupStack::PopAndDestroy(select);
return foundContactIds;
}
const TDesC& UT_CPplPredictiveSearchTable::DetermineTableName(
const TDesC& aSearchString)
{
switch (aSearchString[0])
{
case '0':
return KSqlContactPredSearchTable0;
case '1':
return KSqlContactPredSearchTable1;
case '2':
return KSqlContactPredSearchTable2;
case '3':
return KSqlContactPredSearchTable3;
case '4':
return KSqlContactPredSearchTable4;
case '5':
return KSqlContactPredSearchTable5;
case '6':
return KSqlContactPredSearchTable6;
case '7':
return KSqlContactPredSearchTable7;
case '8':
return KSqlContactPredSearchTable8;
case '9':
return KSqlContactPredSearchTable9;
case 'a':
return KSqlContactPredSearchTable10;
case 'b':
return KSqlContactPredSearchTable11;
default:
return KNullDesC;
}
}
TInt64 UT_CPplPredictiveSearchTable::LowerLimitL(const TDesC& aString) const
{
return ConvertToNbrL(aString, '0');
}
TInt64 UT_CPplPredictiveSearchTable::UpperLimitL(const TDesC& aString) const
{
return ConvertToNbrL(aString, 'f');
}
TInt64 UT_CPplPredictiveSearchTable::ConvertToNbrL(const TDesC& aString,
TChar aPadChar) const
{
HBufC* nbrBuffer = HBufC::NewLC(KMaxTokenLength);
TPtrC p = aString.Left(KMaxTokenLength);
TPtr nbrPtr = nbrBuffer->Des();
nbrPtr.Append(p);
// Append pad chars until length is KMaxTokenLength
while (nbrPtr.Length() < KMaxTokenLength)
{
nbrPtr.Append(aPadChar);
}
// RDebug::Print(_L("UT_CPplPredictiveSearchTable::ConvertToNbrL padded '%S'"), nbrBuffer);
TLex16 lex(*nbrBuffer);
TInt64 nbrValue(0);
User::LeaveIfError(lex.Val(nbrValue, EHex));
CleanupStack::PopAndDestroy(nbrBuffer);
// RDebug::Print(_L("UT_CPplPredictiveSearchTable::ConvertToNbrL result 0x%lx"), nbrValue);
return nbrValue;
}
// TEST TABLE
EUNIT_BEGIN_TEST_TABLE(
UT_CPplPredictiveSearchTable,
"UT_CPplPredictiveSearchTable",
"UNIT" )
EUNIT_TEST(
"CreateInDbL - dummy case to check resource leak",
"UT_CPplPredictiveSearchTable",
"",
"FUNCTIONALITY",
SetupL, UT_DummyL, Teardown )
EUNIT_TEST(
"CreateInDbL - test",
"UT_CPplPredictiveSearchTable",
"CreateInDbL",
"FUNCTIONALITY",
SetupL, UT_CreateInDbLL, Teardown )
EUNIT_TEST(
"CreateInDbL - test add many contacts",
"UT_CPplPredictiveSearchTable",
"CreateInDbL",
"FUNCTIONALITY",
SetupL, UT_CreateInDbManyContactsL, Teardown )
EUNIT_TEST(
"CreateInDbL - test contacts with *,+,# characters",
"UT_CPplPredictiveSearchTable",
"CreateInDbL",
"FUNCTIONALITY",
SetupL, UT_CreateInDbWithHashAndStarL, Teardown )
EUNIT_TEST(
"UpdateL - test updating FN",
"UT_CPplPredictiveSearchTable",
"UpdateL",
"FUNCTIONALITY",
SetupL, UT_UpdateLL, Teardown )
EUNIT_TEST(
"UpdateL - test updating FN and LN",
"UT_CPplPredictiveSearchTable",
"UpdateL",
"FUNCTIONALITY",
SetupL, UT_UpdateLBothFieldsL, Teardown )
EUNIT_TEST(
"Search - test",
"UT_CPplPredictiveSearchTable",
"predictive search",
"FUNCTIONALITY",
SetupL, UT_SearchL, Teardown )
EUNIT_TEST(
"Search with spaces - test",
"UT_CPplPredictiveSearchTable",
"predictive search",
"FUNCTIONALITY",
SetupL, UT_SearchWithSpacesL, Teardown )
EUNIT_TEST(
"Delete the only contact - test",
"UT_CPplPredictiveSearchTable",
"DeleteL",
"FUNCTIONALITY",
SetupL, UT_DeleteLL, Teardown )
EUNIT_TEST(
"Delete many contacts - test",
"UT_CPplPredictiveSearchTable",
"DeleteL",
"FUNCTIONALITY",
SetupL, UT_DeleteContactsL, Teardown )
EUNIT_TEST(
"Delete non-existing contact - test",
"UT_CPplPredictiveSearchTable",
"DeleteL",
"FUNCTIONALITY",
SetupL, UT_DeleteNonexistingContactL, Teardown )
EUNIT_TEST(
"Check if predictive search table exists (table does not exist)",
"UT_CPplPredictiveSearchTable",
"DoesPredSearchTableExistL",
"FUNCTIONALITY",
SetupL, UT_CheckIfTableExistsL, Teardown )
EUNIT_TEST(
"Check if predictive search table exists (table exists)",
"UT_CPplPredictiveSearchTable",
"DoesPredSearchTableExistL",
"FUNCTIONALITY",
SetupL, UT_CheckIfTableExists2L, Teardown )
EUNIT_TEST(
"Synchronize DB w/o pred.search tables",
"UT_CPplPredictiveSearchTable",
"CreatePredSearchTablesL",
"FUNCTIONALITY",
SetupSyncL, UT_SynchronizeTableL, Teardown )
EUNIT_TEST(
"Synchronize DB with 12-key, but w/o QWERTY tables",
"UT_CPplPredictiveSearchTable",
"CreatePredSearchTablesL",
"FUNCTIONALITY",
SetupSyncJust12keyExistsL, UT_SynchronizeTableJust12keyExistsL, Teardown )
EUNIT_TEST(
"Delete predictive search tables",
"UT_CPplPredictiveSearchTable",
"DeletePredSearchTablesL",
"FUNCTIONALITY",
SetupL, UT_DeleteTablesL, Teardown )
EUNIT_TEST(
"Language changes: re-create QWERTY tables",
"UT_CPplPredictiveSearchTable",
"DeletePredSearchTablesL",
"FUNCTIONALITY",
SetupLanguageChangesL, UT_LanguageChangesL, Teardown )
EUNIT_TEST(
"Tokenize names",
"UT_CPplPredictiveSearchTable",
"TokenizeNames",
"FUNCTIONALITY",
SetupL, UT_TokenizeNamesL, Teardown )
EUNIT_TEST(
"Write to table",
"UT_CPplPredictiveSearchTable",
"WriteToDbL",
"FUNCTIONALITY",
SetupL, UT_WriteToDbL, Teardown )
EUNIT_TEST(
"ConvertToHexL",
"UT_CPplPredictiveSearchTable",
"ConvertToHexL",
"FUNCTIONALITY",
SetupL, UT_ConvertToHexL, Teardown )
EUNIT_END_TEST_TABLE
// END OF FILE