aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: a816347250d70c1e920e6db42b337b885ab409c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# `covsrv`

This is a small tool that helps increase test coverage. Some procedures like
`malloc()` generally fail very rarely, meaning that error recovery paths tend to
be undertested. The solution that I came up with was to have a server keep track
of which lines of code have been executed, and inform a test program that a
certain call should fail to test out a new error recovery path.

`covsrv` provides a macro, `covsrv_die()`, that returns `1` if a
line is run for the first time during a test run, and `0` otherwise. The idea is
that any/all functions that can fail should be wrapped in a macro that checks
`covsrv_die()`. Something like the following for `malloc()`:

```C
/* replace calls to malloc() with mallocc() to make them fail during testing */
#define mallocc(n) ({covsrv_die() ? NULL : malloc(n)})
```

`./scripts/coverage` (in cooperation with the `Makefile`) shows an example of
what roughly needs to be done to set up coverage testing for a project with
`gcc` and `lcov`. Open `coverage/index.html` with your web browser of choice,
and you should see that all lines in `tests/pass.c` are exercised.
`tests/fail.c` contains a fairly common but dangerous pattern of `realloc()`,
which practically always succeeds, but fails during out test run.

## Future work

It would probably be useful to add functionality to always fail some specific
call to make it easier to debug the error recovery path from `gdb`.

Example integrations into projects that use `autotools` or `cmake` would
probably be useful.