1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmtestenv/mmtestfw/Source/TestFramework/script.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,663 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// This module contains CScript class
1.18 +//
1.19 +//
1.20 +
1.21 +// system includes
1.22 +#include <f32file.h>
1.23 +
1.24 +// test system includes
1.25 +#include <testframework.h>
1.26 +#include "Filename.h"
1.27 +#include "script.h"
1.28 +#include "parseline.h"
1.29 +#include "config.h"
1.30 +
1.31 +#if !defined (__TSU_TESTFRAMEWORK__)
1.32 +/**
1.33 + *
1.34 + * Script files can reference other script files.
1.35 + * KMaxDepthRecursion limits the number of references.
1.36 + * This is to catch accidental circular references in script files
1.37 + * which would otherwise cause the system to continue until all
1.38 + * memory had be used making more CScript objects.
1.39 + *
1.40 + * @xxxx
1.41 + *
1.42 + */
1.43 +const TInt KMaxDepthRecursion = 100;
1.44 +
1.45 +#endif
1.46 +
1.47 +/**
1.48 + *
1.49 + * Global data : count of how deep in script files parser is.
1.50 + * This is to check against infinite recursion
1.51 + *
1.52 + * NB : we must patch this out for Unit Testing, where script.cpp
1.53 + * is part of a DLL
1.54 + *
1.55 + * @xxxx
1.56 + *
1.57 + */
1.58 +// do not define static if Unit Testing
1.59 +#if !defined (__TSU_TESTFRAMEWORK__)
1.60 +GLDEF_D TInt CScript::iScriptDepth = 0;
1.61 +#endif
1.62 +
1.63 +/**
1.64 + *
1.65 + * Console prompts
1.66 + *
1.67 + * @xxxx
1.68 + *
1.69 + */
1.70 +//_LIT(KTxtPressAnyKey,"[press any key to continue]\n"); // EABI warning removal
1.71 +//_LIT(KTxtBreakOnError,"The test has failed, press X to terminate this test\n [press any other key to continue]\n"); // EABI warning removal
1.72 +
1.73 +/**
1.74 + *
1.75 + * CScript first-phase constructor
1.76 + *
1.77 + * @xxxx
1.78 + *
1.79 + */
1.80 +CScript::CScript()
1.81 + {
1.82 + }
1.83 +
1.84 +/**
1.85 + *
1.86 + * CScript second-phase constructor for a script processor which
1.87 + * does not inherit a parser.
1.88 + *
1.89 + * @param "CTestUtils* aTestUtils"
1.90 + * The TestUtils object to use
1.91 + *
1.92 + * @param "CLog* aLog"
1.93 + * The logger to use
1.94 + *
1.95 + * @xxxx
1.96 + *
1.97 + */
1.98 +void CScript::ConstructL(CTestUtils* aTestUtils, CLog* aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
1.99 + {
1.100 + iLog = aLog;
1.101 + iGuardTimer = aGuardTimer;
1.102 +
1.103 + iMatchString = aMatchString.AllocL();
1.104 +
1.105 + iParse = CParseLine::NewL(this, aTestUtils, aLog, aGuardTimer, *iMatchString);
1.106 + iParseOwner = ETrue;
1.107 +
1.108 + iPauseAtEnd = EFalse;
1.109 +
1.110 +#if !defined (__TSU_TESTFRAMEWORK__)
1.111 + iScriptDepth++;
1.112 +#endif
1.113 + }
1.114 +
1.115 +/**
1.116 + *
1.117 + * CScript static constructor for a script processor which
1.118 + * does not inherit a parser.
1.119 + *
1.120 + * @param "CTestUtils* aTestUtils"
1.121 + * The TestUtils object to use
1.122 + *
1.123 + * @param "CLog* aLog"
1.124 + * The logger to use
1.125 + *
1.126 + * @xxxx
1.127 + *
1.128 + */
1.129 +CScript* CScript::NewL(CTestUtils* aTestUtils, CLog * aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
1.130 + {
1.131 + CScript * self = new(ELeave) CScript;
1.132 + CleanupStack::PushL(self);
1.133 + self->ConstructL(aTestUtils, aLog, aGuardTimer, aMatchString);
1.134 + CleanupStack::Pop();
1.135 + return self;
1.136 + }
1.137 +
1.138 +/**
1.139 + *
1.140 + * CScript static constructor for a script processor which
1.141 + * does not inherit a parser.
1.142 + *
1.143 + * @param "CTestUtils* aTestUtils"
1.144 + * The TestUtils object to use
1.145 + *
1.146 + * @param "CLog* aLog"
1.147 + * The logger to use
1.148 + *
1.149 + * @xxxx
1.150 + *
1.151 + */
1.152 +CScript* CScript::NewLC(CTestUtils* aTestUtils, CLog * aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
1.153 + {
1.154 + CScript * self = new(ELeave) CScript;
1.155 + CleanupStack::PushL(self);
1.156 + self->ConstructL(aTestUtils, aLog, aGuardTimer, aMatchString);
1.157 + return self;
1.158 + }
1.159 +
1.160 +/**
1.161 + *
1.162 + * CScript second-phase constructor, for a script processor which
1.163 + * inherits a parser.
1.164 + *
1.165 + * @param "CParseLine* aParse"
1.166 + * The parser to use
1.167 + *
1.168 + * @param "CTestUtils*"
1.169 + * Dummy parameter (would be used for constructing a parser);
1.170 + * retained to maintain overload distinction
1.171 + *
1.172 + * @param "CLog * aLog"
1.173 + * The logger to use
1.174 + *
1.175 + * @xxxx
1.176 + *
1.177 + */
1.178 +void CScript::ConstructL(CParseLine* aParse, CTestUtils*, CLog* aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
1.179 + {
1.180 + iLog = aLog;
1.181 + iGuardTimer = aGuardTimer;
1.182 +
1.183 + iMatchString = aMatchString.AllocL(); // should be the same as that for aParse, for moment don't check
1.184 +
1.185 + iParse = aParse;
1.186 + iParseOwner = EFalse;
1.187 +
1.188 + iPauseAtEnd = EFalse;
1.189 +
1.190 +#if !defined (__TSU_TESTFRAMEWORK__)
1.191 + iScriptDepth++;
1.192 +#endif
1.193 +
1.194 + }
1.195 +
1.196 +/**
1.197 + *
1.198 + * CScript static constructor for a script processor which
1.199 + * inherits a parser.
1.200 + *
1.201 + * @param "CParseLine* aParse"
1.202 + * The parser to use
1.203 + *
1.204 + * @param "CTestUtils* aTestUtils"
1.205 + * The TestUtils object to use
1.206 + *
1.207 + * @param "CLog* aLog"
1.208 + * The logger to use
1.209 + *
1.210 + * @xxxx
1.211 + *
1.212 + */
1.213 +CScript* CScript::NewL(CParseLine* aParse, CTestUtils* aTestUtils, CLog* aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
1.214 + {
1.215 + CScript* self = new(ELeave) CScript;
1.216 + CleanupStack::PushL(self);
1.217 + self->ConstructL(aParse, aTestUtils, aLog, aGuardTimer, aMatchString);
1.218 + CleanupStack::Pop();
1.219 + return self;
1.220 + }
1.221 +
1.222 +/**
1.223 + *
1.224 + * CScript static constructor for a script processor which
1.225 + * inherits a parser.
1.226 + *
1.227 + * @param "CParseLine* aParse"
1.228 + * The parser to use
1.229 + *
1.230 + * @param "CTestUtils* aTestUtils"
1.231 + * The TestUtils object to use
1.232 + *
1.233 + * @param "CLog* aLog"
1.234 + * The logger to use
1.235 + *
1.236 + * @xxxx
1.237 + *
1.238 + */
1.239 +CScript* CScript::NewLC(CParseLine* aParse, CTestUtils* aTestUtils, CLog* aLog, TInt64 aGuardTimer, const TDesC& aMatchString)
1.240 + {
1.241 + CScript* self = new(ELeave) CScript;
1.242 + CleanupStack::PushL(self);
1.243 + self->ConstructL(aParse, aTestUtils, aLog, aGuardTimer, aMatchString);
1.244 + return self;
1.245 + }
1.246 +
1.247 +/**
1.248 + *
1.249 + * CScript destructor
1.250 + *
1.251 + * @xxxx
1.252 + *
1.253 + */
1.254 +CScript::~CScript()
1.255 + {
1.256 + // delete parser if we own it
1.257 + if(iParseOwner)
1.258 + {
1.259 + delete iParse;
1.260 + iParse = NULL;
1.261 + }
1.262 +
1.263 + // delete scriptbuffer
1.264 + delete iScriptBuffer;
1.265 +
1.266 + delete iMatchString;
1.267 +
1.268 +#if !defined (__TSU_TESTFRAMEWORK__)
1.269 + iScriptDepth--;
1.270 +#endif
1.271 + }
1.272 +
1.273 +
1.274 +/**
1.275 + *
1.276 + * Open and read a script file.
1.277 + *
1.278 + * @param "TFileName aScriptFileName"
1.279 + * The script file name
1.280 + *
1.281 + * @return "TBool"
1.282 + * true if script file successfully read
1.283 + *
1.284 + * @xxxx
1.285 + *
1.286 + */
1.287 +#ifdef EXCLUDE_FOR_UNITTEST
1.288 +TBool CScript::OpenScriptFile(CFileName* /*aScriptFileName*/)
1.289 + {
1.290 + // empty function to silence OPT:REF warning under WINS UREL build
1.291 + return ETrue;
1.292 + }
1.293 +#else
1.294 +TBool CScript::OpenScriptFile(CFileName* aScriptFileName)
1.295 + {
1.296 + // get the full pathname default drive name and extension
1.297 + _LIT(KRelated,"\\xx.script");
1.298 + TParse parseScriptFileName;
1.299 + TInt returnCode = parseScriptFileName.Set(aScriptFileName->FileName(), &KRelated, NULL);
1.300 + if (returnCode != KErrNone)
1.301 + {
1.302 + ERR_PRINTF2(_L("Could not set script filename: %S"), &parseScriptFileName.FullName());
1.303 + Pause();
1.304 + return EFalse;
1.305 + }
1.306 +
1.307 +#if !defined (__TSU_TESTFRAMEWORK__)
1.308 + if (iScriptDepth > KMaxDepthRecursion)
1.309 + {
1.310 + // prevent the parser from recursing forever
1.311 + ERR_PRINTF2(_L("Script parser aborting: depth:%d"), iScriptDepth);
1.312 + return EFalse;
1.313 + }
1.314 +#if !defined(__WINS__)
1.315 + if (iScriptDepth > 3)
1.316 + {
1.317 + // on target, we are likely to KERN-EXEC 3 if nesting more than 4 levels
1.318 + WARN_PRINTF2(_L("Warning : script parser depth = %d"), iScriptDepth);
1.319 + }
1.320 +#endif
1.321 +#endif
1.322 +
1.323 + // connect to the fileserver
1.324 + returnCode = iTheFs.Connect();
1.325 + if (returnCode != KErrNone)
1.326 + {
1.327 + ERR_PRINTF1(_L("Error trying to connect to the file server") );
1.328 + return EFalse;
1.329 + }
1.330 +
1.331 +
1.332 + RFile listfile;
1.333 + // have we got a drive letter specified - if not, check all drives
1.334 + if (parseScriptFileName.DrivePresent())
1.335 + {
1.336 + returnCode = listfile.Open(iTheFs, parseScriptFileName.FullName(), EFileRead | EFileShareAny);
1.337 + }
1.338 + else
1.339 + {
1.340 + // checks C, D, E and Z drives - this is ugly, is there a better way of doing this?
1.341 + INFO_PRINTF1(_L("Looking for script file on all drives..."));
1.342 + _LIT(KDriveC, "C:");
1.343 + parseScriptFileName.Set(aScriptFileName->FileName(), &KRelated, &KDriveC);
1.344 + returnCode = listfile.Open(iTheFs, parseScriptFileName.FullName(), EFileRead | EFileShareAny);
1.345 + if (returnCode != KErrNone)
1.346 + {
1.347 + _LIT(KDriveD, "D:");
1.348 + parseScriptFileName.Set(aScriptFileName->FileName(), &KRelated, &KDriveD);
1.349 + returnCode = listfile.Open(iTheFs, parseScriptFileName.FullName(), EFileRead | EFileShareAny);
1.350 + if (returnCode != KErrNone)
1.351 + {
1.352 + _LIT(KDriveE, "E:");
1.353 + parseScriptFileName.Set(aScriptFileName->FileName(), &KRelated, &KDriveE);
1.354 + returnCode = listfile.Open(iTheFs, parseScriptFileName.FullName(), EFileRead | EFileShareAny);
1.355 + if (returnCode != KErrNone)
1.356 + {
1.357 + _LIT(KDriveZ, "Z:");
1.358 + parseScriptFileName.Set(aScriptFileName->FileName(), &KRelated, &KDriveZ);
1.359 + returnCode = listfile.Open(iTheFs, parseScriptFileName.FullName(), EFileRead | EFileShareAny);
1.360 + }
1.361 + }
1.362 + }
1.363 + }
1.364 +
1.365 + // check if open fails
1.366 + if (returnCode != KErrNone)
1.367 + {
1.368 + parseScriptFileName.Set(aScriptFileName->FileName(), &KRelated, NULL);
1.369 + ERR_PRINTF2(_L("Failed to open script file : %S"), &parseScriptFileName.FullName());
1.370 + listfile.Close();
1.371 + iTheFs.Close();
1.372 + Pause();
1.373 + return EFalse;
1.374 + }
1.375 +
1.376 + // display the file being processed
1.377 + INFO_PRINTF2(_L("Reading script %S"), &parseScriptFileName.FullName());
1.378 +
1.379 + // get the script file size
1.380 + TInt listfilesize;
1.381 + returnCode = listfile.Size(listfilesize);
1.382 + if (returnCode != KErrNone)
1.383 + {
1.384 + ERR_PRINTF2(_L("Failed to read script file: %S size "), &parseScriptFileName.FullName());
1.385 + listfile.Close();
1.386 + iTheFs.Close();
1.387 + return EFalse;
1.388 + }
1.389 +
1.390 + // JW 30-10-02 DEF004555
1.391 + // Buffer was being orphaned if already allocated, where there was more than one
1.392 + // script file on the command line
1.393 + // Now, we check for this and delete iScriptBuffer if it already exists
1.394 + if(iScriptBuffer)
1.395 + {
1.396 + delete iScriptBuffer;
1.397 + iScriptBuffer = NULL;
1.398 + }
1.399 +
1.400 + // get a buffer to read the file into
1.401 + TRAPD(err, iScriptBuffer = HBufC8::NewL(listfilesize));
1.402 + if (err != KErrNone || iScriptBuffer == NULL)
1.403 + {
1.404 + ERR_PRINTF2(_L("Failed to allocate memory for script file %S "), &parseScriptFileName.FullName());
1.405 + listfile.Close();
1.406 + iTheFs.Close();
1.407 + return EFalse;
1.408 + }
1.409 +
1.410 + // get a pointer to the buffer
1.411 + TPtr8 ptr = iScriptBuffer->Des();
1.412 +
1.413 + // read the file into the buffer
1.414 + returnCode = listfile.Read(ptr);
1.415 + if (returnCode != KErrNone)
1.416 + {
1.417 + ERR_PRINTF2(_L("Failed to read script file %S "), &parseScriptFileName.FullName());
1.418 + listfile.Close();
1.419 + iTheFs.Close();
1.420 + return EFalse;
1.421 + }
1.422 +
1.423 + listfile.Close();
1.424 + iTheFs.Close();
1.425 + return ETrue;
1.426 + }
1.427 +#endif // EXCLUDE_FOR_UNITTEST
1.428 +
1.429 +/**
1.430 + *
1.431 + * Parse and execute script file.
1.432 + * Assumes script file has been read into iScriptBuffer
1.433 + *
1.434 + * @return "TVerdict"
1.435 + * The script verdict (for logging)
1.436 + *
1.437 + * @xxxx
1.438 + *
1.439 + */
1.440 +TVerdict CScript::ExecuteScriptL()
1.441 + {
1.442 + // use TLex to decode the script
1.443 + TLex8 llex(*iScriptBuffer);
1.444 +
1.445 + // keep a count of the line number
1.446 + TInt8 lineNo = 1;
1.447 +
1.448 + // loop though processing the rest a line at a time
1.449 + while(!llex.Eos())
1.450 + {
1.451 + // skip any spaces
1.452 + while ( llex.Peek() == ' ' )
1.453 + llex.Inc();
1.454 +
1.455 + // mark the start of the line
1.456 + llex.Mark();
1.457 +
1.458 + // move to the next
1.459 + while(!llex.Eos() && llex.Peek() != '\n')
1.460 + llex.Inc();
1.461 +
1.462 + // step over \n
1.463 + if ( llex.Peek() == '\n' )
1.464 + llex.Inc();
1.465 +
1.466 + // get the line
1.467 + TPtrC8 pline = llex.MarkedToken();
1.468 + if (pline.Length() != 0)
1.469 + {
1.470 + // and then process
1.471 + ProcessLineL(pline, lineNo);
1.472 + }
1.473 +
1.474 + // on to the next line
1.475 + lineNo++;
1.476 + }
1.477 +
1.478 + // script processing complete, now return the script verdict
1.479 + // Note: the script verdicts are just for the log
1.480 + // if no tests failed then return pass for the script
1.481 + // this covers scripts which do not test anything
1.482 + return (iFail == 0 ? EPass : EFail );
1.483 + }
1.484 +
1.485 +/**
1.486 + *
1.487 + * Process a single line from the script file.
1.488 + *
1.489 + * @param "const TDesC8& aNarrowline"
1.490 + * The script line
1.491 + *
1.492 + * @param "TInt8 lineNo"
1.493 + * The script line number
1.494 + *
1.495 + * @xxxx
1.496 + *
1.497 + */
1.498 +void CScript::ProcessLineL(const TDesC8& aNarrowline, TInt8 aLineNo)
1.499 + {
1.500 + // call parse to process line
1.501 + iParse->ProcessLineL(aNarrowline, aLineNo);
1.502 + }
1.503 +
1.504 +/**
1.505 + *
1.506 + * Display the accumulated script results.
1.507 + *
1.508 + * @xxxx
1.509 + *
1.510 + */
1.511 +void CScript::DisplayResults()
1.512 + {
1.513 +
1.514 + INFO_PRINTF1(_L("Test Results Summary ") );
1.515 + INFO_PRINTF1(_L("-------------------- ") );
1.516 + INFO_PRINTF2(_L("Passed :%d"), iPass);
1.517 + INFO_PRINTF2(_L("Failed :%d"), iFail);
1.518 + INFO_PRINTF2(_L("Inconclusive :%d"), iInconclusive);
1.519 + INFO_PRINTF2(_L("Test suite errors :%d"), iTestSuiteError);
1.520 + INFO_PRINTF2(_L("Aborted :%d"), iAbort);
1.521 + INFO_PRINTF2(_L("KnownFailure :%d"), iKnownFailure); //A new TVerdict
1.522 + INFO_PRINTF2(_L("Total :%d"), iTotal);
1.523 +
1.524 + if(iPauseAtEnd)
1.525 + {
1.526 + // A pause at the end has been requested
1.527 + Pause();
1.528 + }
1.529 +
1.530 + }
1.531 +
1.532 +/**
1.533 + *
1.534 + * Pause testing.
1.535 + * NOTE : stubbed pending re-implementation of user input
1.536 + *
1.537 + * @xxxx
1.538 + *
1.539 + */
1.540 +void CScript::Pause()
1.541 + {
1.542 + WARN_PRINTF1(_L("Warning : PAUSE not implemented"));
1.543 + }
1.544 +
1.545 +/**
1.546 + *
1.547 + * Display error on the console and invite abort.
1.548 + * NOTE : stubbed pending re-implementation of user input
1.549 + *
1.550 + * @xxxx
1.551 + *
1.552 + */
1.553 +TBool CScript::BreakOnError()
1.554 + {
1.555 + WARN_PRINTF1(_L("Warning : BREAK_ON_ERROR not implemented"));
1.556 + return EFalse;
1.557 + }
1.558 +
1.559 +/**
1.560 + *
1.561 + * Add a test result to the accumulated totals.
1.562 + *
1.563 + * @param "TVerdict aTestVerdict"
1.564 + * The test verdict
1.565 + *
1.566 + * @xxxx
1.567 + *
1.568 + */
1.569 +void CScript::AddResult(TVerdict aTestVerdict)
1.570 + {
1.571 + // another test complete, so increment total
1.572 + iTotal++;
1.573 +
1.574 + // add in the current result
1.575 + switch (aTestVerdict)
1.576 + {
1.577 + case EPass:
1.578 + iPass++;
1.579 + break;
1.580 + case EFail:
1.581 + iFail++;
1.582 + break;
1.583 + case EInconclusive:
1.584 + iInconclusive++;
1.585 + break;
1.586 + case ETestSuiteError:
1.587 + iTestSuiteError++;
1.588 + break;
1.589 + case EAbort:
1.590 + iAbort++;
1.591 + break;
1.592 + case EKnownFailure: //A new TVerdict for a known failed test
1.593 + iKnownFailure++;
1.594 + break;
1.595 + }
1.596 +
1.597 + // display the result
1.598 + TPtrC verdictText = CLog::TestResultText(aTestVerdict);
1.599 + TPtrC currentSuiteName = iParse->CurrentSuiteName();
1.600 + TPtrC currentStepName = iParse->CurrentStepName();
1.601 +
1.602 + iLog->LogResult(aTestVerdict, _L("Test Result for %S:%S is %S "),
1.603 + ¤tSuiteName, ¤tStepName, &verdictText);
1.604 +
1.605 + }
1.606 +
1.607 +/**
1.608 + *
1.609 + * Add a test result from a subscript to the accumulated totals.
1.610 + *
1.611 + * @param "CScript* aSubScript"
1.612 + * The subscript
1.613 + *
1.614 + * @xxxx
1.615 + *
1.616 + */
1.617 +void CScript::AddResult(CScript* aSubScript)
1.618 + {
1.619 +
1.620 + iPass += aSubScript->iPass;
1.621 + iFail += aSubScript->iFail;
1.622 + iInconclusive += aSubScript->iInconclusive;
1.623 + iTestSuiteError += aSubScript->iTestSuiteError;
1.624 + iAbort += aSubScript->iAbort;
1.625 + iKnownFailure += aSubScript->iKnownFailure;
1.626 + iTotal +=aSubScript->iTotal;
1.627 + }
1.628 +
1.629 +/**
1.630 + *
1.631 + * Traceable logging function for parseline.
1.632 + *
1.633 + * @param "const TText8* aFile"
1.634 + * Source code file name
1.635 + *
1.636 + * @param "TInt aLine"
1.637 + * Source code line
1.638 + *
1.639 + * @param "TInt aSeverity"
1.640 + * Severity level required to log
1.641 + *
1.642 + * @param "TRefByValue<const TDesC16> aFmt"
1.643 + * Printf-style format.
1.644 + *
1.645 + * @param "..."
1.646 + * Variable print parameters
1.647 + *
1.648 + * @xxxx
1.649 + *
1.650 + */
1.651 +void CScript::LogExtra(const TText8* aFile, TInt aLine, TInt aSeverity,
1.652 + TRefByValue<const TDesC16> aFmt,...)
1.653 + {
1.654 + VA_LIST aList;
1.655 + VA_START(aList, aFmt);
1.656 +
1.657 + if(aSeverity)
1.658 + {
1.659 + if(iLog)
1.660 + {
1.661 + iLog->LogExtra(aFile, aLine, aSeverity, aFmt, aList);
1.662 + }
1.663 + }
1.664 +
1.665 + VA_END(aList);
1.666 + }