Clone this repo:
  1. 1b54b0f Add new file utilities library by Jack Rosenthal · 6 months ago factory-drallion-13080.B factory-endeavour-13295.B factory-puff-13329.B factory-trogdor-13443.B factory-zork-13427.B firmware-endeavour-13259.B firmware-puff-13324.B firmware-volteer-13521.B firmware-zork-13421.B firmware-zork-13434.B master release-R84-13099.B release-R85-13310.B release-R86-13421.B release-R87-13505.B stabilize-13070.B stabilize-13099.101.B stabilize-13099.110.B stabilize-13099.118.B stabilize-13099.70.B stabilize-13099.72.B stabilize-13099.73.B stabilize-13099.85.B stabilize-13099.90.B stabilize-13099.94.B stabilize-13310.72.B stabilize-13310.74.B stabilize-13310.83.B stabilize-13310.94.B stabilize-13310.99.B stabilize-13360.B stabilize-13421.42.B stabilize-13421.53.B stabilize-13482.B stabilize-13525.B stabilize-13532.B stabilize-lazor-13278.B stabilize-quickfix-13099.93.B stabilize-quickfix-13310.73.B stabilize-quickfix-13310.76.B stabilize-quickfix-13310.91.B stabilize-rust-13514.B
  2. 862e052 cmdline: add some more unit tests by Jack Rosenthal · 6 months ago
  3. 225a168 Get lithium working under LLVM/Clang by Jack Rosenthal · 7 months ago release-R83-13020.B stabilize-13020.55.B stabilize-13020.67.B stabilize-13020.87.B stabilize-sylas-13019.B
  4. 22c6253 Setup repo presubmit config by Jack Rosenthal · 7 months ago
  5. 17f444f Initial import of Lithium to Chromium OS by Jack Rosenthal · 7 months ago

Lithium C Library and Unit Test Framework

Lithium is a C library designed to help you write high quality systems programs in C. Right now, it is in the early stages and is mostly a unit testing framework, but this may change in the future as Lithium grows more features.

Dependencies:

  • A POSIX operating system and libc.

To compile the code as a shared object file, type:

$ make build/release/libithium.so

To compile the code as a static library, type:

$ make build/release/libithium.a

Distribution packages are pending which will install the library and header files.

To run the unit tests (written using Lithium Unit and Lithium Mock), type:

$ make run-tests

Lithium Unit

Lithium Unit is the core of Lithium's unit testing features. Using Lithium Unit, tests can be written anywhere, and are automatically collected by the test runner. This way, even static helper functions can even be tested. To get started, #include <lithium/unit.h> where you want to write your test, and use the DEFTEST macro to define your test. An example is below:

DEFTEST("myproject.utils.math.fibonacci", {})
{
        EXPECT(fib(0) == 0);
        EXPECT(fib(1) == 1);
        EXPECT(fib(11) == 89);
}

The second parameter to DEFTEST is an options struct, for example, to disable tests or make them informational. See the header file for all available fields.

The EXPECT macro will test that the condition is true. If it were false, it would print an error message and mark the test as failed, but continue running. This differs from the ASSERT macro, in that failed assertions will abort the test immediately.

EXPECT will return true if the condition was true: this way you can conditionally choose to run additional code based on the result.

There are 4 other macros to know:

  • EXPECT_NULL - expect that a pointer is null.
  • ASSERT_NULL - assert that a pointer is null, aborting the test if the pointer is non-null.
  • EXPECT_NOT_NULL - expect that a pointer is non-null.
  • ASSERT_NOT_NULL - assert that a pointer is non-null, aborting the test if the pointer is null.

To run your test, compile your code with -DLITHIUM_TEST_BUILD and -lithium. Call return li_unit_run_tests_main(argv); from your main function. The test runner will run all tests in parallel automatically.

Lithium Mock

Lithium takes a different approach to mocking from other test frameworks. Instead of providing specific features to mock a function, its return values, or structures, Lithium provides a single highly-powerful macro to mock any expression in your code.

This relies on providing a “mocked expression variable” which is visible to both the code being mocked and the test code providing mocked values. This variable gets compiled away to nothing and using the macros incurs no additional overhead unless LITHIUM_TEST_BUILD is defined.

First, declare the variable as extern in the header file visible to both the code being mocked and the tests providing mocked values:

#include <lithium/mock.h>

#include "myproject/utils/file.h"

/* We are mocking the "read_file" function. You can also use a data
   type here instead (e.g. "char *"). */
extern LI_MOCKABLE_STORAGE_T(read_file) read_file_mock;

You'll need to provide a definition of the variable too, outside of the header file:

LI_MOCKABLE_STORAGE_T(read_file) read_file_mock = { 0 };

Then, in place of the expression which is mockable, use the LI_MOCKABLE(storage_var, default_value) macro. For example:

if (LI_MOCKABLE(read_file_mock, read_file)(path, buffer, buf_sz) < 0) {
        ...
}

Finally, use LI_SETUP_MOCK(storage_var, mocked_value) in your test code:

static ssize_t mocked_read_file(const char *path, void *buf, size_t buf_sz)
{
        /* implementation of your mocked function ... */
}

DEFTEST("myproject.some.test", {})
{
        LI_SETUP_MOCK(read_file_mock, mocked_read_file);
        /* ... */
}