Using Test Doubles: Difference between revisions

From STRIDE Wiki
Jump to navigation Jump to search
Line 56: Line 56:


==Creating Double Intercepts in the IM==
==Creating Double Intercepts in the IM==
If a function has been configured as a double candidate using SCL as outlined in the above step, then the next step is to compile and bind using [[Build_Tools|STRIDE build tools]] and create the IM that contains the intercept for the double function. The options to [[S2sinstrument|s2sinstrument]] have been updated to support the function double feature as follows:
If a function has been configured as a double candidate using SCL as outlined in the above step, then the next step is to compile and bind using [[Build_Tools|STRIDE build tools]] and create the IM that contains the intercept for the double function. The options to [[s2sinstrument]] have been updated to support the function double feature.


{| border="1" cellspacing="0" cellpadding="10" style="align:left;" 
By default (see [[s2sinstrument]] for details) the IM generated code will contain interceptor code for intercept-able functions there is not need to specify any special IM options.
| '''Option'''
| '''Change'''
| '''Notes'''
|-
| '''--default_mode'''=<mode>[#<group_id>]
| Deprecated
| Use the new format below.
|-
| '''--default_mode'''=<mode>
| New
| Optional. When present, sets the default generation mode. If not present the <mode> is assumed to be “I” for intercept-able functions and “S” for all others. <br>
The format of the <mode> is "SPI[T]", where:<br>
“S” – stub<br>
“P” – proxy<br>
“I” – intercept<br>
“T” – trace
|-
| '''--mode'''=<mode>[#<group_id>] (<interface>[,<interface>…])
| Deprecated
| Use the new format below.
|-
| '''--mode'''=<mode>(<interface>[,<interface>…])
| New
| Interface specific generation mode. The <mode> is the same as above. The <interface> is an interface name.<br>
This option could be repeated as many times as needed. It overrides any --default_mode option otherwise in effect.
|}


Where the allowed mode combinations are:
{| border="1" cellspacing="0" cellpadding="10" style="align:left;" 
| '''S'''
| '''P'''
| '''I'''
| '''T'''
| '''Notes'''
|-
| X
|
|
|
| Generate Stub
|-
|
| X
|
|
| Generate Proxy
|-
|
|
| X
|
| Generate Intercept for a Function Double (see '''''Note''''' below)
|-
|
| X
| X
|
| Generate Intercept for Dynamic Delegate
|-
|
|
| X
| X
| Generate Intercept for Trace Delegate
|-
|
| X
| X
| X
| Generate Intercept for a Dynamic Delegate with Tracing
|}
'''''Note:''''' Currently the only option that supports Function Doubles is the "I" option ''by itself''. Any other option combinations will not allow the double substitution at run-time as outlined in the next step. Also note that the absence of any options will default to the "I" option alone per interface.





Revision as of 00:22, 20 March 2009

Introduction

The Function Double feature provides a means for intercepting C language functions on the target, and directing the call to a substitute function with identical parameters and return value. The use case is a unit test where the function under test uses a ("C") function during its execution, and this dependency is simulated by a substitute or double function during testing. The unit test is able to control the substitution of the dependency during run time, and thereby verify the behavior of the function under test. The following sample illustrates the relationship of the function under test and a dependency:

// depend.h
int depend(int x);
// depend.c
#include "depend.h"
 
int depend(int x)
{
    return x + x;
}
// test.h
int test(int x, int y);
// test.c
#include "test.h"
#include "depend.h"
 
int test(int x, int y)
{
    return depend(x) * y;
}

In the above sample, test() is the function under test and depend() is a dependency candidate for doubling.


The steps required to achieve doubling of a dependency function are as follows:

  1. Configure the double parameters using SCL pragmas
  2. Create the double intercepts in the IM
  3. Switch to/from the double function during runtime

Configuring the Double Using SCL

The syntax of the scl_func and scl_function pragmas have been expanded to include new optional attributes that allow the specification of function interception parameters.

In the above sample, depend() needs to be SCL captured and enabled for interception in a matter to be doubled.

// depend_scl.h
#include "depend.h"

#pragma scl_function(depend, "DEFINITION", "IMPLICIT", "TEST_GROUP")

Creating Double Intercepts in the IM

If a function has been configured as a double candidate using SCL as outlined in the above step, then the next step is to compile and bind using STRIDE build tools and create the IM that contains the intercept for the double function. The options to s2sinstrument have been updated to support the function double feature.

By default (see s2sinstrument for details) the IM generated code will contain interceptor code for intercept-able functions there is not need to specify any special IM options.


Once the IM has been successfully created, the source file containing the depend() implementation must be altered by defining the Group ID and including the generated Intercept Module delegate mangling header file (xxxIM.h):

// depend.c
#include "depend.h"
/* define the Group ID before including the IM header */
#define TEST_GROUP
#include "strideIM.h"

int depend(int x)
{
    return x + x;
}

Switching the Double Function During Runtime

The test unit will have access to the following STRIDE runtime macros for substituting a stub function for a double candidate.

srDOUBLE_GET(fn, pfnDbl)
srDOUBLE_SET(fn, fnDbl)

Where:

  • fn is the function qualified by scl_function or scl_func as a dependency candidate, as above.
  • pfnDbl is a pointer to a object of type srFnDbl_t, declared to hold the current value of the active double function.
  • fnDbl is a function that is to be the current active double. The function passed in should always match the signature of the dependency candidate specified by fn.

Note: the initial value of the current active double is always the dependency candidate function.

These macros are defined in the STRIDE runtime header file sr.h. The following example shows how they are used in a C++ test unit:

#include <srtest.h>

extern "C" int depend_dbl(int a) { return a * a; }

class Test: public stride::srTest
{ 
public:

    Test()
    {
        srDOUBLE_GET(depend, &m_depend_dbl);
        srDOUBLE_SET(depend, depend_dbl);
    }

    ~Test()
    {
        srDOUBLE_SET(depend, m_depend_dbl);
    }

    int test1(void) { return test(1, 2); }
    int test2(void) { return test(5, 6); }

private:
   srFnDbl_t m_depend_dbl;
};
 
#ifdef _SCL
#pragma scl_test_class(Test)
#endif