{"id":13424669,"url":"https://github.com/snitch-org/snitch","last_synced_at":"2026-04-04T12:57:34.332Z","repository":{"id":63471189,"uuid":"549444671","full_name":"snitch-org/snitch","owner":"snitch-org","description":"Lightweight C++20 testing framework.","archived":false,"fork":false,"pushed_at":"2026-02-02T08:17:09.000Z","size":1908,"stargazers_count":308,"open_issues_count":17,"forks_count":15,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-04-01T13:05:12.378Z","etag":null,"topics":["constexpr","cpp20","lightweight","testing"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snitch-org.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-11T07:42:59.000Z","updated_at":"2026-03-26T12:28:42.000Z","dependencies_parsed_at":"2024-01-14T18:48:20.201Z","dependency_job_id":"459b2675-72ef-4fb8-9145-440146fcc243","html_url":"https://github.com/snitch-org/snitch","commit_stats":{"total_commits":782,"total_committers":7,"mean_commits":"111.71428571428571","dds":0.07672634271099743,"last_synced_commit":"74bdd8e75ea73c907ea671e2f93859f54f08cb12"},"previous_names":["snitch-org/snitch","cschreib/snitch"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/snitch-org/snitch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snitch-org%2Fsnitch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snitch-org%2Fsnitch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snitch-org%2Fsnitch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snitch-org%2Fsnitch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snitch-org","download_url":"https://codeload.github.com/snitch-org/snitch/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snitch-org%2Fsnitch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31400460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["constexpr","cpp20","lightweight","testing"],"created_at":"2024-07-31T00:00:57.561Z","updated_at":"2026-04-04T12:57:34.324Z","avatar_url":"https://github.com/snitch-org.png","language":"C++","readme":"# snitch\n\n![Build Status](https://github.com/snitch-org/snitch/actions/workflows/cmake.yml/badge.svg) [![codecov](https://codecov.io/gh/snitch-org/snitch/branch/main/graph/badge.svg?token=X422DE81PN)](https://codecov.io/gh/snitch-org/snitch) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)\n\n![The snitch logo: a jay feather](doc/logo-big.png)\n\nLightweight C++20 testing framework.\n\nThe goal of _snitch_ is to be a simple, cheap, non-invasive, and user-friendly testing framework. The design philosophy is to keep the testing API lean, including only what is strictly necessary to present clear messages when a test fails.\n\n\u003c!-- MarkdownTOC autolink=\"true\" --\u003e\n\n- [Features and limitations](#features-and-limitations)\n- [Example](#example)\n- [Example build configurations with CMake](#example-build-configurations-with-cmake)\n    - [Using _snitch_ as a regular library](#using-snitch-as-a-regular-library)\n    - [Using _snitch_ as a header-only library](#using-snitch-as-a-header-only-library)\n- [Example build configuration with meson](#example-build-configuration-with-meson)\n- [Example build configuration with vcpkg](#example-build-configuration-with-vcpkg)\n- [Benchmark](#benchmark)\n- [Documentation](#documentation)\n    - [Detailed comparison with _Catch2_](#detailed-comparison-with-catch2)\n    - [Test case macros](#test-case-macros)\n        - [Standalone test cases](#standalone-test-cases)\n        - [Test cases with fixtures](#test-cases-with-fixtures)\n    - [Test check macros](#test-check-macros)\n        - [Run-time](#run-time)\n        - [Compile-time](#compile-time)\n        - [Run-time and compile-time](#run-time-and-compile-time)\n        - [Exception checks](#exception-checks)\n        - [Miscellaneous](#miscellaneous)\n    - [Advanced API](#advanced-api)\n    - [Tags](#tags)\n    - [Matchers](#matchers)\n    - [Sections](#sections)\n    - [Captures](#captures)\n    - [Custom string serialization](#custom-string-serialization)\n    - [Reporters](#reporters)\n        - [Built-in reporters](#built-in-reporters)\n        - [Overriding the default reporter](#overriding-the-default-reporter)\n        - [Registering a new reporter](#registering-a-new-reporter)\n    - [Output colors](#output-colors)\n    - [Command-line API](#command-line-api)\n    - [Selecting which tests to run](#selecting-which-tests-to-run)\n    - [Using your own main function](#using-your-own-main-function)\n    - [Exceptions](#exceptions)\n    - [Freestanding](#freestanding)\n    - [Header-only build](#header-only-build)\n    - [IDE integrations](#ide-integrations)\n    - [`clang-format` support](#clang-format-support)\n- [Contributing](#contributing)\n- [Code of conduct](#code-of-conduct)\n- [Why the name _snitch_?](#why-the-name-_snitch_)\n\n\u003c!-- /MarkdownTOC --\u003e\n\n## Features and limitations\n\n - No heap allocation from the testing framework, so heap allocations from your code can be tracked precisely.\n - Works with exceptions disabled, albeit with a minor limitation (see [Exceptions](#exceptions) below).\n - Works on platforms without a console or file system (see [Freestanding](#freestanding) below).\n - No external dependency; just pure C++20 with the STL.\n - Compiles template-heavy tests at least 50% faster than other testing frameworks (see Release [benchmarks](#benchmark)).\n - By defaults, test results are reported to the standard output, with optional coloring for readability. Test events can also be forwarded to a reporter callback for reporting to CI frameworks (Teamcity, ..., see [Reporters](#reporters)).\n - Limited subset of the [_Catch2_](https://github.com/catchorg/Catch2) API, see [Comparison with _Catch2_](#detailed-comparison-with-catch2).\n - [IDE integrations](#ide-integrations) using existing _Catch2_ plugins/adaptors.\n - Additional API not in _Catch2_, or different from _Catch2_:\n   - Matchers use a different API (see [Matchers](#matchers) below).\n   - Additional macros for testing [`constexpr`](#run-time-and-compile-time) and [`consteval`](#compile-time) expressions.\n- Can be disabled at build time, to allow mixing code and tests in the same file with minimal overheads.\n\nIf you need features that are not in the list above, please use _Catch2_ or _doctest_.\n\nNotable current limitations:\n\n - No multithreaded test execution yet; the code is thread-friendly, this is just not implemented.\n\nSupported compilers:\n\n - Mininum: GCC 10, recommended: GCC 11.\n - Minimum: Clang 10, recommended: Clang 13.\n - Minimum: MSVC 14.30 (compiler 19.29).\n\n\n## Example\n\nThis is the same example code as in the [_Catch2_ tutorials](https://github.com/catchorg/Catch2/blob/devel/docs/tutorial.md):\n\n```c++\n#include \u003csnitch/snitch.hpp\u003e\n\nunsigned int Factorial( unsigned int number ) {\n    return number \u003c= 1 ? number : Factorial(number-1)*number;\n}\n\nTEST_CASE(\"Factorials are computed\", \"[factorial]\" ) {\n    REQUIRE( Factorial(0) == 1 ); // this check will fail\n    REQUIRE( Factorial(1) == 1 );\n    REQUIRE( Factorial(2) == 2 );\n    REQUIRE( Factorial(3) == 6 );\n    REQUIRE( Factorial(10) == 3628800 );\n}\n```\n\nOutput:\n\n![Example console output of a regular test](https://user-images.githubusercontent.com/2236577/196043565-531635c5-64e0-401c-8ff6-a533c9bbbf11.png)\n\nAnd here is an example code for a typed test, also borrowed (and adapted) from the [_Catch2_ tutorials](https://github.com/catchorg/Catch2/blob/devel/docs/test-cases-and-sections.md#type-parametrised-test-cases):\n\n```c++\n#include \u003csnitch/snitch.hpp\u003e\n\nusing MyTypes = snitch::type_list\u003cint, char, float\u003e; // could also be std::tuple; any template type list will do\nTEMPLATE_LIST_TEST_CASE(\"Template test case with test types specified inside snitch::type_list\", \"[template][list]\", MyTypes)\n{\n    REQUIRE(sizeof(TestType) \u003e 1); // will fail for 'char'\n}\n```\n\nOutput:\n\n![Example console output of a typed test](https://user-images.githubusercontent.com/2236577/196043558-ed9ab329-5934-4bb3-a422-b48d6781cf96.png)\n\n\n## Example build configurations with CMake\n\n### Using _snitch_ as a regular library\n\nHere is an example CMake file to download _snitch_ and define a test application:\n\n```cmake\ninclude(FetchContent)\n\nFetchContent_Declare(snitch\n                     GIT_REPOSITORY https://github.com/snitch-org/snitch.git\n                     GIT_TAG        v1.2.0) # update version number as needed\nFetchContent_MakeAvailable(snitch)\n\nset(YOUR_TEST_FILES\n  # add your test files here...\n  )\n\nadd_executable(my_tests ${YOUR_TEST_FILES})\ntarget_link_libraries(my_tests PRIVATE snitch::snitch)\n```\n\n_snitch_ will provide the definition of `main()` [unless otherwise specified](#using-your-own-main-function).\n\n\n### Using _snitch_ as a header-only library\n\nHere is an example CMake file to download _snitch_ and define a test application:\n\n```cmake\ninclude(FetchContent)\n\nset(SNITCH_HEADER_ONLY 1)\n\nFetchContent_Declare(snitch\n                     GIT_REPOSITORY https://github.com/snitch-org/snitch.git\n                     GIT_TAG        v1.2.0) # update version number as needed\nFetchContent_MakeAvailable(snitch)\n\nset(YOUR_TEST_FILES\n  # add your test files here...\n  )\n\nadd_executable(my_tests ${YOUR_TEST_FILES})\ntarget_link_libraries(my_tests PRIVATE snitch::snitch-header-only)\n```\n\nOne (and only one!) of your test files needs to include _snitch_ as:\n```c++\n#define SNITCH_IMPLEMENTATION\n#include \u003csnitch_all.hpp\u003e\n```\n\nSee the documentation for the [header-only build](#header-only-build) for more information. This will include the definition of `main()` [unless otherwise specified](#using-your-own-main-function).\n\n\n## Example build configuration with meson\n\nFirst, [meson build](https://mesonbuild.com/) needs a [`subprojects`](https://mesonbuild.com/Subprojects.html#using-a-subproject) directory in your project source root for dependencies. Create this directory if it does not exist, then, from within your project source root, run:\n\n```bash\n\u003e meson wrap install snitch\n```\n\nThis downloads a [_wrap file_](https://mesonbuild.com/Wrap-dependency-system-manual.html#wrap-format), `snitch.wrap`, from [WrapDB](https://mesonbuild.com/Wrapdb-projects.html)\nto the `subprojects` directory. A `[provide]` section declares `snitch = snitch_dep`,\nand that guides meson's [`wrap` dependency system](https://mesonbuild.com/Wrap-dependency-system-manual.html) to use a _snitch_ install, if found, or to download _snitch_ as a fallback.\n\nThe provided `snitch_dep` dependency is retrieved and used in a `meson.build` script, e.g.:\n\n```python\nsnitch_dep = dependency('snitch')\n\ntest('mytest', executable('test','test.cpp',dependencies:snitch_dep) )\n```\n\nAlternatively, you can `git clone` _snitch_ directly to `subprojects/snitch`. A wrap file is then optional. You can retrieve the dependency directly (as is necessary in meson \u003c v0.54):\n\n```python\nsnitch_dep = subproject('snitch').get_variable('snitch_dep')\n```\n\nIf you use _snitch_ only as a [header-only library](#header-only-build)\nthen you can disable the library build by configuring with:\n\n- `-D snitch:create_library=false`\n\nOtherwise, if you use _snitch_ only as a regular library,\nthen you can configure with:\n\n- `-D snitch:create_header_only=false`\n\nAnd this disables the build step that generates the single-header file \"`snitch_all.hpp`\".\n\n\n## Example build configuration with vcpkg\n\nSee [the dedicated page in the docs folder](doc/vcpkg-example/README.md).\n\n\n## Benchmark\n\nThe following benchmarks were done using real-world tests from another library ([_observable_unique_ptr_](https://github.com/cschreib/observable_unique_ptr)), which generates about 4000 test cases and 25000 checks. This library uses \"typed\" tests almost exclusively, where each test case is instantiated several times, each time with a different tested type (here, 25 types). Building and running the tests was done without parallelism to simplify the comparison. The benchmarks were run on a desktop with the following specs:\n - OS: Linux Mint 21.3, linux kernel 6.8.0-64-generic.\n - CPU: AMD Ryzen 5 2600 (6 core).\n - RAM: 16GB.\n - Storage: NVMe.\n - Compiler: GCC 10.5.0 with `-std=c++20`.\n\nThe benchmark tests can be found in different branches of _observable_unique_ptr_:\n - _snitch_: https://github.com/cschreib/observable_unique_ptr/tree/snitch\n - _Catch2_ v3.9.1: https://github.com/cschreib/observable_unique_ptr/tree/catch2\n - _doctest_ v2.4.12: https://github.com/cschreib/observable_unique_ptr/tree/doctest\n - _Boost.UT_ v2.3.1: https://github.com/cschreib/observable_unique_ptr/tree/boost_ut\n\nDescription of results below:\n - *Build framework*: Time required to build the testing framework library (if any), without any test.\n - *Build tests*: Time required to build the tests, assuming the framework library (if any) was already built.\n - *Build all*: Total time to build the tests and the framework library (if any).\n - *Run tests*: Total time required to run the tests.\n - *Library size*: Size of the compiled testing framework library (if any).\n - *Executable size*: Size of the compiled test executable, static linking to the testing framework library (if any).\n\nResults for Debug builds:\n\n| **Debug**       | _snitch_ | _Catch2_ | _doctest_ | _Boost UT_ |\n|-----------------|----------|----------|-----------|------------|\n| Build framework | 4.4s     | 44s      | 2.3s      | 0s         |\n| Build tests     | 71s      | 74s      | 78s       | 197s       |\n| Build all       | 75s      | 118s     | 81s       | 197s       |\n| Run tests       | 45ms     | 82ms     | 76ms      | 80ms       |\n| Library size    | 9.5MB    | 35.1MB   | 2.8MB     | 0MB        |\n| Executable size | 37.1MB   | 46.2MB   | 38.6MB    | 71.4MB     |\n\nResults for Release builds:\n\n| **Release**     | _snitch_ | _Catch2_ | _doctest_ | _Boost UT_ |\n|-----------------|----------|----------|-----------|------------|\n| Build framework | 5.8s     | 50s      | 3.9s      | 0s         |\n| Build tests     | 148s     | 221s     | 217s      | 488s       |\n| Build all       | 153s     | 271s     | 220s      | 488s       |\n| Run tests       | 27ms     | 46ms     | 51ms      | 51ms       |\n| Library size    | 1.4MB    | 2.5MB    | 0.39MB    | 0MB        |\n| Executable size | 10.2MB   | 14.2MB   | 15.7MB    | 18.8MB     |\n\nNotes:\n - No attempt was made to optimize each framework's configuration; the defaults were used. C++20 modules were not used.\n - _Boost UT_ was unable to compile and pass the tests without modifications to its implementation (issues were reported).\n\n\n## Documentation\n\n### Detailed comparison with _Catch2_\n\nSee [the dedicated page in the docs folder](doc/comparison_catch2.md) for a breakdown of _Catch2_ features and their implementation status in _snitch_.\n\nGiven that _snitch_ mostly offers a subset of the _Catch2_ API, why would anyone want to use it over _Catch2_?\n\n - _snitch_ does not do any heap allocation while running tests. This is important if the tests need to monitor the global heap usage, to ensure that the tested code only allocates what it is supposed to (or not at all). This is tricky to do with _Catch2_, since some check macros will trigger heap allocations by using `std::string` and other heap-allocated data structures. To add to the confusion, some `std::string` instances used by _Catch2_ will fall under the small-string-optimization threshold, and won't generate heap allocations on some implementations of the C++ STL. This makes any measurement of heap usage not only noisy, but platform-dependent. If this is a concern to you, then _snitch_ is a better choice.\n\n - _snitch_ has a much smaller compile-time footprint than _Catch2_, see the benchmarks above. If your tested code is very cheap to compile, but you have a large number of tests and/or assertions, your compilation time may be dominated by the testing framework implementation (this is the case in the benchmarks). If the compilation time with _Catch2_ becomes prohibitive or annoying, you can give _snitch_ a try to see if it improves it.\n\n - _snitch_ can be used as a header-only library. This may be relevant for very small projects, or projects that do not use one of the supported build systems. Note however that doing so will likely nullify any compile-time advantage over alternative testing libraries; this is not recommended if compilation time is a concern.\n\n - _snitch_ has better reporting of typed tests (template test cases). While _Catch2_ will only report the type index in the test type list, _snitch_ will actually report the type name. This makes it easier to find which type generated a failure.\n\n - _snitch_ is able to test and decompose expressions both at run-time and compile-time in the same build (see `CONSTEXPR_CHECK`). _Catch2_ on the other hand is only able to test at compile-time (but not decompose) in one build, and test and decompose at run-time in a different build (using `STATIC_CHECK`).\n\nIf none of the above applies, then _Catch2_ will generally offer more value.\n\n\n### Test case macros\n\n#### Standalone test cases\n\n`TEST_CASE(NAME, TAGS) { /* test body */ }`\n\nThis must be called at namespace, global, or class scope; not inside a function or another test case. This defines a new test case of name `NAME`. `NAME` must be a string literal, and may contain any character, up to a maximum length configured by `SNITCH_MAX_TEST_NAME_LENGTH` (default is `1024`). This name will be used to display test reports, and can be used to filter the tests. It is not required to be a unique name. `TAGS` specify which tag(s) are associated with this test case. This must be a string literal with the same limitations as `NAME`. See the [Tags](#tags) section for more information on tags. Finally, `test body` is the body of your test case. Within this scope, you can use the test macros listed [below](#test-check-macros).\n\n\n`TEMPLATE_TEST_CASE(NAME, TAGS, TYPES...) { /* test code for TestType */ }`\n\nThis is similar to `TEST_CASE`, except that it declares a new test case for each of the types listed in `TYPES...`. Within the test body, the current type can be accessed as `TestType`. The full name of the test, used when filtering tests by name, is `\"NAME \u003cTYPE\u003e\"`. If you tend to reuse the same list of types for multiple test cases, then `TEMPLATE_LIST_TEST_CASE()` is recommended instead.\n\n\n`TEMPLATE_LIST_TEST_CASE(NAME, TAGS, TYPES) { /* test code for TestType */ }`\n\nThis is equivalent to `TEMPLATE_TEST_CASE`, except that `TYPES` must be a template type list of the form `T\u003cTypes...\u003e`, for example `snitch::type_list\u003cTypes...\u003e` or `std::tuple\u003cTypes...\u003e`. This type list can be declared once and reused for multiple test cases.\n\n\n#### Test cases with fixtures\n\n`TEST_CASE_METHOD(FIXTURE, NAME, TAGS) { /* test body */ }`\n\nThis is similar to `TEST_CASE`, except that the test body is interpreted \"as if\" it was a member function of a class deriving from the `FIXTURE` class. This means the test body has access to public and protected members of `FIXTURE`, but not to private members. Each time the test is executed, a new instance of `FIXTURE` is created, the test body is run on this temporary instance, and finally the instance is destroyed; the instance is not shared between tests.\n\n\n`TEMPLATE_TEST_CASE_METHOD(NAME, TAGS, TYPES...) { /* test code for TestType */ }`\n\nThis is similar to `TEST_CASE_METHOD`, except that it declares a new test case for each of the types listed in `TYPES...`. Within the test body, the current type can be accessed as `TestType`. If you tend to reuse the same list of types for multiple test cases, then `TEMPLATE_LIST_TEST_CASE_METHOD()` is recommended instead.\n\n\n`TEMPLATE_LIST_TEST_CASE_METHOD(NAME, TAGS, TYPES) { /* test code for TestType */ }`\n\nThis is equivalent to `TEMPLATE_TEST_CASE_METHOD`, except that `TYPES` must be a template type list of the form `T\u003cTypes...\u003e`, for example `snitch::type_list\u003cTypes...\u003e` or `std::tuple\u003cTypes...\u003e`. This type list can be declared once and reused for multiple test cases.\n\n\n### Test check macros\n\nThe following macros can only be used inside a test body, either immediately in the body itself, or inside a function called by the test. They _cannot_ be used if a test is not running (e.g.,  they cannot be used as generic assertion macros).\n\n\n#### Run-time\n\nThe macros in this section evaluate their operands are run-time exclusively.\n\n`REQUIRE(EXPR);`\n\nThis evaluates the expression `EXPR`, as in `if (EXPR)`, and reports a failure if `EXPR` evaluates to `false`. On failure, the current test case is stopped. Execution then continues with the next test case, if any. The value of each operand of the expression will be displayed on failure, provided the types involved can be serialized to a string. See [Custom string serialization](#custom-string-serialization) for more information. If one of the operands is a [matcher](#matchers) and the operation is `==`, then this will report a failure if there is no match. Conversely, if the operation is `!=`, then this will report a failure if there is a match.\n\n\n`CHECK(EXPR);`\n\nThis is similar to `REQUIRE`, except that on failure the test case continues. Further failures may be reported in the same test case.\n\n\n`REQUIRE_FALSE(EXPR);`\n\nThis is equivalent to `REQUIRE(!(EXPR))`, except that it is able to decompose `EXPR` (otherwise, the `!(...)` forces evaluation of the expression, which then cannot be decomposed).\n\n\n`CHECK_FALSE(EXPR);`\n\nThis is equivalent to `CHECK(!(EXPR))`, except that it is able to decompose `EXPR` (otherwise, the `!(...)` forces evaluation of the expression, which then cannot be decomposed).\n\n\n`REQUIRE_THAT(EXPR, MATCHER);`\n\nThis is equivalent to `REQUIRE(EXPR == MATCHER)`, and is provided for compatibility with _Catch2_.\n\n\n`CHECK_THAT(EXPR, MATCHER);`\n\nThis is equivalent to `CHECK(EXPR == MATCHER)`, and is provided for compatibility with _Catch2_.\n\n\n#### Compile-time\n\nThe macros in this section evaluate their operands are compile-time exclusively. To benefit from the run-time infrastructure of _snitch_ (allowed failures, custom reporter, etc.), the test report is still generated at run-time. However, if the operands cannot be evaluated at compile-time, a compiler error will be generated.\n\nThese macros are recommended for testing `consteval` functions, which are always evaluated at compile-time. For `constexpr` functions, which can be evaluated both at compile-time and run-time, prefer the `CONSTEXPR_*` macros described below.\n\n`CONSTEVAL_REQUIRE(EXPR);`\n\nSame as `REQUIRE(EXPR)` but with operands evaluated at compile-time.\n\n`CONSTEVAL_CHECK(EXPR);`\n\nSame as `CHECK(EXPR)` but with operands evaluated at compile-time.\n\n`CONSTEVAL_REQUIRE_FALSE(EXPR);`\n\nSame as `REQUIRE_FALSE(EXPR)` but with operands evaluated at compile-time.\n\n`CONSTEVAL_CHECK_FALSE(EXPR);`\n\nSame as `CHECK_FALSE(EXPR)` but with operands evaluated at compile-time.\n\n`CONSTEVAL_REQUIRE_THAT(EXPR, MATCHER);`\n\nSame as `REQUIRE_THAT(EXPR, MATCHER)` but with operands evaluated at compile-time.\n\n`CONSTEVAL_CHECK_THAT(EXPR, MATCHER);`\n\nSame as `CHECK_THAT(EXPR, MATCHER)` but with operands evaluated at compile-time.\n\n\n#### Run-time and compile-time\n\nThe macros in this section evaluate their operands both are compile-time and at run-time. To benefit from the run-time infrastructure of _snitch_ (allowed failures, custom reporter, etc.), the test report is still generated at run-time regardless of the above. However, if the operands cannot be evaluated at compile-time, a compiler error will be generated.\n\nThese macros are recommended for testing `constexpr` functions, which can be evaluated both at compile-time and at run-time. Since the operands are also evaluated at run-time, the test will contribute to the coverage analysis (if any), which is otherwise impossible for purely compile-time tests (e.g., `CONSTEVAL_*` macros above).\n\n`CONSTEXPR_REQUIRE(EXPR);`\n\nSame as `REQUIRE(EXPR)` but with operands evaluated both at compile-time and run-time.\n\n`CONSTEXPR_CHECK(EXPR);`\n\nSame as `CHECK(EXPR)` but with operands evaluated both at compile-time and run-time.\n\n`CONSTEXPR_REQUIRE_FALSE(EXPR);`\n\nSame as `REQUIRE_FALSE(EXPR)` but with operands evaluated both at compile-time and run-time.\n\n`CONSTEXPR_CHECK_FALSE(EXPR);`\n\nSame as `CHECK_FALSE(EXPR)` but with operands evaluated both at compile-time and run-time.\n\n`CONSTEXPR_REQUIRE_THAT(EXPR, MATCHER);`\n\nSame as `REQUIRE_THAT(EXPR, MATCHER)` but with operands evaluated both at compile-time and run-time.\n\n`CONSTEXPR_CHECK_THAT(EXPR, MATCHER);`\n\nSame as `CHECK_THAT(EXPR, MATCHER)` but with operands evaluated both at compile-time and run-time.\n\n\n#### Exception checks\n\n`REQUIRE_THROWS_AS(EXPR, EXCEPT);`\n\nThis evaluates the expression `EXPR` inside a `try/catch` block, and attempts to catch an exception of type `EXCEPT`. If no exception is thrown, or an exception of a different type is thrown, then this reports a test failure. On failure, the current test case is stopped. Execution then continues with the next test case, if any.\n\n\n`CHECK_THROWS_AS(EXPR, EXCEPT);`\n\nThis is similar to `REQUIRE_THROWS_AS`, except that on failure the test case continues. Further failures may be reported in the same test case.\n\n\n`REQUIRE_THROWS_MATCHES(EXPR, EXCEPT, MATCHER);`\n\nThis is similar to `REQUIRE_THROWS_AS`, but further checks the content of the exception that has been caught. The caught exception is given to the matcher object specified in `MATCHER` (see [Matchers](#matchers)). If the exception object is not a match, then this reports a test failure.\n\n\n`CHECK_THROWS_MATCHES(EXPR, EXCEPT, MATCHER);`\n\nThis is similar to `REQUIRE_THROWS_MATCHES`, except that on failure the test case continues. Further failures may be reported in the same test case.\n\n\n`REQUIRE_NOTHROW(EXPR);`\n\nThis evaluates the expression `EXPR` inside a `try/catch` block. If an exception is thrown, then this reports a test failure. On failure, the current test case is stopped. Execution then continues with the next test case, if any.\n\n\n`CHECK_NOTHROW(EXPR);`\n\nThis is similar to `REQUIRE_NOTHROW`, except that on failure the test case continues. Further failures may be reported in the same test case.\n\n\n#### Miscellaneous\n\n`FAIL(MSG);`\n\nThis reports a test failure with the message `MSG`. The current test case is stopped. Execution then continues with the next test case, if any.\n\n\n`FAIL_CHECK(MSG);`\n\nThis is similar to `FAIL`, except that the test case continues. Further failures may be reported in the same test case.\n\n\n`SKIP(MSG);`\n\nThis reports the current test case as \"skipped\". Any previously reported status for this test case is ignored. The current test case is stopped. Execution then continues with the next test case, if any.\n\n\n`SKIP_CHECK(MSG);`\n\nThis is similar to `SKIP`, except that the test case continues. Further failure will not be reported. This is only recommended as an alternative to `SKIP()` when exceptions cannot be used.\n\n\n### Advanced API\n\n`snitch::notify_exception_handled();`\n\nIf handling exceptions explicitly with a `try/catch` block in a test case, this should be called at the end of the `catch` block. This clears up internal state that would have been used to report that exception, had it not been handled. Calling this is not strictly necessary in most cases, but omitting it can lead to confusing contextual data (incorrect section/capture/info) if another exception is thrown afterwards and not handled.\n\n\n### Tags\n\nTags are assigned to each test case using the [Test case macros](#test-case-macros), as a single string. Within this string, individual tags must be surrounded by square brackets, with no white-space between tags (although white space within a tag is allowed). For example:\n\n```c++\nTEST_CASE(\"test\", \"[tag1][tag 2][some other tag]\") {\n    //             ^---- these are the tags ---^\n}\n```\n\nTags can be used to filter the tests, for example, by running all tests with a given tag. There are also a few \"special\" tags recognized by _snitch_, which change the behavior of the test:\n - `[.]` is the \"hidden\" tag; any test with this tag will be excluded from the default list of tests. The test will only be run if selected explicitly, either when filtering by name, or by tag.\n - `[.\u003csome tag\u003e]` is a shortcut for `[.][\u003csome_tag\u003e]`.\n - `[!mayfail]` indicates that the test may fail; if so, any failure will be recorded, but the test case will still be marked as passed.\n - `[!shouldfail]` indicates that the test must fail; any failure will be recorded, but the test case will still be marked as passed. If no failure is recorded, the test is marked as failed.\n\n\n### Matchers\n\nMatchers in _snitch_ work differently than in _Catch2_. Matchers do not need to inherit from a common base class. The only required interface is:\n\n - `matcher.match(obj)` must return `true` if `obj` is a match, `false` otherwise.\n - `matcher.describe_match(obj, status)` must return a value convertible to `std::string_view`, describing why `obj` is or is not a match, depending on the value of `snitch::matchers::match_status`.\n - `matcher == obj` and `obj == matcher` must return `matcher.match(obj)`, and `matcher != obj` and `obj != matcher` must return `!matcher.match(obj)`; any matcher defined in the `snitch::matchers` namespace will have these operators defined automatically.\n\nThe following matchers are provided with _snitch_:\n\n - `snitch::matchers::contains_substring{\"substring\"}`: accepts a `std::string_view`, and will return a match if the string contains `\"substring\"`.\n - `snitch::matchers::with_what_contains{\"substring\"}`: accepts a `std::exception`, and will return a match if `what()` contains `\"substring\"`.\n - `snitch::matchers::is_any_of{T...}`: accepts an object of any type `T`, and will return a match if it is equal to any of the `T...`.\n\n\nHere is an example matcher that, given a prefix `p`, checks if a string starts with the prefix `\"\u003cp\u003e:\"`:\n```c++\nnamespace snitch::matchers {\nstruct has_prefix {\n    std::string_view prefix;\n\n    bool match(std::string_view s) const noexcept {\n        return s.starts_with(prefix) \u0026\u0026 s.size() \u003e= prefix.size() + 1 \u0026\u0026 s[prefix.size()] == ':';\n    }\n\n    small_string\u003cmax_message_length\u003e\n    describe_match(std::string_view s, match_status status) const noexcept {\n        small_string\u003cmax_message_length\u003e message;\n        append_or_truncate(\n            message, status == match_status::matched ? \"found\" : \"could not find\", \" prefix '\",\n            prefix, \":' in '\", s, \"'\");\n\n        if (status == match_status::failed) {\n            if (auto pos = s.find_first_of(':'); pos != s.npos) {\n                append_or_truncate(message, \"; found prefix '\", s.substr(0, pos), \":'\");\n            } else {\n                append_or_truncate(message, \"; no prefix found\");\n            }\n        }\n\n        return message;\n    }\n};\n} // namespace snitch::matchers\n```\n\n_snitch_ will always call `match()` before calling `describe_match()`. Therefore, you can save any intermediate calculation performed during `match()` as a member variable, to be reused later in `describe_match()`. This can prevent duplicating effort, and can be important if calculating the match is an expensive operation.\n\n\n### Sections\n\nAs in _Catch2_, _snitch_ supports nesting multiple tests inside a single test case, to share set-up/tear-down logic. This is done using the `SECTION(\"name\")` macro. Please see the [Catch2 documentation](https://github.com/catchorg/Catch2/blob/devel/docs/tutorial.md#test-cases-and-sections) for more details. Note: if any exception is thrown inside a section, or if a `REQUIRE()` check fails (or any other check which aborts execution), the whole test case is stopped. No other section will be executed.\n\nHere is a brief example to demonstrate the flow of the test:\n\n```c++\nTEST_CASE( \"test with sections\", \"[section]\" ) {\n    std::cout \u003c\u003c \"set-up\" \u003c\u003c std::endl;\n    // shared set-up logic here...\n\n    SECTION( \"first section\" ) {\n        std::cout \u003c\u003c \" 1\" \u003c\u003c std::endl;\n    }\n    SECTION( \"second section\" ) {\n        std::cout \u003c\u003c \" 2\" \u003c\u003c std::endl;\n    }\n    SECTION( \"third section\" ) {\n        std::cout \u003c\u003c \" 3\" \u003c\u003c std::endl;\n        SECTION( \"nested section 1\" ) {\n            std::cout \u003c\u003c \"  3.1\" \u003c\u003c std::endl;\n        }\n        SECTION( \"nested section 2\" ) {\n            std::cout \u003c\u003c \"  3.2\" \u003c\u003c std::endl;\n        }\n    }\n\n    std::cout \u003c\u003c \"tear-down\" \u003c\u003c std::endl;\n    // shared tear-down logic here...\n}\n```\n\nThe output of this test will be:\n```\nset-up\n 1\ntear-down\nset-up\n 2\ntear-down\nset-up\n 3\n  3.1\ntear-down\nset-up\n 3\n  3.2\ntear-down\n\n```\n\n\n### Captures\n\nAs in _Catch2_, _snitch_ supports capturing contextual information to be displayed in the test failure report. This can be done with the `INFO(message)` and `CAPTURE(vars...)` macros. The captured information is \"scoped\", and will only be displayed for failures happening:\n - after the capture, and\n - in the same scope (or deeper).\n\nFor example, in the test below we compute a complicated formula in a `CHECK()`:\n\n```c++\n#include \u003ccmath\u003e\n\nTEST_CASE(\"test without captures\", \"[captures]\") {\n    for (std::size_t i = 0; i \u003c 10; ++i) {\n        CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4);\n    }\n}\n```\n\nThe output of this test is:\n\n```\nfailed: running test case \"test without captures\"\n          at test.cpp:116\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.309018 \u003c= 0.400000\nfailed: running test case \"test without captures\"\n          at test.cpp:116\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.000001 \u003c= 0.400000\nfailed: running test case \"test without captures\"\n          at test.cpp:116\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.309015 \u003c= 0.400000\n```\n\nWe are told the computed values that failed the check, but from just this information, it is difficult to recover the value of the loop index `i` which triggered the failure. To fix this, we can add `CAPTURE(i)` to capture the value of `i`:\n\n```c++\n#include \u003ccmath\u003e\n\nTEST_CASE(\"test with captures\", \"[captures]\") {\n    for (std::size_t i = 0; i \u003c 10; ++i) {\n        CAPTURE(i);\n        CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4);\n    }\n}\n```\n\nThis new test now outputs:\n\n```\nfailed: running test case \"test with captures\"\n          at test.cpp:116\n          with i := 4\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.309018 \u003c= 0.400000\nfailed: running test case \"test with captures\"\n          at test.cpp:116\n          with i := 5\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.000001 \u003c= 0.400000\nfailed: running test case \"test with captures\"\n          at test.cpp:116\n          with i := 6\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.309015 \u003c= 0.400000\n```\n\nFor convenience, any number of variables or expressions may be captured in a single `CAPTURE()` call; this is equivalent to writing multiple `CAPTURE()` calls:\n\n```c++\n#include \u003ccmath\u003e\n\nTEST_CASE(\"test with many captures\", \"[captures]\") {\n    for (std::size_t i = 0; i \u003c 10; ++i) {\n        CAPTURE(i, 2 * i, std::pow(i, 3.0f));\n        CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.2);\n    }\n}\n```\n\nThis outputs:\n\n```\nfailed: running test case \"test with many captures\"\n          at test.cpp:122\n          with i := 5\n          with 2 * i := 10\n          with std::pow(i, 3.0f) := 125.000000\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.4), got 0.000001 \u003c= 0.400000\n```\n\nThe only requirement is that the captured variable or expression must be of a type that _snitch_ can serialize to a string. See [Custom string serialization](#custom-string-serialization) for more information.\n\nA more free-form way to add context to the tests is to use `INFO(...)`. The parameters to this macro will be serialized together to form a single string, which will be appended as one capture. This can be combined with `CAPTURE()`. For example:\n\n```c++\n#include \u003ccmath\u003e\n\nTEST_CASE(\"test with info\", \"[captures]\") {\n    for (std::size_t i = 0; i \u003c 5; ++i) {\n        INFO(\"first loop (i \u003c 5, with i = \", i, \")\");\n        CAPTURE(i);\n        CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.2);\n    }\n    for (std::size_t i = 5; i \u003c 10; ++i) {\n        INFO(\"second loop (i \u003e= 5, with i = \", i, \")\");\n        CAPTURE(i);\n        CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.2);\n    }\n}\n```\n\nThis outputs:\n\n```\nfailed: running test case \"test with info\"\n          at test.cpp:123\n          with second loop (i \u003e= 5, with i = 5)\n          with i := 5\n          CHECK(std::abs(std::cos(i * 3.14159 / 10)) \u003e 0.2), got 0.000001 \u003c= 0.200000\n\n```\n\n### Custom string serialization\n\nWhen the _snitch_ framework needs to serialize a value to a string, it does so with the free function `append(span, value)`, where `span` is a `snitch::small_string_span`, and `value` is the value to serialize. The function must return a boolean, equal to `true` if the serialization was successful, or `false` if there was not enough room in the output string to store the complete textual representation of the value. On failure, it is recommended to write as many characters as possible, and just truncate the output; this is what built-in functions do.\n\nBuilt-in serialization functions are provided for all fundamental types: integers, enums (serialized as their underlying integer type), floating point, booleans, standard `string_view` and `char*`, and raw pointers.\n\nIf you want to serialize custom types not supported out of the box by _snitch_, you need to provide your own `append()` function. This function must be placed in the same namespace as your custom type or in the `snitch` namespace, so it can be [found by ADL (argument-dependent lookup)](https://en.cppreference.com/w/cpp/language/adl). ADL rules can be complex to follow, so if in doubt, simply define your `append()` function in the `snitch` namespace.\n\nIn most cases, the `append()` function can be written in terms of serialization of fundamental types which are already supported by _snitch_, and therefore won't require low-level string manipulation. For example, to serialize a structure representing the 3D coordinates of a point:\n\n```c++\nnamespace my_namespace {\n    struct vec3d {\n        float x;\n        float y;\n        float z;\n    };\n\n    bool append(snitch::small_string_span ss, const vec3d\u0026 v) {\n        return append(ss, \"{\", v.x, \",\", v.y, \",\", v.z, \"}\");\n    }\n}\n```\n\nAlternatively, to serialize a class with an existing `toString()` member:\n\n```c++\nnamespace my_namespace {\n    class MyClass {\n        // ...\n\n    public:\n        std::string toString() const;\n    };\n\n    bool append(snitch::small_string_span ss, const MyClass\u0026 c) {\n        return append(ss, c.toString());\n    }\n}\n```\n\nIf you cannot write your serialization function in this way (or for optimal speed), you will have to explicitly manage the string span. This typically involves:\n - calculating the expected length `n` of the textual representation of your value,\n - checking if `n` would exceed `ss.available()` (return `false` if so),\n - storing the current size of the span, using `old_size = ss.size()`,\n - growing the string span by this amount using `ss.grow(n)` or `ss.resize(old_size + n)`,\n - actually writing the textual representation of your value into the raw character array, accessible between `ss.begin() + old_size` and `ss.end()`.\n\nNote that _snitch_ small strings have a fixed capacity; once this capacity is reached, the string cannot grow further, and the output must be truncated. This will normally be indicated by a `...` at the end of the strings being reported (this is automatically added by _snitch_; you do not need to do this yourself). If this happens, depending on which string was truncated, there are a number of compilation options that can be modified to increase the maximum string length. See `CMakeLists.txt`, or `snitch_config.hpp`, or the top of `snitch_all.hpp`, for a complete list.\n\n\n### Reporters\n\nBy default, _snitch_ will report the test results to the standard output, using its own report format. There are two ways you can override this:\n - Register a new reporter with `REGISTER_REPORTER(...)` and select it from the command-line. This is more flexible as you can change which reporter to use without re-compiling, but it requires a bit more boilerplate. See [Registering a new reporter](#registering-a-new-reporter). A list of standard reporters is provided with _snitch_ and enabled by default; see [Built-in reporters](#built-in-reporters).\n - Override the default reporter by directly supplying your own callback function to the test registry. This is simpler but requires [using your own main function](#using-your-own-main-function), and is only a good option if the reporter never needs to change. See [Overriding the default reporter](#overriding-the-default-reporter).\n\nIn both cases, the core of the reporter is its \"report\" callback function. It is a `noexcept` function, taking two arguments:\n - a reference to the `snitch::registry` that generated the event\n - a reference to the `snitch::event::data` containing the event data. This type is a `std::variant`; use `std::visit` to act on the event.\n\nMost events are generated during the course of a normal test run. The only exceptions are `list_test_run_started`, `list_test_run_ended`, and `test_case_listed`, which are generated when listing tests (`--list-tests` option).\n\nWhen receiving a test event, the event object will only contain non-owning references (e.g., in the form of string views) to the actual event data. These references are only valid until the report function returns; after this, the event data will be destroyed or overwritten. If you need persistent access to this data (e.g., because your reporting format requires reporting the data at a different time than when the event is generated), you must explicitly copy the relevant data, and not the references. For example, for strings, this could involve creating a `std::string` (or `snitch::small_string`) from the `std::string_view` stored in the event object.\n\nFinally, note that events being sent to the reporter are affected by the chosen verbosity:\n - `quiet`: `assertion_failed`, `test_case_skipped`, `list_test_run_started`, `list_test_run_ended`, and `test_case_listed` only.\n - `normal`: same as `quiet`, plus `test_run_started` and `test_run_ended`.\n - `high`: same as `normal`, plus `test_case_started` and `test_case_ended`.\n - `full`: same as `high`, plus `assertion_succeeded` (i.e., all events).\n\nIt may be necessary to override the default verbosity when the reporter is initialized if the reporter requires certain events to be sent.\n\n\n#### Built-in reporters\n\nWith the default build configuration, _snitch_ provides the following built-in reporters. They can all be disabled by turning off the CMake option `SNITCH_WITH_ALL_REPORTERS` or Meson option `with_all_reporters`, then enabled individually with specific build options if desired.\n - `console`: This is the default reporter, always present.\n - `teamcity`: Reports events in a format suitable for JetBrains TeamCity.\n - `xml`: Reports events in the _Catch2_ XML format. Provided for compatibility with _Catch2_.\n\n\n#### Overriding the default reporter\n\nThe default reporter callback can be registered either as a free function, a stateless lambda, or a member function. This is the reporter that is used if no `--reporter` option is passed to the command-line. You can register your own callback as follows:\n\n```c++\n// Free function.\n// --------------\nvoid report_function(const snitch::registry\u0026 r, const snitch::event::data\u0026 e) noexcept {\n    /* ... */\n}\n\nsnitch::tests.report_callback = \u0026report_function;\n\n// Stateless lambda (no captures).\n// -------------------------------\nsnitch::tests.report_callback = [](const snitch::registry\u0026 r, const snitch::event::data\u0026 e) noexcept {\n    /* ... */\n};\n\n// Stateful lambda (with captures).\n// -------------------------------\nauto lambda = [\u0026](const snitch::registry\u0026 r, const snitch::event::data\u0026 e) noexcept {\n    /* ... */\n};\n\n// 'lambda' must remain alive for the duration of the tests!\nsnitch::tests.report_callback = lambda;\n\n// Member function (const or non-const, up to you).\n// ------------------------------------------------\nstruct Reporter {\n    void report(const snitch::registry\u0026 r, const snitch::event::data\u0026 e) /*const*/ noexcept {\n        /* ... */\n    }\n};\n\nReporter reporter; // must remain alive for the duration of the tests!\n\nsnitch::tests.report_callback = {reporter, snitch::constant\u003c\u0026Reporter::report\u003e{}};\n```\n\nIf you need to use a reporter member function, please make sure that the reporter object remains alive for the duration of the tests (e.g., declare it static, global, or as a local variable declared in `main()`), or make sure to de-register it when your reporter is destroyed.\n\n\n#### Registering a new reporter\n\nThere are two macros available to register a new reporter: `REGISTER_REPORTER` and `REGISTER_REPORTER_CALLBACKS`. The former registers a reporter class or struct, and is useful for stateful reporters. The latter registers a reporter as a series of callback functions, which only need defining as needed. Both offer the same functionality, and you can simply choose the one that is most convenient for you.\n\n`REGISTER_REPORTER(NAME, TYPE);`\n\nThis must be called at namespace, global, or class scope; not inside a function or another test case. This registers a new reporter with name `NAME` (which is used to select it from the command-line), and type `TYPE`. The type must define:\n - A constructor taking a `snitch::registry\u0026`, called when the reporter is selected.\n - A `bool configure(snitch::registry\u0026, std::string_view k, std::string_view v)` member function, called for each reporter option from the command-line. It is called once for each of the options provided on the command-line, with `k` the name of the option, and `v` its value. The function is expected to return `false` if the option was unknown, and `true` otherwise.\n - A `void report(const snitch::registry\u0026, const snitch::event::data\u0026)` member function. It is the main report callback, and should be implemented as described in the [Reporters](#reporters) section.\n\nAn example can be found in [`include/snitch_catch2_xml.hpp`](include/snitch_catch2_xml.hpp) / [`src/snitch_catch2_xml.cpp`](src/snitch_catch2_xml.cpp).\n\n\n`REGISTER_REPORTER_CALLBACKS(NAME, INIT, CONFIG, REPORT, FINISH);`\n\nThis is similar to `REGISTER_REPORTER`, but takes four separate callback functions instead of a single type as argument. The four callback functions are:\n - `INIT` has signature `void(snitch::registry\u0026 r) noexcept` and is used to initialize the reporter. It is called once when the reporter is selected.\n - `CONFIG` has signature `bool(snitch::registry\u0026 r, std::string_view k, std::string_view v) noexcept` and is used to configure the reporter. It is called once for each of the options provided on the command-line, with `k` the name of the option, and `v` its value. The function is expected to return `false` if the option was unknown, and `true` otherwise.\n - `REPORT` has signature `void(const snitch::registry\u0026 r, const snitch::event::data\u0026 e) noexcept`. It is the main report callback, as described in [Reporters](#reporters).\n - `FINISH` has signature `void(snitch::registry\u0026 r) noexcept` and is used to close the reporter. It is called once when the tests are finished running.\n\nAll callback functions are optional except `REPORT`. If a callback is unused, simply specify the function as `{}`. Otherwise, please refer to [Overriding the default reporter](#overriding-the-default-reporter) for instructions on how to specify your own callback functions.\n\nAn example can be found in [`include/snitch_reporter_teamcity.hpp`](include/snitch_reporter_teamcity.hpp) / [`src/snitch_reporter_teamcity.cpp`](src/snitch_reporter_teamcity.cpp).\n\n\n### Output colors\n\n_snitch_ is able to use color codes when outputting text to the console. These help with readability, but only when the output is printed directly into a terminal that supports color codes. If the chosen output target does not support color codes (which includes in particular the Windows command prompt, outputting to a file, or some CI frameworks), the output will contain gibberish symbols, e.g., `\u001b[1;31merror:\u001b[0m missing ...`, hence color codes should be disabled. There are two ways to do this:\n\n 1. At build-time using `-DSNITCH_DEFAULT_WITH_COLOR=on/off` (CMake) or `-Dsnitch:default_with_color=true/false` (meson). This selects whether color codes are used or not when no specific command-line option is provided to the test executable. This is enabled by default, but you can turn it off if your typical output targets do not support color codes.\n 2. At run-time using the `--color` (or `--colour-mode`) command-line option (see [the command-line API](#command-line-api) for more information). This allows enabling and disabling color codes for each test run, without rebuilding the tests. This is more useful if your workflow involves some targets which support color codes, and others that do not.\n\n\n### Command-line API\n\n_snitch_ offers the following command-line API:\n - positional arguments for filtering tests by name, see next section.\n - `-h,--help`: show command-line help.\n - `-l,--list-tests`: list all tests.\n - `   --list-tags`: list all tags.\n - `   --list-tests-with-tag`: list all tests with a given tag.\n - `   --list-reporters`: list all registered reporters.\n - `-r,--reporter \u003creporter[::key=value]*\u003e`: choose which reporter to use to output the test events.\n - `-v,--verbosity \u003cquiet|normal|high|full\u003e`: select level of detail for test events.\n - `-o,--output \u003cpath\u003e`: save test output to a file rather than the standard output.\n - `   --color \u003calways|default|never\u003e`: enable/disable colors in the default reporter.\n\nThe following options are provided for compatibility with _Catch2_:\n - `   --colour-mode \u003cansi|default|none\u003e`: enable/disable colors in the default reporter.\n\n\n### Selecting which tests to run\n\nThe command-line arguments (other than options starting with `--`) are used to select which tests to run. If no positional argument is given, all test cases will be run, except those that are explicitly hidden with special tags (see [Tags](#tags), and see also the note below on filtering hidden tests). Otherwise, each argument is a \"filter\" that is applied to the list of test cases.\n\nA filter may contain any number of \"wildcard\" character, `*`, which can represent zero or more characters. For example:\n - `ab*` will include all test cases with names starting with `ab`.\n - `*cd` will include all test cases with names ending with `cd`.\n - `ab*cd` will include all test cases with names starting with `ab` and ending with `cd`.\n - `abcd` will only include the test case with name `abcd`.\n - `*` will include all test cases.\n\nIf a filter starts with `~`, the meaning of the filter is negated. For example `~ab*` will include all test cases with name not starting with `ab`.\n\nA filter can contain white spaces, however be mindful that your shell will require the filter to be surrounded by quotes to treat it as a single command-line argument (e.g., `./snitch_app \"some test\"`).\n\nBy default, a filter applies to the test case name (which includes the test type for templated tests, using the format `name \u003ctype\u003e`). However, if a filter starts with `[` or `~[`, then it applies to the test case tags instead. This behavior can be bypassed by escaping the bracket `\\[`, in which case the filter applies to the test case name again (see note below on escaping).\n\nFinally, if multiple filters are provided, they are combined using the following logic:\n - When provided as separate command-line arguments, e.g., `\"\u003cfilter1\u003e\" \"\u003cfilter2\u003e\"`, the filters are combined with an \"AND\" operation (tests must match both filters to be selected).\n - When provided as a single comma-separated command-line argument, e.g., `\"\u003cfilter1\u003e,\u003cfilter2\u003e\"`, the filters are combined with an \"OR\" operation (tests must match either of the filters to be selected).\n - For tag filters only, when multiple tags are specified in the same command-line argument, e.g., `\"[\u003cfilter1\u003e][\u003cfilter2\u003e]\"`, the tag filters are combined with an \"AND\" operation (test tags must match both filters to be selected).\n\nName and tag filters can be used in any combination. To summarize, here are some examples with the equivalent C++ boolean logic (where `f*` represents a filter):\n\n| CLI test filters  | C++ boolean equivalent        |\n|-------------------|-------------------------------|\n| `f`               | `f`                           |\n| `~f`              | `!f`                          |\n| `f1 f2`           | `f1 \u0026\u0026 f2`                    |\n| `f1 f2 f3 ...`    | `f1 \u0026\u0026 f2 \u0026\u0026 f3 \u0026\u0026 ...`       |\n| `f1,f2`           | `f1 \\|\\| f2`                  |\n| `f1,f2,f3,...`    | `f1 \\|\\| f2 \\|\\| f3 \\|\\| ...` |\n| `f1,f2 f3`        | `(f1 \\|\\| f2) \u0026\u0026 f3`          |\n\n**Note 1:** To match the actual characters `*`, `,`, `[`, `]`, or `\\` in a test name, the character in the filter must be escaped using a backslash, like `\\*`. In general, any character located after a single backslash will be interpreted as a regular character, with no special meaning. Be mindful that most shells (Bash, etc.) will also require the backslash itself be escaped to be interpreted as an actual backslash in _snitch_. The table below shows examples of how edge-cases are handled:\n\n| Bash    | _snitch_ | matches                                     |\n|---------|----------|---------------------------------------------|\n| `\\\\`    | `\\`      | nothing (ill-formed filter)                 |\n| `\\\\*`   | `\\*`     | any name which is exactly the `*` character |\n| `\\\\\\\\`  | `\\\\`     | any name which is exactly the `\\` character |\n| `\\\\\\\\*` | `\\\\*`    | any name starting with the `\\` character    |\n| `[a*`   | `[a*`    | any tag starting with `[a`                  |\n| `\\\\[a*` | `\\[a*`   | any name starting with `[a`                 |\n\n**Note 2:** Hidden test cases are treated differently from normal test cases. For a hidden test to be run, it must be *explicitly included* with the chosen filters. This means that the test case a) must not have been excluded by any filter, and b) must have matched at least one non-negated filter. For example, if a hidden test is named `abc`, it will not be run with the filter `~b*` (\"all tests except those starting with `b`\") even though its name would be a match; it was only matched \"implicitly\", by not being excluded. It will, however, be run with the filter `a*` (\"all tests starting with `a`\"), since this is an explicit match. This is somewhat subtle, but prevents more confusing results. If in doubt, hidden test cases can always be explicitly selected with the `[.]` filter tag, and explicitly excluded with the `~[.]` filter tag.\n\n\n### Using your own main function\n\nBy default _snitch_ defines `main()` for you. To prevent this and provide your own `main()` function, when compiling _snitch_, `SNITCH_DEFINE_MAIN` must be set to `0`.\n\nIf using the header-only mode, this can be done in the file that defines the _snitch_ implementation:\n\n```c++\n#define SNITCH_IMPLEMENTATION\n#define SNITCH_DEFINE_MAIN 0\n#include \u003csnitch_all.hpp\u003e\n```\n\nIf using CMake, this can be done by setting the option just before calling `FetchContent_Declare()`:\n\n```cmake\nset(SNITCH_DEFINE_MAIN OFF)\n```\n\nIf using meson, then you can configure with `-D snitch:define_main=false`.\n\nHere is a recommended `main()` function that replicates the default behavior of snitch:\n\n```c++\nint main(int argc, char* argv[]) {\n    // Parse the command-line arguments.\n    std::optional\u003csnitch::cli::input\u003e args = snitch::cli::parse_arguments(argc, argv);\n    if (!args) {\n        // Parsing failed, an error has been reported, just return.\n        return 1;\n    }\n\n    // Configure snitch using command-line options.\n    // You can then override the configuration below, or just remove this call to disable\n    // command-line options entirely.\n    snitch::tests.configure(*args);\n\n    // Your own initialization code goes here.\n    // ...\n\n    // Actually run the tests.\n    // This will apply any filtering specified on the command-line.\n    return snitch::tests.run_tests(*args) ? 0 : 1;\n}\n```\n\n\n### Exceptions\n\nBy default, _snitch_ assumes exceptions are enabled, and uses them in two cases:\n\n 1. Obviously, in test macros that check exceptions being thrown (e.g., `REQUIRE_THROWS_AS(...)`).\n 2. In `REQUIRE*()`, `FAIL()`, and `SKIP()` macros, to abort execution of the current test case and continue to the next one.\n\nIf _snitch_ detects that exceptions are not available (or is configured with exceptions disabled, by setting `SNITCH_WITH_EXCEPTIONS` to `0`), then\n\n 1. Test macros that check exceptions being thrown will not be defined.\n 2. `REQUIRE*()`, `FAIL()`, and `SKIP()` macros will simply use `std::terminate()` to abort execution. Consequently, the whole test application stops and the following test cases are not executed. If this is undesirable, use the alternative macros that do not abort execution: `CHECK*()`, `FAIL_CHECK()`, and `SKIP_CHECK()`, then do the control flow yourself (e.g., return from the test case).\n\n\n### Freestanding\n\n_snitch_ offers several configuration options to support \"freestanding\" environments (e.g., lacking an operating system). This includes enabling/disabling the following:\n\n - Exceptions (`SNITCH_WITH_EXCEPTIONS`). See above.\n\n - Console (`SNITCH_WITH_STDOUT`). When disabled, there is no default implementation for the console; you will have to supply your own function:\n\n   ```c++\n    // Your own implementation: write this message somewhere, or just discard the message.\n    // Below is an illustrative example with the C++ STL.\n\n    void my_console_print(std::string_view message) noexcept {\n        // NB: The \"message\" will already include line endings.\n        std::cout \u003c\u003c message \u003c\u003c std::flush;\n    }\n\n    int main(int argc, char* argv[]) {\n        // Override the default 'console_print'.\n        // You must do this before calling any other function from snitch.\n        snitch::cli::console_print = \u0026my_console_print;\n\n        // Usual main function...\n    }\n    ```\n\n - File I/O (`SNITCH_WITH_STD_FILE_IO`). When disabled, there is no default implementation for file I/O; if you need to write results to a \"file\" (or a file-like object, like a socket), you will have to supply your own functions:\n\n   ```c++\n    // You can use the supplied \"storage\" if you need to manage any state specific to that file.\n    // Below is an illustrative example with the C++ STL.\n\n    void my_file_open(snitch::file_object_storage\u0026 storage, std::string_view path) {\n        auto\u0026 stream = storage.emplace\u003cstd::ofstream\u003e(std::string(path));\n        if (!stream.is_open()) {\n            snitch::assertion_failed(\"output file could not be opened for writing\");\n        }\n    }\n\n    void my_file_write(const snitch::file_object_storage\u0026 storage,\n                       std::string_view message) noexcept {\n        // NB: The \"message\" will already include line endings.\n        storage.get_mutable\u003cstd::ofstream\u003e() \u003c\u003c message \u003c\u003c std::flush;\n    }\n\n    void my_file_close(snitch::file_object_storage\u0026 storage) noexcept {\n        storage.reset();\n    }\n\n    int main(int argc, char* argv[]) {\n        // Override the default implementation.\n        // You must do this before calling any other function from snitch.\n        snitch::io::file_open  = \u0026my_file_open;\n        snitch::io::file_write = \u0026my_file_write;\n        snitch::io::file_close = \u0026my_file_close;\n\n        // Usual main function...\n    }\n    ```\n\n\n### Header-only build\n\nThe recommended way to use _snitch_ is to build and consume it like any other library. This provides the best incremental build times, a standard way to include and link to the _snitch_ implementation, and a cleaner separation between your code and _snitch_ code, but this also requires a bit more set up (using a build generator like CMake, meson, or some other build system).\n\nFor extra convenience, _snitch_ is also provided as a header-only library. The main header is called `snitch_all.hpp`, and can be downloaded as an artifact from each release on GitHub. It is also produced by any local CMake or meson build, so you can also use it like any other library.\n\nWith CMake, just link to `snitch::snitch-header-only` instead of `snitch::snitch`.\n\nWith meson, the `snitch_dep` dependency works for both library and header-only usage.\n\n`snitch_all.hpp` is the only header required to use the library; other headers may be provided for convenience functions (e.g., reporters for common CI frameworks) and these must still be included separately.\n\nTo use _snitch_ as header-only in your code, simply include `snitch_all.hpp` instead of `snitch.hpp`. Then, one of your files must include the _snitch_ implementation. This can be done with a `.cpp` file containing only the following:\n\n```c++\n#define SNITCH_IMPLEMENTATION\n#include \u003csnitch_all.hpp\u003e\n```\n\n### IDE integrations\n\nThere are no IDE integrations created specifically for _snitch_. However, since _snitch_ implements most of the _Catch2_ command-line API, _Catch2_ integrations tend to work for _snitch_ test applications as well. See in particular:\n - [Visual Studio Code](https://code.visualstudio.com/) and the [C++ TestMate](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter) extension. Tested successfully on 26/08/2023.\n - [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) and the [_Catch2_ Test Adapter](https://marketplace.visualstudio.com/items?itemName=JohnnyHendriks.ext01) extension. Tested successfully on 27/08/2023.\n - [CLion](https://www.jetbrains.com/clion/) using the builtin _Catch2_ configuration. Tested partially on 20/08/2023 (I don't have a CLion license).\n\nFeel free to report any issues you encounter using these IDE integrations; If you would like to contribute\n\n\n### `clang-format` support\n\nWith its default configuration, `clang-format` will incorrectly format code using `SECTION()` if the section is the first statement inside a test case. This is because it does not know the semantic of this macro, and by default interprets it as a declaration rather than a control statement.\n\nFixing this requires `clang-format` version 13 at least, and requires adding the following to your `.clang-format` file:\n```yaml\nIfMacros: ['SECTION', 'SNITCH_SECTION']\nSpaceBeforeParens: ControlStatementsExceptControlMacros\n```\n\n## Contributing\n\nPlease refer to the separate [contributing](CONTRIBUTING.md) page.\n\n\n## Code of conduct\n\nPlease refer to the separate [code of conduct](CODE_OF_CONDUCT.md) page.\n\n\n## Why the name _snitch_?\n\nLibraries and programs sometimes do shady or downright illegal stuff (i.e., bugs, crashes). _snitch_ is a library like any other; it may have its own bugs and faults. But it's a snitch! It will tell you when other libraries and programs misbehave, with the hope that you will overlook its own wrongdoings.\n\nThe logo is a jay feather. Jays are known for alerting other animals of danger.\n","funding_links":[],"categories":["Tests","Test Framework"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnitch-org%2Fsnitch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnitch-org%2Fsnitch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnitch-org%2Fsnitch/lists"}