Assertions

The doxytest.py script provides two assertions that you can use in your doctests.

These assertions are defined and included in every test program generated by doxytest.py.

The assertions are:

The assert macro is a simple boolean condition checker that expands to an if statement that checks the condition and throws a doxy::error exception if the condition is false. You can also pass a variadic argument list of additional arguments that are sent to the std::format function to produce a custom message, which also becomes part of the doxy::error.what string.

The assert_eq macro is a macro for checking equality that expands to an if statement that checks if the first two arguments are equal and throws a doxy::error exception if they are not. You can also pass a variadic argument list of additional arguments that are sent to the std::format function to produce a custom message, which also becomes part of the doxy::error.what string.

For example:

assert_eq(a, b, "Are the lengths off? a.len() = {}, b.len() = {}", a.len(), b.len());

If the assertion fails, the program will print the custom message along with the values of the arguments to the assertion, which might look like this:

FAILED `assert_eq(a, b)` [a.h:10]
1Are the lengths off? a.len() = 10, b.len() = 20
2lhs = ...
3rhs = ...
1
This is the fully formatted custom message you provided to the assertion.
2
This is the value of the a argument that went into the assertion.
3
This is the value of the b argument that went into the assertion.
The first two lhs and rhs arguments to assert_eq must be printable using std::format. If they are your own types, they will need to have an appropriate specialisation for std::formatter.
If a failure occurs, the error message displays the location of the corresponding doctest in the source header file. We only show the basename for the header file. Showing the full path is generally overkill and results in very noisy error messages.

Why just two assertions?

The short answer is that the two assertions provided by doxytest.py are sufficient for most purposes.

Of course, it is tempting to add more assertions (assert_ne, assert_lt, …), but really I haven’t found them needed in the sort of example code one is likely to include in simple doctests.

For example, if you need to assert that a value is within a range, you can do this:

assert(a >= 0 && a <= 100, "a is not in the range 0-100");

If you do need more complex assertions, you can always roll your own tests and throw doxy::error exceptions to integrate with the doxytest system.

if(a > b) {
    throw doxy::error("a: {} is smaller than b: {}", a, b);
}

Why macros?

The main reason we use macros instead of a function is that we need to stringify the assertion condition and assertion arguments to produce a helpful message if the assertion fails. We could use the doxytest.py script to automate this process, but it adds script complexity without much benefit.

Macros do have the downside that they depend on comma placement to separate arguments, which can be a bit of a gotcha in some cases. For example, if you are equality testing between two std::pair variables. You can often get around any issues by the judicious use of parentheses, but it is something to be aware of if you start to see weird compiler errors.
For Microsoft Visual C++, you should be sure to use their more standards-compliant, modern preprocessor, accessed with the /Zc:preprocessor compiler option. The traditional Microsoft preprocessor isn’t happy with our assertion macros.

Next steps

See the full reference for all the options understood by doxytest.py.

Get more information about the custom Doxytest usage.

If you use CMake, be sure also to check out doxytest.cmake.

Back to top