{"id":20355128,"url":"https://github.com/risc-os-community/greatest","last_synced_at":"2026-06-11T14:31:11.454Z","repository":{"id":42520471,"uuid":"405682722","full_name":"RISC-OS-Community/GreaTest","owner":"RISC-OS-Community","description":"This is a RISC OS port of the C Unit Testing header only library Greatest. This library works fine with both GCC and DDE compilers.","archived":false,"fork":false,"pushed_at":"2023-07-17T19:40:16.000Z","size":68,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-04T17:36:55.851Z","etag":null,"topics":["c","c99","dde","gcc","hacktoberfest","hacktoberfest2022","risc-os","riscos","test","test-runner","testing","tests","unit-test","unit-testing","unit-testing-framework","unittesting"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RISC-OS-Community.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}},"created_at":"2021-09-12T15:44:54.000Z","updated_at":"2022-12-01T01:47:40.000Z","dependencies_parsed_at":"2025-03-04T17:44:02.955Z","dependency_job_id":null,"html_url":"https://github.com/RISC-OS-Community/GreaTest","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":"RISC-OS-Community/StandardRepoTemplate","purl":"pkg:github/RISC-OS-Community/GreaTest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RISC-OS-Community%2FGreaTest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RISC-OS-Community%2FGreaTest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RISC-OS-Community%2FGreaTest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RISC-OS-Community%2FGreaTest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RISC-OS-Community","download_url":"https://codeload.github.com/RISC-OS-Community/GreaTest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RISC-OS-Community%2FGreaTest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34204177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["c","c99","dde","gcc","hacktoberfest","hacktoberfest2022","risc-os","riscos","test","test-runner","testing","tests","unit-test","unit-testing","unit-testing-framework","unittesting"],"created_at":"2024-11-14T23:11:20.940Z","updated_at":"2026-06-11T14:31:11.436Z","avatar_url":"https://github.com/RISC-OS-Community.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# greatest\n\nThis is a RISC OS port of GreaTest, a testing system for C, contained in 1 header file.\n\nThis port is very simple (the original library required only one minor patch in total) and, obviously sources reorganisation for RISC OS filesystem and creation of building scripts for both DDE and GCC on RISC OS. So the source is pretty much intact (makes it easy to keep up with new updates from mainstream library).\n\nThe other advantage of this Library compared to LibmUnit is that it also works fine with ROOL's SCL, so no need for UnixLib.\n\n## Key Features and Project Goals\n\n- **Small, Portable, Lightweight**\n\n    greatest doesn't depend on anything beyond ANSI C89, and the test\n    scaffolding should build without warnings when compiled with\n    `-Wall -Wextra -pedantic`. It is under 1,000 LOC (SLOCCount),\n    and does no dynamic allocation.\n\n- **Permissive License**\n\n    greatest is released under the [ISC License][ISC]. You can use it\n    freely, even for commercial purposes.\n\n- **Easy To Set Up**\n\n    To use, just `#include \"greatest.h\"` in your project. There is\n    very little boilerplate. Most features are optional.\n\n- **Un-Opinionated**\n\n    When a command-line test runner is useful, greatest can provide one,\n    but it can also run as part of other programs. It doesn't depend on\n    a particular build system or other tooling, and should accommodate a\n    variety of testing approaches. It actively avoids imposing\n    architectural choices on code under test. While greatest was\n    designed with C in mind, it attempts to be usable from C++.\n\n- **Modular**\n\n    Tests can be run individually, or grouped into suites. Suites can\n    share common setup, and can be in distinct compilation units.\n\n- **Low Friction**\n\n    Specific tests or suites can be run by name, for focused and rapid\n    iteration during development. greatest adds very little startup\n    latency.\n\n\nThere are some compile-time options, and slightly nicer syntax for\nparametric testing (running tests with arguments) if compiled\nwith a C99 or later language standard.\n\nThe library original author has written a blog post with more info:\n[blog post](http://spin.atomicobject.com/2013/07/31/greatest-c-testing-embedded/)\nWhile it's several years old, it's still accurate about the main functionality.\n\n[theft][], a related project, adds [property-based testing][pbt].\n\n[1]: http://spin.atomicobject.com/2013/07/31/greatest-c-testing-embedded/\n[theft]: https://github.com/silentbicycle/theft\n[pbt]: https://spin.atomicobject.com/2014/09/17/property-based-testing-c/\n[ISC]: https://opensource.org/licenses/ISC\n\n## Basic Usage\n\n```c\n#include \"greatest.h\"\n\n/* A test runs various assertions, then calls PASS(), FAIL(), or SKIP(). */\nTEST x_should_equal_1(void) {\n    int x = 1;\n    /* Compare, with an automatic \"1 != x\" failure message */\n    ASSERT_EQ(1, x);\n\n    /* Compare, with a custom failure message */\n    ASSERT_EQm(\"Yikes, x doesn't equal 1\", 1, x);\n\n    /* Compare, and if they differ, print both values,\n     * formatted like `printf(\"Expected: %d\\nGot: %d\\n\", 1, x);` */\n    ASSERT_EQ_FMT(1, x, \"%d\");\n    PASS();\n}\n\n/* Suites can group multiple tests with common setup. */\nSUITE(the_suite) {\n    RUN_TEST(x_should_equal_1);\n}\n\n/* Add definitions that need to be in the test runner's main file. */\nGREATEST_MAIN_DEFS();\n\nint main(int argc, char **argv) {\n    GREATEST_MAIN_BEGIN();      /* command-line options, initialization. */\n\n    /* Individual tests can be run directly in main, outside of suites. */\n    /* RUN_TEST(x_should_equal_1); */\n\n    /* Tests can also be gathered into test suites. */\n    RUN_SUITE(the_suite);\n\n    GREATEST_MAIN_END();        /* display results */\n}\n```\n\nOutput:\n\n```sh\n$ make simple \u0026\u0026 ./simple\ncc -g -Wall -Werror -pedantic    simple.c   -o simple\n\n* Suite the_suite:\n.\n1 test - 1 passed, 0 failed, 0 skipped (5 ticks, 0.000 sec)\n\nTotal: 1 test (47 ticks, 0.000 sec), 3 assertions\nPass: 1, fail: 0, skip: 0.\n```\n\nTests are run with `RUN_TEST(test_name)`, which can be called directly\nfrom the test runner's `main` function or grouped into suites (which are\nrun with `RUN_SUITE(suite_name)`). (Calls to `RUN_TEST` from inside\nanother test are ignored.)\n\nTest cases can be run with arguments: `RUN_TEST1(test_name, arg)` passes\na single argument, and if C99 features are supported, then\n`RUN_TESTp(test_name, ...)` uses `__VA_ARGS__` to run a test case with\none or mare arguments. `greatest_set_test_suffix` sets a name suffix, so\noutput from the test runner can include info about arguments.\n\nTest cases should call assertions and then end with `PASS()`, `SKIP()`,\n`FAIL()`, or their custom message variants (e.g. `SKIPm(\"TODO\");`).\nIf there are any test failures, the test runner will return 1,\notherwise it will return 0. (Skips do not cause the test runner to\nreport failure.)\n\n`PASS()`, `SKIP()`, `FAIL()`, and their custom message variants are\nmacros that updating internal bookkeeping and then returning and enum\nvalue, such as `GREATEST_TEST_RES_FAIL`. They all `return` from the\ncurrent test case function.\n\n`PASS()`/`PASSm(\"msg\")` prints as a dot when verbosity is zero, or\nthe test name and custom message (if any) with verbosity \u003e= 1.\n\n`FAIL()`/`FAILm(\"msg\")` always prints \"FAIL test_name: msg file:line\".\n\n`SKIP()`/`SKIPm(\"msg\")` prints as an 's' when verbosity is zero, or the\ntest name and custom message (if any) with verbosity \u003e= 1. Because skips\nare not treated as a failure by the test runner, they can be used to\nskip test cases that aren't relevant in a particular build or\nenvironment, a way to temporarily disable broken tests, or as a sort of\ntodo list for tests and functionality under active development.\n\nTests and suites are just functions, so normal C scoping rules apply.\nFor example, a test or suite named `main` will have a name collision.\n\n(For more examples, look at `example.c` and `example_suite.c`.)\n\n\n## Filtering By Name\n\ngreatest runs all tests by default, but can be configured to only run\nsuites or tests whose names contain a filter string, and/or exclude\ntests whose name contains a filter string. When test name filtering and\nexclusion are used together, exclusion takes precedence.\n\n    void greatest_set_suite_filter(const char *name);\n    void greatest_set_test_filter(const char *name);\n    void greatest_set_test_exclude(const char *name);\n\nThese correspond to the following command line test runner options:\n\n    `-s SUITE`:   Only run suites whose names contain the string \"SUITE\"\n    `-t TEST`:    Only run tests whose names contain the string \"TEST\"\n    `-x EXCLUDE`: Exclude tests whose names contain the string \"EXCLUDE\"\n\nFor example, to run any tests with \"tree\" in the name, in suites with\n\"pars\" in the name (such as \"parser\"), but exclude any tests whose names\nalso contain \"slow\":\n\n    ./test_project -s pars -t tree -x slow\n\nThe string matching includes optional test name suffixes.\n\nThe `greatest_set_exact_name_match()` function and corresponding `-e`\ncommand line runner flag can be used to only run tests and/or suites\nwhose names exactly match the name filter(s). Note: exact-match suite\nfiltering by name will not skip tests that are run outside of any suite.\n\n\n## Available Assertions\n\nAssertions fail the current test unless some condition holds. All\nassertions have a custom message variant (with an `m` suffix), which\ntakes a  message string as its first argument. For example, the\nassertion `ASSERT_EQ(apple, orange);` could instead be used like\n`ASSERT_EQm(\"these should match\", apple, orange)`. Non-message\nassertions create a default message.\n\n\n### `ASSERT(COND)`\n\nAssert that `COND` evaluates to a true (non-zero) value.\n\n\n### `ASSERT_FALSE(COND)`\n\nAssert that `COND` evaluates to a false (zero) value.\n\n\n### `ASSERT_EQ(EXPECTED, ACTUAL)`\n\nAssert that `EXPECTED == ACTUAL`. To print the values if they\ndiffer, use `ASSERT_EQ_FMT`. To compare with custom equality test\nand print functions, use `ASSERT_EQUAL_T` instead.\n\n\n### `ASSERT_NEQ(EXPECTED, ACTUAL)`\n\nAssert that `EXPECTED != ACTUAL`.\n\n\n### `ASSERT_GT(EXPECTED, ACTUAL)`\n\nAssert that `EXPECTED \u003e ACTUAL`.\n\n\n### `ASSERT_GTE(EXPECTED, ACTUAL)`\n\nAssert that `EXPECTED \u003e= ACTUAL`.\n\n\n### `ASSERT_LT(EXPECTED, ACTUAL)`\n\nAssert that `EXPECTED \u003c ACTUAL`.\n\n\n### `ASSERT_LTE(EXPECTED, ACTUAL)`\n\nAssert that `EXPECTED \u003c= ACTUAL`.\n\n\n### `ASSERT_EQ_FMT(EXPECTED, ACTUAL, FORMAT)`\n\nAssert that `EXPECTED == ACTUAL`. If they are not equal, print their\nvalues using `FORMAT` as the `printf` format string.\n\nFor example: `ASSERT_EQ_FMT(123, result, \"%d\");` will call `printf`\nlike `printf(\"Expected: %d\\nGot: %d\\n\", 123, result);` if its\n`EXPECTED` and `ACTUAL` arguments don't match.\n\nNote: `EXPECTED` and `ACTUAL` will be evaluated more than once on\nfailure, so they should not be a function call with side effects.\n(Since their type is not known by the macro, they cannot be\ncaptured in a local variable. `typeof` is a GCC extension.)\n\n\n### `ASSERT_IN_RANGE(EXPECTED, ACTUAL, TOLERANCE)`\n\nAssert that `ACTUAL` is within `EXPECTED` +/- `TOLERANCE`, once the\nvalues have been converted to a configurable floating point type\n(`GREATEST_FLOAT`).\n\ngreatest does not depent on floating point math.\nIt is only used within `ASSERT_IN_RANGE`'s macro expansion.\n\n\n### `ASSERT_STR_EQ(EXPECTED, ACTUAL)`\n\nAssert that the strings are equal\n(i.e., `strcmp(EXPECTED, ACTUAL) == 0`).\n\n\n### `ASSERT_STRN_EQ(EXPECTED, ACTUAL, SIZE)`\n\nAssert that the first `SIZE` bytes of the strings are equal\n(i.e., `strncmp(EXPECTED, ACTUAL, SIZE) == 0`).\n\n\n### `ASSERT_MEM_EQ(EXPECTED, ACTUAL, SIZE)`\n\nAssert that the first `SIZE` bytes of memory pointed to by `EXPECTED`\nand `ACTUAL` are equal. If their memory differs, print a hexdump and\nhighlight the lines and individual bytes which do not match.\n\n\n### `ASSERT_ENUM_EQ(EXPECTED, ACTUAL, ENUM_STR_FUN)`\n\nAssert that the enum value `EXPECTED` is equal to `ACTUAL`. If not,\nconvert each enum value to a string using `ENUM_STR_FUN` before printing\nthem.\n\n`ENUM_STR_FUN` should have a type like:\n\n    const char *FUN(int x);\n\n\n### `ASSERT_EQUAL_T(EXPECTED, ACTUAL, TYPE_INFO, UDATA)`\n\nAssert that `EXPECTED` and `ACTUAL` are equal, using the\n`greatest_equal_cb` function pointed to by `TYPE_INFO-\u003eequal` to compare\nthem. The assertion's `UDATA` argument can be used to pass in arbitrary\nuser data (or `NULL`) to the callbacks. If the values are not equal and\nthe `TYPE_INFO-\u003eprint` function is defined, it will be used to print an\n\"Expected: X, Got: Y\" message.\n\n\n### `ASSERT_OR_LONGJMP(COND)`\n\nAssert that `COND` evaluates to a true value. If not, then use\n`longjmp(3)` to immediately return from the test case and any\nintermediate function calls.\n\nIf built with `GREATEST_USE_LONGJMP` `#define`d to 0, then all\nsetjmp/longjmp-related functionality will be compiled out. This also\nreduces memory usage by `sizeof jmp_buf`, which may be several hundred\nbytes, depending on the platform.\n\n\n## Random Shuffling\n\nGroups of suites or tests can be run in shuffled order by using\n`GREATEST_SHUFFLE_SUITES` and `GREATEST_SHUFFLE_TESTS`, respectively.\nThis can help find and eliminate accidental coupling between tests.\n\nThe shuffling depends on the seed and the test/suite count, so a\nconsistent seed will only lead to reproducible ordering until the\ngroup's count changes.\n\nShuffling suites:\n\n    SHUFFLE_SUITES(seed, {\n        RUN_SUITE(suite1);\n        RUN_SUITE(suite2);\n        RUN_SUITE(suite3);\n        RUN_SUITE(suite4);\n        RUN_SUITE(suite5);\n    });\n\nShuffling tests:\n\n    SHUFFLE_TESTS(seed, {\n        RUN_TEST(test_a);\n        RUN_TEST1(test_b, 12345);\n        RUN_TEST(test_c);\n        RUN_TESTp(test_d, \"some_argument\");\n        RUN_TEST(test_e);\n    });\n\nNote: Any other code inside the block will be executed several times.\nThe shuffling macro expands to a loop with (count + 1) iterations -- the\nfirst pass counts, and the following passes only execute the next chosen\nsuite/test. In particular, avoid running tests directly inside of a\n`SHUFFLE_SUITES` block without a suite, because the test will be run\non each iteration.\n\n\n## Test Name Suffixes\n\n`greatest_set_test_suffix` can be used to set an optional name suffix\nfor the next test:\n\n    for (i = 0; i \u003c row_count; i++) {\n        const struct table_row *row = \u0026table[row_count];\n        greatest_set_test_suffix(row-\u003ename);\n        RUN_TEST1(test_with_arg, row);\n    }\n\nThis will cause the test name to print with a `_` separator and the\nsuffix in all pass/fail/skip messages (i.e., `test_with_arg_KEY`). This\nis especially useful when running a test several times with different\narguments, in shuffled order. The name suffix is included when using\nname-based filtering.\n\nThe test name and optional suffix are copied into an internal buffer.\nIts size can be configured by `#define`ing the constant\n`GREATEST_TESTNAME_BUF_SIZE`. (If not `#define`d, it defaults to 128\nbytes.) If the buffer is not large enough for the name and suffix, it\nwill truncate after `size - 1` bytes, to ensure that it is properly\n`\\0`-terminated.\n\nThe name suffix pointer is cleared after each `RUN_TEST*` call, so a\nsuffix can be constructed in a stack allocated buffer without later\ndereferencing a pointer that has gone out of scope.\n\n\n## Sub-Functions\n\nBecause of how `PASS()`, `ASSERT()`, `FAIL()`, etc. are implemented\n(returning a test result enum value), calls to functions that use them\ndirectly from test functions must be wrapped in `CHECK_CALL`:\n\n    TEST example_using_subfunctions(void) {\n        CHECK_CALL(less_than_three(5));\n        PASS();\n    }\n\nThis is only necessary if the called function can cause test failures.\nThe function should have a return type of `enum greatest_test_res`.\n\n\n## Command Line Options\n\nTest runners build with the following command line options:\n\n    Usage: (test_runner) [-hlfave] [-s SUITE] [-t TEST] [-x EXCLUDE]\n      -h, --help  print this Help\n      -l          List suites and tests, then exit (dry run)\n      -f          Stop runner after first failure\n      -a          Abort on first failure (implies -f)\n      -v          Verbose output\n      -s SUITE    only run suite w/ name containing substring SUITE\n      -t TEST     only run test w/ name containing substring TEST\n      -e          only run exact name match for -s or -t\n      -x EXCLUDE  exclude tests containing string substring EXCLUDE\n\nAny arguments after `--` will be ignored.\n\nIf you want to run multiple test suites in parallel, look at\n[parade](https://github.com/silentbicycle/parade).\n\nThese command line options are processed by `GREATEST_MAIN_BEGIN();`.\n\n\n## Running Tests In Another Program\n\nRather than producing a command line test runner (which checks the\ncommand line options, and exits with a pass/fail return code after\nrunning tests), greatest can be used more like a library. Instead of\nusing `GREATEST_MAIN_BEGIN()`, use `GREATEST_INIT()` to (re-)initialize\ngreatest, then use either `GREATEST_PRINT_REPORT()` to print the report\nto `GREATEST_STDOUT`, or use `greatest_get_report(\u0026report)` to get the\npass, fail, skip, and assertion counters.\n\nThe command line flags above have corresponding functions:\n\n- `greatest_stop_at_first_fail()`\n- `greatest_abort_on_fail()`\n- `greatest_list_only()`\n- `greatest_set_exact_name_match()`\n- `greatest_set_suite_filter(const char *filter)`\n- `greatest_set_test_filter(const char *filter)`\n- `greatest_set_test_exclude(const char *filter)`\n- `greatest_get_verbosity()`\n- `greatest_set_verbosity(unsigned int verbosity)`\n\n\n## Aliases\n\nMost of the macros have prefixed and unprefixed forms. For example,\n`SUITE` is the same as `GREATEST_SUITE`.\n\nCheck the source for the list -- search for `GREATEST_USE_ABBREVS`.\n\nThese aliases can be disabled by `#define`-ing `GREATEST_USE_ABBREVS` to 0.\n\n\n## Color Output\n\nIf you want color output (`PASS` in green, `FAIL` in red, etc.), you can\npipe the output through the included `greenest` script in `contrib/`:\n\n```sh\n$ ./example -v | greenest\n```\n\n(Note that `greenest` depends on a Unix-like environment.)\n\ngreatest itself doesn't have built-in coloring to stay small and portable.\n\n\n## TAP Format\n\nThere is an awk script provided, `contrib/entapment`, that converts the\nverbose output from the default CLI test runner to TAP version 13\nformat:\n\n    ./example -v | contrib/entapment\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frisc-os-community%2Fgreatest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frisc-os-community%2Fgreatest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frisc-os-community%2Fgreatest/lists"}