Difference between revisions of "Studio:Using Scripts to Simulate Missing Software Units"

From STRIDE Wiki
Jump to: navigation, search
(New page: Category:Scripting)
 
Line 1: Line 1:
 +
==Perl===
  
 +
===TestScript.pl===
  
 +
<source lang="perl">
 +
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";
 +
}
 +
</source>
 +
 +
===LeapYearMock.pl===
 +
 +
<source lang="perl">
 +
# 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";
 +
}
 +
 +
</source>
 +
 +
==JScript===
 +
 +
===TestScript.js===
 +
<source lang="javascript">
 +
 +
// 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";
 +
}
 +
</source>
 +
 +
===LeapYearMock.js===
 +
<source lang="javascript">
 +
// 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";
 +
}
 +
 +
 +
</source>
 
[[Category:Scripting]]
 
[[Category:Scripting]]

Revision as of 16:30, 6 March 2008

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";
}