parent
0ffc08fc41
commit
7e0c088cf0
249
README.md
249
README.md
|
@ -20,7 +20,7 @@ License along with this program. If not, see
|
||||||
A simple unit testing framework for C programs in Plan9
|
A simple unit testing framework for C programs in Plan9
|
||||||
|
|
||||||
This provides the library file `9unit.a` and the header `9unit.h`.
|
This provides the library file `9unit.a` and the header `9unit.h`.
|
||||||
The header file is relatively well commented and can provide a fairly
|
The header is relatively well commented and can provide a fairly
|
||||||
comprehensive breakdown of the API. This document will however
|
comprehensive breakdown of the API. This document will however
|
||||||
provide a basic overview below.
|
provide a basic overview below.
|
||||||
|
|
||||||
|
@ -35,23 +35,23 @@ structure. As its name would imply, it contains the current state of
|
||||||
the tests in progress, however it should almost never be necessary to
|
the tests in progress, however it should almost never be necessary to
|
||||||
interact with it directly. With the exception of `run_tests()`
|
interact with it directly. With the exception of `run_tests()`
|
||||||
(described below), all functions provided by the library will take
|
(described below), all functions provided by the library will take
|
||||||
take a pointer to a `TestState` value as their first parameter.
|
take a pointer to the current `TestState` value as their first
|
||||||
|
parameter.
|
||||||
|
|
||||||
## `run_tests()`
|
## `run_tests()`
|
||||||
|
|
||||||
This will typically be the first function you call in your tests. It
|
This will typically be the first function you call. It sets up the
|
||||||
sets up the testing framework, creates an initial `TestState` value,
|
testing framework, creates an initial `TestState` value, runs the
|
||||||
runs the tests provided to it and displays a log and summary at the
|
tests provided to it, and displays a log and summary at the end. If
|
||||||
end. If any of the provided tests failed, it will cause the test
|
any of the provided tests fail, it will cause the test program to exit
|
||||||
program to exit with status of `"test(s) failed"`. Its prototype
|
with a status of `"test(s) failed"`. Its prototype follows:
|
||||||
follows:
|
|
||||||
|
|
||||||
```C
|
```C
|
||||||
void run_test(void (*tests)(TestState *))
|
void run_tests(void (*)(TestState *));
|
||||||
```
|
```
|
||||||
|
|
||||||
The `tests` parameter is a pointer to a function which then is
|
Its only argument is a pointer to a function which is then
|
||||||
responsible for running the actual tests. A pointer to the newly
|
responsible for acuually running the tests. A pointer to the newly
|
||||||
created `TestState` value will be passed to this function.
|
created `TestState` value will be passed to this function.
|
||||||
|
|
||||||
## Simple Tests
|
## Simple Tests
|
||||||
|
@ -71,20 +71,40 @@ unsurprisingly) the result of the test. The options are as follows:
|
||||||
|
|
||||||
- `test_success`: the test was completed successfully
|
- `test_success`: the test was completed successfully
|
||||||
- `test_failure`: the test failed
|
- `test_failure`: the test failed
|
||||||
- `test_pending`: the test is pending and should be ignored for now
|
- `test_pending`: the test is pending, and should be ignored for now
|
||||||
|
|
||||||
Tests of this type can be run by passing them to the `run_test()`
|
Tests of this type can be run by passing a pointer to them to the
|
||||||
function, which has the following prototype:
|
`run_test()` function, which has the following prototype:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
void run_test(
|
void run_test(
|
||||||
TestState *s,
|
TestState *,
|
||||||
TestResult (*test)(TestState *)
|
TestResult (*)(TestState *)
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
This function will run the provided test and update the provided
|
This function will run the provided test and update the state to
|
||||||
`TestState` to reflect the result of the test.
|
reflect the result of the test. Thus, the above hypothetical test
|
||||||
|
could by run as follows:
|
||||||
|
|
||||||
|
```C
|
||||||
|
void
|
||||||
|
tests(TestState *s)
|
||||||
|
{
|
||||||
|
run_test(s, my_test);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
run_tests(tests);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Passing a null `TestState` pointer will cause nothing to happen. This
|
||||||
|
is true of all functions in this library. Passing a null function
|
||||||
|
pointer to `run_test()` will be interpreted as a pending test.
|
||||||
|
|
||||||
## Passing Values to Tests
|
## Passing Values to Tests
|
||||||
|
|
||||||
|
@ -96,8 +116,191 @@ into a generic test so that it can be reused multiple times.
|
||||||
|
|
||||||
### The `ptr` Value
|
### The `ptr` Value
|
||||||
|
|
||||||
The `TestState` struct has a value called `ptr` which is a void
|
The `TestState` struct has a value called `ptr` which is a `void`
|
||||||
pointer that can be set prior to calling `run_test()`. This value can
|
pointer that can be set prior to calling `run_test()` (or any other
|
||||||
then be read by the test function, giving you the ability to
|
function, really). This value can then be read by the test function,
|
||||||
essentially pass in *any* type of data you may need. While not ideal,
|
giving you the ability to essentially pass in *any* type of data you
|
||||||
it's *a* solution.
|
may need. While not ideal, it's *a* solution.
|
||||||
|
|
||||||
|
The library does not perform any kind of validation or automatic
|
||||||
|
memory management on the `ptr` value (this is C after all), so the
|
||||||
|
responsibility for this falls to the programmer implementing the
|
||||||
|
tests.
|
||||||
|
|
||||||
|
### Convenience Functions
|
||||||
|
|
||||||
|
As the tests become more and more complex, managing a single `ptr`
|
||||||
|
value can become increasingly burdensome. For this reason, there are
|
||||||
|
a few convenience functions that provide an alternate mechanism of
|
||||||
|
passing data into a function, without altering the `ptr` value. (They
|
||||||
|
actually do internally, but they restore the original value before
|
||||||
|
passing the state on.) Two such functions are `run_test_with()` and
|
||||||
|
`run_test_compare()`.
|
||||||
|
|
||||||
|
`run_test_with()` has the following prototype:
|
||||||
|
|
||||||
|
```C
|
||||||
|
void run_test_with(
|
||||||
|
TestState *,
|
||||||
|
TestResult (*)(TestState *, void *),
|
||||||
|
void *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The first argument points to the current test state. The second
|
||||||
|
points to a test function much like the simple test function described
|
||||||
|
above, but that takes a void pointer as a second argument. Finally,
|
||||||
|
the third argument is the pointer that gets passed into the test
|
||||||
|
function.
|
||||||
|
|
||||||
|
`run_test_compare()` is similar, but it allows two pointers to be
|
||||||
|
passed into the test. This is useful for comparing an actual value to
|
||||||
|
an expected one, for instance comparing the actual output from a
|
||||||
|
function to an expected value.
|
||||||
|
|
||||||
|
The prototype for `run_test_compare()` follows:
|
||||||
|
|
||||||
|
```C
|
||||||
|
void run_test_compare(
|
||||||
|
TestState *,
|
||||||
|
TestResult (*)(TestState *, void *, void *),
|
||||||
|
void *,
|
||||||
|
void *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Contexts
|
||||||
|
|
||||||
|
It is useful to document what your tests are doing. This can be
|
||||||
|
achieved using contexts. These are essentially just string values
|
||||||
|
describing what the provided test(s) are for. Contexts can be nested
|
||||||
|
into hierarchies. This is useful both for organization purposes as
|
||||||
|
well as creating reusable test code. The following functions allow
|
||||||
|
for the creation of test contexts as well as displaying information
|
||||||
|
about the tests as they're run.
|
||||||
|
|
||||||
|
### `test_context()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void test_context(
|
||||||
|
TestState *,
|
||||||
|
const char *,
|
||||||
|
void (*)(TestState *)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function takes a pointer to the current `TestState`, a string
|
||||||
|
describing the context, and a function pointer that is used the same
|
||||||
|
way as the funciton pointer passed to `run_tests()`.
|
||||||
|
|
||||||
|
### `test_context_with()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void test_context_with(
|
||||||
|
TestState *,
|
||||||
|
const char *,
|
||||||
|
void (*)(TestState *, void *),
|
||||||
|
void *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
This funciton allows for the passing of a `void` pointer into the test
|
||||||
|
function, in much the same way as the `run_test_with()` function. Its
|
||||||
|
arguments are (in order), a pointer to the current state, the context
|
||||||
|
description, a pointer to the test function, and the pointer being
|
||||||
|
passed into that function.
|
||||||
|
|
||||||
|
### `test_context_compare()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void test_context_compare(
|
||||||
|
TestState *,
|
||||||
|
const char *,
|
||||||
|
void (*)(TestState *, void *, void *),
|
||||||
|
void *,
|
||||||
|
void *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
This funciton allows the passing to two `void` pointers into a context
|
||||||
|
in a manner similar to `run_test_compare()`.
|
||||||
|
|
||||||
|
### `single_test_context()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void single_test_context(
|
||||||
|
TestState *,
|
||||||
|
const char *,
|
||||||
|
TestState (*)(TestState *)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function applies the context label to a *single* test. The
|
||||||
|
function passed in is expected to operate in the same way as a
|
||||||
|
function passed to `run_test()`.
|
||||||
|
|
||||||
|
### `single_test_context_with()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void single_test_context_with(
|
||||||
|
TestState *,
|
||||||
|
const char *,
|
||||||
|
TestState (*)(TestState *, void *),
|
||||||
|
void *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
This is similar to `single_test_context()` but allows a `void` pointer
|
||||||
|
to be passed as in `run_test_with()`.
|
||||||
|
|
||||||
|
### `single_test_context_compare()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void single_test_context_compare(
|
||||||
|
TestState *,
|
||||||
|
const char *,
|
||||||
|
TestResult (*)(TestState *, void *, void *),
|
||||||
|
void *,
|
||||||
|
void *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
I assume you get the idea at this point.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
When `run_tests()` finishes running the tests, it displays a log and
|
||||||
|
summary. The summary is simply a count of the number of tests run,
|
||||||
|
passed, failed, and pending. While this is useful (and probably all
|
||||||
|
you need to know when all the tests pass) you probably want more
|
||||||
|
detail when something goes wrong. To facilitate this, tests can
|
||||||
|
append to the test log, which is automatically displayed just before
|
||||||
|
the summary. There are two functions for doing this.
|
||||||
|
|
||||||
|
### `append_test_log()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void append_test_log(
|
||||||
|
TestState *,
|
||||||
|
const char *
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
This appends an arbitrary string to the end of the test log. The
|
||||||
|
string is copied into the log, so the value pointed to by the second
|
||||||
|
argument does not need to persist in memory beyond the end of the call
|
||||||
|
to the function. Log entries are expected to be single lines. No
|
||||||
|
trailing newline should be present (but the trailing NUL character
|
||||||
|
should (obviously)).
|
||||||
|
|
||||||
|
### `log_test_context()`
|
||||||
|
|
||||||
|
```C
|
||||||
|
void log_test_context(TestState *);
|
||||||
|
```
|
||||||
|
|
||||||
|
This function appends an entry to the log indicating the test's
|
||||||
|
current *full* context. If no context is defined, the log entry will
|
||||||
|
be `"<no context>"`. If the test is inside of a context labeled
|
||||||
|
`"foo"` which is inside of another context labeled `"bar"`, the
|
||||||
|
resulting log entry will read `"bar: foo"`.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user