Studio:Using Scripts to Simulate Missing Software Units
Jump to navigation
Jump to search
Perl
TestScript.pl
use strict;
use Win32::OLE;
Win32::OLE->Option(Warn => 3);
# Create a new test in the parent suite
my $test = $main::testSuite->Tests->Add("Leap Year Positive Test");
# Start the mock script running asynchronously
StartMockScript("LeapYearMock.pl");
# Wait for the mock script to register as the owner of the function
WaitForOwnerRegistration("IsLeapYear");
# Initialize the test input values
my @input = (1600, 1604, 1996, 2000);
# Get the function user interface
my $f = $main::ascript->Functions->Item("IsLeapYear")->User;
# Iterate through the memebers of @input
for my $i (0..$#input)
{
# Set the parameter value
$f->ParameterList->{uYear} = $input[$i];
# Call the function synchronously; the STRIDE runtime will route the call to the
# currently registered function owner
$f->Call();
# Test the return value;
# note that the value is returned as the name of the enumerator
if ($f->ReturnValue eq "YES") {
$test->{Status} = "PASS";
}
else {
$test->{Status} = "FAIL";
last;
}
}
# Notify the mock script that it should end
NotifyStopMockScript("LeapYearMock.pl");
#---------------------------------
# Starts a script in the current workspace running asynchronously
#
# Param:
# scriptName - Name of the script to be run (name with extension only; no path)
# Notes:
# - The specified script must be a member of the current Studio Workspace
# - The shutdown notification trigger file is deleted if it exists
#---------------------------------
sub StartMockScript()
{
my $scriptName = shift;
# make sure trigger file isn't there
unlink GetTriggerFileName($scriptName);
my $file = $main::studio->Workspace->Files->Item($scriptName);
if (!$file->IsRunning) {
$file->RunNonBlocking();
}
}
#---------------------------------
# Notifies an asynchronously running script that it should end
#
# Param:
# scriptName - Name of the script to notify (name with extension only; no path)
# Notes:
# - The specified script must be a member of the current Studio Workspace<br>
# - No notification occurs if the specified script isn't currently running
#---------------------------------
sub NotifyStopMockScript()
{
my $scriptName = shift;
my $file = $main::studio->Workspace->Files->Item($scriptName);
if ($file->IsRunning) {
# create trigger file informing mock script to end
my $triggerName = GetTriggerFileName($scriptName);
open FILE, ">", $triggerName;
}
}
#---------------------------------
# Waits for the Owner registration of the specified function
#
# Param:
# functionName - Name of the function to be waited upon
# Notes:
# - Once the function Owner is registerd, it can be called through the STRIDE runtime
# - The function gives up waiting after 1000 ms
#---------------------------------
sub WaitForOwnerRegistration()
{
my $functionName = shift;
my $f = $main::ascript->Functions->Item($functionName)->Owner;
# note: time is expressed in seconds in perl
my $startTime = time;
do {
$main::ascript->Sleep(100);
} while (!$f->IsRegistered && time - $startTime < 2);
}
#---------------------------------
# Returns the full path of a shutdown trigger file used to communicate between
# scripts running on different threads.
#
# Param:
# scriptName - Name of the script to be notified
# Notes:
# - By convention, we use the existence of a file to notify an asynchronously running
# script that it should end. The file is written in the current workspace directory.
#---------------------------------
sub GetTriggerFileName()
{
my $scriptName = shift;
return $main::studio->Workspace->Path."\\__$scriptName.shutdown";
}
LeapYearMock.pl
# standard STRIDE stuff
use strict;
use Win32::OLE;
Win32::OLE->Option(Warn => 3);
# get the owner instance of the function
my $f = $main::ascript->Functions->Item("IsLeapYear")->Owner;
# Register the script as the owner of the IsLeapYear() function.
# Now all calls to IsLeaprYear() will be routed to this implementation by
# the STRIDE runtime.
$f->Register();
# This causes ascript.WaitForEvent() to time out every 500 ms.
# We do this so that in the message loop below, the while() test
# will be evaluated when no messages are arriving.
$main::ascript->{WaitTimeoutPeriod} = 500;
do {
# Wait for the runtime to notify us that an event has been routed to this script
my $e = $main::ascript->WaitForEvent();
if ($e->Type eq "FunctionOwner" && $e->Name eq "IsLeapYear") {
# Get the passed-in parameter
my $uYear = $e->ParameterList->uYear;
# Call the mock function; set the Owner function return value
$e->{ReturnValue} = IsLeapYear($uYear);
# Return from the function call.
$e->Return();
}
# uncomment the following lines to see the timeout error generated when no
# envent is received after 500 ms of waiting
#else {
# $main::studio->Output->PrintMessage($e->Type." - ".$e->Name);
#}
} while (!IsTimeToQuit());
# Here we retrieve the value of a symbol #defined in a .h file seen by the
# STRIDE compiler
my $FirstGregorianYear = $main::ascript->Constants->Item("FIRST_GREGORIAN_YEAR");
#---------------------------------
# This is our script implementation of the fucntion we want to simulate (mock)
#
# Param:
# uYear - The year to be tested
# Return:
# String "YES" or "NO"
# Notes:
# - Any year that is less than FIRST_GREGORIAN_YEAR is considered not a leap year
#---------------------------------
sub IsLeapYear()
{
# get the passed-in argument
my $uYear = shift;
if ($uYear < $FirstGregorianYear) {
return "NO";
}
if ($uYear % 4) {
return "NO";
}
if ($uYear % 100) {
return "YES";
}
if ($uYear % 400) {
return "NO";
}
return "YES";
}
#---------------------------------
# Returns a value indicating whether the script should end
#
# Return:
# 0 -> the script should not end; 1 -> the script should end
# Notes:
# - By convention, we use the existence of a specific file to notify an asynchronously running
# script that it should end. The file is written in the current workspace directory.
# - If the trigger file exists it is deleted
#---------------------------------
sub IsTimeToQuit()
{
# check for existence of trigger file
my $scriptName = $main::ascript->ScriptName;
my $triggerName = GetTriggerFileName($scriptName);
# check for file existence
if (-e $triggerName)
{
# delete the trigger file
unlink $triggerName;
return 1;
}
return 0;
}
#---------------------------------
# Returns the full path of a shutdown trigger file used to communicate between
# scripts running on different threads
#
# Param:
# scriptName - Name of the script to be notified
# Return:
# String
#---------------------------------
sub GetTriggerFileName()
{
my $scriptName = shift;
return $main::studio->Workspace->Path."\\__$scriptName.shutdown";
}
JScript
TestScript.js
// create a new test in the parent suite
var test = testSuite.Tests.Add("Leap Year Positive Test");
// start the mock script running asynchronously
startMockScript("LeapYearMock.js");
// wait for the mock script to register as the owner of the function
waitForOwnerRegistration("IsLeapYear");
// initialize the test input values
var arInput = new Array(1600, 1604, 1996, 2000);
// get the function user instance
var f = ascript.Functions.Item("IsLeapYear").User;
// iterate through the members of arInput
for (var nIndex in arInput) {
// set the parameter value
f.ParameterList.uYear = arInput[nIndex];
// call the function synchronously; the STRIDE runtime will route the call to the
// currently registered function owner
f.Call();
// test the return value;
// note that the value is returned as the name of the enumerator
if (f.ReturnValue == "YES") {
test.Status = "PASS";
}
else {
test.Status = "FAIL";
break;
}
}
// notify the mock script that it should end
notifyStopMockScript("LeapYearMock.js");
/**
* Starts a script in the current workspace running asynchronously
*
* @notes
* - The specified script must be a member of the current Studio Workspace<br>
* - The shutdown notification trigger file is deleted if it exists
* @param scriptName Name of the script to be run (name with extension only; no path)
*/
function startMockScript(scriptName)
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
// make sure that the trigger file isn't there
var triggerName = GetTriggerFileName(scriptName);
if (fso.FileExists(triggerName)) {
// delete the shutdown trigger file if it exists
fso.DeleteFile(triggerName);
}
// get the stride file object from studio
var file = studio.Workspace.Files.Item(scriptName);
if (!file.IsRunning) {
// start the script running in a separate thread
file.RunNonBlocking();
}
}
/**
* Notifies an asynchronously running script that it should end
*
* @notes
* - The specified script must be a member of the current Studio Workspace<br>
* - No notification occurs if the specified script isn't currently running
* @param scriptName Name of the script to notify (name with extension only; no path)
*/
function notifyStopMockScript(scriptName)
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
// get the stride file object from studio
var file = studio.Workspace.Files.Item(scriptName);
if (file.IsRunning) {
var triggerName = GetTriggerFileName(scriptName);
// create the trigger file; used to notify the script running asynchronously
fso.CreateTextFile(triggerName);
}
}
/**
* Waits for the Owner registration of the specified function
* @notes
* - Once the function Owner is registerd, it can be called through the STRIDE runtime<br>
* - The function gives up waiting after 1000 ms
* @param functionName
* Name of the function to be waited upon
*/
function waitForOwnerRegistration(functionName)
{
var f = ascript.Functions.Item(functionName).Owner;
var timeStart = new Date();
do {
ascript.Sleep(100);
var timeNow = new Date();
} while (!f.IsRegistered & timeNow - timeStart < 1000);
}
/**
* Returns the full path of a shutdown trigger file used to communicate between
* scripts running on different threads.
* @notes
* - By convention, we use the existence of a file to notify an asynchronously running
* script that it should end. The file is written in the current workspace directory.
* @param scriptName Name of the script to be notified
*/
function GetTriggerFileName(scriptName)
{
return studio.Workspace.Path + "\\__" + scriptName + ".shutdown";
}
LeapYearMock.js
// get the owner instance of the function
var f = ascript.Functions.Item("IsLeapYear").Owner;
// register this script as the owner of the IsLeapYear() function
// now all calls to IsLeapYear() will be routed to this implementation by
// the STRIDE runtime
f.Register();
// This causes ascript.WaitForEvent() to timeout every 500 ms.
// We do this so that in the message loop below, the while() test
// will be evaluated when no messages are arriving
ascript.WaitTimeoutPeriod = 500;
do {
// wait for runtime to notify us that an event has been routed to this script
var e = ascript.WaitForEvent();
switch (e.Type) {
case "FunctionOwner":
if (e.Name == "IsLeapYear") {
// get the passed-in parameter
var uYear = e.ParameterList.uYear;
// call the mock function; set the Owner function return value
e.ReturnValue = IsLeapYear(uYear);
// return from the function call
e.Return();
}
break;
/* uncomment these lines to see the timeout errors generated when no
event is received after 500 ms of waiting
default:
studio.Output.PrintMessage(e.Type+" - "+e.Name);
*/
}
} while (!IsTimeToQuit());
// Here we retrieve the value of a symbol #defined in a .h file seen by the
// STRIDE compiler
var firstGregorianYear = ascript.Constants.Item("FIRST_GREGORIAN_YEAR").Value;
/**
* This is our script implementation of the function we want to simulate (mock)
*
* @param uYear The year to be tested
* @return
* String "YES" or "NO"
* @notes
* - Any year less than FIRST_GREGORIAN_YEAR is considered not a leap year
*/
function IsLeapYear(uYear)
{
if (uYear < firstGregorianYear) {
return "NO";
}
if (uYear % 4) {
return "NO";
}
if (uYear % 100) {
return "YES";
}
if (uYear % 400) {
return "NO";
}
return "YES";
}
/**
* Returns true or false, indicating whether this script should end
*
* @notes
* - By convention, we use the existence of a specific file to notify an asynchronously running
* script that it should end. The file is written in the current workspace directory.<br>
* - If the trigger file exists it is deleted
*/
function IsTimeToQuit()
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
// check for existence of trigger file
var scriptName = ascript.ScriptName;
if (fso.FileExists(GetTriggerFileName(scriptName))) {
// delete the trigger file
fso.DeleteFile(GetTriggerFileName(scriptName));
return true;
}
return false;
}
/**
* Returns the full path of a shutdown trigger file used to communicate between
* scripts running on different threads.
* @notes
* - By convention, we use the existence of a file to notify an asynchronously running
* script that it should end. The file is written in the current workspace directory.
* @param scriptName Name of the script to be notified
*/
function GetTriggerFileName(scriptName)
{
return studio.Workspace.Path + "\\__" + scriptName + ".shutdown";
}