Assert macros (C++ SDK)
Assert macros define test properties about your software or workload. They are part of the Antithesis C++ SDK.
Every macro takes a parameter message, which is a human-readable identifier for assertions; and a parameter details, which allows you to allows you to record additional contextual information.
Always assertions
Always assertions assert that every time the assertion is encountered, some condition is true. If a single counterexample to the asserted property is found, the assertion will fail. See the always properties documentation for further details.
ALWAYS(bool condition, const char* message, const JSON& details)
Asserts that condition
is true every time this macro is called, and that it is called at least once. The corresponding test property will be viewable in the Antithesis SDK: Always group of your triage report.
Parameters: See common parameters below.
Example
#include <antithesis_sdk.h>
// ...
int bar(int x, int y){
ALWAYS(x > 0, "x is positive", {{"x", x}});
// Include the value of x to help debug if this fails
}
ALWAYS_OR_UNREACHABLE(bool condition, const char* message, const JSON& details)
Asserts that condition
is true every time this macro is called. The corresponding test property will pass if the assertion is never encountered (unlike Always
assertion types). This test property will be viewable in the “Antithesis SDK: Always” group of your triage report.
This function is similar to assertions in most assertions libraries that you may be familiar with.
Parameters: See common parameters below.
UNREACHABLE(const char* message, const JSON& details)
Asserts that a line of code cannot be reached. The assertion will fail if it is reached, and will pass if it is never reached. Assertions of this form will be grouped in the “Antithesis SDK: Reachability” section of the triage report.
Parameters: See common parameters below.
#include <antithesis_sdk.h>
// The queue should never have more than 100 elements
// So the following code should never be exercised
if (queue_length > 100) {
UNREACHABLE("Queue overflow handling should never be reached", {{"queue_length", queue_length}});
}
ALWAYS_GREATER_THAN(T left, T right, const char* message, const JSON& details)
ALWAYS_GREATER_THAN_OR_EQUAL_TO(T left, T right, const char* message, const JSON& details)
ALWAYS_LESS_THAN(T left, T right, const char* message, const JSON& details)
ALWAYS_LESS_THAN_OR_EQUAL_TO(T left, T right, const char* message, const JSON& details)
Equivalent to asserting ALWAYS(left > right, message, details)
etc.
Parameters: T
is numeric. See also common parameters below.
Example
#include <antithesis_sdk.h>
// ...
int bar(int x, int y){
ALWAYS_GREATER_THAN(x, 0, "x is positive", {});
// The value of x will automatically be included in 'details'
}
ALWAYS_SOME(std::vector<std::pair<string, bool>> named_bools, const char* message, const JSON& details)
Asserts that every time the macro is called, at least one bool in named_bools
is true. Equivalent to ALWAYS(named_bools[0].second || named_bools[1].second || ..., message, details)
. If you use these macros for assertions about the behavior of booleans, you may help Antithesis find more bugs. Information about named_bools
will automatically be added to the details
parameter, and the keys will be the names of the bools.
Parameters: See common parameters below. Note that the NAMED_LIST
utility macro is provided to pass the named_bools
argument more conveniently.
Example
#include <antithesis_sdk.h>
// You have a variable my_data
// Always, my_data should be stored in at least one replica
ALWAYS_SOME(NAMED_LIST(replica1.contains(my_data), replica2.contains(my_data), replica3.contains(my_data)), "Data is always in some replica", {})
Sometimes assertions
Sometimes assertions assert that at least one time the assertion is encountered, some condition is true. If a single example of the asserted property is found, the assertion will pass. See why you should use sometimes properties for further details.
SOMETIMES(bool condition, const char* message, const JSON& details)
Asserts that condition
is true at least one time that this macro was called. (If the assertion is never encountered, the test property will therefore fail.) This test property will be viewable in the “Antithesis SDK: Sometimes” group.
Parameters: See common parameters below.
Example
#include <antithesis_sdk.h>
// A function to square a number
// Your tests should sometimes test negative inputs
float squareNumber(float x){
SOMETIMES(x < 0, "Input to squareNumber is negative", {{"x", x}})
return x*x
}
REACHABLE(const char* message, const JSON& details)
Assert that a line of code is reached at least once. The assertion will pass if it is reached at least once. (If it is never reached, it will therefore fail.) The resulting property will be grouped in the “Antithesis SDK: Reachability” section of your triage report.
Parameters:
Example
#include <antithesis_sdk.h>
// Some sort of retry logic
// Your tests should exercise this functionality at least once
void retryTransaction{
REACHABLE("Retry logic is reachable")
// More code
}
SOMETIMES_GREATER_THAN(T left, T right, const char* message, const JSON& details)
SOMETIMES_GREATER_THAN_OR_EQUAL_TO(T left, T right, const char* message, const JSON& details)
SOMETIMES_LESS_THAN(T left, T right, const char* message, const JSON& details)
SOMETIMES_LESS_THAN_OR_EQUAL_TO(T left, T right, const char* message, const JSON& details)
Equivalent to asserting SOMETIMES(T left > T right, ...)
etc.
Parameters:
SOMETIMES_ALL(std::vector<std::pair<string, bool>> named_bools, const char* message, const JSON& details)
Asserts that at least one time the macro is called, every bool in named_bools is true. Equivalent to SOMETIMES(named_bools[0].second && named_bools[1].second && ..., message, details)
. If you use these macros for assertions about the behavior of booleans, you may help Antithesis find more bugs. Information about named_bools
will automatically be added to the details parameter, and the keys will be the names of the bools.
Parameters:
Note that the NAMED_LIST
utility macro is provided to pass the named_bools
argument more conveniently.
#include <antithesis_sdk.h>
// When testing, sometimes all of the replicas should be alive
SOMETIMES_ALL(NAMED_LIST(replica1.isAlive(), replica2.isAlive(), replica3.isAlive()), "Sometimes all replicas are alive", {})
Common parameters
message
const char* that must be known at compile time. A human readable identifier used to aggregate assertions. Antithesis generates one test property per unique message
and this test property will be named message
in triage reports.
This test property either passes or fails, which depends upon the evaluation of every assertion that shares its message
. Different assertions in different parts of the code should have different message
, but the same assertion should always have the same message
even if it is moved to a different file.
details
Utility macros
The macro NAMED_LIST
is provided to conveniently pass arguments to boolean assertions such as SOMETIMES_ALL
and ALWAYS_SOME
. It can also be used to pass the details
argument.
NAMED_LIST(foo, bar, baz)
expands to { { "foo", foo }, { "bar", bar }, { "baz", baz } }
.
NAMED_LIST(dog.say("woof"), cat.say("meow"))
expands to { { "dog.say(\"woof\")", dog.say("woof") }, { "cat.say(\"meow\")", cat.say("meow") } }
.
The macro takes between 1 and 10 parameters (inclusive). Contact us if you require the macro to support more parameters.
Additional Considerations
Assertions can be added to template definitions. However, you should ensure that the assertion identifier message
is distinct for each instantiation of the template.
We recommend using the __PRETTY_FUNCTION__
macro, which shows the actual name of the instantiated function or method. This should be used in message
to ensure that each instantiation’s assertion has a unique identifier:
#include <antithesis_sdk.h>
template<typename T>
bool is_in_range(T val, T min_val, T max_val) {
bool in_range = ((val >= min_val) && (x <= max_val));
ALWAYS(in_range, "Is in range: " __PRETTY_FUNCTION__, {});
return in_range;
}
Alternatively, __PRETTY_FUNCTION__
can be included in the details
associated with the assertion:
#include <antithesis_sdk.h>
template<typename T>
bool is_in_range(T val, T min_val, T max_val) {
bool in_range = ((val >= min_val) && (x <= max_val));
ALWAYS(in_range, "Is in range", {{"where", __PRETTY_FUNCTION__}});
return in_range;
}