{"id":30722695,"url":"https://github.com/coderarjob/yukti","last_synced_at":"2025-09-03T11:10:58.931Z","repository":{"id":305558235,"uuid":"485516002","full_name":"coderarjob/yukti","owner":"coderarjob","description":"Single header Parameterised testing and mocking library C/C++","archived":false,"fork":false,"pushed_at":"2025-08-21T12:02:32.000Z","size":1088,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-21T13:36:23.092Z","etag":null,"topics":["c","gcc","mocking","single-header-library","testing","unittest","unittesting"],"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/coderarjob.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-04-25T19:57:55.000Z","updated_at":"2025-08-21T12:02:35.000Z","dependencies_parsed_at":"2025-08-21T13:20:43.326Z","dependency_job_id":"d106ab91-c10a-4d33-a259-029b9120d673","html_url":"https://github.com/coderarjob/yukti","commit_stats":null,"previous_names":["coderarjob/yukti"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/coderarjob/yukti","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderarjob%2Fyukti","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderarjob%2Fyukti/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderarjob%2Fyukti/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderarjob%2Fyukti/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coderarjob","download_url":"https://codeload.github.com/coderarjob/yukti/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderarjob%2Fyukti/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273431564,"owners_count":25104525,"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","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"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","gcc","mocking","single-header-library","testing","unittest","unittesting"],"created_at":"2025-09-03T11:10:55.758Z","updated_at":"2025-09-03T11:10:58.886Z","avatar_url":"https://github.com/coderarjob.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./docs/images/logo.png\"/\u003e\n\u003c/p\u003e\n\u003cimg src=\"https://github.com/coderarjob/yukti/actions/workflows/build.yaml/badge.svg\"/\u003e\n\n## About\n\nYukti is a single header testing library for C/C++ projects. It has no 3rd party dependencies and is\nfully contained within a single header file.\n\nIt provides most of the features available in other popular testing library but in a small single\nheader library.\n\n* [Screenshots](#screenshots)\n* [Examples](#examples)\n* [Documentation](#documentation)\n    * [Test macros](#test-macros)\n    * [Assertion macros](#assertion-macros)\n    * [Interaction/behaviour validation macros](#interaction-or-behaviour-validation-macros)\n    * [Mock or Fake function creation macros](#mock-or-fake-function-declaration)\n* [Breaking changes - Upgrade guide](#upgrade-guide)\n* [Testing yukti.h](#running-tests)\n* [Versioning](#versioning)\n* [Feedback](#feedback)\n\n## Goals\n\n- [X] **State testing**\n    - [X] State/scalar value assertion macros\n    - [X] Continuous data like array, string assertion macros\n    - [X] YT_EQ_DOUBLE macro for approx matching of values\n- [X] **Parameterised testing macros**\n- [X] **Faking/Mocking external functions**\n    - [X] Macros to fake external functions\n    - [X] Behaviour modification of faked functions using custom Handler functions\n- [X] **Interaction testing**\n    - [X] Assert if an external function was called with expected arguments\n    - [X] Assert if an external function was called with optional arguments\n    - [X] Assert if an external function was never called\n    - [ ] Assert if an external function was called with floating point or structures passed by-value in parameters.\n- [X] **Reporting**\n    - [X] Report line numbers and source file of failed expectations\n    - [X] Report list of all the tests which failed\n    - [X] Tests executables exit with non-zero code if any of its tests fails\n    - [X] Time taken to run each test\n\n## Screenshots\n\n| Case: Some test are failing. Shows source file location and summary lists the failing tests | Case: All test are passing. Shows elapsed time for each test.            |\n|---------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|\n| [![Failure](./docs/images/failure_thumb.png)](./docs/images/failure.png)                    | [![Passing](./docs/images/passing_thumb.png)](./docs/images/passing.png) |\n\n## Examples\n\nDifferent examples are placed in the [example](./example) folder.\n\n## Documentation\n\n### Test macros\n\n`YT_TEST` \u0026 `YT_TESTP` macros are used to create a non-parameterised test and a parameterised\ntest respectively. Tests functions are identified by their name, that is the 2nd argument in these\nmacros. These tests functions need to be called in the `main()` function explicitly. Arguments for\nparameterised tests are given when calling them in the `main()`, non-parameterised tests do not take\nany argument.\n\nEach test function must end with `YT_END()` macro. If omitted will result in compilation errors.\n\n| Macro name                     | Purpose                                                                                                                 |\n|--------------------------------|-------------------------------------------------------------------------------------------------------------------------|\n| `YT_TEST(g, tn)`               | Creates a new non-parameterised test `tn` under group `g`. Group name is not yet used for any purpose.                  |\n| `YT_TESTP(g, tn, t1, t2, ...)` | Creates a new parameterised test `tn` under group `g`. `t1`, `t2` etc are types of parameters to be passed to the test. |\n| `YT_END()`                     | Ends a test function. It must exist at the very end of each test function.                                              |\n| `YT_INIT()`                    | Initializes yukti test internals. Must be called from `main` before test functions are run.                             |\n| `YT_RETURN_WITH_REPORT()`      | Returns from `main` after printing a summary.                                                                           |\n\nSee [Parameterised test](./example/add_parameterised_test.c) example\n\n### Assertion macros\n\nAssertions macros check state expectations from an SUT (System Under Test). These are several of\nthese macros.\n\n| Macro name                   | Validates                                                 |\n|------------------------------|-----------------------------------------------------------|\n| `YT_EQ_SCALAR(a, b)`         | a == b                                                    |\n| `YT_NEQ_SCALAR(a, b)`        | a != b                                                    |\n| `YT_GEQ_SCALAR(a, b)`        | a \u003e= b                                                    |\n| `YT_LEQ_SCALAR(a, b)`        | a \u003c= b                                                    |\n| `YT_GRT_SCALAR(a, b)`        | a \u003e b                                                     |\n| `YT_LES_SCALAR(a, b)`        | a \u003c b                                                     |\n| `YT_EQ_MEM(a, b, sz)`        | First `sz` bytes in buffers `a` \u0026 `b` are equal           |\n| `YT_NEQ_MEM(a, b, sz)`       | First `sz` bytes in buffers `a` \u0026 `b` are not equal       |\n| `YT_EQ_STRING(a, b)`         | String `a` and `b` are equal                              |\n| `YT_NEQ_STRING(a, b)`        | String `a` and `b` are not equal                          |\n| `YT_EQ_DOUBLE_ABS(a, b, e)`  | Approx match a == b. Passes if `mod(a - b) \u003c= e`          |\n| `YT_NEQ_DOUBLE_ABS(a, b, e)` | Approx match a != b. Passes if `mod(a - b) \u003e e`           |\n| `YT_EQ_DOUBLE_REL(a, b, e)`  | Approx match a == b. Passes if `mod(a - b) \u003c= max(a,b)*e` |\n| `YT_NEQ_DOUBLE_REL(a, b, e)` | Approx match a != b. Passes if `mod(a - b) \u003e max(a,b)*e`  |\n\n`YT_EQ_DOUBLE_REL(a, b, e)` passes if `abs(a - b)` is `\u003c=` than `e`% of the larger floating point\nnumber. For example, `YT_EQ_DOUBLE_REL(1.1234, 1.12, 0.01)` passes because their difference of\n0.0034 is \u003c 1% of 1.1234.\n\nSee [Basic tests](./example/basic_tests.c) example\n\n### Interaction or behaviour validation macros\n\nMore complex files work in conjunction with mocked functions. They help in validating interaction\nbetween SUT and external functions. They help in determining if these external functions were called\nin what order and which what parameters.\n\n| Macro name                                        | Validates                                                                                 |\n|---------------------------------------------------|-------------------------------------------------------------------------------------------|\n| `YT_MUST_CALL_IN_ORDER(f, ...)`                   | Function `f` is called with the given arguments at least once in an particular order      |\n| `YT_MUST_CALL_IN_ORDER_ATLEAST_TIMES(n, f, ...)`  | Function `f` is called with the given arguments at least `n` times in an particular order |\n| `YT_MUST_CALL_ANY_ORDER(f, ...)`                  | Function `f` is called with the given arguments at least once in no particular order      |\n| `YT_MUST_CALL_ANY_ORDER_ATLEAST_TIMES(n, f, ...)` | Function `f` is called with the given arguments at least `n` times in no particular order |\n| `YT_MUST_NEVER_CALL(f, ...)`                      | Function `f` with the given arguments is never called                                     |\n| `YT_IN_SEQUENCE(n)`                               | Repeats expectations `n` number of times. Used to put expectations for a loop.            |\n\nSee these examples\n* [printer_fail](./example/sensor_test.c) example\n* [printer_success](./example/sensor_test.c) example\n\n### Mock or Fake function declaration\n\nWhen unittesting it might be required to provide a fake definitions of external functions. This is\nwhere these macros come in. These fake functions also enable the above mentioned interaction\nvalidations and one can modify the behaviour of these fake functions in various ways.\n\n| Macro name                             | Validates                                                                                                                                    |\n|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|\n| `YT_DECLARE_FUNC(rt, f, ...)`          | Declaration for fake function `f` which takes any number of arguments returns some non void type `rt`                                        |\n| `YT_DECLARE_FUNC_VOID(f, ...)`         | Declaration for fake function `f` which takes any number of arguments returns void                                                           |\n| `YT_DEFINE_FUNC(rt, f, ...)`           | Definition for fake function `f` previously declared using `YT_DECLARE_FUNC`.                                                                |\n| `YT_DEFINE_FUNC_VOID(f, ...)`          | Definition for fake function `f` previously declared using `YT_DECLARE_FUNC_VOID`.                                                           |\n| `YT_DEFINE_FUNC_FALLBACK(rt, f, ...)`  | Definition for fake function `f` previously declared using `YT_DECLARE_FUNC`. `MUST_CALL*`/`NEVER_CALL*` macros cannot be used on them.      |\n| `YT_DEFINE_FUNC_VOID_FALLBACK(f, ...)` | Definition for fake function `f` previously declared using `YT_DECLARE_FUNC_VOID`. `MUST_CALL*`/`NEVER_CALL*` macros cannot be used on them. |\n| `YT_RESET_MOCK(f)`                     | Resets internal state of a mock/fake function previously defined using `YT_DEFINE_FUNC*`.                                                    |\n\n`YT_DEFINE_FUNC_FALLBACK` and `YT_DEFINE_FUNC_VOID_FALLBACK` should be used to define functions with\none or more non integer arguments (floating point or `structs` passed by-value etc) as such\narguments do not work with `MUST_CALL*`/`NEVER_CALL*` macros at this time. Expectations set on them\nusing `MUST_CALL*` can never be met and those with `NEVER_CALL*` will always pass - thus giving\nwrong impression of what's actually happening. But if used correctly, there will be no way to form\nan expectation because `YT_V` construct will fail.\n\nSee [Mocking and faking](./example/sensor_test.c) example\n\n## Upgrade guide\n\n* Old `YT_EQ_DOUBLE` was equivalent to `YT_EQ_DOUBLE_ABS`, so the former can be replaced with the\n  later.\n* When comparing large floating point numbers, the newer `YT_EQ_DOUBLE_REL` works better.\n\n## Running tests\n\nIn order to test yukti.h run `tests/run_all_tests.sht`. This runs integration tests \u0026 examples.\n\n## Versioning\n\nIt uses semantic versioning. See [https://semver.org/](https://semver.org).\n\n## Feedback\n\nOpen a GitHub issue or drop a email at arjobmukherjee@gmail.com. I would love to hear your\nsuggestions and feedbacks.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderarjob%2Fyukti","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoderarjob%2Fyukti","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderarjob%2Fyukti/lists"}