OSI script for data exchange
There are many ways for defining data exchanges. Here, some examples are provided in order to illustrate several possibilities. In order to provide OSI functions overloading default implementations in TestBrowser , those have to be provided in one or more files which are stored in the same directory.
When running TestBrowser , those function are loaded automatically, when the directory path has been provided in ODABA option or environment variable OSI_Library. In order to provide user defined OSI functions in OShell, one has to load those functions in addition as shown below.
In order to refer to external data sources, a file description for import/export may be defined. This setting is optional, since TestBrowser does provide dummy functions for Import/export, only, which have to be overloaded in any case. Those import/export functions define the way to refer to external files. The setting for IMPEXP_DEF is required for the example, only.
OSI script language provides many other features, which cannot be illustrated here. For more information see ODABA Script Interface .
// set OSI library path
set OSI_Library=%cd%/TestBrowser/osi/*.osi
// set external file description
set IMPEXP_DEF=%cd%/TestBrowser/osi/Imports.fsc
// OShell laoding user-defined OSI functions
// data source has to be opened first
cd TBDat
// activate user defined osi functions from OSILibrary path (OShell.ini)
osi do
dictionary.loadOSILibraries;
end
The export example creates a simple CSV output file filled with data from different levels in the test case hierarchy.
// the function overwrites the default implementation in TestBrowser resource database
// and is called when pressing the export button in the Test Browser application
// (above test suite tree).
collection bool DirEntry::ExportToCSV (string sPath )
{
VARIABLES
SET < VOID > exp;
PROCESS
exp.openExtern(objectSpace,sPath,Option("IMPEXP_DEF").toString,"",odaba::AccessModes::Write,false);
ExportToCSV_intern(exp);
exp.closeAll;
FINAL
return(true);
};
collection bool DirEntry::ExportToCSV_intern (set< VOID > &exp )
{
top;
while ( next ) {
if ( test )
ExportEntry(exp);
entries.ExportToCSV_intern(exp);
}
return(true);
};
collection bool DirEntry::ExportEntry (set< VOID > &exp)
{
exp.initializeInstance;
if ( !selected ) {
exp.test = "test";
exp.isTest= "isTest";
exp.dataRequirements= "dataRequirements";
exp.result= "result";
exp.testDescription= "testDescription";
exp.testCase = "testCase";
exp.caseDescription= "caseDescription";
exp.suiteDescription = "suiteDescription";
exp.suiteDescription = "suiteDescription";
exp.comment = "comment";
exp.save;
} else {
exp.test = displayname;
exp.isTest= "true";
exp.dataRequirements=(GetAttribute("Data"));
exp.result=GetAttribute("Result");
exp.testDescription=ReadData("suite");
exp.testCase = par(0).displayname;
exp.caseDescription = par(0).ReadData("suite");
exp.testSuite = par(0).par(0).displayname;
exp.suiteDescription = par(0).par(0).ReadData("suite");
exp.comment = GetAttribute("Comment");
exp.save;
}
The import example loads data from an CSV file, which defines a hierarchical structure for grouping test cases in test suites. Tests cases are provided based on software requirements, e.g. this is an example for requirement driven test. It is a bit more complex than the export example, but it demonstrates several features provided by OSI.
// The function overwrites the default implementation in TestBrowser resource database
// and is called when pressing the import button in the Test Browser application
// (above test suite tree).
//
// The function imports test cases from a requirements csv file with following columns:
// id - requirement identifier
// description - requirement description
// testCatecory - coded test category (see description below)
// reviewState - Requirement review state
// lastModified - last modification of requirement
// This names ate taken from CSV file head line or from external file description file.fsc
// The test suite hietarchy is setup according to testCategory value, which is defined
// for each line in the import file:
// Hn_title - Heading level (n) with optional title (title)
// Tn - Test case with test priority (n)
// TH - table heading column (number of table columns results from number of following
// TH records. Each line in a table defines a test case
// TCn - Table cell data, where the first column in a table line defines the test case
// priority (n)
// Table lines result in one test case, but information is stored for all cells in the test
// intend, which is filled with requirement description(s).
collection bool DirEntry::ImportFromCSV (string sPath )
{
VARIABLES
extern ImportProgress importProgress;
SET < VOID > imp;
SET < DirEntry > &curSuite = self;
String sCategory();
string description;
string title;
string category;
string id;
string str;
string type;
string sType;
string sTotal;
int32 current;
int32 priority = 0;
int32 level = 0;
int32 curLevel = 0;
int32 colCount;
int32 curColumn;
string(100) colTitle[20];
bool bTableHeader = false;
bool bTable = false;
bool bHeader = false;
bool bTest = false;
PROCESS
imp.openExtern(objectSpace,sPath,Option("IMPEXP_DEF").toString,"",odaba::AccessModes::Read,true);
sTotal = '/' + (string)imp.count;
while ( imp.next ) {
++current;
if ( current%10 == 0 )
importProgress.Progress((string)current + sTotal);
sCategory.assign(imp.testCategory);
category = sCategory.splitTop('_');
title = sCategory;
type = category.left(1);
sType = category.mid(1,1);
switch ( type ) {
case 'H' : level = category.mid(1).toInteger;;
while ( level > curLevel + 1 ) {
curSuite &= curSuite.entries;
++curLevel;
str = "Missing headline level " + (string)curLevel;
curSuite.CreateSuite("",0,curLevel,str,"",imp);
Message(str);
}
if ( level == curLevel + 1 ) {
curSuite &= curSuite.entries;
curLevel = level;
} else while ( level < curLevel ) {
curSuite &= curSuite.parent;
--curLevel;
}
id = imp.id;
description = imp.description;
priority = 0;
bTable = false;
bTableHeader = false;
bTest = false;
bHeader = true;
break;
case 'T' : if ( !bTest ) {
curSuite &= curSuite.entries;
++curLevel;
bTest = true;
if ( !curSuite.positioned ) curSuite.tryGet(0);
}
bHeader = false;
sType = category.mid(1,1);
switch ( sType ) {
case 'H' : if ( !bTableHeader ) {
bTableHeader = true;
colCount = 0;
bTable = false;
if ( curSuite.positioned ) {
if ( curSuite.entries.tryGet("0") )
curSuite.entries.Delete;
if ( curSuite.entries.tryGet("1") )
curSuite.entries.Delete;
}
}
colTitle[colCount] = imp.description;
++colCount;
break;
case 'C' : if ( bTableHeader || bTable ) {
bTableHeader = false;
bTable = true;
if ( curColumn == 0 ) {
id = imp.id;
priority = category.mid(2).toInteger;
}
description += colTitle[curColumn] + ': ' + imp.description + '\n';
++curColumn;
} else
Message("Missing table header before column with ID: " + imp.id);
break;
default : priority = category.mid(1).toInteger;
id = imp.id;
description = imp.description;
bTable = false;
bTableHeader = false;
}
break;
}
if ( type == 'H' || type == 'T' ) {
if ( bHeader ||
(bTest && !bTable && !bTableHeader) ||
(bTable && curColumn == colCount) )
{
if ( bTable )
curSuite &= curSuite.entries;
curSuite.CreateSuite(id,priority,curLevel,title,description,bHeader,imp);
if ( bTable )
curSuite &= curSuite.parent;
description = "";
title = "";
id = "";
curColumn = 0;
}
}
}
imp.closeAll;
FINAL
return(true);
};
collection bool DirEntry::CreateSuite (string id, int32 priority, int32 level, string title, string description, bool bHeader, set< VOID > &imp )
{
top;
while ( next )
if ( GetAttribute("ID") == id )
break;
if ( !positioned ) {
Create(parent.FullPath,(string)NextNumber(count-2),true,false);
if ( !bHeader ) {
entries.Create(FullPath,"0",true,true);
entries.SetAttribute("Result","success");
entries.Create(FullPath,"1",true,true);
entries.SetAttribute("Result","error");
}
}
WriteData("suite",description);
if ( id != "" ) {
SetAttribute("ID",id);
if ( bHeader )
SetAttribute("Header",(string)level);
else
SetAttribute("Priority",(string)priority);
if ( title != "" )
SetAttribute("Title",title);
SetAttribute("ReviewState",imp.reviewState);
SetAttribute("LastModified",imp.lastModified);
}
displayname = DisplayName;
return(true);
};