Userspace unit testing with PCUT
PCUT - plain C unit testing - is (still somewhat experimental) framework/library that ought to simplify writing unit tests in C. Its main advantage is simple usage and integration with HelenOS.
PCUT itself is a standalone project with its own wiki. This page provides mostly information specific for HelenOS (at least for now).
Building and running PCUT tests
The PCUT tests are built by default but are not included in the final image unless explicitly enabled. To enable them, turn on the Include userspace unit tests (PCUT)
option during HelenOS configuration.
The tests then reside in the test/
directory, named test-<component>
where <component>
may refer to a standalone application or a library. It is possible to run them separately by launching individual binaries or run them all with the following command:
batch /test/run_all
This batch script also copies the result to /data/web
, thus making them accessible by simply pointing your browser to /test.html (assuming you started the HelenOS web server).
The tests output their results in a Test-Anything-Protocol format that is easy to understand, below is an example from successful run of test-libc
:
1..11 #> Starting suite sprintf. ok 1 no_formatting ok 2 string_plain ok 3 string_dynamic_width ok 4 string_dynamic_width_align_left ok 5 string_pad ok 6 string_pad_but_cut ok 7 char_basic ok 8 int_various_padding ok 9 int_negative_various_padding ok 10 long_negative_various_padding ok 11 int_as_hex #> Finished suite sprintf (failed 0 of 11).
Writing your own tests
The test sources are typically stored in a test/
subdirectory of the application/library they are testing. If you want to extend already existing test case or add a new test case, open an existing file with the tests and add it there. The file may look like this (example taken from bdsh
):
/* ... */ static tokenizer_t tokenizer; static token_t tokens[MAX_TOKENS]; /* * Implementation of * void prepare(const char *input, size_t expected_token_count) * is omitted. */ #define ASSERT_TOKEN(index, token_type, token_text) \ do { \ PCUT_ASSERT_INT_EQUALS(token_type, tokens[index].type); \ PCUT_ASSERT_STR_EQUALS(token_text, tokens[index].text); \ } while (0) PCUT_TEST_SUITE(tokenizer); PCUT_TEST_AFTER { /* Destroy the tokenizer. */ tok_fini(&tokenizer); } PCUT_TEST(empty_input) { prepare("", 0); } PCUT_TEST(only_spaces) { prepare(" ", 1); ASSERT_TOKEN(0, TOKTYPE_SPACE, " "); } PCUT_TEST(two_text_tokens) { prepare("alpha bravo", 3); ASSERT_TOKEN(0, TOKTYPE_TEXT, "alpha"); ASSERT_TOKEN(1, TOKTYPE_SPACE, " "); ASSERT_TOKEN(2, TOKTYPE_TEXT, "bravo"); } PCUT_MAIN()
Individual test cases are enclosed in PCUT_TEST(test_name)
, available asserts are listed here. You might also want to read how to create test suites that may share a set-up and tear-down code. It is also possible to split the tests into more files.
Adding tests to previously untested code
It is recommended to put the test sources under test/
directory to separate them from the tested code.
Add sources with the tests to the TEST_SOURCES
variable. If your are testing a library, the test executable will be automatically linked with it. For an application (or server), you need to add all the necessary source files by yourself (it is not possible to add all of them automatically because PCUT creates its own main()
function that would collide with the main()
of the application).
Add path to the test to the RD_TESTS
variable in boot/Makefile.common
.
Basically, look how it is done for existing tests (libc
, libposix
, liburi
or bdsh
) until this how-to is improved.