{"id":28061830,"url":"https://github.com/rupt/c-explicitly-controlled-testing","last_synced_at":"2025-05-12T10:29:54.730Z","repository":{"id":197739763,"uuid":"699226362","full_name":"Rupt/c-explicitly-controlled-testing","owner":"Rupt","description":"You can test C code without hiding control flow in macros.","archived":false,"fork":false,"pushed_at":"2023-10-08T17:54:56.000Z","size":44,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2023-10-09T17:37:05.619Z","etag":null,"topics":["c","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/Rupt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-10-02T07:47:49.000Z","updated_at":"2023-10-09T17:37:05.619Z","dependencies_parsed_at":null,"dependency_job_id":"9ad6fa69-e655-4bf4-b284-a2a7e8cee70a","html_url":"https://github.com/Rupt/c-explicitly-controlled-testing","commit_stats":null,"previous_names":["rupt/c-explicitly-controlled-testing"],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rupt%2Fc-explicitly-controlled-testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rupt%2Fc-explicitly-controlled-testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rupt%2Fc-explicitly-controlled-testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rupt%2Fc-explicitly-controlled-testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Rupt","download_url":"https://codeload.github.com/Rupt/c-explicitly-controlled-testing/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253719616,"owners_count":21952850,"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","testing"],"created_at":"2025-05-12T10:29:54.011Z","updated_at":"2025-05-12T10:29:54.722Z","avatar_url":"https://github.com/Rupt.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"[//]: # (WARNING: We generate README.md from README.template.md.)\n[//]: # (Do not edit README.md. Make it with `make README.md`)\n\n# TECT: Explicitly Controlled Testing\n\nYou can test C code without hiding control flow in macros.\n\nThis repository is a goofy illustration of that, written in GNU C23.\n\n## Example\n\nMacros `tect_once` and `tect_report` hide checking and reporting logic.\n\n[//]: # (Replace \"SCRIPT_*\" with generated content)\n\n```c\n// example_one.c\n#include \"tect.h\"\n\nint check_for_tea_too() {\n  const int answer = 6 * 9;\n\n  if (!tect_once(answer == 42)) // Triggers at most _once_ by hiding state.\n    return tect_report(\"answer == %d\", answer); // Appends to the output log.\n\n  if (!tect_once(3 == 4)) // We next check this.\n    return tect_report();\n\n  return 0; // =\u003e We are done. Other return values are yours to interpret.\n}\n\nint main() {\n  while (check_for_tea_too())\n    ;\n}\n```\n\nThis outputs:\n\n```text\nexample_one.c:6: check_for_tea_too: !tect_once(answer == 42); answer == 54\nexample_one.c:9: check_for_tea_too: !tect_once(3 == 4); \n```\n\nNote that we run `check_example` twice.\nReturning and retrying gives you freedom to interpret and handle the returned\nvalue however the language allows.\n\nSee `example_two.c` for a more involved example.\n\nThis repeated-run style is _inspired by_ (and not an implementation of)\nAndrei Alexandrescu's\n[\"Unit Test Should Nest\"](https://youtu.be/trGJsOcA4hY?t=2887),\nwhich is inspired by\n[Catch2](https://github.com/catchorg/Catch2).\n\n## Non-Example\n\nCommon C testing tools use such powerful macros that their code does not\nresemble C.\n\nThey instead define new, domain-specific languages, because their macros\nhide both declarations and control flow.\n\nFor example, a pastiche of the C testing tools from\n[Awesome C](https://github.com/oz123/awesome-c#testing)\ncould look like:\n\n```c\nDECLARE_TEST(context, \"some associated text\") {\n    CHECK(6 * 9 == 42);\n    CHECK(3 == 4);\n}\n\n```\n\nBy hiding core language features, such designs make me I feel uncomfortably\nincapable of composing these tools with core language features.\n\nOur `tect_*` macros also hide state and output.\n\nAnd they are arguably disgusting abuses of language extensions.\n\nBut they do give users control of control flow.\n\n## Usage\n\nInstall tools in `Ubuntu 23.04`:\n\n```shell\nsudo apt install clang-format gcc-13 make\n\n```\n\nBuild and run our examples:\n\n```shell\nmake\n\n```\n\nOther make commands:\n\n```shell\nmake check # Run some basic tests on the examples' outputs.\n\nmake fmt # Auto-format our C source files.\n\nmake README.md # Generate `README.md` from the template file.\n\n```\n\nFor development, please run `make -s README.md fmt check` before each commit.\n\n## Documentation\n\nWe generate this section from comments in `tect.h`.\n\n[//]: # (Append in-source documentation below)\n\n### `tect_once` (function-like macro)\n\n`(expression) -\u003e int`\n\nReturn assertion's integral value, and print when it is _first_ false.\n\nYou should follow `tect_once` by calling `tect_report` as follows:\n\n```c\nint check_example() {\n  const int result = square(4);\n\n  if (!tect_once(result == 16))\n    return tect_report(\"result == %d\", result);\n\n  if (!tect_once(square(0) == 0))\n    return tect_report();\n\n  return 0;\n}\n```\n\nTo fully run this test, use a loop such as:\n\n```c\n while (check_example())\n   ;\n```\n\nWe track the first activation in a mutating static variable.\n\nOn a false assertion, our printed message adapts `assert`'s style.\n\n### `tect_report` (function-like macro)\n\n`(const char *format, ...args) -\u003e int, or () -\u003e int`\n\nCall `printf` with any arguments, print `'\\n'`, and return (int) 1.\n\nSee `tect_once` for usage.\n\n[//]: # (Avoid trailing newlines)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frupt%2Fc-explicitly-controlled-testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frupt%2Fc-explicitly-controlled-testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frupt%2Fc-explicitly-controlled-testing/lists"}