{"id":19364272,"url":"https://github.com/mity/acutest","last_synced_at":"2025-12-18T00:14:46.004Z","repository":{"id":12113651,"uuid":"14703326","full_name":"mity/acutest","owner":"mity","description":"Simple header-only C/C++ unit testing facility.","archived":false,"fork":false,"pushed_at":"2024-06-03T05:46:36.000Z","size":206,"stargazers_count":360,"open_issues_count":14,"forks_count":95,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-03-28T22:13:56.904Z","etag":null,"topics":["c","c-plus-plus","cli","header-only","mit-license","single-file","single-header","tap-producer","test-runner","testing-tools","tests","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mity.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"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}},"created_at":"2013-11-26T01:04:41.000Z","updated_at":"2025-03-25T23:20:06.000Z","dependencies_parsed_at":"2024-11-17T08:02:36.472Z","dependency_job_id":"11c05878-8247-448a-b46b-3271748bf1c6","html_url":"https://github.com/mity/acutest","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mity%2Facutest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mity%2Facutest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mity%2Facutest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mity%2Facutest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mity","download_url":"https://codeload.github.com/mity/acutest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247261612,"owners_count":20910108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["c","c-plus-plus","cli","header-only","mit-license","single-file","single-header","tap-producer","test-runner","testing-tools","tests","unit-testing"],"created_at":"2024-11-10T07:36:51.686Z","updated_at":"2025-12-18T00:14:45.955Z","avatar_url":"https://github.com/mity.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Acutest Readme\n\nHome: https://github.com/mity/acutest\n\n\n## What Is Acutest\n\nAcutest is C/C++ unit testing facility aiming to be as simple as possible, not\nto stand in the developer's way and to minimize any external dependencies.\n\nTo achieve that, the complete implementation resides in a single C header file,\nand its core depends only on few standard C library functions.\n\n\n## Overview\n\n**Main features:**\n* Unit tests in C or C++ are supported.\n* No need to install/setup/configure any testing framework. Acutest is just\n  a single header file, `acutest.h`.\n* The header provides the program entry point (function `main()`).\n* Minimal dependencies: Core features only depend on few standard C headers,\n  optional features may use more if available on the particular system.\n* Trivial interface for writing unit tests: Few preprocessor macros described\n  further below.\n* Rudimentary support for [Test Anything Protocol](https://testanything.org/)\n  (use `--tap` option).\n* Rudimentary support for xUnit-compatible XML output (use `--xml-output=FILE`).\n\n**C++ specific features:**\n* Acutest catches any C++ exception thrown from any unit test function. When\n  that happens, the given test is considered to fail.\n* If the exception is derived from `std::exception`, `what()` is written out\n  in the error message.\n\n**Unix/Posix specific features:**\n* By default, every unit test is executed as a child process.\n* By default, if the output is directed to a terminal, the output is colorized.\n* If the system offers Posix timer (`clock_gettime()`), user can measure test\n  execution times with `--time=real` (same as `--time`) and `--time=cpu`.\n\n**Linux specific features:**\n* If a debugger is detected, the default execution of tests as child processes\n  is suppressed in order to make the debugging easier.\n\n**Windows specific features:**\n* By default, every unit test is executed as a child process.\n* If a debugger is detected, the default execution of tests as child processes\n  is suppressed in order to make the debugging easier.\n* By default, if the output is directed to a terminal, the output is colorized.\n* Acutest installs a SEH filter to print out uncaught SEH exceptions.\n* User can measure test execution times with `--time`.\n\n**macOS specific features:**\n* If a debugger is detected, the default execution of tests as child processes\n  is suppressed in order to make the debugging easier.\n\nAny C/C++ module implementing one or more unit tests and including `acutest.h`,\ncan be built as a standalone program. We call the resulted binary as a \"test\nsuite\" for purposes of this document. The suite is then executed to run the\ntests, as specified with its command line options.\n\nWe say any unit test succeeds if and only if:\n1. all condition checks (as described below) called throughout its execution\n   pass;\n2. the test does not throw any exception (C++ only); and\n3. (on Windows or Unix) the unit test subprocess is not interrupted/terminated\n   (e.g. by a signal on Unix or SEH on Windows).\n\n\n## Writing Unit Tests\n\n### Basic Use\n\nTo use Acutest, simply include the header file `acutest.h` on the beginning of\nthe C/C++ source file implementing one or more unit tests. Note the header\nprovides implementation of the `main()` function.\n\n```C\n#include \"acutest.h\"\n```\n\nEvery test is supposed to be implemented as a function with the following\nprototype:\n\n```C\nvoid test_example(void);\n```\n\nThe tests can use some preprocessor macros to validate the test conditions.\nThey can be used multiple times, and if any of those conditions fails, the\nparticular test is considered to fail.\n\n`TEST_CHECK` is the most commonly used testing macro which simply tests a\nboolean condition and fails if the condition evaluates to false (or zero).\n\nFor example:\n\n```C\nvoid test_example(void)\n{\n    void* mem;\n    int a, b;\n\n    mem = malloc(10);\n    TEST_CHECK(mem != NULL);\n\n    mem = realloc(mem, 20);\n    TEST_CHECK(mem != NULL);\n}\n```\n\nNote that the tests should be completely independent on each other. Whenever\nthe test suite is invoked, the user may run any number of tests in the suite,\nin any order. Furthermore by default, on platforms where supported, each unit\ntest is executed as a standalone (sub)process.\n\nFinally, the test suite source file has to list the unit tests, using the\nmacro `TEST_LIST`. The list specifies name of each test (it has to be unique)\nand pointer to a function implementing the test. I recommend names which are\neasy to use on command line: especially avoid space and other special\ncharacters which might require escaping in shell; also avoid dash (`-`) as a\nfirst character of the name, as it could then be interpreted as a command line\noption and not as a test name.\n\n```C\nTEST_LIST = {\n   { \"example\", test_example },\n   ...\n   { NULL, NULL }     /* zeroed record marking the end of the list */\n};\n```\n\nNote the test list has to be ended with zeroed record.\n\nFor a basic test suites this is more or less all you need to know. However\nAcutest provides some more macros which can be useful in some specific\nsituations. We cover them in the following sub-sections.\n\n### Aborting on a Check Failure\n\nThere is a macro `TEST_ASSERT` which is very similar to `TEST_CHECK` but, if it\nfails, it aborts execution of the current unit test instantly.\n\nFor example:\n\n```C\nvoid test_example(void)\n{\n    void* mem;\n    int a, b;\n\n    mem = malloc(10);\n    TEST_ASSERT(mem != NULL);\n\n    mem = realloc(mem, 20);\n    TEST_ASSERT(mem != NULL);\n}\n```\n\nThe abortion in the case of failure is performed either by calling `abort()`\n(if the test is executed as a child process) or via `longjmp()` (if it is not).\n\nTherefore it should be used only if you understand the costs connected with\nsuch a brutal abortion of the test. Depending on what your unit test does,\nit may include unflushed file descriptors, memory leaks, C++ objects destructed\nwithout their destructors being called and more.\n\nIn general, `TEST_CHECK` should be preferred over `TEST_ASSERT`, unless you\nknow exactly what you do and why you chose `TEST_ASSERT` in some particular\nsituation.\n\n### Testing C++ Exceptions\n\nFor C++, there is an additional macro `TEST_EXCEPTION` for verifying the given\ncode (typically just a function or a method call) throws the expected type of\nexception.\n\nThe check fails if the function does not throw any exception or if it throws\nanything incompatible.\n\nFor example:\n\n```C++\nvoid test_example(void)\n{\n    TEST_EXCEPTION(CallSomeFunction(), std::exception);\n}\n```\n\n### Richer Failure Diagnosis\n\nIf a condition check fails, it is often useful to provide some additional\ninformation about the situation so the problem is easier to debug. Acutest\nprovides the macros `TEST_MSG` and `TEST_DUMP` for this purpose.\n\nThe former one outputs any `printf`-like message, the other one outputs a\nhexadecimal dump of a provided memory block.\n\nSo for example:\n\n```C\nvoid test_example(void)\n{\n    char produced[100];\n    char expected[] = \"Hello World!\";\n\n    SomeSprintfLikeFunction(produced, \"Hello %s!\", \"world\");\n    TEST_CHECK(strcmp(produced, expected) == 0);\n    TEST_MSG(\"Expected: %s\", expected);\n    TEST_MSG(\"Produced: %s\", produced);\n\n    /* Or, if the function could provide some binary stuff, we might rather\n     * use TEST_DUMP instead in order to output a hexadecimal dump of the data.\n     */\n    TEST_DUMP(\"Expected:\", expected, strlen(expected));\n    TEST_DUMP(\"Produced:\", produced, strlen(produced));\n}\n```\n\nNote that both macros output anything only when the most recently checking\nmacro has failed. In other words, these two are equivalent:\n\n```C\nif(!TEST_CHECK(some_condition != 0))\n    TEST_MSG(\"some message\");\n```\n\n```C\nTEST_CHECK(some_condition != 0);\nTEST_MSG(\"some message\");\n```\n\n(Note that `TEST_MSG` requires the compiler with variadic macros support.)\n\n### Loops over Test Vectors\n\nSometimes, it is useful to design your testing function as a loop over data\nproviding a collection of test vectors and their respective expected outputs.\nFor example imagine our unit test is supposed to verify some kind of a hashing\nfunction implementation and we've got a collection of test vectors for it in\nthe hash specification.\n\nIn such cases, it is very useful to get some name associated with every test\nvector and output the name in the output log so that if any check fails, it is\neasy to identify the guilty test vector. However, the loop body may execute\ndozens of checking macros and so it may be impractical to add such name to\ncustomize every check message in the loop.\n\nTo solve this, Acutest provides the macro `TEST_CASE`. The macro specifies\na string serving as the test vector name. When used, Acutest makes sure that\nin the output log the provided name precedes any message from subsequent\ncondition checks.\n\nFor example, lets assume we are testing `SomeFunction()` which is supposed,\nfor a given byte array of some size, return another array of bytes in a newly\n`malloc`-ed buffer. Then we can do something like this:\n\n```C\nstruct TestVector {\n    const char* name;\n    const uint8_t* input;\n    size_t input_size;\n    const uint8_t* expected_output;\n    size_t expected_output_size;\n};\n\nstruct TestVector test_vectors[] = {\n    /* some data */\n};\n\nvoid test_example(void)\n{\n    int i;\n    const uint8_t* output;\n    size_t output_size;\n\n    for(i = 0; i \u003c sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {\n        struct TestVector* vec = \u0026test_vectors[i];\n\n        /* Output the name of the tested test vector. */\n        TEST_CASE(vec.name);\n\n        /* Now, we can check the function produces what it should for the\n         * current test vector. If any of the following checking macros\n         * produces any output (either because the check fails, or because\n         * high `--verbose` level is used), Acutest also outputs the  currently\n         * tested vector's name. */\n        output = SomeFunction(vec-\u003einput, vec-\u003einput_size, \u0026output_size);\n        if(TEST_CHECK(output != NULL)) {\n            TEST_CHECK(output_size == vec-\u003eexpected_output_size);\n            TEST_CHECK(memcmp(output, vec-\u003eexpected_output, output_size) == 0);\n            free(output);\n        }\n    }\n}\n```\n\nThe specified name applies to all checks executed after the use of `TEST_CASE`\n* until the unit test ends; or\n* until `TEST_CASE` is used again to specify another name; or\n* until the name is explicitly reset by using `TEST_CASE` with the `NULL`\n  as its argument.\n\n### Custom Log Messages\n\nMany of the macros mentioned in the earlier sections have a counterpart which\nallows to output a custom messages instead of some default ones.\n\nAll of these have the same name as the aforementioned macros, just with the\nunderscore suffix added. With the suffix, they then expect `printf`-like string\nformat and corresponding additional arguments.\n\nSo, for example, instead of the simple checking macros\n```C++\nTEST_CHECK(a == b);\nTEST_ASSERT(x \u003c y);\nTEST_EXCEPTION(SomeFunction(), std::exception);\n```\nwe can use their respective counterparts with a custom messages:\n```C++\nTEST_CHECK_(a == b, \"%d is equal to %d\", a, b);\nTEST_ASSERT_(x \u003c y, \"%d is lower than %d\", x, y);\nTEST_EXCEPTION_(SomeFunction(), std::exception, \"SomeFunction() throws std::exception\");\n```\n\nYou should use some neutral wording for them because, with the command line\noption `--verbose`, the messages are logged out even if the respective check\npasses successfully.\n\n(If you need to output some diagnostic information just in the case the check\nfails, use the macro `TEST_MSG`. That's exactly its purpose.)\n\nSimilarly, instead of\n```C\nTEST_CASE(\"name\");\n```\nwe can use richer\n```C\nTEST_CASE_(\"iteration #%d\", 42);\n```\n\nHowever note all of these can only be used if your compiler supports variadic\npreprocessor macros. Variadic macros became a standard part of the C language\nwith C99.\n\n\n## Building the Test Suite\n\nWhen we are done with implementing the tests, we can simply compile it as\na simple C/C++ program. For example, assuming `cc` is your C compiler:\n\n```sh\n$ cc test_example.c -o test_example\n```\n\n\n## Running Unit Tests\n\nWhen the test suite is compiled, the resulted testing binary can be used to run\nthe tests.\n\nExit code of the test suite is 0 if all the executed unit tests pass, 1 if any\nof them fails, or any other number if an internal error occurs.\n\nBy default (without any command line options), it runs all implemented unit\ntests. It can also run only subset of the unit tests as specified on the\ncommand line:\n\n```sh\n$ ./test_example                  # Runs all tests in the suite\n$ ./test_example test1 test2      # Runs only tests specified\n$ ./test_example --exclude test3  # Runs all tests but those specified\n```\n\nNote that a single command line argument can select a whole group of test units\nbecause Acutest implements several levels of unit test selection (the 1st one\nmatching at least one test unit is used):\n\n1. *Exact match*: When the argument matches exactly the whole name of a unit\n   test then just the given test is selected.\n\n2. *Word match*: When the argument does not match any complete test name, but\n   it does match whole word in one or more test names, then all such tests are\n   selected.\n\n   The following characters are recognized as word delimiters: space ` `,\n   tabulator `\\t`, dash `-`, underscore `_`, slash `/`, dot `.`, comma `,`,\n   colon `:`, semicolon `;`.\n\n3. *Substring match*: If even the word match failed to select any test, then\n   all tests with a name which contains the argument as its substring are\n   selected.\n\nBy adopting an appropriate test naming strategy, this allows user to run (or\nto skip if `--exclude` is used) easily whole family of related tests with a\nsingle command line argument.\n\nFor example consider test suite `test_example` which implements tests `foo-1`,\n`foo-2`, `foomatic`, `bar-1` and `bar-10`:\n\n```sh\n$ ./test_example bar-1   # Runs only the test 'bar-1' (exact match)\n$ ./test_example foo     # Runs 'foo-1' and 'foo-2' (word match)\n$ ./test_example oo      # Runs 'foo-1', 'foo-2' and 'foomatic' (substring match)\n$ ./test_example 1       # Runs 'foo-1' and 'bar-1' (word match)\n```\n\nYou may use `--list` or `-l` to just list all unit tests implemented by the\ngiven test suite:\n\n```sh\n$ ./test_example --list\n```\n\nTo see description for all the supported command line options, run the binary\nwith the option `--help`:\n\n```sh\n$ ./test_example --help\n```\n\n\n## FAQ\n\n**Q: Wasn't this project known as \"CUTest\"?**\n\n**A:** Yes. It has been renamed as the original name was found to be\n[too much overloaded](https://github.com/mity/cutest/issues/6).\n\n\n**Q: Do I need to distribute file `README.md` and/or `LICENSE.md`?**\n\n**A:** No. The header `acutest.h` includes URL to our repo, copyright note and\nthe MIT license terms inside of it. As long as you leave those intact, we are\ncompletely fine if you only add the header into your project. After all,\nthe simple use and all-in-one-header nature of it is our primary aim.\n\n\n## License\n\nAcutest is covered with MIT license, see the file `LICENSE.md` or beginning of\n`acutest.h` for its full text.\n\n\n## More Information\n\nThe project resides on github:\n\n* https://github.com/mity/acutest\n\nYou can find the latest version of Acutest there, contribute with enhancements\nor report bugs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmity%2Facutest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmity%2Facutest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmity%2Facutest/lists"}