// Copyright (c) 2006-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:
// It would have been nice to create a new object every time we jump to
// a new config block but reporting (INFO_PRINTF and ERR_PRINTF) doesn't
// work from sub-objects. All in all the structure isn't what I'd like,
// perhaps I'm missing some TEF functionality which would get around this.
// Various bits of repetition may be removed into utility class(es).
// Some utility methods probably should go into utility class(es).
// Unimplemented 8-bit methods, e.g Exec8.
//
//
#include "sqlfn.h"
#include "Te_SQL_SuiteDefs.h"
#include "common.h"
// Contains code to perform functions on SQLite databases - what functions
// and in what order is determined by the content of the config (.ini) file.
CSQLFnStep::~CSQLFnStep()
/**
* Destructor
*/
{
// Get rid of the RFs object.. Note this isn't set up in the constructor
// but in doTestStepL.
irfs.Close();
// Get rid of the semaphore objects.
isemA.Close();
isemB.Close();
// Get rid of the hashes. These are originally set up in doTestStepL.
delete ierrhsh;
delete icoltypehsh;
delete iactionhsh;
delete icaphsh;
delete ipolhsh;
delete iobjhsh;
// Get rid of the config item.
if(icfg)delete icfg;
}
CSQLFnStep::CSQLFnStep()
{
// Create a global semaphore to be used by all instances of this framework
// to be used for synchronising separate threads when 'CONCURRENT' is
// used. If it already exists, then perhaps another thread already has it
// which is fine - in that case just open it.
TInt err = isemA.CreateGlobal(_L("SQLiteSemA"), 0);
if(err == KErrAlreadyExists)
{
err = isemA.OpenGlobal(_L("SQLiteSemA"));
}
if(err != KErrNone)
{
INFO_PRINTF2(_L("Error %d creating semaphore"), err);
__ASSERT_ALWAYS(err == KErrNone, User::Invariant());
}
//
// Second semaphore require for DEF140385.
//
err = isemB.CreateGlobal(_L("SQLiteSemB"), 0);
if(err == KErrAlreadyExists)
{
err = isemB.OpenGlobal(_L("SQLiteSemB"));
}
if(err != KErrNone)
{
INFO_PRINTF2(_L("Error %d creating semaphoreB"), err);
__ASSERT_ALWAYS(err == KErrNone, User::Invariant());
}
}
TVerdict CSQLFnStep::doTestPostambleL()
{
// Try to make sure that the database and statement resources have been
// properly closed (in case of problems).
isqlst.Close();
isqldb.Close();
return TestStepResult();
}
TVerdict CSQLFnStep::doTestStepL()
/**
* @return - TVerdict code
* Override of base class pure virtual. Our implementation only gets called
* if the base class doTestStepPreambleL() did not leave. That being the case,
* the current test result value will be EPass.
*/
{
// Create the RFs object so we can talk to the file-system when necessary.
// Moved from the constructor to shut up leavescan.
User::LeaveIfError(irfs.Connect());
irfs.ShareProtected();
// Make sure the database and statement objects get cleaned up..
CleanupClosePushL(isqldb);
CleanupClosePushL(isqlst);
// Make sure that the icfg member is definitely unset when we start.
icfg = NULL;
// Get the hashes we use to associate words with numbers (e.g
// KErrNone with 0). If these fail due to lack of memory they will
// PANIC, which is fine. If we're that short of memory nothing is
// going to work anyway.
ierrhsh = new CSQLErrHash();
icoltypehsh = new CSQLColTypeHash();
iactionhsh = new CSQLTEFAction();
icaphsh = new CSQLCapability();
ipolhsh = new CSQLPolicy();
iobjhsh = new CSQLObject();
// Set the test result to PASS to start with and call the main block..
SetTestStepResult(EPass);
SQLDbStepL(ConfigSection());
// Clean up the database and statement objects.
CleanupStack::PopAndDestroy(2, &isqldb);
return TestStepResult();
}
// This is our 'main' function. It works out what method (e.g RSqlStatement::
// Close) the user wants (based on the configuration file) and then calls
// the appropriate wrapper function which runs the wanted method and reports
// on any unexpected errors.
void CSQLFnStep::SQLDbStepL(const TPtrC& acfgblk)
{
_LIT(KTestFunction, "SQLDbStep");
/*
* Go through all of the actions defined in the configuration file
* acting on each. The counter will keep incrementing until we
* fail to find a config item called 'CreateNN', or 'OpenNN' etc.
* The two arrays hold Parameter and Column indices for use in
* any method that needs one. E.G..
*/
TInt ended=0;
iasync = i8bit = EFalse;
for(TInt count=0 ; ; count++)
{
TPtrC argument;
TInt whatfun=Efn_undefined;
for(TInt i=0 ; i < Efn_undefined ; i++)
{
// Construct something like 'ColumnInt37'
TBuf<KStatementFunMaxLength> stfn(*(iactionhsh->GetStringFromNum(i)));
stfn.AppendNum(count);
// Does it exist in the config file? If not try e.g 'ColumnReal37'
if(!GetStringFromConfig(acfgblk, stfn, argument))
continue;
whatfun = i;
if(whatfun == Ectrl_endblock)
ended = 1;
// The GetString was successful, so we drop out anyway.
break;
}
// If we hit an EndBlock marker or couldn't find any keyword with
// the current counter number then drop out.
if((whatfun == Efn_undefined) || (whatfun == Ectrl_endblock))
break;
// If there's a comma in the argument, split it up. We do
// this here (rather than, more logically, in the called methods)
// because we'd end up repeating the 'CommaSeparated' call in
// all of the wrapper methods. Also, we need the indices for
// Column and Parameter index resolution.
TInt arg1, arg2;
TPtrC arg3;
CommaSeparated(argument, arg1, arg2);
CommaSeparated(argument, arg1, arg3);
TInt err=0;
switch(whatfun)
{
case Efn_nop: break;
// First the RSqlDatabase methods...
case Efn_create:
Create(argument, acfgblk, count);
break;
case Efn_createl:
CreateL_(argument, acfgblk, count);
break;
case Efn_createsp:
CreateSP(argument, acfgblk, count);
break;
case Efn_open:
Open(argument, acfgblk, count);
break;
case Efn_openl:
OpenL_(argument, acfgblk, count);
break;
case Efn_attach:
Attach(argument, acfgblk, count);
break;
case Efn_detach:
Detach(argument, acfgblk, count);
break;
case Efn_copy:
Copy(argument, acfgblk, count);
break;
case Efn_close:
Close();
break;
case Efn_delete:
Delete(argument, acfgblk, count);
break;
case Efn_lasterrormessage:
LastErrorMessage(argument);
break;
case Efn_exec:
Exec(argument, acfgblk, count);
break;
case Efn_setisolationlevel:
SetIsolationLevel(argument, acfgblk, count);
break;
case Efn_reservedrivespace:
ReserveDriveSpace(arg1, acfgblk, count);
break;
case Efn_freereservedspace:
FreeReservedSpace();
break;
case Efn_getreserveaccess:
GetReserveAccess(acfgblk, count);
break;
case Efn_releasereserveaccess:
ReleaseReserveAccess();
break;
// Now the RSqlStatement methods...
case Erstmt_prepare:
Prepare(argument, acfgblk, count);
break;
case Erstmt_preparel:
PrepareL_(argument, acfgblk, count);
break;
case Erstmt_close:
Close(1);
break;
case Erstmt_atrow:
AtRow(argument);
break;
case Erstmt_reset:
err = isqlst.Reset();
ReportOnError(KTestFunction, _L("Reset"), acfgblk,
count, err);
break;
case Erstmt_exec:
{
TBuf<KConfigItemMaxNameLength> apiname(_L("st_exec"));
if(!iasync)
err = isqlst.Exec();
else
{
TChar ch = 'A';
apiname.Append(ch);
TRequestStatus trs;
isqlst.Exec(trs);
User::WaitForRequest(trs);
err = trs.Int();
}
ReportOnError(KTestFunction, apiname,
acfgblk, count, err);
}
break;
case Erstmt_next:
Next(argument, acfgblk, count);
break;
case Erstmt_paramindex:
{
TInt pidx = ParamIndex(argument, acfgblk, count);
// The test designer will have to remember how many
// param indices have been stuck in this array..
if(pidx >= 0)ipidxs.Append(pidx);
}
break;
case Erstmt_colindex:
{
TInt cidx = ColumnIndex(argument, acfgblk, count);
// The test designer will have to remember how many
// column indices have been stuck in this array..
if(cidx >= 0)icidxs.Append(cidx);
}
break;
case Erstmt_coltype:
// ColumnType needs the ColumnIndex (the last arg)
// and also the expected result, which it will get from
// the config file. We have to deal with the ColumnIndex
// here because it lives in our scope, not that of the
// method we're calling..
// The test designer will have to remember how many
// column indices have been stuck in this array..
ColumnType(icidxs[arg1], arg3);
break;
case Erstmt_colsize:
ColumnSize(icidxs[arg1], arg2);
break;
case Erstmt_bindnull:
BindNull(ipidxs[arg1], acfgblk, count);
break;
case Erstmt_bindint:
BindInt(ipidxs[arg1], arg2, acfgblk, count);
break;
case Erstmt_bindint64:
BindInt64(ipidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_bindreal:
{
TLex tl = arg3;
TReal tr;
tl.Val(tr);
BindReal(ipidxs[arg1], tr, acfgblk, count);
}
break;
case Erstmt_bindtext:
BindText(ipidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_bindbigtext:
// Not an RSqlStatement method, but calls BindText
// after reading from a file.
BindBigTextL(ipidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_bindbinary:
BindBinaryL(ipidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_isnull:
IsNull(icidxs[arg1], arg3);
break;
case Erstmt_colint:
ColumnInt(icidxs[arg1], arg2);
break;
case Erstmt_colint64:
ColumnInt64(icidxs[arg1], arg3);
break;
case Erstmt_colreal:
{
TLex tl = arg3;
TReal tr2;
tl.Val(tr2);
ColumnReal(icidxs[arg1], tr2);
}
break;
case Erstmt_coltextL:
ColumnTextL(icidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_coltextP:
ColumnTextPL(icidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_coltextD:
ColumnTextDL(icidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_colbinL:
ColumnBinaryL(icidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_colbinP:
ColumnBinaryPL(icidxs[arg1], arg3, acfgblk, count);
break;
case Erstmt_colbinD:
ColumnBinaryDL(icidxs[arg1], arg3, acfgblk, count);
break;
case Esp_create:
SPCreate(acfgblk, count);
break;
case Esp_createl:
SPCreate(argument, acfgblk, count);
break;
case Esp_close:
SPClose();
break;
case Esp_setdbpolicy:
SPSetDBPolicy(argument, acfgblk, count);
break;
case Esp_setpolicy:
SPSetPolicy(argument, acfgblk, count);
break;
case Esp_externalizel:
SPExternalize(argument, acfgblk, count);
break;
case Esp_internalizel:
SPInternalize(argument, acfgblk, count);
break;
case Estreamwrite_bindtext:
SWBindTextL(ipidxs[arg1], arg3, acfgblk, count);
break;
case Estreamwrite_bindbinary:
SWBindBinaryL(ipidxs[arg1], arg3, acfgblk, count);
break;
case Estreamread_columntext:
SRColumnTextL(icidxs[arg1], arg3, acfgblk, count);
break;
case Estreamread_columnbinary:
SRColumnBinaryL(icidxs[arg1], arg3, acfgblk, count);
break;
case Edefineconfig:
{
if(icfg)
delete icfg;
TInt len = argument.Length();
if(len)
{
// At the time of writing, configuration strings
// are limited to 255 bytes.
TBuf8<256> arg;
arg.Copy(argument);
icfg = new TPtrC8(arg);
}
else
icfg = NULL;
}
break;
// Actions that aren't direct method calls..
case Ectrl_newblock:
// Continue executing from another configuration
// block. Obviously this restarts the step
// counter at zero. It's unfortunate that we can't
// create a new test object here, that would be
// so much neater. But logging doesn't work in
// sub-objects (it could be bodged around but it
// really would be a bodge). A shame, we could have
// lots of member vars holding all this junk we're
// passing around. Note that because we don't create
// a new object we are playing with the same
// RSqlDatabase and RSqlStatement objects.
SQLDbStepL(argument);
break;
case Ectrl_function:
// Pure virtual. Lives elsewhere..
ResolveTestFunctionL(acfgblk, count, argument);
break;
case Ectrl_waitA:
// Wait for the isem member semaphore to receive
// arg1 signals for this thread. Obviously this assumes
// there's another thread that's going to execute
// a 'Signal' at some point.
for(TInt ii=0 ; ii<arg1 ; ++ii)
{
WaitA();
}
break;
case Ectrl_waitB:
// Wait for the isemB member semaphore to receive
// arg1 signals for this thread. Obviously this assumes
// there's another thread that's going to execute
// a 'SignalB' at some point.
for(TInt ii=0 ; ii<arg1 ; ++ii)
{
WaitB();
}
break;
case Ectrl_signalA:
// E.G Signal37=6 to wake up six threads that are
// waiting on isem.
SignalA(arg1);
break;
case Ectrl_signalB:
// E.G SignalB37=6 to wake up six threads that are
// waiting on isemB..
SignalB(arg1);
break;
case Ectrl_sleep:
INFO_PRINTF2(_L("Sleeping for %d microseconds"), arg1);
User::After(arg1);
break;
case Ectrl_eightbit:
if((argument == _L("On")) || (argument == _L("True")))
i8bit = ETrue;
else
i8bit = EFalse;
break;
case Ectrl_async:
if((argument == _L("On")) || (argument == _L("True")))
iasync = ETrue;
else
iasync = EFalse;
break;
// Big problems if this stuff executes.
case Efn_undefined:
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF1(_L("This should never happen. A"));
INFO_PRINTF1(HTML_COLOUR_OFF);
break;
default:
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF1(_L("This should never happen. B"));
INFO_PRINTF1(HTML_COLOUR_OFF);
break;
}
// Let's get rid of any colour. Can get tangled in multi-threaded
// tests.
INFO_PRINTF1(HTML_COLOUR_OFF);
}
// If we get to this point and the 'ended' flag hasn't been set then
// we haven't seen an 'EndBlockNN=' line in the config file. That
// usually means the test has a missing <keyword><number> item
// which is a test failure.
if(!ended)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF2(_L("Put an 'EndBlock' marker at the end of all config blocks. This is intended to\nspot missing numbers (which cause the test to drop out) failing to generate a failure (%S)"), &acfgblk);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
}
// ----------Methods to exercise RSqlDatabase methods ------------------------
TBool CSQLFnStep::Create(const TPtrC& adbnm,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Create");
INFO_PRINTF3(_L("%S: Database name is %S "), &KTestFunction, &adbnm);
// Try to create the database.
TInt rc = isqldb.Create(adbnm, icfg);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
TBool CSQLFnStep::CreateL_(const TPtrC& adbnm,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "CreateL");
INFO_PRINTF3(_L("%S: Database name is %S "), &KTestFunction, &adbnm);
// Try to create the database. Trap any leave (we're actually duplicating
// what is in the non-leaving Create method, but hey, this is black box
// testing, we're not supposed to know that..)
TInt rc=KErrNone;
TRAP(rc, isqldb.CreateL(adbnm, icfg));
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
TBool CSQLFnStep::CreateSP(const TPtrC& adbnm, const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "CreateSP");
INFO_PRINTF3(_L("%S: Database name is %S "), &KTestFunction, &adbnm);
TInt rc = isqldb.Create(adbnm, isqlsp, icfg);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
TBool CSQLFnStep::Open(const TPtrC& adbnm,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Open");
INFO_PRINTF3(_L("%S: Database name is %S "), &KTestFunction, &adbnm);
// Try to open the database.
TInt rc = isqldb.Open(adbnm, icfg);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
TBool CSQLFnStep::OpenL_(const TPtrC& adbnm,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "OpenL");
INFO_PRINTF3(_L("%S: Database name is %S "), &KTestFunction, &adbnm);
// Try to open the database.
TInt rc = KErrNone;
TRAP(rc, isqldb.OpenL(adbnm, icfg));
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
// Close the current database.
void CSQLFnStep::Close()
{
// _LIT(KTestFunction, "Close");
isqldb.Close();
return;
}
void CSQLFnStep::Attach(const TPtrC &arg,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Attach");
TPtrC sqldb, sqldbname;
// Break arg into 'sqldb', the path/filename of the database to attach
// and sqldbname, the name by which the database will be referred to
// through this Attach.
CommaSeparated(arg, sqldb, sqldbname);
TInt rc = isqldb.Attach(sqldb, sqldbname);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
return;
}
void CSQLFnStep::Detach(const TPtrC &arg,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Detach");
TInt rc = isqldb.Detach(arg);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
return;
}
void CSQLFnStep::Copy(const TPtrC &arg,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Copy");
TPtrC sqldb1, sqldb2;
CommaSeparated(arg, sqldb1, sqldb2);
TInt rc = isqldb.Copy(sqldb1, sqldb2);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
return;
}
TBool CSQLFnStep::Delete(const TPtrC& adbnm,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Delete");
INFO_PRINTF3(_L("%S: Database name is %S "), &KTestFunction, &adbnm);
// Try to delete the database.
TInt rc = isqldb.Delete(adbnm);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
void CSQLFnStep::LastErrorMessage(const TPtrC& arg)
{
_LIT(KTestFunction, "LastErrorMessage");
TPtrC lem = isqldb.LastErrorMessage();
if(arg.Length() == 0)
{
INFO_PRINTF3(_L("%S: '%S'"), &KTestFunction, &lem);
return; // No particular error message was expected, so just return.
}
if(lem != arg)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: Expected Message '%S', got '%S'"), &KTestFunction,
&arg, &lem);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected Message '%S'"), &KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
void CSQLFnStep::Exec(const TPtrC& arg,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "Exec");
TBuf<KConfigItemMaxNameLength> apiname(KTestFunction);
TInt rc;
if(i8bit == EFalse)
{
if(!iasync)
rc = isqldb.Exec(arg);
else
{
TChar ch = 'A';
apiname.Append(ch);
TRequestStatus trs;
isqldb.Exec(arg, trs);
User::WaitForRequest(trs);
rc = trs.Int();
}
}
else
{
apiname.AppendNum(8);
RBuf8 b8;
b8.Create(arg.Length());
b8.Copy(arg);
if(!iasync)
rc = isqldb.Exec(b8);
else
{
TChar ch = 'A';
apiname.Append(ch);
TRequestStatus trs;
isqldb.Exec(b8, trs);
User::WaitForRequest(trs);
rc = trs.Int();
}
b8.Close();
}
ReportOnError(KTestFunction, apiname, acfgblk, acnnum, rc);
return;
}
void CSQLFnStep::SetIsolationLevel(const TPtrC& arg,
const TDesC &acfgblk, TInt acnnum)
{
_LIT(KTestFunction, "SetIsolationLevel");
// Get the expected error code..
TPtrC experrS;
TInt experr = ActionNoToErrEnum(acfgblk, acnnum, experrS);
INFO_PRINTF2(_L("SetIsolationLevel: %S"), &arg);
RSqlDatabase::TIsolationLevel sil;
if(arg == _L("EReadUncommitted"))
sil = RSqlDatabase::EReadUncommitted;
else if(arg == _L("EReadCommitted"))
sil = RSqlDatabase::EReadCommitted;
else if(arg == _L("ERepeatableRead"))
sil = RSqlDatabase::ERepeatableRead;
else if(arg == _L("ESerializable"))
sil = RSqlDatabase::ESerializable;
else
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Unrecognized TIsolationLevel '%S'"),
&KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
TInt rc = isqldb.SetIsolationLevel(sil);
TPtrC err;
ErrEnumToString(rc,err);
if(rc != experr)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("Unexpected SetIsolationLevel error %d/%S"), rc, &err);
TPtrC lem = isqldb.LastErrorMessage();
ERR_PRINTF2(_L(" - Last Error Message: %S"), &lem);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
else
INFO_PRINTF2(_L("SetIsolation level, got error %S as expected"), &err);
return;
}
void CSQLFnStep::ReserveDriveSpace(TInt ares,
const TDesC& acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "ReserveDriveSpace");
// Try to reserve space..
TInt rc = isqldb.ReserveDriveSpace(ares);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
return;
}
void CSQLFnStep::FreeReservedSpace()
{
// _LIT(KTestFunction, "FreeReservedSpace");
isqldb.FreeReservedSpace();
return;
}
void CSQLFnStep::GetReserveAccess(const TDesC& acfgblk,
const TInt acnnum)
{
_LIT(KTestFunction, "GetReserveAccess");
// Try to reserve space..
TInt rc = isqldb.GetReserveAccess();
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
return;
}
void CSQLFnStep::ReleaseReserveAccess()
{
// _LIT(KTestFunction, "ReleaseReserveSpace");
isqldb.ReleaseReserveAccess();
return;
}
// ----------Methods to exercise RSqlStatement methods ------------------------
//
// Execute a Close on the current RSqlStatement. This also clears out the
// arrays of RBufs and RBuf8s which are used for BindText and
// BindBinary (just a way of keeping the buffers in scope until the
// Exec/Close happens) and loses all of the ParameterIndex and ColumnIndex's.
// The 'TInt' argument is just to differentiate between the RSqlDatabase
// Close wrapper, and this RSqlStatement Close wrapper.
void CSQLFnStep::Close(TInt)
{
// _LIT(KTestFunction, "St_Close");
// Close the RSqlStatement.
isqlst.Close();
// Empty the arrays where we keep references to BindXXX buffers,
// closing those buffers as we go.
for(TInt count = iBindRBufarr.Count() - 1 ; count >= 0; count--)
{
iBindRBufarr[count].Close();
iBindRBufarr.Remove(count);
}
for(TInt count = iBindRBuf8arr.Count() - 1 ; count >= 0 ; count--)
{
iBindRBuf8arr[count].Close();
iBindRBuf8arr.Remove(count);
}
if((iBindRBuf8arr.Count() != 0) || (iBindRBufarr.Count() != 0))
{
User::Panic(_L("RBuf arrays not empty"), 512);
}
// Empty the ParameterIndex and ColumnIndex arrays.
while(ipidxs.Count()) ipidxs.Remove(0);
while(icidxs.Count()) icidxs.Remove(0);
return;
}
void CSQLFnStep::Next(TPtrC& arg,
const TDesC &acfgblk, TInt acnnum=-1)
{
_LIT(KTestFunction, "Next");
TInt rc = isqlst.Next();
// If arg is not zero length it will be KSqlAtEnd/KSqlAtRow, turn that
// into the enumeration.
if(arg.Length())
{
TInt expn = ErrStringToEnum(arg);
TPtrC errS;
ErrEnumToString(rc, errS); // Convert the actual rc to a string.
if(expn != rc)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF7(_L("%S/%S: Got %S/%d, expected %S/%d"), &KTestFunction,
&acfgblk, &errS, rc, &arg, expn );
INFO_PRINTF1(HTML_COLOUR_OFF);
}
}
ReportOnError(KTestFunction, _L("Next"), acfgblk, acnnum, rc);
return;
}
// Call the RSqlStatement method 'AtRow'. This returns a boolean. This
// method expects the config file to contain a line resembling
// 'AtRow57=false'. The return value is checked against the config
// value and error/info is reported.
void CSQLFnStep::AtRow(const TPtrC &arg)
{
_LIT(KTestFunction, "AtRow");
TBuf<8> atrres(arg);
atrres.LowerCase();
TBool expected = EFalse;
if(atrres == _L("false"))
expected = EFalse;
else if(atrres == _L("true"))
expected = ETrue;
else
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: expected config item to be true/false, got %S"),
&KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
TBool atr = isqlst.AtRow();
if(atr != expected)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: expected AtRow to return %S, got %d"),
&KTestFunction, &atrres, atr);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %S"), &KTestFunction, &atrres);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
// Call the RSqlStatement method 'Prepare'. This returns an int. This
// method expects the config file to contain a line resembling
// 'Prepare43=Create Table tbl3(f1 etc)'. The return value is checked
// against the expected error (in ReportOnError).
void CSQLFnStep::Prepare(const TPtrC &arg,
const TDesC &acfgblk, TInt acnnum=-1)
{
_LIT(KTestFunction, "Prepare");
INFO_PRINTF3(_L("%S: Prepare command is %S"), &KTestFunction, &arg);
TInt rc;
if(i8bit == EFalse)
rc = isqlst.Prepare(isqldb, arg);
else
{
RBuf8 b8;
b8.Create(arg.Length());
b8.Copy(arg);
rc = isqlst.Prepare(isqldb, b8);
b8.Close();
}
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
}
void CSQLFnStep::PrepareL_(const TPtrC &arg,
const TDesC &acfgblk, TInt acnnum=-1)
{
_LIT(KTestFunction, "PrepareL");
INFO_PRINTF3(_L("%S: PrepareL command is %S"), &KTestFunction, &arg);
TInt rc=KErrNone;
if(i8bit == EFalse)
{
TRAP(rc, isqlst.PrepareL(isqldb, arg));
}
else
{
RBuf8 b8;
b8.Create(arg.Length());
b8.Copy(arg);
TRAP(rc, isqlst.PrepareL(isqldb, b8));
b8.Close();
}
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
}
// Call the RSqlStatement method 'ParamIndex'. This returns an int. This
// method expects the config file to contain a line resembling
// 'ParamIndex12=:Frog'. The return value is returned.
TInt CSQLFnStep::ParamIndex(const TDesC &arg,
const TDesC &acfgblk, TInt acnnum=-1)
{
_LIT(KTestFunction, "ParameterIndex");
// If the test specifies ':?' was the parameter index, we'll assume that
// ':?' was given in the SELECT (a nameless parameter), this always gives
// '1' for the paramIndex.
if(arg == _L(":?"))
return 1;
// If arg resembles '23,*explicit*', then return the leading integer.
// This is so we can call BindEtc with bad values for PANIC testing
// or otherwise generate a specific parameter index.
TInt pidx=0;
TPtrC rhs;
CommaSeparated(arg, pidx, rhs);
if(rhs == _L("*explicit*"))
{
INFO_PRINTF3(_L("%S: Returning explicit Parameter Index %d"),
&KTestFunction, pidx);
return pidx;
}
// Ok, run ParameterIndex.
pidx = isqlst.ParameterIndex(arg);
// ParameterIndex returns a non-negative integer on success. If the
// return is negative, we have a problem. We cannot know what the
// return is if the operation has succeeded, so checking the error
// code is limited to required errors, i.e < 0.
// ReportOnError will set test result to failure if the error doesn't
// match our expected error.
if(pidx < 0)
ReportOnError(KTestFunction, _L("ParameterIndex"),
acfgblk, acnnum, pidx);
return pidx;
}
// Call the RSqlStatement method 'ColumnIndex'. This returns an int. This
// method expects the config file to contain a line resembling
// 'ColumnIndex12=Fld3'. The return value is returned.
TInt CSQLFnStep::ColumnIndex(const TPtrC& arg,
const TDesC &acfgblk, TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnIndex");
// If no column is specified then return zero - this may be necessary
// if the test is for example counting lines in a table ...
// >select count(*) from mytbl;
// In this case obviously there is no namable column, but the Api just
// requires that the index for ColumnInt will be zero.
if(arg.Length() == 0) return 0;
// If arg resembles '23,*explicit*', then return the leading integer.
// This is so we can call ColumnEtc with bad values for PANIC testing
// or otherwise generate a specific parameter index.
TInt colIndex=0;
TPtrC rhs;
CommaSeparated(arg, colIndex, rhs);
if(rhs == _L("*explicit*"))
{
INFO_PRINTF3(_L("%S: Returning explicit Column Index %d"),
&KTestFunction, colIndex);
return colIndex;
}
colIndex = isqlst.ColumnIndex(arg);
// ColumnIndex returns a non-negative integer on success. If the
// return is negative, we have a problem. We cannot know what the
// return is if the operation has succeeded, so checking the error
// code is limited to required errors, i.e < 0.
// ReportOnError will set test result to failure if the error doesn't
// match our expected error.
if(colIndex < 0)
ReportOnError(KTestFunction, _L("ColumnIndex"),
acfgblk, acnnum, colIndex);
return colIndex;
}
// Call the RSqlStatement method 'ColumnType'.
void CSQLFnStep::ColumnType(const TInt &acidx, const TPtrC &aexp)
{
_LIT(KTestFunction, "ColumnType");
TSqlColumnType gottype = isqlst.ColumnType(acidx);
TPtrC got(SqlColumnTypeToString(gottype));
if((aexp.Length() ==0) || (StringToSqlColumnType(aexp)==gottype))
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got Column type %S"), &KTestFunction, &got);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// If the expected type hasn't been specified then just display what
// we've got.
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: Got Column type %S, expected %S"),
&KTestFunction, &got, &aexp);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Call the RSqlStatement method 'ColumnSize'. Check it against the
// expected size specified in the config file.
void CSQLFnStep::ColumnSize(const TInt& acolidx, const TInt &axexp)
{
_LIT(KTestFunction, "ColumnSize");
TInt csize = isqlst.ColumnSize(acolidx);
if((axexp != -1) && (axexp != csize))
{
INFO_PRINTF1(HTML_RED);
SetTestStepResult(EFail);
ERR_PRINTF4(_L("%S: Got Column size %d, expected %d"),
&KTestFunction, csize, axexp);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// If colsize is -1 display what we have.
INFO_PRINTF3(_L("%S: Got Column size %d"), &KTestFunction, csize);
return;
}
// Onto the Bind methods...
void CSQLFnStep::BindNull(const TInt& apidx,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "BindNull");
TInt err = isqlst.BindNull(apidx);
ReportOnError(KTestFunction, _L("BindNull"), acfgblk, acnnum, err);
return;
}
void CSQLFnStep::BindInt(const TInt& apidx, const TInt& atob,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "BindInt");
TInt err = isqlst.BindInt(apidx, atob);
ReportOnError(KTestFunction, _L("BindInt"), acfgblk, acnnum, err);
return;
}
void CSQLFnStep::BindInt64(const TInt& apidx, const TPtrC& atob,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "BindInt64");
TInt64 bind;
TLex tl = atob;
tl.Val(bind);
TInt err = isqlst.BindInt64(apidx, bind);
ReportOnError(KTestFunction, _L("BindInt64"), acfgblk, acnnum, err);
return;
}
void CSQLFnStep::BindReal(const TInt& apidx, const TReal& areal,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "BindReal");
TInt err = isqlst.BindReal(apidx, areal);
ReportOnError(KTestFunction, _L("BindReal"), acfgblk, acnnum, err);
return;
}
// BindText from the config line...
// May be modified to return a ref which we can keep on the
// stack in the main loop. Then, when we hit a 'Next' that can be cleared.
// This is necessary because there are scoping problems with text and
// binarys - the SQL code expects buffers to remain in scope until
// the Exec/Next.
void CSQLFnStep::BindText(const TInt& apidx, const TPtrC& atxt,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "BindText");
TInt err = isqlst.BindText(apidx, atxt);
ReportOnError(KTestFunction, _L("BindText"), acfgblk, acnnum, err);
return;
}
// An additional method to let us bind more than one line of text from
// a config file...
// If the Bind is successful the buffer which has been bound is appended
// to the 'iBindRBufarr' array. This is necessary to keep it in scope until
// the 'Next'/'Exec' actions.
void CSQLFnStep::BindBigTextL(const TInt& apidx, const TPtrC& arg,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "BindBigText");
RBuf buf;
TInt fsize = FileSize(arg);
if(fsize < 0) return; // This will have reported an error if necessary.
#ifdef _UNICODE
fsize >>= 1; // We're assuming here that one character is two bytes..
#endif
// Create a buffer big enough for the text in the file.
TInt err = buf.Create(fsize);
if(err != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Can't allocate file buffer %S"), &KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Don't push buf onto the cleanup stack. We'll keep a reference to it
// which get removed on RSqlStatement::Reset.
// Use an RFileReadStream because we need to worry about characters,
// not just bytes.
RFileReadStream rflrs;
if(rflrs.Open(irfs, arg, EFileRead) != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Can't open file %S"), &KTestFunction, &arg);
buf.Close();
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
CleanupClosePushL(rflrs);
rflrs.ReadL(buf);
// Do the bind...
err = isqlst.BindText(apidx, buf);
ReportOnError(KTestFunction, _L("BindText"), acfgblk, acnnum, err);
// Drop out if it failed.
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &rflrs);
buf.Close();
return;
}
CleanupStack::PopAndDestroy(1, &rflrs);
// Tack the buffer onto the internal array. This keeps it in
// scope until a RSqlStatement::Close is performed when it will get
// destroyed.
iBindRBufarr.Append(buf);
return;
}
// If the Bind is successful the buffer which has been bound is appended
// to the 'iBindRBuf8arr' array. This is necessary to keep it in scope until
// the 'Next'/'Exec' actions.
void CSQLFnStep::BindBinaryL(const TInt& apidx, const TDesC& arg,
const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "BindBinary");
TInt fsize = FileSize(arg);
if(fsize < 0)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Can't find file %S"), &KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Create the buffer we're going to bind from. We'll keep a reference
// to this so it doesn't go out of scope (it mustn't
// until Exec/Reset) so don't put it on the cleanup stack.
RBuf8 ap;
TInt err = ap.Create(fsize);
ReportOnError(KTestFunction, _L("BufferCreate"), acfgblk, acnnum, err);
if(err != KErrNone) return;
// Now open the file specified in the argument.
RFile file;
TFileName fn = arg;
err = file.Open(irfs, fn, 0);
ReportOnError(KTestFunction, _L("FileOpen"), acfgblk, acnnum, err);
if(err != KErrNone)
{
ap.Close();
return;
}
CleanupClosePushL(file);
// Attempt to read from the file.
err = file.Read(ap, fsize);
ReportOnError(KTestFunction, _L("FileRead"), acfgblk, acnnum, err);
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &file);
ap.Close();
return;
}
// Do the bind...
err = isqlst.BindBinary(apidx, ap);
ReportOnError(KTestFunction, _L("BindBinary"), acfgblk, acnnum, err);
// Drop out if it failed.
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &file);
ap.Close();
return;
}
CleanupStack::PopAndDestroy(1, &file);
// Ok things seemed to have worked. Tack the buffer onto our internal
// RBuf8 array to keep it in scope. It will finally get trashed when
// we do the next RSqlStatement::Reset.
iBindRBuf8arr.Append(ap);
return;
}
void CSQLFnStep::IsNull(const TInt& apidx, const TPtrC& atxt)
{
_LIT(KTestFunction, "IsNull");
TBuf<8> isn(atxt);
isn.LowerCase();
TBool expected;
if(isn == _L("false"))
expected = EFalse;
else if(isn == _L("true"))
expected = ETrue;
else
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: expected argument item to be true/false, got %S"),
&KTestFunction, &atxt);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
if(isqlst.IsNull(apidx) != expected)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: expected IsNull to return %S"), &KTestFunction,
&atxt);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %S"), &KTestFunction, &atxt);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
void CSQLFnStep::ColumnInt(const TInt& acidx, const TInt& aint)
{
_LIT(KTestFunction, "ColumnInt");
TInt got = isqlst.ColumnInt(acidx);
if(got != aint)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: expected ColumnInt to return %d, got %d"),
&KTestFunction, aint, got);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %d"), &KTestFunction,
got);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
void CSQLFnStep::ColumnInt64(const TInt& acidx, const TPtrC& aintS)
{
_LIT(KTestFunction, "ColumnInt64");
TLex tl(aintS);
TInt64 aint;
tl.Val(aint);
TInt64 got = isqlst.ColumnInt64(acidx);
if(got != aint)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: expected ColumnInt to return %S"),
&KTestFunction, &aint);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %ld"), &KTestFunction,
got);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
void CSQLFnStep::ColumnReal(const TInt& acidx, const TReal& areal)
{
_LIT(KTestFunction, "ColumnReal");
TReal got = isqlst.ColumnReal(acidx);
if(got != areal)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: expected ColumnReal to return %f, got %f"),
&KTestFunction, areal, got);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %f"), &KTestFunction, got);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
void CSQLFnStep::ColumnTextL(const TInt& acidx, const TPtrC& atxt,
const TDesC &acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnTextL");
TPtrC got = isqlst.ColumnTextL(acidx);
TInt err;
// First the simplest, does the text match the config text?
if(got == atxt)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %S"), &KTestFunction,
&got);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Perhaps 'atxt' is a file, CompareTextAgainstFile will
// return KErrNotFound if it can't find the file.
if((err = CompareTextAgainstFileL(got, atxt)) == KErrNone)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Text match with file %S"), &KTestFunction,
&atxt);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
ReportOnError(KTestFunction, _L("ColumnTextL"), acfgblk, acnnum, err);
return;
}
void CSQLFnStep::ColumnTextPL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnTextP");
TPtrC got;
TInt err = isqlst.ColumnText(acidx, got);
ReportOnError(KTestFunction, _L("ColumnTextP"), acfgblk, acnnum, err);
// First the simplest, does the text match the config text?
if(got == arg)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %S"), &KTestFunction,
&got);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Perhaps 'arg' is a file, CompareTextAgainstFile will
// return KErrNotFound if it can't find the file.
if((err = CompareTextAgainstFileL(got, arg)) == KErrNone)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Text match with file %S"), &KTestFunction,
&arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
ReportOnError(KTestFunction, _L("ColumnTextP"), acfgblk, acnnum, err);
}
void CSQLFnStep::ColumnTextDL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnTextD");
// Masses of duplication.. We should have a common method to get around
// this, but perhaps when time permits..
// How big is this item? This is measured in bytes, not characters.
TInt colsize = isqlst.ColumnSize(acidx);
// Allocate a buffer.
RBuf buf;
TInt err = buf.Create(colsize);
INFO_PRINTF3(_L("%S: colsize %d"), &KTestFunction, colsize);
if(err != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Failed to allocate %d"), &KTestFunction,
colsize);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
CleanupClosePushL(buf);
// Call ColumnText(TInt aColumnIndex, TDes& aDest);
err = isqlst.ColumnText(acidx, buf);
ReportOnError(KTestFunction, _L("ColumnTextD"), acfgblk, acnnum, err);
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &buf);
return;
}
// First the simplest, does the text match the config text?
if(buf == arg)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Got expected result, %S"), &KTestFunction,
&buf);
INFO_PRINTF1(HTML_COLOUR_OFF);
CleanupStack::PopAndDestroy(1, &buf);
return;
}
// Perhaps 'arg' is a file, CompareTextAgainstFile will
// return KErrNotFound if it can't find the file.
if((err = CompareTextAgainstFileL(buf, arg)) == KErrNone)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Text match with file %S"), &KTestFunction,
&arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
CleanupStack::PopAndDestroy(1, &buf);
return;
}
ReportOnError(KTestFunction, _L("ColumnTextD"), acfgblk, acnnum, err);
CleanupStack::PopAndDestroy(1, &buf);
return;
}
void CSQLFnStep::ColumnBinaryL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnBinaryL");
// Get the output from ColumnBinary.
TPtrC8 colb = isqlst.ColumnBinaryL(acidx);
INFO_PRINTF3(_L("%S: Got length %d"), &KTestFunction, colb.Length());
// If both are zero length, then we're expected nothing, which is a
// reasonable possibility.
if((colb.Length() == 0) && (arg.Length() == 0))
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF2(_L("%S: Got expected empty buffer."), &KTestFunction);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Compare ColumnBinary return against a file.
TInt err = CompareBinaryAgainstFileL(colb, arg);
ReportOnError(KTestFunction, _L("ColumnBinaryL"), acfgblk, acnnum, err);
return;
}
void CSQLFnStep::ColumnBinaryPL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnBinaryP");
TInt csize = isqlst.ColumnSize(acidx);
INFO_PRINTF3(_L("%S: Colsize %d"), &KTestFunction, csize);
#ifdef _UNICODE
if(isqlst.ColumnType(acidx) == ESqlText) csize <<= 1;
#endif
RBuf8 data;
TInt err;
if((err = data.Create(csize)) != KErrNone)
{
ReportOnError(KTestFunction, _L("Createbuf"), acfgblk, acnnum, err);
return;
}
CleanupClosePushL(data);
err = isqlst.ColumnBinary(acidx, data);
ReportOnError(KTestFunction, _L("ColumnBinaryP"), acfgblk, acnnum, err);
if((data.Length()==0) && (arg.Length()==0))
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF2(_L("%S: Got expected empty buffer."), &KTestFunction);
INFO_PRINTF1(HTML_COLOUR_OFF);
CleanupStack::PopAndDestroy(1, &data);
return;
}
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &data);
return;
}
// Compare ColumnBinary return against a file.
err = CompareBinaryAgainstFileL(data, arg);
ReportOnError(KTestFunction, _L("FileCompare"), acfgblk, acnnum, err);
CleanupStack::PopAndDestroy(1, &data);
return;
}
void CSQLFnStep::ColumnBinaryDL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "ColumnBinaryD");
// How big is this item?
TInt colsize = isqlst.ColumnSize(acidx);
INFO_PRINTF3(_L("%S: colsize %d"), &KTestFunction, colsize);
#ifdef _UNICODE
if(isqlst.ColumnType(acidx) == ESqlText) colsize <<= 1;
#endif
// Allocate a buffer.
RBuf8 buf;
TInt err = buf.Create(colsize);
if(err != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Failed to allocate %d bytes"), &KTestFunction,
colsize);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
CleanupClosePushL(buf);
// Call ColumnBinary(TInt aColumnIndex, TDes8& aDest);
err = isqlst.ColumnBinary(acidx, buf);
ReportOnError(KTestFunction, _L("ColumnBinaryD"), acfgblk, acnnum, err);
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &buf);
return;
}
if((buf.Length()==0) && (arg.Length()==0))
{
CleanupStack::PopAndDestroy(1, &buf);
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF2(_L("%S: Got expected empty buffer."), &KTestFunction);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
// Compare ColumnBinary return against a file.
err = CompareBinaryAgainstFileL(buf, arg);
ReportOnError(KTestFunction, _L("ColumnBinaryD"), acfgblk, acnnum, err);
CleanupStack::PopAndDestroy(1, &buf);
return;
}
// The following four methods, SWBindText, SWBindBinary, SRColumnText and
// SRColumnBinary are Stream-Write and Stream-Read methods.
// In each case 'arg' specifies a file which is opened as a source (SW)
// of data, or else as another stream (SR) to compare against.
void CSQLFnStep::SWBindTextL(const TInt& apidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "SWBindText");
RSqlParamWriteStream sqlw;
// Get the WriteStream to stuff data down..
TInt err = sqlw.BindText(isqlst, apidx);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, err);
if(err != KErrNone) return;
WriteFileToStreamL(sqlw, arg);
sqlw.Close();
return;
}
void CSQLFnStep::SWBindBinaryL(const TInt& apidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "SWBindBinary");
RSqlParamWriteStream sqlw;
// Get the WriteStream to stuff data down..
TInt err = sqlw.BindBinary(isqlst, apidx);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, err);
if(err != KErrNone) return;
WriteFileToStreamL(sqlw, arg);
sqlw.Close();
return;
}
void CSQLFnStep::SRColumnTextL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "SRColumnText");
// First find out how much data is in this cell..
TInt dsize = isqlst.ColumnSize(acidx);
INFO_PRINTF3(_L("%S: ColumnSize is %d"), &KTestFunction, dsize);
RSqlColumnReadStream sqlr;
TInt err = sqlr.ColumnText(isqlst, acidx);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, err);
if(err != KErrNone) return;
// Ok, we have a Read Stream..
CleanupClosePushL(sqlr);
// Compare it..
TInt rc = CompareTextStreamAgainstFileL(sqlr, dsize, arg);
if(rc)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Stream comparison failure, file %S"),
&KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Stream comparison success, file %S"),
&KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
CleanupStack::PopAndDestroy(1,&sqlr);
return;
}
void CSQLFnStep::SRColumnBinaryL(const TInt& acidx, const TPtrC &arg,
const TDesC& acfgblk, const TInt acnnum=-1)
{
_LIT(KTestFunction, "SRColumnBinary");
// First find out how much data is in this cell..
TInt dsize = isqlst.ColumnSize(acidx);
INFO_PRINTF3(_L("%S: Colsize is %d"), &KTestFunction, dsize);
#ifdef _UNICODE
if(isqlst.ColumnType(acidx) == ESqlText) dsize <<= 1;
#endif
// Get our RReadStream and check for errors.
RSqlColumnReadStream sqlr;
TInt err = sqlr.ColumnBinary(isqlst, acidx);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, err);
if(err != KErrNone) return;
// Ok, we have a Read Stream..
CleanupClosePushL(sqlr);
// Compare it..
TInt rc = CompareBinaryStreamAgainstFileL(sqlr, dsize, arg);
if(rc)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Stream comparison failure, file %S"),
&KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
else
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF3(_L("%S: Stream comparison success, file %S"),
&KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
CleanupStack::PopAndDestroy(1,&sqlr);
return;
}
TBool CSQLFnStep::SPCreate(const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "SPCreate");
TSecurityPolicy defaultPolicy;
// Try to create the SQLDB security policy.
TInt rc = isqlsp.Create(defaultPolicy);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
TBool CSQLFnStep::SPCreate(const TPtrC&, const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "SPCreate");
TSecurityPolicy defaultPolicy;
// Try to create the SQLDB security policy.
TInt rc = KErrNone;
TRAP(rc, isqlsp.CreateL(defaultPolicy));
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
void CSQLFnStep::SPClose()
{
isqlsp.Close();
return;
}
TBool CSQLFnStep::SPSetDBPolicy(const TPtrC& apol, const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "SPSetDBPolicy");
//extract the policy level and capability from the argument passed in
TPtrC level, cap;
CommaSeparated(apol, level, cap);
//create the security policy object with the supplied capability
TSecurityPolicy sp((TCapability)(icaphsh->GetNumFromString(cap)));
INFO_PRINTF2(_L("SetDBPolicy: %S"), &level);
INFO_PRINTF2(_L("Capabilities are: %S"), &cap);
TInt rc = isqlsp.SetDbPolicy(((RSqlSecurityPolicy::TPolicyType)ipolhsh->GetNumFromString(level)), sp);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
TBool CSQLFnStep::SPSetPolicy(const TPtrC& apol, const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "SPSetPolicy");
//extract the policy level and capability from the argument passed in
TPtrC arg, arg2, object, name, level, caps;
CommaSeparated(apol, object, arg);
CommaSeparated(arg, name, arg2);
CommaSeparated(arg2, level, caps);
//create the security policy object with the supplied capability
TSecurityPolicy sp((TCapability)(icaphsh->GetNumFromString(caps)));
INFO_PRINTF2(_L("SetPolicy: %S"), &level);
INFO_PRINTF2(_L("Capabilities are: %S"), &caps);
INFO_PRINTF2(_L("Object type is: %S"), &object);
INFO_PRINTF2(_L("Object name is: %S"), &name);
TInt rc = isqlsp.SetPolicy(((RSqlSecurityPolicy::TObjectType)iobjhsh->GetNumFromString(object)), name, ((RSqlSecurityPolicy::TPolicyType)ipolhsh->GetNumFromString(level)), sp);
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
if(rc == KErrNone) return ETrue;
return EFalse;
}
void CSQLFnStep::SPExternalize(const TPtrC &arg, const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "SPExternalize");
RFileWriteStream rfws;
TInt err = rfws.Create(irfs, arg, EFileStream);
if(err != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: Can't open file %S, err %d"), &KTestFunction, &arg,
err );
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
TInt rc = KErrNone;
TRAP(rc, isqlsp.ExternalizeL(rfws));
TRAP(rc, rfws.CommitL());
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
rfws.Close();
return;
}
void CSQLFnStep::SPInternalize(const TPtrC &arg, const TDesC &acfgblk, const TInt acnnum)
{
_LIT(KTestFunction, "SPInternalize");
RFileReadStream rfrs;
TInt err = rfrs.Open(irfs, arg, EFileStream);
if(err != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Failed to open stream from file %S"), &KTestFunction, &arg);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
TInt rc = KErrNone;
TRAP(rc, isqlsp.InternalizeL(rfrs));
ReportOnError(KTestFunction, KTestFunction, acfgblk, acnnum, rc);
rfrs.Close();
return;
}
// - Utility functions... --- we should remove these into a separate class --
//
// Stream functions - should we have a persistent stream? Here it goes
// out of scope once the method completes, but what about a case where for
// example we write to a cell, then write some more later to the same cell?
//
// Loads more duplication..
TInt CSQLFnStep::CompareTextStreamAgainstFileL(RReadStream &as, TInt asiz,
const TPtrC &afile)
{
_LIT(KTestFunction, "CompareTextStreamAgainstFile");
// Get the file size. This is in bytes, so for Unicode will be
// out by a factor of two. Also, if created with notepad or similar
// will have a 'FEFF' two byte marker at the start (which SQLite
// strips when it sees it).
TInt fsize = FileSize(afile);
if(fsize < 0) return fsize;;
// We don't divide asiz by two: This will have originated in ColumnSize
// which returns the number of characters in a cell.
TInt textlen = asiz;
#ifdef _UNICODE
fsize >>= 1;
#endif
// If fsize is 1 different (2 bytes) from textlen, then we'll expect
// a unicode marker. If not 1 or zero give up straight away.
TInt diff = fsize - textlen;
TInt ucmark = (diff == 1);
if((diff>1) || (diff<0))
{
INFO_PRINTF1(HTML_COLOUR_OFF);
ERR_PRINTF4(_L("%S Size mismatch. Expected %d, got %d"),
&KTestFunction, fsize, textlen);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return KTEFSQLSizeError;
}
// Open the reference file specified in the argument.
// Use an RFileReadStream because we need to worry about characters,
// not just bytes.
RFileReadStream rflrs;
TInt err = rflrs.Open(irfs, afile, EFileRead);
if(err != KErrNone)
return err;
CleanupClosePushL(rflrs);
// Dumps the FEFF marker bytes for unicode files.
// SQLite does the same for text.
if(ucmark)
{
TInt16 mark = rflrs.ReadInt16L(); // byte order?
if((mark != (TInt16)0xfeff) && (mark != (TInt16)0xfffe))
{
CleanupStack::PopAndDestroy(1, &rflrs);
return KTEFSQLSizeError;
}
}
// For each 32768 chars in the text buffer...
const TInt slice = 32768;
RBuf fbuf, abuf;
err = fbuf.Create(slice);
if(err == KErrNone) err = abuf.Create(slice);
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &rflrs);
return KErrNoMemory;
}
CleanupClosePushL(fbuf);
CleanupClosePushL(abuf);
TInt rc = KErrNone;
for(TInt pos=0; pos < textlen ; pos += slice)
{
TInt toread = textlen - pos;
if(toread > slice)
toread = slice;
// Read 'toread' characters from the file and from the passed in
// data.
as.ReadL(abuf, toread);
TPtrC txtslice = abuf.Left(toread);
rflrs.ReadL(fbuf, toread);
TPtrC fileslice = fbuf.Left(toread);
// Compare ..
if (fileslice != txtslice)
{
rc = KTEFSQLSizeError;
break;
}
}
CleanupStack::PopAndDestroy(3, &rflrs);
return rc;
}
// Loads more duplication..
TInt CSQLFnStep::CompareBinaryStreamAgainstFileL(RReadStream &as, TInt asiz,
const TPtrC &afile)
{
_LIT(KTestFunction, "CompareBinaryStreamAgainstFile");
// Get the file size. This is in bytes.
TInt fsize = FileSize(afile);
if(fsize < 0) return fsize;;
// If sizes differ give up immediately.
if(fsize - asiz)
{
INFO_PRINTF1(HTML_COLOUR_OFF);
ERR_PRINTF4(_L("%S Size mismatch. Expected %d, got %d"),
&KTestFunction, fsize, asiz);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return KTEFSQLSizeError;
}
// Open the reference file specified in the argument.
// Use an RFileReadStream because we need to worry about characters,
// not just bytes.
RFileReadStream rflrs;
TInt err = rflrs.Open(irfs, afile, EFileRead);
if(err != KErrNone) return err;
CleanupClosePushL(rflrs);
// For each 32768 chars in the text buffer...
const TInt slice = 32768;
RBuf8 fbuf, abuf;
err = fbuf.Create(slice);
if(err == KErrNone) err = abuf.Create(slice);
if(err != KErrNone)
{
CleanupStack::PopAndDestroy(1, &rflrs);
return err;
}
CleanupClosePushL(fbuf);
CleanupClosePushL(abuf);
TInt rc = KErrNone;
for(TInt pos=0; pos < asiz ; pos += slice)
{
TInt toread = asiz - pos;
if(toread > slice)
toread = slice;
// Read 'toread' characters from the file and from the passed in
// data. Do we really need to chop out only the read bits for
// comparison? Wouldn't comparing fbuf and abuf work?
rflrs.ReadL(fbuf, toread);
TPtr8 fslice = fbuf.LeftTPtr(toread);
as.ReadL(abuf, toread);
TPtr8 aslice = abuf.LeftTPtr(toread);
// Compare .. (does this compare only what's been read?)
if (fslice != aslice)
{
rc = KTEFSQLSizeError;
break;
}
}
CleanupStack::PopAndDestroy(3, &rflrs);
return rc;
}
void CSQLFnStep::WriteFileToStreamL(RWriteStream &as1, const TPtrC &afile)
{
_LIT(KTestFunction, "WriteFileToStream");
// Open the reference file specified in the argument.
RFileReadStream rflrs;
TInt err = rflrs.Open(irfs, afile, EFileRead);
// Do we want to return anything?
if(err != KErrNone)
{
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("%S: Failed to open stream from file %S"),
&KTestFunction, &afile);
INFO_PRINTF1(HTML_COLOUR_OFF);
return;
}
CleanupClosePushL(rflrs);
as1.WriteL(rflrs);
CleanupStack::PopAndDestroy(1, &rflrs);
return;
}
TInt CSQLFnStep::CompareBinaryAgainstFileL(const TDesC8 &abuf,
const TFileName& afile)
{
_LIT(KTestFunction, "CompareBinaryAgainstFile");
// Get the file size.
TInt fsize = FileSize(afile);
if(fsize < 0) return fsize;
// How much binary do we have?
TInt binlen = abuf.Length();
INFO_PRINTF4(_L("%S: Filelen %d, Binlen %d"), &KTestFunction, fsize, binlen);
// If sizes differ drop out immediately.
if(fsize - binlen)
return KTEFSQLSizeError;
// Open the reference file specified in the argument.
// Use an RFileReadStream because we need to worry about characters,
// not just bytes.
RFileReadStream rflrs;
TInt err = rflrs.Open(irfs, afile, EFileRead);
if(err != KErrNone)
return err;
CleanupClosePushL(rflrs);
// For each 32768 chars in the text buffer...
const TInt slice = 32768;
RBuf8 fbuf;
fbuf.Create(slice);
CleanupClosePushL(fbuf);
TInt rc = KErrNone;
for(TInt pos=0; pos < binlen ; pos += slice)
{
TInt toread = binlen - pos;
if(toread > slice)
toread = slice;
// Read 'toread' bytes from the file and from the passed in
// data.
rflrs.ReadL(fbuf, toread);
TPtrC8 fileslice = fbuf.Left(toread);
TPtrC8 binslice = abuf.Mid(pos, toread);
// Compare ..
if (fileslice != binslice)
{
rc = KTEFSQLSizeError;
break;
}
}
INFO_PRINTF2(_L("%S: Comparison successful"), &KTestFunction);
CleanupStack::PopAndDestroy(2, &rflrs);
return rc;
}
// Tested and working..
TInt CSQLFnStep::CompareTextAgainstFileL(const TDesC &atxt,
const TFileName& afile)
{
// Get the file size. This is in bytes, so for Unicode will be
// out by a factor of two. Also, if created with notepad or similar
// will have a 'FEFF' two byte marker at the start (which SQLite
// strips when it sees it).
TInt fsize = FileSize(afile);
if(fsize < 0) return fsize;
#ifdef _UNICODE
fsize >>= 1;
#endif
// How much text do we have?
TInt textlen = atxt.Length();
// If fsize is 1 different (2 bytes) from textlen, then we'll expect
// a unicode marker. If not 1 or zero give up straight away.
TInt diff = fsize - textlen;
TInt ucmark = (diff == 1);
if((diff>1) || (diff<0))
{
ERR_PRINTF3(_L("FSIZE is %d, textlen is %d"), fsize, textlen);
return KTEFSQLSizeError;
}
// Open the reference file specified in the argument.
// Use an RFileReadStream because we need to worry about characters,
// not just bytes.
RFileReadStream rflrs;
TInt err = rflrs.Open(irfs, afile, EFileRead);
if(err != KErrNone)
return err;
CleanupClosePushL(rflrs);
// Dumps the FEFF marker bytes for unicode files.
// SQLite does the same for text.
if(ucmark)
{
TInt16 mark = rflrs.ReadInt16L(); // byte order?
if((mark != (TInt16)0xfeff) && (mark != (TInt16)0xfffe))
{
CleanupStack::PopAndDestroy(1, &rflrs);
return KTEFSQLSizeError;
}
}
// For each 32768 chars in the text buffer...
const TInt slice = 32768;
RBuf fbuf;
fbuf.Create(slice);
CleanupClosePushL(fbuf);
TInt rc = KErrNone;
for(TInt pos=0; pos < textlen ; pos += slice)
{
TInt toread = textlen - pos;
if(toread > slice)
toread = slice;
// Read 'toread' characters from the file and from the passed in
// data.
rflrs.ReadL(fbuf, toread);
TPtrC txtslice = atxt.Mid(pos, toread);
// Compare ..
if (fbuf != txtslice)
{
rc = KTEFSQLSizeError;
break;
}
}
CleanupStack::PopAndDestroy(2, &rflrs);
return rc;
}
// Get the expected error code for the current action. Assume KErrNone if it
// isn't in the config file. We might have (in the config file)
// ExpectedError27=KSqlErrPermission
int CSQLFnStep::ActionNoToErrEnum(const TDesC& acfgsec, const TInt aActionNum,
TPtrC& aes)
{
TBuf<KConfigItemMaxNameLength> cnfgerr(_L("ExpectedError"));
if(aActionNum != -1) cnfgerr.AppendNum(aActionNum);
if(!GetStringFromConfig(acfgsec, cnfgerr, aes))
aes.Set(_L("KErrNone"));
return(ErrStringToEnum(aes));
}
TInt CSQLFnStep::ErrStringToEnum(TPtrC &aerr)
{
return(ierrhsh->GetNumFromString(aerr));
}
void CSQLFnStep::ErrEnumToString(const TInt &aerr, TPtrC &aptrstr)
{
aptrstr.Set(*(ierrhsh->GetStringFromNum(aerr)));
return;
}
const TPtrC CSQLFnStep::SqlColumnTypeToString(TSqlColumnType &asqltype)
{
return *icoltypehsh->GetStringFromNum(asqltype);
}
TSqlColumnType CSQLFnStep::StringToSqlColumnType(const TDesC &atype)
{
return (TSqlColumnType) icoltypehsh->GetNumFromString(atype);
}
/*
* A helper function to report on an error. This won't say anything if the
* error received (aerr) is equal to the error expected as defined in the
* configuration file.
*/
void CSQLFnStep::ReportOnError(const TDesC &afnnam, const TDesC &apinam,
const TDesC &acfgblk, const TInt acfgno,
const TInt aerr)
{
// Get the expected error.
TPtrC experrS;
TInt experr = ActionNoToErrEnum(acfgblk, acfgno, experrS);
// Some methods such as Exec and Next return a positive value on
// success. If we're not expecting an error and the actual error code
// is positive just return, everything is cool.
if((experr == KErrNone) && (aerr >= 0))
return;
// Is the actual error the same as the expected error?
if(aerr != experr)
{
INFO_PRINTF1(HTML_RED);
SetTestStepResult(EFail);
TPtrC errS;
ErrEnumToString(aerr, errS); // Convert the actual error to a string.
ERR_PRINTF7(_L("%S: %S gave error %d/%S, expected %d/%S"),
&afnnam, &apinam, aerr, &errS, experr, &experrS);
// Run 'LastErrorMessage' if we unexpectedly have 'KSqlErrGeneral',
// often what it has to say is very helpful.
if(aerr == KSqlErrGeneral)
LastErrorMessage(_L(""));
INFO_PRINTF1(HTML_COLOUR_OFF);
}
else if(aerr != KErrNone)
{
INFO_PRINTF1(HTML_GREEN);
INFO_PRINTF5(_L("%S: %S got expected error %d/%S"), &afnnam, &apinam,
aerr, &experrS);
INFO_PRINTF1(HTML_COLOUR_OFF);
}
return;
}
TBool CSQLFnStep::FromConfig(const TDesC &afnnam, const TDesC &acfgblk,
const TDesC &acfgname, TPtrC &acfgval)
{
if(!GetStringFromConfig(acfgblk, acfgname, acfgval))
{
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: Failed to get %S:%S parameter."), &afnnam, &acfgblk,
&acfgname);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return EFalse;
}
return ETrue;
}
TBool CSQLFnStep::FromConfig(const TDesC &afnnam, const TDesC &acfgblk,
const TDesC &acfgname, TInt &acfgval)
{
if(!GetIntFromConfig(acfgblk, acfgname, acfgval))
{
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: Failed to get %S:%S parameter."), &afnnam, &acfgblk,
&acfgname);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return EFalse;
}
return ETrue;
}
TBool CSQLFnStep::FromConfig(const TDesC &afnnam, const TDesC &acfgblk,
const TDesC &acfgname, TReal &acfgval)
{
TPtrC gotS;
if(!GetStringFromConfig(acfgblk, acfgname, gotS))
{
INFO_PRINTF1(HTML_RED);
ERR_PRINTF4(_L("%S: Failed to get %S:%S parameter."), &afnnam, &acfgblk,
&acfgname);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return EFalse;
}
TLex tl = gotS;
if(tl.Val(acfgval) != KErrNone)
{
ERR_PRINTF5(_L("%S:%S Failed to convert %S:%S to real."),
&afnnam, &acfgblk, &acfgname, &gotS);
return EFalse;
}
return ETrue;
}
// Looking for, e.g, "9876,1234"
void CSQLFnStep::CommaSeparated(const TPtrC& ainp, TInt &aint, TInt &aint2)
{
// _LIT(KTestFunction, "CommaSeparated");
// Read in what kind of binds we'll be doing..
TInt origlen = ainp.Length();
TChar comma(',');
TInt comoffset = ainp.Locate(comma);
if(comoffset != KErrNotFound)
{
TPtrC left = ainp.Left(comoffset);
TLex tl(left);
tl.Val(aint);
TInt rightlen = origlen - comoffset - 1;
TPtrC right = ainp.Right(rightlen);
tl = right;
tl.Val(aint2);
}
else
{
TLex tl(ainp);
tl.Val(aint);
aint2=-1;
}
}
// Looking for, e.g, "9876,some words"
void CSQLFnStep::CommaSeparated(const TPtrC& ainp, TInt &aint, TPtrC &astr)
{
// _LIT(KTestFunction, "CommaSeparated");
TInt origlen = ainp.Length();
TChar comma(',');
TInt comoffset = ainp.Locate(comma);
if(comoffset != KErrNotFound)
{
TPtrC left = ainp.Left(comoffset);
TLex tl(left);
tl.Val(aint);
TInt rightlen = origlen - comoffset - 1;
astr.Set(ainp.Right(rightlen));
}
else
{
TLex tl(ainp);
tl.Val(aint);
astr.Set(_L(""));
}
}
void CSQLFnStep::CommaSeparated(const TPtrC& ainp, TPtrC &aleft, TPtrC &aright)
{
// _LIT(KTestFunction, "CommaSeparated");
aleft.Set(ainp);
aright.Set(_L(""));
TInt origlen = ainp.Length();
TChar comma(',');
TInt comoffset = ainp.Locate(comma);
if(comoffset != KErrNotFound)
{
aleft.Set(ainp.Left(comoffset));
TInt rightlen = origlen - comoffset - 1;
aright.Set(ainp.Right(rightlen));
}
else
return;
}
TInt CSQLFnStep::FileSize(const TPtrC &afile)
{
// First open the file specified in the argument.
// This lot gets duplicated a lot.
RFile file;
TFileName fn = afile;
TInt err;
if((err = file.Open(irfs, fn, 0)) != KErrNone)
{
INFO_PRINTF1(HTML_RED);
ERR_PRINTF3(_L("Cannot open %S to get filesize, err %d"), &afile, err);
SetTestStepResult(EFail);
INFO_PRINTF1(HTML_COLOUR_OFF);
return err;
}
TInt fsize;
file.Size(fsize);
file.Close();
return fsize;
}