

Самая чрезмерная библиотека утверждений C ++
Философия библиотеки: предоставьте как можно больше полезной диагностической информации.
Некоторые из удивительных вещей, которые делает библиотека:
void zoog ( const std::map<std::string, int >& map) {
DEBUG_ASSERT (map. contains ( " foo " ), " expected key not found " , map);
}
ASSERT (vec.size() > min_items(), "vector doesn't have enough items", vec);
std::optional< float > get_param ();
float f = * ASSERT_VAL (get_param());
Типы утверждений:
Условные утверждения:
DEBUG_ASSERT : зарегистрировано в отладке, но ничего не делает в выпуске (аналогично assert стандартной библиотеки)ASSERT : зарегистрировано как в отладке, так и в выпускеASSUME : зарегистрировано в отладке и служит намеком на оптимизацию в выпускеБезусловные утверждения:
PANIC : триггеры как в отладке, так и в выпускеUNREACHABLE : триггеры в отладке, отмеченные как недоступные в выпуске Предпочитаете assert Lowecase?
Вы можете включить нижнюю часть debug_assert и assert псевдонимы с помощью -DLIBASSERT_LOWERCASE .
Сводка функций:
ASSERT_EQ и т. Д.DEBUG_ASSERT_VAL и ASSERT_VAL , которые возвращают значение, чтобы их можно было легко интегрировать в код, например, FILE* f = ASSERT_VAL(fopen(path, "r") != nullptr) include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)
# On windows copy libassert.dll to the same directory as the executable for your_target
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif () Обязательно настройте с помощью -DCMAKE_BUILD_TYPE=Debug или -DDCMAKE_BUILD_TYPE=RelWithDebInfo для символов и информации.
На MacOS рекомендуется генерировать файл .dsym, см. Logistics Platform Logistics ниже.
Другие способы использования библиотеки, например, через менеджеры пакетов или общеобразовательную установку, см. Использование ниже.
По сути, роль утверждений заключается в проверке предположений, сделанных в программном обеспечении, и выявить нарушения, близкие к их источникам. Инструменты утверждения должны расставить приоритеты для предоставления как можно большего количества информации и контекста для разработчика, чтобы обеспечить быструю сортировку. К сожалению, существующий языковой и библиотечный инструмент предоставляет очень ограниченную информацию о сортировке.
Например, с утверждениями Stdlib, такое утверждение, как assert(n <= 12); не предоставляет никакой информации о неудаче о том, почему он потерпел неудачу или что привело к его провалу. Предоставление трассировки стека и ценность n Greatley улучшает сортировку и отладку. В идеале сбой утверждения должен предоставить достаточно диагностической информации, что программке не нужно повторять от отладчика, чтобы определить проблему.
Версия 1 этой библиотеки стала исследование, посвященное тому, сколько полезной информации и функциональности можно было упаковать в утверждения, а также обеспечить быстрый и простой интерфейс для разработчика.
Версия 2 этой библиотеки берет уроки, извлеченные из версии 1, чтобы создать инструмент, который я лично нашел незаменимым в разработке.
Наиболее важной функцией, которую поддерживает эта библиотека, является автоматическое разложение выражения. Нет необходимости в ASSERT_LT или других подобных хлопот, assert(vec.size() > 10); автоматически понимается, как показано выше.
Значения, связанные с выражениями, отображаются. Избыточную диагностику, такую как 2 => 2 избегают.
DEBUG_ASSERT (map.count( 1 ) == 2);
Только полное выражение Assert может быть извлечено из макроса. Показывая, какие части выражения соответствуют тому, какие значения требуют некоторого базового анализа выражения. Грамматика C ++ неоднозначна, но большинство выражений могут быть устранены.
Все утверждения в этой библиотеке поддерживают дополнительные диагностические сообщения, а также произвольные другие диагностические сообщения.
FILE* f = ASSERT_VAL(fopen(path, " r " ) != nullptr , " Internal error with foobars " , errno, path); Специальная обработка предусмотрена для errno , и Strerror автоматически вызывается.
Примечание. Дополнительная диагностика оценивается только по пути сбоя утверждения.

Много работ было проведено в создании красивых трассов и форматировании их как можно более хорошо. CPPTRACE используется в качестве портативного и автономного решения для StackTraces Pre-C ++ 23. Необязательные конфигурации можно найти в документации библиотеки.
Одна особенность, которую стоит отметить, заключается в том, что вместо того, чтобы всегда печатать полные пути, напечатано только минимальное количество каталогов, необходимых для дифференциации путей.

Другая особенность, которую стоит указать, заключается в том, что следы стека будут складываться с глубокими рекурсиями:

Обработчик утверждения применяет синтаксис, выделяя везде, где это необходимо, как видно во всех снимках экрана выше. Это помогает улучшить читаемость.
Libassert поддерживает индивидуальные обработчики сбоев утверждения:
void handler (assert_type type, const assertion_info& assertion) {
throw std::runtime_error ( " Assertion failed: n " + assertion. to_string ());
}
int main () {
libassert::set_failure_handler (handler);
} Много внимания уделяется максимально эффективной производительности отладки значений: строки, символы, числа должны быть напечатаны, как и следовало ожидать. Кроме того, контейнеры, кортежи, std :: Необязательные, умные указатели и т. Д. Все строки, чтобы показать как можно больше информации. Если пользователь определял operator<<(std::ostream& o, const S& s) , эта перегрузка будет вызвана. В противном случае это сообщение по умолчанию будет напечатано. Кроме того, предоставлена точка настройки Stringification:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};

Значения утверждений напечатаны в шестнадцатеричном или бинарном, а также в десятичном виде, если шестнадцатеричный/двоичный используется по обе стороны от выражения утверждения:
ASSERT (get_mask() == 0b00001101);
Поскольку выражения уже автоматически разлагаются, вы можете сделать сравнения, выполненные автоматически, выполненные автоматически с безопасностью знака с -DLIBASSERT_SAFE_COMPARISONS :
ASSERT ( 18446744073709551606ULL == - 10 );
Libassert предоставляет два заголовка <libassert/assert-catch2.hpp> и <libassert/assert-gtest.hpp> для использования с Catch2 и Googletest.
Пример вывода из GTest:

Более подробную информацию ниже.
Libassert предоставляет три типа утверждений, каждый из которых немного изменяется в зависимости от того, когда его следует проверить и как его следует интерпретировать:
| Имя | Эффект |
|---|---|
DEBUG_ASSERT | Проверяется в отладке, нет CodeGen в выпуске |
ASSERT | Зарегистрировано в сборке отладки и выпуска |
ASSUME | Проверяется в отладке, if(!(expr)) { __builtin_unreachable(); } в выпуске |
Безусловные утверждения
| Имя | Эффект |
|---|---|
PANIC | Триггеры как в отладке, так и в выпуске |
UNREACHABLE | Запускается в отладке, отмеченной как недоступная в выпуске. |
Одним из преимуществ PANIC и UNREACHABLE по сравнению с ASSERT(false, ...) является то, что компилятор получает информацию [[noreturn]] .
ASSUME , что отмечает путь отказа как недоступный в выпуске, потенциально предоставляя полезную информацию для оптимизатора. Это не поведение по умолчанию для всех утверждений, потому что непосредственное следствие этого состоит в том, что отказ утверждения в -DNDEBUG может привести к UB, и лучше сделать это очень явным.
Варианты утверждения, которые можно использовать в линии в выражении, например, FILE* file = ASSERT_VAL(fopen(path, "r"), "Failed to open file"); , также доступны:
| Имя | Эффект |
|---|---|
DEBUG_ASSERT_VAL | Проверено в отладке, должна быть оценена как в отладке, так и в выпуске |
ASSERT_VAl | Зарегистрировано в сборке отладки и выпуска |
ASSUME_VAL | Проверяется в отладке, if(!(expr)) { __builtin_unreachable(); } в выпуске |
ПРИМЕЧАНИЕ. Даже в выпуске строится выражение для DEBUG_ASSERT_VAL все еще должно быть оценено, в отличие от DEBUG_ASSERT . Конечно, если результат не используется и не дает никаких побочных эффектов, он будет оптимизирован.
Производительность: Что касается производительности времени выполнения, влияние на Callingites очень минимально ниже -Og или выше. Быстрый путь в коде (то есть, где утверждение не проходит), будет быстро. Для обработки сбоев утверждения требуется много работы, как только они произойдут. Однако, поскольку неудачи должны быть редкими, это не должно иметь значения.
Скорости компиляции: существует затраты на время компиляции, связанные со всеми временными экземплярами шаблонов, необходимыми для магии этой библиотеки.
Другой:
Примечание
Из -за разложения выражения, ASSERT(1 = 2); компилируется.
Все функции утверждения - макросы. Вот некоторые псевдо-декларации для взаимодействия с ними:
void DEBUG_ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSUME (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) DEBUG_ASSERT_VAL(expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSERT_VAL (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSUME_VAL (expression, [optional message], [optional extra diagnostics, ...]);
void PANIC ([optional message], [optional extra diagnostics, ...]);
void UNREACHABLE ([optional message], [optional extra diagnostics, ...]); -DLIBASSERT_PREFIX_ASSERTIONS можно использовать для префикса этих макросов с помощью LIBASSERT_ . Это полезно для завершения утверждений Libassert.
-DLIBASSERT_LOWERCASE можно использовать для включения псевдонимов debug_assert и assert что для DEBUG_ASSERT и ASSERT . Смотрите: замена <Assert>.
expression expression автоматически разлагается, поэтому может быть предоставлена диагностическая информация. Результирующий тип должен быть конвертируемым для логического.
Операция между левой и правой стороны операции верхнего уровня в дереве выражения оценивается функциональным объектом.
ПРИМЕЧАНИЕ. Логические операторы логических лиц ( && и || ) не разлагаются по умолчанию из -за короткого замыкания.
assertion message Необходимое сообщение о утверждении может быть предоставлено. Если первый аргумент после выражения утверждения или первый аргумент в панике/недостатке, является любым типом строки, который он будет использоваться в качестве сообщения (если вы хотите, чтобы первый параметр, который оказался строкой, является дополнительным диагностическим значением вместо этого просто просто передайте пустую строку, т.е. ASSERT(foo, "", str); ).
ПРИМЕЧАНИЕ. Выражение сообщения о утверждении оценивается только в пути сбоя утверждения.
extra diagnosticsМожет быть предоставлено произвольное количество дополнительных диагностических значений. Они отображаются ниже диагностики экспрессии, если проверка не удается.
Примечание. Дополнительная диагностика оценивается только по пути сбоя утверждения.
Существует специальная обработка, когда предоставляется errno : значение strerror отображается автоматически.
Чтобы облегчить простоту интеграции в код _VAL , предоставляются варианты, которые возвращают значение из выражения ASSERT. Возвращенное значение определяется следующим образом:
ASSERT_VAL(foo()); или ASSERT_VAL(false); ) в выражении утверждения значение выражения просто возвращается.== ,! != , < , <= , > , >= , && , || или или любое назначение или комплексное назначение, тогда возвращается значение левого операнда .& , | , ^ , << , >> , или любой бинарный оператор с приоритетом выше, а затем возвращается значение всего выражения. Т.е. ASSERT_VAL(foo() > 2); Возвращает вычисленный результат из foo() и ASSERT_VAL(x & y); Возвращает вычисленный результат x & y ;
Если значение из выбранного выражения утверждения, которое будет возвращено, является LVALUE, тип вызова утверждения будет ссылкой на LVALUE. Если значение из выражения утверждения является RValue, то тип вызова будет RValue.
namespace libassert {
[[nodiscard]] std::string stacktrace (
int width = 0 ,
const color_scheme& scheme = get_color_scheme(),
std::size_t skip = 0
);
template < typename T> [[nodiscard]] std::string_view type_name () noexcept ;
template < typename T> [[nodiscard]] std::string pretty_type_name () noexcept ;
template < typename T> [[nodiscard]] std::string stringify ( const T& value);
}stacktrace : генерирует трассировку стека, форматы к заданной ширине (0 без форматирования ширины)type_name : возвращает название типа tpretty_type_name : возвращает имя с предварительным типом для tstringify : создает строку отладки значения namespace libassert {
void enable_virtual_terminal_processing_if_needed ();
inline constexpr int stdin_fileno = 0 ;
inline constexpr int stdout_fileno = 1 ;
inline constexpr int stderr_fileno = 2 ;
bool isatty ( int fd);
[[nodiscard]] int terminal_width ( int fd);
}enable_virtual_terminal_processing_if_needed : включить последовательности ANSI для выхода для терминалов в Windows, необходимых для вывода цвета.isatty : возвращает true, если дескриптор файла соответствует терминалуterminal_width : возвращает ширину терминала, представленной FD или 0 по ошибке namespace libassert {
// NOTE: string view underlying data should have static storage duration, or otherwise live as
// long as the scheme is in use
struct color_scheme {
std::string_view string, escape, keyword, named_literal, number, punctuation, operator_token,
call_identifier, scope_resolution_identifier, identifier, accent, unknown, reset;
static const color_scheme ansi_basic;
static const color_scheme ansi_rgb;
static const color_scheme blank;
};
void set_color_scheme ( const color_scheme&);
const color_scheme& get_color_scheme ();
} По умолчанию color_scheme::ansi_rgb используется. Чтобы отключить цвета, используйте color_scheme::blank .
set_color_scheme : устанавливает цветовую схему для обработчика утверждения по умолчанию, когда Stderr является терминалом namespace libassert {
void set_separator (std::string_view separator);
}set_separator : устанавливает разделитель между выражением и значением в выходе диагностики утверждения. По умолчанию: => . ПРИМЕЧАНИЕ: не безопасно. namespace libassert {
enum class literal_format_mode {
infer, // infer literal formats based on the assertion condition
no_variations, // don't do any literal format variations, just default
fixed_variations // always use a fixed set of formats (in addition to the default format)
};
void set_literal_format_mode (literal_format_mode);
enum class literal_format : unsigned {
// integers and floats are decimal by default, chars are of course chars, and everything
// else only has one format that makes sense
default_format = 0 ,
integer_hex = 1 ,
integer_octal = 2 ,
integer_binary = 4 ,
integer_character = 8 , // format integers as characters and characters as integers
float_hex = 16 ,
};
[[nodiscard]] constexpr literal_format operator |(literal_format a, literal_format b);
void set_fixed_literal_format (literal_format);
}set_literal_format_mode : устанавливает, должна ли библиотека отображать буквальные изменения или сделать ихset_fixed_literal_format : установить фиксированную конфигурацию литерального формата, автоматически изменяет Literal_format_Mode; Обратите внимание, что формат по умолчанию всегда будет использоваться вместе с другими namespace libassert {
enum class path_mode {
full, // full path is used
disambiguated, // only enough folders needed to disambiguate are provided
basename, // only the file name is used
};
LIBASSERT_EXPORT void set_path_mode (path_mode mode);
}set_path_mode : устанавливает режим сокращения пути для вывода утверждения. По умолчанию: path_mode::disambiguated . namespace libassert {
enum class assert_type {
debug_assertion,
assertion,
assumption,
panic,
unreachable
};
struct LIBASSERT_EXPORT binary_diagnostics_descriptor {
std::string left_expression;
std::string right_expression;
std::string left_stringification;
std::string right_stringification;
};
struct extra_diagnostic {
std::string_view expression;
std::string stringification;
};
struct LIBASSERT_EXPORT assertion_info {
std::string_view macro_name;
assert_type type;
std::string_view expression_string;
std::string_view file_name;
std:: uint32_t line;
std::string_view function;
std::optional<std::string> message;
std::optional<binary_diagnostics_descriptor> binary_diagnostics;
std::vector<extra_diagnostic> extra_diagnostics;
size_t n_args;
std::string_view action () const ;
const cpptrace::raw_trace& get_raw_trace () const ;
const cpptrace::stacktrace& get_stacktrace () const ;
[[nodiscard]] std::string header ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string tagline ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string location () const ;
[[nodiscard]] std::string statement ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_binary_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_extra_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_stacktrace ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string to_string ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
};
} Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Debug Assertion failed : assertion_info.action()demo.cpp:194 : assertion_info.file_name and assertion_info.linevoid foo::baz() : assertion_info.pretty_functionInternal error with foobars : assertion_info.messagedebug_assert : assertion_info.macro_nameopen(path, 0) >= 0 : assertion_info.expression_string... : определено с помощью assertion_info.n_args , в котором общее количество аргументов, передаваемых на макрос утвержденияopen(path, 0) : assertion_info.binary_diagnostics.left_expression-1 : assertion_info.binary_diagnostics.left_stringification0 => 0 не полезно)errno : assertion_info.extra_diagnostics[0].expression2 "No such file or directory" : assertion_info.extra_diagnostics[0].stringificationassertion_info.get_stacktrace() , или assertion_info.get_raw_trace() чтобы получить трассировку без разрешения егоПомощники:
assertion_info.header() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.tagline() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
assertion_info.location() :
Примечание
Обработка пути будет выполняться в соответствии с режимом пути
demo.cpp:194
assertion_info.statement() :
debug_assert(open(path, 0) >= 0, ...);
assertion_info.print_binary_diagnostics() :
Where:
open(path, 0) => -1
assertion_info.print_extra_diagnostics() :
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.print_stacktrace() :
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Libassert предоставляет точку настройки для пользовательских типов:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};По умолчанию любые контейнерные типы, определенные пользователями, будут автоматически осуществляться.
Кроме того, LIBASSERT_USE_FMT может использоваться, чтобы позволить Libassert использовать fmt::formatter S.
Наконец, любые типы с operator<< перегрузка может быть строки.
namespace libassert {
void set_failure_handler ( void (*handler)( const assertion_info&));
}set_failure_handler : устанавливает обработчик утверждения для программы.Пример обработчика утверждения, похожий на обработчик по умолчанию:
void libassert_default_failure_handler ( const assertion_info& info) {
libassert::enable_virtual_terminal_processing_if_needed (); // for terminal colors on windows
std::string message = info. to_string (
libassert::terminal_width (libassert::stderr_fileno),
libassert::isatty (libassert::stderr_fileno)
? libassert::get_color_scheme ()
: libassert::color_scheme::blank
);
std::cerr << message << std::endl;
switch (info. type ) {
case libassert::assert_type::assertion:
case libassert::assert_type::debug_assertion:
case libassert::assert_type::assumption:
case libassert::assert_type::panic:
case libassert::assert_type::unreachable:
( void ) fflush (stderr);
std::abort ();
// Breaking here as debug CRT allows aborts to be ignored, if someone wants to make a
// debug build of this library
break ;
default :
std::cerr << " Critical error: Unknown libassert::assert_type " << std::endl;
std::abort ( 1 );
}
}По умолчанию Libassert прерывается от всех типов утверждений. Тем не менее, может быть желательно выбросить исключение из некоторых или всех типов утверждений вместо прерывания.
Важный
Обработчики сбоя не должны возвращаться для assert_type::panic и assert_type::unreachable .
Libassert поддерживает программные точки останова в отношении неспособности сделать утверждения более благоприятными отладчиками, нарушая линию утверждения, а не несколько слоев глубоко в вызове:

Эта функциональность в настоящее время выходит на участие, и ее можно включить, определив LIBASSERT_BREAK_ON_FAIL . Это лучше всего сделано в виде флага компилятора: -DLIBASSERT_BREAK_ON_FAIL или /DLIBASSERT_BREAK_ON_FAIL .
Внутренне библиотека проверяет на предмет договоренности отладчика перед выполнением инструкции по точке с отладчиком. По умолчанию чек выполняется только один раз при первом сбое утверждения. В некоторых сценариях может быть желательно настроить эту проверку, чтобы всегда выполняться, например, если вы используете пользовательский обработчик утверждения, который бросает исключение вместо прерывания, и вы можете восстановиться после сбоя утверждений, позволяя дополнительным сбоям позже, и вы прилагаете только частично отладку через пробег своей программы. Вы можете использовать libassert::set_debugger_check_mode для управления тем, как выполняется эта проверка:
namespace libassert {
enum class debugger_check_mode {
check_once,
check_every_time,
};
void set_debugger_check_mode (debugger_check_mode mode) noexcept ;
}Библиотека также разоблачает свои внутренние утилиты для установки точек останова и проверки того, отлаживается ли программа:
namespace libassert {
bool is_debugger_present () noexcept ;
}
# define LIBASSERT_BREAKPOINT () <...internals...>
# define LIBASSERT_BREAKPOINT_IF_DEBUGGING () <...internals...>Этот API имитирует API P2514, который был принят в C ++ 26.
Примечание о constexpr : для Clang и MSVC Libassert может использовать внутреннюю часть компилятора, однако, для встроенной сборки GCC. Встроенная сборка не допускается в функциях contexPR Pre-C ++ 20, однако GCC поддерживает его с предупреждением после GCC 10, и библиотека может удивить, что предупреждение для GCC 12.
Определяет:
LIBASSERT_USE_MAGIC_ENUM : используйте Magic Enum для строительства значений enumLIBASSERT_DECOMPOSE_BINARY_LOGICAL : decpose && ||LIBASSERT_SAFE_COMPARISONS : включить безопасные сравнения подписанных подписанных для разложенных выраженийLIBASSERT_PREFIX_ASSERTIONS : префиксы все макросы утверждения с LIBASSERT_LIBASSERT_USE_FMT : включает интеграцию libfmtLIBASSERT_NO_STRINGIFY_SMART_POINTER_OBJECTS : отключает строку содержимого интеллектуального указателяCmake:
LIBASSERT_USE_EXTERNAL_CPPTRACE : используйте Externam cpptrace вместо того, чтобы приостановить библиотеку с помощью FetchContentLIBASSERT_USE_EXTERNAL_MAGIC_ENUM : используйте externam Magic Enum вместо того, чтобы приостановить библиотеку с помощью FetchContentПримечание
Из-за неконформирующего препроцессора MSVC нет простого способа обеспечить обертки утверждений. Для использования интеграции библиотеки тестовых библиотеки /Zc:preprocessor .
Libassert обеспечивает интеграцию Catch2 в libassert/assert-catch2.hpp :
# include < libassert/assert-catch2.hpp >
TEST_CASE ( " 1 + 1 is 2 " ) {
ASSERT ( 1 + 1 == 3 );
}
В настоящее время единственным предоставленным макросом является ASSERT , который будет выполнять REQUIRE внутри.
ПРИМЕЧАНИЕ. До v3.6.0 цветовые коды ANSI мешают линейной упаковке Catch2, поэтому цвет отключен в старых версиях.
Libassert обеспечивает интеграцию GTEST в libassert/assert-gtest.hpp :
# include < libassert/assert-gtest.hpp >
TEST (Addition, Arithmetic) {
ASSERT ( 1 + 1 == 3 );
}
В настоящее время Libassert предоставляет ASSERT и EXPECT макросов для GTEST.
Это не так красиво, как я хотел бы, однако, это выполняет работу.
Эта библиотека нацелена> = C ++ 17 и поддерживает все основные компиляторы и все основные платформы (Linux, MacOS, Windows и Mingw).
ПРИМЕЧАНИЕ. Библиотека полагается на некоторые расширения компилятора и специфические функции компилятора, поэтому она не совместима с -pedantic .
С Cmake FetchContent:
include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)ПРИМЕЧАНИЕ. В Windows и MacOS рекомендуется дополнительная работа, см. Logistics Platform Logistics ниже.
Обязательно настройте с помощью -DCMAKE_BUILD_TYPE=Debug или -DDCMAKE_BUILD_TYPE=RelWithDebInfo для символов и информации.
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j
sudo make installИспользование через Cmake:
find_package (libassert REQUIRED)
target_link_libraries (<your target > libassert::assert) Обязательно настройте с помощью -DCMAKE_BUILD_TYPE=Debug или -DDCMAKE_BUILD_TYPE=RelWithDebInfo для символов и информации.
Или компилировать с -lassert :
g++ main.cpp -o main -g -Wall -lassert
./mainЕсли вы получите ошибку в соответствии с
error while loading shared libraries: libassert.so: cannot open shared object file: No such file or directory
Возможно, вам придется запустить sudo /sbin/ldconfig для создания любых необходимых ссылок и обновлять кэши, чтобы система могла найти libcpptrace.so (я должен был сделать это на Ubuntu). Только при установке всей системы. Обычно ваш пакет Manger делает это для вас при установке новых библиотек.
git clone https: // github.com / jeremy - rifkin / libassert.git
git checkout v2. 1.2
mkdir libassert / build
cd libassert / build
cmake . . - DCMAKE_BUILD_TYPE = Release
msbuild libassert.sln
msbuild INSTALL.vcxprojПримечание. Вам нужно будет работать в качестве администратора в разработчике PowerShell или использовать vcvarsall.bat, распространяемый с Visual Studio, чтобы установить правильные переменные среды.
Чтобы установить только для локального пользователя (или любого пользовательского префикса):
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX= $HOME /wherever
make -j
sudo make installИспользование через Cmake:
find_package (libassert REQUIRED PATHS $ENV{HOME} /wherever)
target_link_libraries (<your target > libassert::assert)Использование вручную:
g++ main.cpp -o main -g -Wall -I$HOME/wherever/include -L$HOME/wherever/lib -lassert
Чтобы использовать библиотеку без CMAKE, сначала следуйте инструкциям по установке при установке в масштабе системы, установке локального пользователя или менеджеров пакетов.
Используйте следующие аргументы для компиляции с Libassert:
| Компилятор | Платформа | Зависимости |
|---|---|---|
| GCC, Clang, Intel и т. Д. | Linux/macOS/Unix | -libassert -I[path] [cpptrace args] |
| Mingw | Окна | -libassert -I[path] [cpptrace args] |
| MSVC | Окна | assert.lib /I[path] [cpptrace args] |
| герметичный | Окна | -libassert -I[path] [cpptrace args] |
Для [path] Заполнителя в -I[path] и /I[path] укажите путь к папке включения, содержащей libassert/assert.hpp .
Если вы связываете статически, вам также необходимо указать -DLIBASSERT_STATIC_DEFINE .
Заполнитель [cpptrace args] обратитесь к документации CPPTRACE.
Libassert доступен через Conan по адресу https://conan.io/center/recipes/libassert.
[requires]
libassert/2.1.2
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
# ...
find_package (libassert REQUIRED)
# ...
target_link_libraries (YOUR_TARGET libassert::assert) vcpkg install libassert
find_package (libassert CONFIG REQUIRED)
target_link_libraries (YOUR_TARGET PRIVATE libassert::assert)Windows и MacOS требуют немного дополнительной работы, чтобы получить все в нужном месте
Копирование библиотеки .dll в Windows:
# Copy the assert.dll on windows to the same directory as the executable for your_target.
# Not required if static linking.
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif ()В MacOS рекомендуется генерировать файл DSYM, содержащий информацию отладки для вашей программы:
В Xcode Cmake это можно сделать с
set_target_properties (your_target PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" ) И вне Xcode это можно сделать с помощью dsymutil yourbinary :
# Create a .dSYM file on macos. Currently required, but hopefully not for long
if ( APPLE )
add_custom_command (
TARGET your_target
POST_BUILD
COMMAND dsymutil $<TARGET_FILE:your_target>
)
endif () Эта библиотека не является заменой для <cassert> . -DLIBASSERT_LOWERCASE может использоваться для создания псевдонимов строчных средств для макросов утверждения, но имейте в виду, что ASSERT Libassert по -прежнему проверяется в выпуске. Чтобы заменить <cassert> использовать с помощью Libassert, замените assert на DEBUG_ASSERT или создайте псевдоним по следующим линиям:
# define assert (...) DEBUG_ASSERT(__VA_ARGS__) Одна вещь, которую нужно знать: переопределение assert Cassert технически не разрешено стандартом, но это не должно быть проблемой для любого здравомыслящего компилятора.
Нет, пока нет.
cpp-sort Даже с такими конструкциями, как assert_eq , диагностика утверждения часто не хватает. Например, в ржавчине отображаются значения левого и правого, но не сами выражения:
fn main ( ) {
let count = 4 ;
assert_eq ! ( count , 2 ) ;
} thread 'main' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `2`', /app/example.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Это не так полезно, как могло бы быть.
Функциональность других языков / их стандартные библиотеки предоставляют:
| C/C ++ | Ржавчина | C# | Ява | Питон | JavaScript | Либассерт | |
|---|---|---|---|---|---|---|---|
| Выражение строки | ✔ | ✔ | |||||
| Расположение | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| Стек трассировки | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| Сообщение утверждения | ** | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| Дополнительная диагностика | * | * | * | * | ✔ | ||
| Бинарные специализации | ✔ | ✔ | ✔ | ||||
| Автоматическое разложение выражения | ✔ | ||||||
| Субэкспрессионные строки | ✔ |
* : Возможно через форматирование строки, но это субйдаально.
** : assert(expression && "message") обычно используется, но это субйдаально и разрешает только строковые буквальные сообщения.
Дополнительные дополнения:
| C/C ++ | Ржавчина | C# | Ява | Питон | JavaScript | Либассерт | |
|---|---|---|---|---|---|---|---|
| Синтаксис выделение | ? | ✔ | |||||
| Буквальное форматирование консистенции | ✔ | ||||||
| Строки выражения и значения выражения везде | ✔ | ||||||
| Возврат значения из утверждения, чтобы разрешить быть интегрированными в встроенные выражения | ✔ |