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