################################################################################
# TEST: EMOS_FRM_driver_lib
################################################################################
# Copyright (C) 2000 EMOS Computer Consulting GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# For further information please contact:
#
# Dean Rajovic
# EMOS Computer Consulting GmbH
# Oskar-Messter-Straße 25
# 85737 Ismaning
# Germany
# tel.: +49 89 608 765-0
# mailto:drajovic@emos.de
# http://www.emos.de
################################################################################
# $Revision: 1.8 $
# $Author: drajovic $
# $Date: 2005/01/27 08:53:54 $
# $Source: C:/Archive/FRAMEWORK/EMOS_GPL/FRM/emos_frm_driver_lib/script,v $
# $NoKeywords: $
################################################################################
#**#
#* The library routines for the EMOS_FRM_driver test.
#*/
static const PREFIX = "IDX:";
static const GER_COLUMNS = "Bearbeiten?,Testscript,Testtabelle,Testset";
static const GER_ERROR_MODES = "1 - Weiter,2 - Test anhalten,3 - Testset anhalten,4 - Testsuite anhalten,5 - Block wiederholen";
#* Properties (parameters that can be set/get)
static script_home;
static data_home;
static default_suite_table;
static ask = FALSE;
static columns = GER_COLUMNS;
static new_test_driver = FALSE;
static fail_on_unknown_test = FALSE;
static def_error_mode = E_FRM_CONTINUE;
static error_modes = GER_ERROR_MODES;
#/**
#* Home directory for test scripts
#*/
public function FRM_DRV_set_script_home ( in dir )
{
script_home = dir;
}
#/**
#* Home directory for test data
#*/
public function FRM_DRV_set_data_home ( in dir )
{
data_home = dir;
}
#/**
#* Name of the test suite table
#*/
public function FRM_DRV_set_default_suite_table ( in name )
{
default_suite_table = name;
}
#/**
#* Set routine for activating the new test driver logic
#*/
public function FRM_DRV_set_new_test_driver ( in test_driver )
{
new_test_driver = test_driver;
}
#/**
#* Get routine for activating the new test driver logic
#*/
public function FRM_DRV_is_new_test_driver ( )
{
return new_test_driver;
}
#/**
#* Turns failure on unknown test on/off [default: FALSE]
#* @param mode (in) TRUE raises an error by FRM_DRV_test_set_driver()
#* if an unknown test (i.e. nonexisting column) is called, FALSE doesn't
#*/
public function FRM_DRV_set_fail_on_unknown_test ( in mode )
{
fail_on_unknown_test = mode;
}
#/**
#* Get routine for activating activating failure on unknown test
#*/
public function FRM_DRV_is_fail_on_unknown_test ( )
{
return fail_on_unknown_test;
}
#/**
#* Sets the default error mode. This value is evaluated by the emos driver in
#* in order to determine how to proceed after an error has been detected in
#* some test block. In interactive mode a dialog is displayed where you can
#* interactively choose the desired behaviour. In batchmode or if you choose
#* "Cancel" in interactive mode the default mode which is set here is applied.
#* By default the <code>E_FRM_CONTINUE</code> is used (which means that
#* no test block will be skipped due to errors).
#* @param mode (in) possible values <code>E_FRM_TEST_STOP, E_FRM_SET_STOP,
#* E_FRM_SUITE_STOP, E_FRM_CONTINUE</code> if eny other value was passed
#* (including <code>E_FRM_RETRY</code>) the default mode will be set to
#* <code>E_FRM_CONTINUE</code>.
#* @param eror_modes (in) String list defining mode names
#* <pre>[default:"1 - Weiter,2 - Test anhalten,3 - Testset anhalten,4 - Testsuite anhalten,5 - Block wiederholen"]</pre>
#* Make sure to preserve the numbers, the meaning of modes and no blanks after comma!
#* @return the mode actually set (note it may be different from the wanted one!)
#*/
public function FRM_DRV_set_default_error_mode ( in mode, in mode_list )
{
if ( mode_list != "" )
error_modes = mode_list;
switch( mode )
{
case E_FRM_TEST_STOP:
case E_FRM_SET_STOP:
case E_FRM_SUITE_STOP:
def_error_mode = mode;
break;
default:
def_error_mode = E_FRM_CONTINUE;
}
return def_error_mode;
}
#/**
#* TRUE: gives you the option to choose the alternative suite table;
#* FALSE: opens the defined table only [default]
#*/
public function FRM_DRV_set_ask ( in par )
{
ask = par;
}
#/**
#* Comma-separated string defining the
#* titles of the four important columns
#* [default: <pre>"Bearbeiten?,Testscript,Testtabelle,Testset[,Kommentar]"</pre>]
#*/
public function FRM_DRV_set_columns ( in cols )
{
columns = cols;
}
#**
#* The main loop processes all rows in the suite table.
#* @param arg1 home directory for test scripts
#* @param arg2 home directory for test data
#* @param arg3 name of the test suite table
#* @param arg4 TRUE: gives you the option to choose
#* alternative suite table; FALSE: opens the defined table only [default]
#* @param arg5 comma-separated string defining the
#* titles of the four important columns
#* [default: <pre>"Bearbeiten?,Testscript,Testtabelle,Testset[,Kommentar]"</pre>]
#* @return
#* E_OK: success
#* !E_OK: failure
#*/
#public function FRM_DRV_main( in script_home, in data_home, in default_suite_table, in ask, in columns )
public function FRM_DRV_main( in arg1, in arg2, in arg3, in arg4, in arg5 )
{
auto suite_table, stid, cols[], rc, rows;
# these ifs are just for backward compatibility (when function arguments were not optional)
if ( arg1 != "" ) FRM_DRV_set_script_home( arg1 );
if ( arg2 != "" ) FRM_DRV_set_data_home( arg2 );
if ( arg3 != "" ) FRM_DRV_set_default_suite_table( arg3 );
if ( arg4 != "" ) FRM_DRV_set_ask( arg4 );
if ( arg5 != "" ) FRM_DRV_set_columns( arg5 );
# column titles can be dynamically defined via columns
# by default they are in german (backwards compatibility)
if ( columns == "" )
columns = GER_COLUMNS;
# sanity check that we have at lest four cols
if ( split( columns, cols, "," ) < 4 )
{
tl_step( "columns", FAIL, "invalid parameter" );
return E_ILLEGAL_PARAMETER;
}
# find out which table is to be used
if( fail( FRM_DRV_choose_table( data_home, default_suite_table, ask, suite_table ) ) ) return getLastRc();
# ask whether retry of the run is wanted
FRM_DRV_ask_retry();
# forget the garbage from the previous run
FRM_close_all();
# open table and init iterator
if( fail( FRM_open( suite_table, columns, stid ) ) ) return getLastRc();
if( fail( FRM_get_row_count( stid, rows ) ) ) return getLastRc();
# <suite_table> must stay opened
# see below FRM_close_all_except
rc = FRM_DRV_test_suite_driver(script_home, data_home, stid, cols, rows );
FRM_close_all( );
return rc;
}
#**
#* Picks the appropriate file. If <ask> = TRUE [defult], then a
#* file browse dialog is shown to interactively pick the file. In batch
#* mode, the dialog is not shown.
#*@param dir (in) directory
#*@param name (in) file name
#*@param ask (in) (optional) TRUE/FALSE [default: TRUE]
#*@param path (out) full path name to be used
#*@return
#* E_OK: success
#* !E_OK: failure
#*/
static function FRM_DRV_choose_table ( in dir, in name, in ask, out path )
{
auto rc = E_OK;
if ( ask || ask == "" )
{
if ( fail( DDT_choose_table( join_path( dir, name ), dir, name ) ) ) return getLastRc();
}
path = join_path( dir, name, "\\" );
return E_OK;
}
#**
#* Waits for the user input (an edit field and OK/Cancel buttons) if a table
#* cell contains a specielly formatted data. The data is "specially formatted"
#* if it either begins with the question mark or with some other string as
#* defined by <code>flag</code> parameter.
#* @param tid (in) table ID
#* @param param (in) column name
#* @param msg (in) message to be displayed
#* @param val (out) value choosen (empty string indicates Cancel)
#* @param flag (in) (optional) prefix which indicates the "askable" data [default: ?]
#* @return
#* E_OK: success; <code>val</code> contains valid data
#* !E_OK: failure; do not rely on <code>val</code>
#*/
static function FRM_DRV_ask ( in tid, in param, in msg, out val, in flag )
{
auto rc, len;
if ( flag == "" )
flag = "?";
len = length( flag );
if ( fail( FRM_get( tid, param, val ) ) ) return getLastRc();
if ( length( val ) < len )
return E_OK;
if ( substr( val, 1, len ) == flag )
{
val = substr( val, len+1 );
rc = create_input_dialog( msg & ": " & val );
if ( rc != "" )
val = rc;
}
return E_OK;
}
#**
#* execute a test suite excel table.
#* @param script_home home directory for test scripts
#* @param data_home home directory for test data
#* @param stid suite_table ID ( as returned by FRM_open() )
#* @param cols
#* @param rows
#*/
static function FRM_DRV_test_suite_driver( in script_home, in data_home, in stid, inout cols[], in rows )
{
auto data_table, xtabs[];
auto table, script, testset, comment;
auto doit;
auto row;
auto i;
auto rc;
auto suite_rc;
rc = E_OK;
suite_rc = E_OK;
xtabs[stid] = FRM_get_name( stid );
wrlog_suite_start( xtabs[stid] );
# iterate through all rows
DDT_ACCESS_init( stid, "1-"& rows );
while( DDT_ACCESS_has_more( stid ) )
{
# fetch test-set data from excel table
row = DDT_ACCESS_get_next( stid );
rc = FRM_set_row( stid, row );
if ( rc != E_OK )
{
suite_rc += rc;
break;
}
rc = FRM_get( stid, cols[1], doit );
rc+= FRM_get( stid, cols[2], script );
rc+= FRM_get( stid, cols[3], table );
rc+= FRM_get( stid, cols[4], testset );
FRM_get( stid, cols[5], comment ); # comment column is not mandatory
if ( rc != E_OK )
{
report_msg( "Row " & row & " ignored." );
continue;
}
rc+= FRM_DRV_ask( stid, cols[1], "("&table&": "&testset&")? ", doit );
if ( rc != E_OK )
{
suite_rc += rc;
break;
}
if ( !Ja( doit ) )
{
report_msg( "Row " & row & " skipped." );
continue;
}
table = join_path( data_home, table, "\\" );
#script = join_path( script_home, script );
rc = FRM_DRV_ask( stid, cols[4], cols[4], testset );
if ( rc != E_OK )
{
suite_rc += rc;
break;
}
report_msg( cols[2] & ": " & script );
report_msg( cols[3] & ": " & table );
report_msg( cols[4] & ": " & testset );
if ( comment != "" )
{
report_msg( cols[5] & ": " & comment );
}
# process test set
rc = FRM_DRV_test_set_driver(script, table, testset);
suite_rc += rc;
FRM_close_all_except( xtabs );
}
DDT_ACCESS_clean( stid );
wrlog_suite_stop( xtabs[stid], suite_rc );
return suite_rc;
}
#**
#* Executes a set of tests from a specified data table by the specified script.
#* @param script (in) test driver (full path or accessable vie search path)
#* @param table (in) data table (full path name!)
#* @param testset (in) names of the tests to be executed (individual entries
#* are comma-separated; numeric ranges can be shortend by hyphen, e.g. 1-5 which
#* stands for 1,2,3,4,5; ranges can also be defined within name spaces and are
#* similarly shortened, e.g. a1-3 stands for a1,a2,a3)
#*/
public function FRM_DRV_test_set_driver(in script, in table, in testset, in comment )
{
auto test, tid;
auto via_IDX;
auto expr, msg;
auto rc, set_rc;
extern RLENGTH;
rc = E_OK;
set_rc = E_OK;
wrlog_set_start( testset );
if ( comment != "" )
{
wrlog_set_data( "DESCRIPTION", comment );
}
# NOTE!
# If testset begins with "IDX:", it indicates that test
# are defined accross rows instead of column-wise.
# For this to work correctly ALL collumns have to be
# loaded at once. Normally, only the columns specified
# by the testset are loaded.
via_IDX = ( substr( testset, 1, length( PREFIX ) ) == PREFIX);
if ( via_IDX )
{
testset = substr( testset, length(PREFIX)+1 );
rc = FRM_open( table, "<<ALL>>", tid );
}
else
{
rc = FRM_open( table, testset, tid );
}
if ( rc != E_OK )
{
wrlog_set_stop( testset, rc );
return rc;
}
DDT_ACCESS_init( table, testset );
while ( DDT_ACCESS_has_more( table ) )
{
rc = E_OK;
test = DDT_ACCESS_get_next( table );
if ( via_IDX || FRM_is_parameter( tid, test ) == E_OK )
{
wrlog_test_start( test, table, script );
if ( FRM_DRV_is_retry() && FRM_DRV_retry_lookup_log( table, test ) == 0 )
{
report_msg( "Test: " & test & "\t--> won't be retried" );
rc = 0;
}
else
{
FRM_DRV_retry_log_test1( table, test );
report_msg( "Test: " & test & "\t--> is being processed" );
if ( FRM_DRV_is_new_test_driver() )
{
if ( isCompiledModule( script & "_lib" )
|| isCompiledModule( script ) )
{
expr = sprintf( "treturn call_close \"DRV/emos_test_driver\" ( \"%s\", \"%s\", \"%s\" );", script, tid, test );
}
else
{
expr = sprintf( "treturn call_close \"%s\" ( \"%s\", \"%s\", TRUE );", script, tid, test );
}
}
else
{
expr = sprintf( "treturn call_close \"%s\" ( \"%s\", \"%s\", TRUE );", script, tid, test );
}
rc = eval( expr );
tl_step( test, rc, script & " returned rc=[" & rc & "]" );
FRM_DRV_retry_log_test2( rc );
set_rc += rc;
if ( rc == E_OK )
FRM_RES_add_test_statistics("# of successful tests" );
else
FRM_RES_add_test_statistics("# of failed tests" );
}
wrlog_test_stop( test, rc );
}
else
{
wrlog_test_start( test, table, script );
if ( fail_on_unknown_test )
{
rc = E_NOT_FOUND;
msg = sprintf( "Test \"%s\" not found", test );
tl_step( test, rc, msg );
}
else
{
rc = ""; # empty string is shown as ? in ttracx
msg = sprintf( "Test \"%s\" --> UNKNOWN, ignored", test );
report_msg( msg );
}
wrlog_test_data( "MSG", msg );
wrlog_test_stop( test, rc );
set_rc += rc;
FRM_RES_add_test_statistics("# of ignored/unknown tests" );
}
if ( rc == E_FRM_SET_STOP || rc == E_FRM_SUITE_STOP )
{
DDT_ACCESS_clean( table );
wrlog_set_stop( testset, rc );
return rc;
}
}
DDT_ACCESS_clean( table );
wrlog_set_stop( testset, set_rc );
return set_rc;
}
#/**
#* The main lop for driving the test navigation.
#* @param lib (in) library that contains application-specific test navigation functions
#* @param tid (in) table ID of the Excel table that contains the sepcified <code>test</code>
#* @param test (in) name of the test (i.e. column) that is to be processed
#* @return E_OK if successfull, else failure
#*/
public function FRM_DRV_test_driver ( in lib, in tid, in test )
{
auto step;
auto mode;
auto step_rc;
auto rc;
auto i;
rc = load_drv_lib( lib, 0, 1 );
if ( rc != E_OK )
return rc;
rc+= AUT_DRV_report ( tid, test );
rc+= AUT_DRV_load ( tid, test );
rc+= AUT_DRV_init_steps( tid, test );
if ( rc != E_OK )
{
return rc;
}
step_rc = E_OK;
while( FRM_STP_has_more_steps( tid, test ) )
{
rc = FRM_STP_get_next_step( tid, test, step, mode );
if ( rc == E_FILE_EOF )
{
break;
}
if ( rc == E_FRM_TEST_STOP || rc == E_FRM_SET_STOP || rc == E_FRM_SUITE_STOP )
{
return rc;
}
if ( rc != E_OK )
{
step_rc++;
continue;
}
do
{
rc = AUT_DRV_call_block( tid, test, step, mode );
if ( rc == E_FRM_NOT_IMPLEMENTED )
{
step_rc++;
tl_step( step, rc, "Test block [" & step & "] not implemented yet" );
wrlog_block_stop ( step, "unimplemented" );
}
else if ( rc == E_FRM_UNKNOWN )
{
step_rc++;
tl_step( step, rc, "Test block [" & step & "] unknown" );
wrlog_block_stop ( step, "unknown" );
}
else
{
rc = FRM_DRV_handle_processed_block( step, test, rc, step_rc );
switch( rc )
{
case E_FRM_TEST_STOP:
case E_FRM_SET_STOP:
case E_FRM_SUITE_STOP:
return rc;
}
}
} while ( rc == E_FRM_RETRY );
}
return step_rc;
}
#/**
#* Formats the report for unimplemented test blocks. Note that this function
#* increases the inout variable <code>frm_rc</code> by 1.
#* @param block (in) the name of the test block
#* @param frm_rc (inout) the status variable (increased by 1 upon the exit)
#*/
public function FRM_DRV_handle_unimplemented_block( in block, inout frm_rc )
{
frm_rc++;
tl_step( block, frm_rc, "Test block [" & block & "] not implemnted" );
wrlog_block_stop ( block, "unimplemented" );
return frm_rc;
}
#/**
#* Formats the report for unknown test blocks. Note that this function
#* increases the inout variable <code>frm_rc</code> by 1.
#* @param block (in) the name of the test block
#* @param frm_rc (inout) the status variable (increased by 1 upon the exit)
#*/
public function FRM_DRV_handle_unknown_block( in block, inout frm_rc )
{
frm_rc++;
tl_step( block, frm_rc, "Test block [" & block & "] unknown" );
wrlog_block_stop ( block, "unknown" );
}
#/**
#* Formats the report for procesed test blocks. Note that this function
#* increases the inout variable <code>frm_rc</code> by 1 in case of <code>rc!=0</code>.
#* @param block (in) the name of the test block
#* @param test (in) the name of the test case
#* @param rc (in) status returned by the processed test block
#* @param frm_rc (in) the current value of the status variable
#* @return 0 to continue with the test case, 1 to stop the execution of the test case
#*/
public function FRM_DRV_handle_processed_block( in block, in test, in rc, inout frm_rc )
{
auto rc2;
wrlog_block_stop ( block, rc );
if ( rc != E_OK )
{
tl_step( block, rc, "Test block=[" & block & "], rc=[" & rc & "]" );
rc2 = create_list_dialog( "Test block failed", block, error_modes );
# "1 - Continue,2 - Stop test,3 - Stop test set,4 - Stop test suite,5 - Retry block"
switch( substr( rc2, 1, 1 ) )
{
case 1: frm_rc = rc; break;
case 2: frm_rc = E_FRM_TEST_STOP; break;
case 3: frm_rc = E_FRM_SET_STOP; break;
case 4: frm_rc = E_FRM_SUITE_STOP; break;
case 5: frm_rc = E_FRM_RETRY; break;
default: # either batch mode or Cancel
frm_rc = (def_error_mode == E_FRM_CONTINUE) ? rc : def_error_mode;
}
return frm_rc;
}
return E_OK;
}
#/**
#* Loads driver libs.
#* <p>NOTE1<br>
#* Each invocation of LINK|LINA|LINX instruction will cause a new "reload"
#* of the specified driver library. This is necessary in order to ensure
#* proper loading when multiple divers are used (big projects tend to use
#* this strategy). If you want to skeep such unecessary reloading, you may
#* remove the name of the driver from the LINK commands wherever you are
#* sure that the proper driver has already been loaded, for example
#* <pre>
#* LINK~drv/xxx~~1_1
#* LINK~~~1_2
#* LINK~~~1_3
#* </pre>
#* <p>NOTE2<br>
#* For compatibility reasons with older projects you should name your new
#* driver libraries using the "_lib" suffix. If you preserve the rest of
#* the driver name (e.g. if "DRV/xxx" is changed to "DRV/xxx_lib", then you
#* need not modify anything in your Excel tables because this routine will
#* automatically append "_lib" to all names that do not use this suffix.
#*/
static function load_drv_lib ( in lib, in p1, in p2 )
{
auto rc;
if ( lib == "" )
return E_OK;
if ( isCompiledModule( lib ) )
return reload( lib, p1, p2 );
else
return reload( lib & "_lib", p1, p2 );
}
#/**
#* Executes several test sets as defined by the parameter <code>callArr[]</code>.
#* <p>NOTE1<br>
#* Input array must be a two-dimensional array. First dimension must be sequentially
#* indexed from 0 onwards. The second dimension must be sequentially numbered from
#* 0 onwards where 0 holds "test driver name", 1 hodls "test table name", and 2 holds
#* "test set name". The easiest way to initialise such array in the callong script
#* is via the following construct:
#* <pre>
#* static callArr[] = {
#* { "drv/main", "table1.xls", "1-5" }
#* ,{ "drv/main", "table2.xls", "1-3" }
#* ,{ "drv/xxxx", "table2.xls", "3-9" }
#* };
#* </pre>
#* @param callArr (inout) array contianing test set instructions (see above)
#* @return E_OK if success else error
#*/
public function FRM_DRV_execute_set_array( inout callArr[] )
{
extern DATA_HOME;
auto rc, rc2;
auto driver, table, set;
auto i, count=0;
for (i in callArr ) count++;
if ( count%3 != 0 )
{
# malformed input array (# of elements not the multipe of 3)
return E_ILLEGAL_PARAMETER;
}
count/=3;
rc2 = 0;
FRM_close_all();
for (i=0; i<count; i++)
{
driver = callArr[i,0];
table = callArr[i,1];
set = callArr[i,2];
wrlog_set_start( set );
if ( driver == "" || callArr[i,1] == "" || set == "" )
rc = E_ILLEGAL_PARAMETER;
else
rc = FRM_DRV_test_set_driver( driver, table, set );
wrlog_set_stop( set, rc );
if( rc == E_FRM_SET_STOP || rc == E_FRM_SUITE_STOP )
{
rc2 = rc;
break;
}
rc2 += rc;
}
FRM_close_all();
return rc2;
}