Next Previous Contents

3. Examples

Before continuing it is worthwhile noting that the examples in this chapter are bundled within the examples directory of the TESS distribution (along with a Makefile and baseline test.ref output), and that they have been written under the assumption that an operational version of TESS is installed on your system.

It should also be noted that a TESS script is merely a S-Lang script which has, somewhere along its execution path, loaded TESS. Normally S-Lang scripts are named with a .sl suffix, however the author has adopted the convention of suffixing them with .t instead. Not only does this serve as a useful mnemonic, it also prevents tests from being accidently loaded by S-Lang through its default script loading mechanism (fostering the use of nearly identical names for both test scripts and the package components which they exercise).

3.1 Scripts

Let's begin our example by augmenting the add() function defined above with a corresponding subtract() function, and migrating the definition of both into a S-Lang script named sillymath.sl, as follows:

        define add()
        {
           variable i, j;
           if (_NARGS < 2) usage("add(i,j)");
           (i,j) = ();
           return i+j;
        }

        define subtract()
        {
           variable i, j;
           if (_NARGS < 2) usage("subtract(i,j)");
           (i,j) = ();
           return i - j;
        }
Two TESS scripts which more thoroughly exercise sillymath.sl, then, are:
add.t: 

    require("tess");

    tess_invoke(1, &add);
    tess_invoke(1, &add, "hi there!");
    tess_invoke(1, &add, 2);
    tess_invoke(0, &add, 2, 3);

    tess_invoke(1, &add, "one", 2);
    tess_invoke(0, &add, "hello", " there!");
subtract.t:

    require("tess");

    variable f = &subtract;
    tess_invoke(1, f);
    tess_invoke(1, f, "hi there!");
    tess_invoke(1, f, 2);
    tess_invoke(0, f, 2, 3);

    tess_invoke(1, f, "one", 2);
    tess_invoke(1, f, "hello", " there!");

3.2 Output

The first of these should emit feedback resembling that given below. Since the result of add.t closely resembles that of subtract.t (differing only in that case 5 signals an exception in one but not the other, since string subtraction is undefined while string addition is equivalent to concatenation) we omit output from the latter.

    Usage: add(i,j)

    Test Case 1: add: PASSED (SHOULD signal error, DID)

    Usage: add(i,j)

    Test Case 2: add: PASSED (SHOULD signal error, DID)

    Stack Contents:
    (0)[String_Type]:hi there!

    Usage: add(i,j)

    Test Case 3: add: PASSED (SHOULD signal error, DID)

    Stack Contents:
    (0)[Integer_Type]:2


    Test Case 4: add: PASSED (SHOULD NOT signal error, DID NOT)

    Stack Contents:
    (0)[Integer_Type]:5

    S-Lang Error: Type Mismatch: String_Type + Integer_Type is not possible

    Test Case 5: add: PASSED (SHOULD signal error, DID)


    Test Case 6: add: PASSED (SHOULD NOT signal error, DID NOT)

    Stack Contents:
    (0)[String_Type]:hello there!


    =============== add Test Summary ===============

                Number of Failures: 0
                Number of Passes  : 6

3.3 Analysis

In the above tests the absence of an explicit ERROR_BLOCK, and the cleaner code which results, should be immediately apparent. For example, add.t contains one fewer non-blank lines than does the example in section Motivation, while tripling the number of cases tested (6 versus 2). Also revealed is the fact that tess_invoke() is the single most important function in the interface.

tess-common.sl

A more subtle point of interest is that sillymath.sl does not appear to be loaded by either test script. How, then, do they function? The answer is that the evalfile() has been pushed into a file tess-common.sl, which TESS will transparently load if found within the current directory at startup.

This exploits a common pattern within test suites, namely that prior to testing any component within a package a test script must first load the package itself. Furthermore, tess-common.sl can be used to define variables, data structures, or functions that might be commonly used amongst all test scripts within a given suite.

Type Mismatch Exceptions

Consider the case

        tess_invoke(1, &add, "one", 2);
defined for add() (and the similar test defined for subtract()), which attempts to add an Integer_Type to a String_Type and results in a type mismatch exception. Even with an ERROR_BLOCK defined S-Lang 1.x would not, on its own, catch this exception (although S-Lang 2.x will). This is because S-Lang 1 regards type mismatches as fatal errors, so the interpreter will not permit execution to continue after they occur.

Because it can be useful to test such conditions, however, TESS relaxes this constraint by installing an error handler which resets S-Lang 1 internal state and allows scripts to continue processing. Older versions of TESS installs this handler by default at startup, but as noted in the function reference it may be deactivated (or reactivated) by calling tess_catch_type_errors().

Stack Maintenance

After each test TESS also reports the number and type (or value, for objects which are not aggregates) of any items remaining on the S-Lang stack. Consider the line

        Stack Contents:
        (0)[String_Type]:hello there!
present in the output of add.t above. It shows that after test case 6 has completed the S-Lang stack contains 1 item (as it should), namely the result of concatenating the strings "hello" and " there!".

This provides an excellent way of validating the return values of exercised functions, without requiring any additional work on the part of the test developer. Conversely, this feature also identifies functions which create unintended side effects by leaving detritus on the stack.

Results Summary

Another point of interest from the add.t output is that the pass/fail statistics of each test script are automatically summarized, again with zero work required on the part of the test developer. This happens because TESS installs an exit handler which, by default, transparently calls tess_summary when the test application terminates. As noted in the function reference, this behavior may be customized.

Exit Status

If the test application offers an exit intrinsic then TESS will invoke it at completion time, passing in the number of failures observed while running the script. This enables higher-level Makefiles, or tessrun, to take appropriate action, such as terminating when a non-zero status is returned.


Next Previous Contents