7#ifndef NO_ANTITHESIS_SDK
9#if __cplusplus < 202000L
10 #error "The Antithesis C++ API requires C++20 or higher"
11 #define NO_ANTITHESIS_SDK
14#if !defined(__clang__)
15 #error "The Antithesis C++ API requires a clang compiler"
16 #define NO_ANTITHESIS_SDK
19#if __clang_major__ < 16
20 #error "The Antithesis C++ API requires clang version 16 or higher"
21 #define NO_ANTITHESIS_SDK
26#if __cplusplus < 201700L
27 #error "The Antithesis C++ API (with NO_ANTITHESIS_SDK) requires C++17 or higher"
49 typedef std::variant<JSON, std::nullptr_t, std::string, bool, char, int, uint64_t, float, double, const char*, JSONArray> JSONValue;
54 template<typename T, typename std::enable_if<std::is_convertible<T, JSONValue>::value,
bool>::type =
true>
63 for (
auto& pair : more_args) {
64 (*this)[pair.first] = pair.second;
87#ifdef ANTITHESIS_RANDOM_OVERRIDE
88 return ANTITHESIS_RANDOM_OVERRIDE();
100#ifndef NO_ANTITHESIS_SDK
105namespace antithesis::internal::json {
107 inline constexpr bool always_false_v =
false;
112 const char HEX[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F' };
114 case '\t': out <<
"\\t";
break;
115 case '\b': out <<
"\\b";
break;
116 case '\n': out <<
"\\n";
break;
117 case '\f': out <<
"\\f";
break;
118 case '\r': out <<
"\\r";
break;
119 case '\"': out <<
"\\\"";
break;
120 case '\\': out <<
"\\\\";
break;
122 if (
'\u0000' <= c && c <=
'\u001F') {
123 out <<
"\\u00" << HEX[(c >> 4) & 0x0F] << HEX[c & 0x0F];
133 if constexpr (std::is_same_v<T, std::string>) {
139 }
else if constexpr (std::is_same_v<T, bool>) {
140 out << (arg ?
"true" :
"false");
141 }
else if constexpr (std::is_same_v<T, char>) {
145 }
else if constexpr (std::is_same_v<T, int>) {
147 }
else if constexpr (std::is_same_v<T, uint64_t>) {
149 }
else if constexpr (std::is_same_v<T, float>) {
151 }
else if constexpr (std::is_same_v<T, double>) {
153 }
else if constexpr (std::is_same_v<T, const char*>) {
155 for (
auto str = arg; *str !=
'\0'; str++) {
159 }
else if constexpr (std::is_same_v<T, std::nullptr_t>) {
161 }
else if constexpr (std::is_same_v<T, JSON>) {
163 }
else if constexpr (std::is_same_v<T, JSONArray>) {
166 for (
auto &item : arg) {
175 static_assert(always_false_v<T>,
"non-exhaustive JSONValue visitor!");
186 for (
auto [key, value] : details) {
194 out <<
'"' <<
':' << value;
210#ifndef NO_ANTITHESIS_SDK
224namespace antithesis::internal::handlers {
225 constexpr const char*
const ERROR_LOG_LINE_PREFIX =
"[* antithesis-sdk-cpp *]";
226 constexpr const char* LIB_PATH =
"/usr/lib/libvoidstar.so";
227 constexpr const char* LOCAL_OUTPUT_ENVIRONMENT_VARIABLE =
"ANTITHESIS_SDK_LOCAL_OUTPUT";
229 using namespace antithesis::internal::json;
232 virtual ~LibHandler() =
default;
233 virtual void output(
const char* message)
const = 0;
234 virtual uint64_t random() = 0;
236 void output(
const JSON& json)
const {
239 output(
out.str().c_str());
243 struct AntithesisHandler : LibHandler {
244 void output(
const char* message)
const override {
245 if (message !=
nullptr) {
246 fuzz_json_data(message,
strlen(message));
251 uint64_t random()
override {
252 return fuzz_get_random();
256 void* shared_lib = dlopen(LIB_PATH, RTLD_NOW);
258 error(
"Can not load the Antithesis native library");
262 void* fuzz_json_data = dlsym(shared_lib,
"fuzz_json_data");
263 if (!fuzz_json_data) {
264 error(
"Can not access symbol fuzz_json_data");
268 void* fuzz_flush = dlsym(shared_lib,
"fuzz_flush");
270 error(
"Can not access symbol fuzz_flush");
274 void* fuzz_get_random = dlsym(shared_lib,
"fuzz_get_random");
275 if (!fuzz_get_random) {
276 error(
"Can not access symbol fuzz_get_random");
281 reinterpret_cast<fuzz_json_data_t
>(fuzz_json_data),
282 reinterpret_cast<fuzz_flush_t
>(fuzz_flush),
283 reinterpret_cast<fuzz_get_random_t
>(fuzz_get_random)));
287 typedef void (*fuzz_json_data_t)(
const char* message,
size_t length );
288 typedef void (*fuzz_flush_t)();
289 typedef uint64_t (*fuzz_get_random_t)();
292 fuzz_json_data_t fuzz_json_data;
293 fuzz_flush_t fuzz_flush;
294 fuzz_get_random_t fuzz_get_random;
296 AntithesisHandler(fuzz_json_data_t fuzz_json_data, fuzz_flush_t fuzz_flush, fuzz_get_random_t fuzz_get_random) :
297 fuzz_json_data(fuzz_json_data), fuzz_flush(fuzz_flush), fuzz_get_random(fuzz_get_random) {}
299 static void error(
const char* message) {
300 fprintf(stderr,
"%s %s: %s\n", ERROR_LOG_LINE_PREFIX, message, dlerror());
304 struct LocalHandler : LibHandler{
305 ~LocalHandler()
override {
306 if (file !=
nullptr) {
311 void output(
const char* message)
const override {
312 if (file !=
nullptr && message !=
nullptr) {
313 fprintf(file,
"%s\n", message);
317 uint64_t random()
override {
318 return random_gen.random();
328 LocalHandler(FILE* file): file(file), random_gen() {
334 static FILE* create_internal() {
335 const char* path =
std::getenv(LOCAL_OUTPUT_ENVIRONMENT_VARIABLE);
336 if (!path || !path[0]) {
341 FILE* file =
fopen(path,
"w");
342 if (file ==
nullptr) {
343 fprintf(stderr,
"%s Failed to open path %s: %s\n", ERROR_LOG_LINE_PREFIX, path,
strerror(errno));
346 int ret = fchmod(fileno(file), 0644);
348 fprintf(stderr,
"%s Failed to set permissions for path %s: %s\n", ERROR_LOG_LINE_PREFIX, path,
strerror(errno));
358 struct stat stat_buf;
359 if (stat(LIB_PATH, &stat_buf) == 0) {
362 fprintf(stderr,
"%s Failed to create handler for Antithesis library\n", ERROR_LOG_LINE_PREFIX);
367 return LocalHandler::create();
371 inline LibHandler& get_lib_handler() {
372 static LibHandler* lib_handler =
nullptr;
373 if (lib_handler ==
nullptr) {
374 lib_handler = init().release();
378 {
"version", __VERSION__}
381 JSON version_message{
382 {
"antithesis_sdk", JSON{
383 {
"language", language_block},
388 lib_handler->output(version_message);
401#ifndef NO_ANTITHESIS_SDK
403namespace antithesis::internal::assertions {
404 using namespace antithesis::internal::handlers;
406 struct AssertionState {
407 uint8_t false_not_seen : 1;
408 uint8_t true_not_seen : 1;
411 AssertionState() : false_not_seen(true), true_not_seen(true), rest(0) {}
416 ALWAYS_OR_UNREACHABLE_ASSERTION,
419 UNREACHABLE_ASSERTION,
422 inline constexpr bool get_must_hit(AssertionType type) {
424 case ALWAYS_ASSERTION:
425 case SOMETIMES_ASSERTION:
426 case REACHABLE_ASSERTION:
428 case ALWAYS_OR_UNREACHABLE_ASSERTION:
429 case UNREACHABLE_ASSERTION:
434 inline constexpr const char* get_assert_type_string(AssertionType type) {
436 case ALWAYS_ASSERTION:
437 case ALWAYS_OR_UNREACHABLE_ASSERTION:
439 case SOMETIMES_ASSERTION:
441 case REACHABLE_ASSERTION:
442 case UNREACHABLE_ASSERTION:
443 return "reachability";
447 inline constexpr const char* get_display_type_string(AssertionType type) {
449 case ALWAYS_ASSERTION:
return "Always";
450 case ALWAYS_OR_UNREACHABLE_ASSERTION:
return "AlwaysOrUnreachable";
451 case SOMETIMES_ASSERTION:
return "Sometimes";
452 case REACHABLE_ASSERTION:
return "Reachable";
453 case UNREACHABLE_ASSERTION:
return "Unreachable";
457 struct LocationInfo {
458 const char* class_name;
459 const char* function_name;
460 const char* file_name;
466 {
"class", class_name},
467 {
"function", function_name},
469 {
"begin_line",
line},
470 {
"begin_column", column},
475 inline std::string make_key([[maybe_unused]]
const char* message,
const LocationInfo& location_info) {
479 inline void assert_impl(
bool cond,
const char* message,
const JSON& details,
const LocationInfo& location_info,
480 bool hit,
bool must_hit,
const char* assert_type,
const char* display_type,
const char*
id) {
482 {
"antithesis_assert", JSON{
484 {
"must_hit", must_hit},
485 {
"assert_type", assert_type},
486 {
"display_type", display_type},
487 {
"message", message},
490 {
"location", location_info.to_json()},
491 {
"details", details},
494 antithesis::internal::handlers::get_lib_handler().output(assertion);
497 inline void assert_raw(
bool cond,
const char* message,
const JSON& details,
498 const char* class_name,
const char* function_name,
const char* file_name,
const int line,
const int column,
499 bool hit,
bool must_hit,
const char* assert_type,
const char* display_type,
const char*
id) {
500 LocationInfo location_info{ class_name, function_name, file_name,
line, column };
501 assert_impl(cond, message, details, location_info, hit, must_hit, assert_type, display_type,
id);
506 inline CatalogEntryTracker& get_catalog_entry_tracker() {
507 static CatalogEntryTracker catalog_entry_tracker;
508 return catalog_entry_tracker;
512 AssertionState state;
515 LocationInfo location;
517 Assertion(
const char* message, AssertionType type, LocationInfo&& location) :
518 state(), type(type), message(message), location(
std::
move(location)) {
519 this->add_to_catalog();
522 void add_to_catalog()
const {
524 CatalogEntryTracker& tracker = get_catalog_entry_tracker();
525 if (!tracker.contains(
id)) {
527 const bool condition = (type == REACHABLE_ASSERTION ? true :
false);
528 const bool hit =
false;
529 const char* assert_type = get_assert_type_string(type);
530 const bool must_hit = get_must_hit(type);
531 const char* display_type = get_display_type_string(type);
532 assert_impl(condition, message, {}, location, hit, must_hit, assert_type, display_type,
id.c_str());
536 [[clang::always_inline]]
inline void check_assertion(
auto&& cond,
const JSON& details)
537 requires requires {
static_cast<bool>(std::forward<decltype(cond)>(cond)); } {
538 #if defined(NO_ANTITHESIS_SDK)
539 #error "Antithesis SDK has been disabled"
541 if (__builtin_expect(state.false_not_seen || state.true_not_seen,
false)) {
542 check_assertion_internal(
static_cast<bool>(
std::forward<
decltype(cond)>(cond)), details);
547 void check_assertion_internal(
bool cond,
const JSON& details) {
549 if (!cond && state.false_not_seen) {
551 state.false_not_seen =
false;
554 if (cond && state.true_not_seen) {
556 state.true_not_seen =
false;
560 const bool hit =
true;
561 const char* assert_type = get_assert_type_string(type);
562 const bool must_hit = get_must_hit(type);
563 const char* display_type = get_display_type_string(type);
565 assert_impl(cond, message, details, location, hit, must_hit, assert_type, display_type,
id.c_str());
578 inline constexpr const char* get_guidance_type_string(GuidepostType type) {
580 case GUIDEPOST_MAXIMIZE:
581 case GUIDEPOST_MINIMIZE:
586 case GUIDEPOST_EXPLORE:
591 inline constexpr bool does_guidance_maximize(GuidepostType type) {
593 case GUIDEPOST_MAXIMIZE:
596 case GUIDEPOST_EXPLORE:
597 case GUIDEPOST_MINIMIZE:
603 template <
typename NumericValue,
class Value=std::pair<NumericValue, NumericValue>>
604 struct NumericGuidepost {
606 LocationInfo location;
611 NumericGuidepost(
const char* message, LocationInfo&& location, GuidepostType type) :
612 message(message), location(
std::
move(location)), type(type) {
613 this->add_to_catalog();
614 if (type == GUIDEPOST_MAXIMIZE) {
621 inline void add_to_catalog() {
624 {
"antithesis_guidance", JSON{
625 {
"guidance_type", get_guidance_type_string(type)},
626 {
"message", message},
628 {
"location", location.to_json()},
629 {
"maximize", does_guidance_maximize(type)},
633 get_lib_handler().output(catalog);
638 if (std::is_integral_v<NumericValue>) {
641 if (left % 2 == 1 && right % 2 == 1)
642 return compute_half_gap( left - 1, right - 1);
645 if (left % 2 == 1 || right % 2 == 1) {
647 return compute_half_gap( left - 1, right );
649 return compute_half_gap( left, right - 1 );
653 NumericValue half_left =
left / 2;
654 NumericValue half_right =
right / 2;
655 NumericValue
midpoint = half_left + half_right;
670 if (this->type == GUIDEPOST_MAXIMIZE) {
674 }
else if (!half_gap.
second && extreme_half_gap.
second) {
677 }
else if (half_gap.
second && extreme_half_gap.
second) {
679 return half_gap.
first >= extreme_half_gap.
first;
682 return half_gap.
first <= extreme_half_gap.
first;
688 }
else if (!half_gap.
second && extreme_half_gap.
second) {
691 }
else if (half_gap.
second && extreme_half_gap.
second) {
693 return half_gap.
first <= extreme_half_gap.
first;
696 return half_gap.
first >= extreme_half_gap.
first;
701 [[clang::always_inline]]
inline void send_guidance(Value value) {
703 if (should_send_value(half_gap)) {
704 extreme_half_gap = half_gap;
705 std::string id = make_key(this->message, this->location);
707 {
"antithesis_guidance", JSON{
708 {
"guidance_type", get_guidance_type_string(this->type)},
709 {
"message", this->message},
711 {
"location", this->location.to_json()},
712 {
"maximize", does_guidance_maximize(this->type)},
713 {
"guidance_data", JSON{
714 {
"left", value.first },
715 {
"right", value.second } }},
719 get_lib_handler().output(guidance);
724 template <
typename Gu
idanceType>
725 struct BooleanGuidepost {
727 LocationInfo location;
730 BooleanGuidepost(
const char* message, LocationInfo&& location, GuidepostType type) :
731 message(message), location(
std::
move(location)), type(type) {
732 this->add_to_catalog();
735 inline void add_to_catalog() {
738 {
"antithesis_guidance", JSON{
739 {
"guidance_type", get_guidance_type_string(type)},
740 {
"message", message},
742 {
"location", location.to_json()},
743 {
"maximize", does_guidance_maximize(type)},
747 get_lib_handler().output(catalog);
750 inline virtual void send_guidance(GuidanceType data) {
751 std::string id = make_key(this->message, this->location);
753 {
"antithesis_guidance", JSON{
754 {
"guidance_type", get_guidance_type_string(this->type)},
755 {
"message", this->message},
757 {
"location", location.to_json()},
758 {
"maximize", does_guidance_maximize(this->type)},
759 {
"guidance_data",
data},
763 get_lib_handler().output(guidance);
770 template <std::
size_t N>
771 struct fixed_string {
773 constexpr fixed_string() {
774 for(
unsigned int i=0; i<N; i++) contents[i] = 0;
777 #pragma clang diagnostic push
778 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
779 constexpr fixed_string(
const char (&arr)[N] )
781 for(
unsigned int i=0; i<N; i++) contents[i] = arr[i];
784 static constexpr fixed_string<N> from_c_str(
const char* s ) {
786 for(
unsigned int i=0; i<N && s[i]; i++)
787 it.contents[i] = s[i];
790 #pragma clang diagnostic pop
792 const char* c_str()
const {
return contents.data(); }
795 template <std::
size_t N>
796 fixed_string(
const char (&arr)[N] ) -> fixed_string<N>;
798 #pragma clang diagnostic push
799 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
800 static constexpr size_t string_length(
const char * s ) {
801 for(
int l = 0; ; l++)
805 #pragma clang diagnostic pop
807 template <antithesis::
internal::assertions::AssertionType type, fixed_
string message, fixed_
string file_name, fixed_
string function_name,
int line,
int column>
808 struct CatalogEntry {
809 [[clang::always_inline]]
static inline antithesis::internal::assertions::Assertion
create() {
810 antithesis::internal::assertions::LocationInfo location{
"", function_name.c_str(), file_name.c_str(),
line, column };
811 return antithesis::internal::assertions::Assertion(message.c_str(), type, std::move(location));
814 static inline antithesis::internal::assertions::Assertion assertion =
create();
817 template<
typename Gu
idanceDataType, antithesis::
internal::assertions::Gu
idepostType type, fixed_
string message, fixed_
string file_name, fixed_
string function_name,
int line,
int column>
818 struct BooleanGuidanceCatalogEntry {
819 [[clang::always_inline]]
static inline antithesis::internal::assertions::BooleanGuidepost<GuidanceDataType>
create() {
820 antithesis::internal::assertions::LocationInfo location{
"", function_name.c_str(), file_name.c_str(),
line, column };
822 case antithesis::internal::assertions::GUIDEPOST_ALL:
823 case antithesis::internal::assertions::GUIDEPOST_NONE:
824 return antithesis::internal::assertions::BooleanGuidepost<GuidanceDataType>(message.c_str(), std::move(location), type);
830 static inline antithesis::internal::assertions::BooleanGuidepost<GuidanceDataType> guidepost =
create();
833 template<
typename NumericType, antithesis::
internal::assertions::Gu
idepostType type, fixed_
string message, fixed_
string file_name, fixed_
string function_name,
int line,
int column>
834 struct NumericGuidanceCatalogEntry {
835 [[clang::always_inline]]
static inline antithesis::internal::assertions::NumericGuidepost<NumericType>
create() {
836 antithesis::internal::assertions::LocationInfo location{
"", function_name.c_str(), file_name.c_str(),
line, column };
838 case antithesis::internal::assertions::GUIDEPOST_MAXIMIZE:
839 case antithesis::internal::assertions::GUIDEPOST_MINIMIZE:
840 return antithesis::internal::assertions::NumericGuidepost<NumericType>(message.c_str(), std::move(location), type);
846 static inline antithesis::internal::assertions::NumericGuidepost<NumericType> guidepost =
create();
857#define _NL_1(foo) { #foo, foo }
858#define _NL_2(foo, ...) { #foo, foo }, _NL_1(__VA_ARGS__)
859#define _NL_3(foo, ...) { #foo, foo }, _NL_2(__VA_ARGS__)
860#define _NL_4(foo, ...) { #foo, foo }, _NL_3(__VA_ARGS__)
861#define _NL_5(foo, ...) { #foo, foo }, _NL_4(__VA_ARGS__)
862#define _NL_6(foo, ...) { #foo, foo }, _NL_5(__VA_ARGS__)
863#define _NL_7(foo, ...) { #foo, foo }, _NL_6(__VA_ARGS__)
864#define _NL_8(foo, ...) { #foo, foo }, _NL_7(__VA_ARGS__)
865#define _NL_9(foo, ...) { #foo, foo }, _NL_8(__VA_ARGS__)
866#define _NL_10(foo, ...) { #foo, foo }, _NL_9(__VA_ARGS__)
868#define _ELEVENTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
870#define _GET_NL(...) \
871 _ELEVENTH_ARG(__VA_ARGS__, _NL_10, _NL_9, _NL_8, _NL_7, _NL_6, _NL_5, _NL_4, _NL_3, _NL_2, _NL_1)
873#define NAMED_LIST(...) { _GET_NL(__VA_ARGS__)(__VA_ARGS__) }
875#ifdef NO_ANTITHESIS_SDK
877#ifndef ANTITHESIS_SDK_ALWAYS_POLYFILL
878 #define ANTITHESIS_SDK_ALWAYS_POLYFILL(...)
881#ifndef ANTITHESIS_SDK_SOMETIMES_POLYFILL
882 #define ANTITHESIS_SDK_SOMETIMES_POLYFILL(...)
885#ifndef ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL
886 #define ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL(...) \
887 ANTITHESIS_SDK_ALWAYS_POLYFILL(__VA_ARGS__)
890#define ALWAYS(cond, message, ...) \
891 ANTITHESIS_SDK_ALWAYS_POLYFILL(cond, message, __VA_ARGS__)
892#define ALWAYS_OR_UNREACHABLE(cond, message, ...) \
893 ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL(cond, message, __VA_ARGS__)
894#define SOMETIMES(cond, message, ...) \
895 ANTITHESIS_SDK_SOMETIMES_POLYFILL(cond, message, __VA_ARGS__)
896#define REACHABLE(message, ...) \
897 ANTITHESIS_SDK_SOMETIMES_POLYFILL(true, message, __VA_ARGS__)
898#define UNREACHABLE(message, ...) \
899 ANTITHESIS_SDK_ALWAYS_POLYFILL(false, message, __VA_ARGS__)
900#define ALWAYS_GREATER_THAN(val, threshold, message, ...) \
901 ANTITHESIS_SDK_ALWAYS_POLYFILL((val > threshold), message, __VA_ARGS__)
902#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) \
903 ANTITHESIS_SDK_ALWAYS_POLYFILL((val >= threshold), message, __VA_ARGS__)
904#define SOMETIMES_GREATER_THAN(val, threshold, message, ...) \
905 ANTITHESIS_SDK_SOMETIMES_POLYFILL((val > threshold), message, __VA_ARGS__)
906#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) \
907 ANTITHESIS_SDK_SOMETIMES_POLYFILL((val >= threshold), message, __VA_ARGS__)
908#define ALWAYS_LESS_THAN(val, threshold, message, ...) \
909 ANTITHESIS_SDK_ALWAYS_POLYFILL((val < threshold), message, __VA_ARGS__)
910#define ALWAYS_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) \
911 ANTITHESIS_SDK_ALWAYS_POLYFILL((val <= threshold), message, __VA_ARGS__)
912#define SOMETIMES_LESS_THAN(val, threshold, message, ...) \
913 ANTITHESIS_SDK_SOMETIMES_POLYFILL((val < threshold), message, __VA_ARGS__)
914#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) \
915 ANTITHESIS_SDK_SOMETIMES_POLYFILL((val <= threshold), message, __VA_ARGS__)
916#define ALWAYS_SOME(pairs, message, ...) \
917 ANTITHESIS_SDK_ALWAYS_POLYFILL(([&](){ \
918 std::initializer_list<std::pair<std::string, bool>> ps = pairs; \
919 for (auto const& pair : ps) \
920 if (pair.second) return true; \
921 return false; }()), message, __VA_ARGS__)
922#define SOMETIMES_ALL(pairs, message, ...) \
923 ANTITHESIS_SDK_SOMETIMES_POLYFILL(([&](){ \
924 std::initializer_list<std::pair<std::string, bool>> ps = pairs; \
925 for (auto const& pair : ps) \
926 if (!pair.second) return false; \
927 return true; }()), message, __VA_ARGS__)
931#include <source_location>
933#define FIXED_STRING_FROM_C_STR(s) (antithesis::internal::fixed_string<antithesis::internal::string_length(s)+1>::from_c_str(s))
935#define ANTITHESIS_ASSERT_RAW(type, cond, message, ...) ( \
936 antithesis::internal::CatalogEntry< \
938 antithesis::internal::fixed_string(message), \
939 FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \
940 FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \
941 std::source_location::current().line(), \
942 std::source_location::current().column() \
943 >::assertion.check_assertion(cond, (antithesis::JSON(__VA_ARGS__)) ) )
945#define ALWAYS(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_ASSERTION, cond, message, __VA_ARGS__)
946#define ALWAYS_OR_UNREACHABLE(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_OR_UNREACHABLE_ASSERTION, cond, message, __VA_ARGS__)
947#define SOMETIMES(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::SOMETIMES_ASSERTION, cond, message, __VA_ARGS__)
948#define REACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::REACHABLE_ASSERTION, true, message, __VA_ARGS__)
949#define UNREACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::UNREACHABLE_ASSERTION, false, message, __VA_ARGS__)
951#define ANTITHESIS_NUMERIC_ASSERT_RAW(name, assertion_type, guidepost_type, left, cmp, right, message, ...) \
953 static_assert(std::is_same_v<decltype(left), decltype(right)>, "Values compared in " #name " must be of same type"); \
954 ANTITHESIS_ASSERT_RAW(assertion_type, left cmp right, message, __VA_ARGS__ __VA_OPT__(,) {{ "left", left }, { "right", right }} ); \
955 antithesis::internal::NumericGuidanceCatalogEntry< \
958 antithesis::internal::fixed_string(message), \
959 FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \
960 FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \
961 std::source_location::current().line(), \
962 std::source_location::current().column() \
963 >::guidepost.send_guidance({ left, right }); \
966#define ALWAYS_GREATER_THAN(left, right, message, ...) \
967ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_GREATER_THAN, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, >, right, message, __VA_ARGS__)
968#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \
969ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_GREATER_THAN_OR_EQUAL_TO, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, >=, right, message, __VA_ARGS__)
970#define SOMETIMES_GREATER_THAN(left, right, message, ...) \
971ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_GREATER_THAN, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, >, right, message, __VA_ARGS__)
972#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \
973ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_GREATER_THAN_OR_EQUAL_TO, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, >=, right, message, __VA_ARGS__)
974#define ALWAYS_LESS_THAN(left, right, message, ...) \
975ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_LESS_THAN, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, <, right, message, __VA_ARGS__)
976#define ALWAYS_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \
977ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_LESS_THAN_OR_EQUAL_TO, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, <=, right, message, __VA_ARGS__)
978#define SOMETIMES_LESS_THAN(left, right, message, ...) \
979ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_LESS_THAN, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, <, right, message, __VA_ARGS__)
980#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \
981ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_LESS_THAN_OR_EQUAL_TO, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, <=, right, message, __VA_ARGS__)
983#define ALWAYS_SOME(pairs, message, ...) \
985 bool disjunction = false; \
986 std::vector<std::pair<std::string, bool>> vec_pairs = pairs; \
987 for (std::pair<std::string, bool> pair : vec_pairs) { \
989 disjunction = true; \
993 ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_ASSERTION, disjunction, message, __VA_ARGS__ __VA_OPT__(,) pairs); \
994 antithesis::JSON json_pairs = antithesis::JSON(pairs); \
995 antithesis::internal::BooleanGuidanceCatalogEntry< \
996 decltype(json_pairs), \
997 antithesis::internal::assertions::GUIDEPOST_NONE, \
998 antithesis::internal::fixed_string(message), \
999 FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \
1000 FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \
1001 std::source_location::current().line(), \
1002 std::source_location::current().column() \
1003 >::guidepost.send_guidance(json_pairs); \
1006#define SOMETIMES_ALL(pairs, message, ...) \
1008 bool conjunction = true; \
1009 std::vector<std::pair<std::string, bool>> vec_pairs = pairs; \
1010 for (std::pair<std::string, bool> pair : vec_pairs) { \
1011 if (!pair.second) { \
1012 conjunction = false; \
1016 ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::SOMETIMES_ASSERTION, conjunction, message, __VA_ARGS__ __VA_OPT__(,) pairs); \
1017 antithesis::JSON json_pairs = antithesis::JSON(pairs); \
1018 antithesis::internal::BooleanGuidanceCatalogEntry< \
1019 decltype(json_pairs), \
1020 antithesis::internal::assertions::GUIDEPOST_ALL, \
1021 antithesis::internal::fixed_string(message), \
1022 FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \
1023 FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \
1024 std::source_location::current().line(), \
1025 std::source_location::current().column() \
1026 >::guidepost.send_guidance(json_pairs); \
1035#ifdef NO_ANTITHESIS_SDK
1050 {
"antithesis_setup", JSON{
1051 {
"status",
"complete"},
1052 {
"details", details}
1055 antithesis::internal::handlers::get_lib_handler().output(json);
1058 inline void send_event(
const char* name,
const JSON& details) {
1059 JSON json = { { name, details } };
1060 antithesis::internal::handlers::get_lib_handler().output(json);
1074#ifdef NO_ANTITHESIS_SDK
1079 return random_gen.
random();
1087 return antithesis::internal::handlers::get_lib_handler().random();
1094 template <
typename Iter>
1096 ssize_t num_things = end - begin;
1097 if (num_things == 0) {
1102 ssize_t index = uval % num_things;
1103 return begin + index;
JSONValue begin(JSONValue ... args)
JSONValue end(JSONValue ... args)
Value to_json(ripple::Number const &number)
void setup_complete(const JSON &details)
std::variant< JSON, std::nullptr_t, std::string, bool, char, int, uint64_t, float, double, const char *, JSONArray > JSONValue
const char * PROTOCOL_VERSION
Iter random_choice(Iter begin, Iter end)
void send_event(const char *name, const JSON &details)
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
JSONArray(std::vector< T > vals)
JSON(std::initializer_list< std::pair< const std::string, JSONValue > > args)
JSON(std::initializer_list< std::pair< const std::string, JSONValue > > args, std::vector< std::pair< const std::string, JSONValue > > more_args)
std::random_device device
std::uniform_int_distribution< unsigned long long > distribution