## `prog::test` -- automatic comparing of calculation results

#### Introduction

`prog::test(`stmt, res`)` evaluates both MuPAD expressions `stmt` and `res` and compares the results.

#### Call(s)

`prog::test(stmt, res <, message>)`
`prog::test(stmt, TrapError = errnr <, message>)`
`prog::test(stmt <, message>)`

#### Parameters

`statement` | - | a MuPAD statement to test
`res` | - | a MuPAD expression or statement that determines the expected result.
`errnr` | - | a positive integer that determines a MuPAD error
`message` | - | a string that will be displayed as message if the test fails

#### Options

`TrapError = errnr` | - | With this option it is possible to check the error behavior of a function. The tested call must produce an error, and the internal error number must be equal to `errnr`. In this case no error message is printed. In all other cases the test fails and an error message is printed.

#### Returns

`prog::test` returns the void object `null()`. While executing, messages will be printed on screen or into files.

#### Related Functions

`prog::error`, `prog::testinit`, `prog::testexit`, `prog::testfunc`, `TESTPATH`

#### Details

- If the results of the evaluation of both arguments `stmt` and `res` are different, a message is printed on screen that contains several information.

- `prog::test` works in two different modes: interactive and inside of test files.

- In interactive mode a single call of `prog::test` can be used to compare two MuPAD statements.

  If the evaluation of both first arguments leads to the same MuPAD object, nothing is printed and `prog::test` returns the void object `null()`.

  If the results are different, the test fails and an error message is printed.

- The other mode is using `prog::test` inside of test files.

  A test file must contain at least a starting and an exit statement.

  First the function `prog::testinit` initializes the test file. Next `prog::testfunc` determines the name of the tested function.

  Now several tests can be performed (see next paragraph).

  With `prog::testfunc` another function can be initialized in the same file. The number of the tests is reseted by `prog::testfunc`.

  The last statement in a test file must be `prog::testexit`.

- The tests can be arbitrary MuPAD statements and `prog::test` statements. However, most of the functionality should be executed as argument of `prog::test`. Only initialization of variables should be performed outside of `prog::test` statements in a test file, because:

  `prog::test` traps every error (with the function `traperror`) and prints a specific error message.

  If an error occurs outside of `prog::test`, the reading of the test file is interrupted.

  If no error occurs (as should be the default case), the results are compared and a message is printed, if they are different.

- If a test fails, i.e., the two first arguments of `prog::test` lead to different MuPAD objects, a message is printed in the format:

  `Error in test 'interactive' 1: 1 + 2 = 4 [<> 3] (first test)`

  `prog::test` emits messages with up to six pieces of information:

  1. The name of the test as given by `prog::testfunc` or `interactive`, if `prog::test` is called without a prior call to `prog::testinit`.
  2. All tests are numbered (in this case we get number `1` for the first interactive test). The numbering is reset by `prog::testfunc` (and also by `reset`).
  3. Then the unevaluated test equation is printed (`1 + 2 = 4`), `1 + 2` is the first argument of `prog::test`,
  4. `4` is the second argument.
  5. Next, we get the result of the first statement (`3`), which is different from the expected test result `4`.
  6. The string `first test` was given by the last optional argument of `prog::test` and can be used to identify a test (see next paragraph).

- If the third argument `string` is given, `string` is evaluated and appended to the end of a message, if the test fails (in the last example `"first test"`). With this message a test inside of a test file can be identified easier.

- If only one argument is given, the argument is evaluated and compared with `TRUE`, i.e., `prog::test(`ex`)` is equivalent to `prog::test(`ex, TRUE`)`.

- After the statement `setuserinfo(`prog::test, 2), additional information for every test is printed on screen.

- When a test is initialized with `prog::testinit` and ended by `prog::testexit`, a short message is printed with the format:

  `Info: 2 tests, 1 error, time: 3.10 / 4.52 s`

  The message contains the number of all tests performed (`2`), the number of errors (`1`), and two times: the first time is the number of seconds for only the evaluations of all first statements, the second time is the time between the call of `prog::testinit` and `prog::testexit`.

#### Option: TrapError

- The evaluation of `stmt` may lead to a MuPAD error on purpose. In this case the result can be the equation `TrapError = errnr`, whereby `errnr` is the internal MuPAD error number, which is returned by the function `traperror`.

#### Example 1

`prog::test` can be called interactively:

    >> prog::test(1 + 1, 2):
       prog::test(is(2 > 1)):
       prog::test(sin(PI), 0, "check sin"):

These tests checked all right, therefore nothing was printed. In the next tests wrong results are tested against, to demonstrate the messages given by `prog::test`:

    >> prog::test(1 + 2, 2):
       prog::test(is(x > 1)):
       prog::test(sin(PI), PI, "check sin"):

          Error in test 'interactive' 3:  1 + 2 = 2 [<> 3]
          Error in test 'interactive' 4:  is(1 < x) = TRUE [<> UNKNOWN]
          Error in test 'interactive' 5:  sin(PI) = PI [<> 0] (check sin)

#### Example 2

This is a short example for a test file with name `"test.tst"`:

          // test file "test.tst"
          test:= (a, b) -> a^2 + 2*b^2 - a*b:
          prog::testinit("test"):
          prog::testfunc(test):
          prog::test(test(1, 4), 29, "my first example"):
          prog::test(test(3, -2), 24, "the second example"):
          prog::test(error("test"), TrapError = 1028):
          prog::testexit():

The first statement is only a comment. The second line contains an initialization of a test procedure called `test`. Then the test is initialized with `prog::testinit` and the function name is set with `prog::testfunc`.

After that three tests are performed: The first test is right, the second expected result is wrong, and the third test produces an error, but the expected result is this error, the error number returned by `traperror` is `1028` (user call of `error`).

The whole test takes nearly no time:

    >> read("test.tst")

          Error in test 'test' 2: test(3, -2) = 24 [<> 23] (the second example)
          Info: 2 tests, 1 error,  time:  0.00 / 0.01 s

    >> setuserinfo(prog::test, 2):
       read("test.tst")

          testing 'test' 1
            for test(1, 4) = 29
          testing 'test' 2
            for test(3, -2) = 24
          Error in test 'test' 2: test(3, -2) = 24 [<> 23] (the second example)
          Info: 2 tests, 1 error,  time:  0.00 / 0.01 s

#### Changes

- `prog::test` can be used interactively.
- The expected result can be an error number to check the error behavior of a function.
- If the test fails, the returned result will be printed at end of the message.
- An optional third argument can be given to identify tests.

Do you have questions or comments?
Copyright © SciFace Software GmbH & Co. KG 2000