{"id":42308855,"url":"https://github.com/christianhujer/aceunit","last_synced_at":"2026-01-27T11:13:39.722Z","repository":{"id":12589094,"uuid":"15259861","full_name":"christianhujer/aceunit","owner":"christianhujer","description":"AceUnit (Advanced C and Embedded Unit): A comfortable C code unit test framework. AceUnit is JUnit 5.x style, easy, modular and flexible. AceUnit can be used in resource constrained environments, e.g. embedded software development.","archived":false,"fork":false,"pushed_at":"2025-12-22T19:11:49.000Z","size":901,"stargazers_count":50,"open_issues_count":6,"forks_count":16,"subscribers_count":5,"default_branch":"trunk","last_synced_at":"2025-12-23T03:14:11.990Z","etag":null,"topics":["c","embedded","freestanding-environments","tdd","test","testing","unit-test","unittest"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/christianhujer.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2013-12-17T16:34:46.000Z","updated_at":"2025-12-22T19:11:53.000Z","dependencies_parsed_at":"2024-12-21T10:25:12.469Z","dependency_job_id":"c19b4bef-5a1f-437d-b73d-9381efb2ab34","html_url":"https://github.com/christianhujer/aceunit","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/christianhujer/aceunit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christianhujer%2Faceunit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christianhujer%2Faceunit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christianhujer%2Faceunit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christianhujer%2Faceunit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/christianhujer","download_url":"https://codeload.github.com/christianhujer/aceunit/tar.gz/refs/heads/trunk","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christianhujer%2Faceunit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28812372,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T07:41:26.337Z","status":"ssl_error","status_checked_at":"2026-01-27T07:41:08.776Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["c","embedded","freestanding-environments","tdd","test","testing","unit-test","unittest"],"created_at":"2026-01-27T11:13:38.777Z","updated_at":"2026-01-27T11:13:39.715Z","avatar_url":"https://github.com/christianhujer.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AceUnit 3.0.1-SNAPSHOT\n\nWelcome to AceUnit, the Advanced C and Embedded Unit test framework.\nAceUnit is a comfortable (test discovery!) unit test framework for C, in the best tradition of xUnit frameworks (like JUnit).\nIts target audience are developers using the C programming language to develop firmware, drivers, operating systems, and other C programs, like command line programs.\nIt is tiny and thus suitable even for extremely resource-constraint environments.\n\nAceUnit can also be used to study or teach Test-Driven Development.\nAlthough, you don't really need a framework for that in C, did you know that?\nA framework just helps making your life more comfortable.\n\nThe purpose of AceUnit is to be portable, small, and usable in resource-constraint environments as well as on PCs.\n\nThis is the third version of AceUnit, and a complete rewrite from scratch.\nThe \"template\" for this version of AceUnit is no longer JUnit 4 but JUnit 5.\n\n```C\n#include \"leapyear.h\"\n#include \u003cassert.h\u003e\n\nvoid testLeapYears(void) {\n    assert(isLeapYear(0));\n    assert(isLeapYear(4));\n    assert(isLeapYear(400));\n}\n\nvoid testNonLeapYears(void) {\n    assert(!isLeapYear(1));\n    assert(!isLeapYear(100));\n}\n```\n\n## Attributes and Design Goals\n* JUnit 5.x-style naming.\n* Consumes only very little resources.\n* Works for hosted, freestanding,  and even exotic freestanding environments.\n* Supports C89/C90, C99, C11, C17, and C23.\n* Configurable.\n* Can be run with pure C89/C90 and thus can be used in environments for which C++ is not available or used (i.e. 80x51).\n* Minimal framework noise in the test code.\n  Especially, \u003cem\u003eno macro noise\u003c/em\u003e and \u003cem\u003eno fixture management noise\u003c/em\u003e.\n* Make use of existing C features from the hosted environment and POSIX, but _without requiring_ a hosted environment or POSIX.\n  It will also work just fine on the freestanding environment of an embedded controller.\n\n## Quick Guide\n\nFor each fixture (object file with test cases), AceUnit looks for functions that _start_ with the following names:\n* `beforeAll()` (0‥1) One-time Setup\n* `beforeEach()` (0‥1) Setup per test case\n* `test()` (n) Test cases\n* `afterEach()` (0‥1) Teardown per test case\n* `afterAll()` (0‥1) One-time Teardown\n\nIn addition to that, functions can be prefixed with a user-defined prefix.\nFor example, if you have modules and use a prefix convention, you can use this in your tests, too.\nYou could name functions like `HeapTest_beforeAll()`, `HeapTest_beforeEach()`, and `HeapTest_test1()` by adding `-p HeapTest_` to the command line options of `aceunit`.\n\n## Prerequisites\nAceUnit needs the following things to work:\n* `bash` version 5, `ksh`, or `zsh`.\n  This doesn't affect your work.\n  For your work you can continue to use any shell you like.\n  Just the aceunit script itself needs `bash` version 5, `ksh`, or `zsh` to run.\n  Package maintainers on systems that do not support one-of-n dependencies should choose the one that's more likely to be present, for example, bash 5 on Linux, ksh on Solaris, or zsh on macOS.\n* GNU make 3.81 or newer if you want to build AceUnit yourself using the existing Makefiles.\n  On some systems, like BSD, the binary name for GNU make usually is `gmake`, not `make`.\n* A tool that can extract a symbol table from an object file, like `nm`, `objdump`, or `readelf`.\n  Package maintainers on systems that do not support one-of-n dependencies should choose the tool that's most likely to be present.\n* A C compiler suite.\n\n## Compilers\n\nThis new version of AceUnit has been tested extensively using the following compilers:\n* GCC 11 w/ the following settings on `x86_64`: c90 c99 c11 c17 c2x gnu90 gnu99 gnu11 gnu17 gnu2x\n* GCC 12 as cross-compiler w/ the following target platforms: aarch64-linux-gnu, alpha-linux-gnu, arm-linux-gnueabi, hppa-linux-gnu, mips64-linux-gnuabi64, mips-linux-gnu, powerpc64le-linux-gnu, powerpc64-linux-gnu, powerpc-linux-gnu, riscv64-linux-gnu, s390x-linux-gnu (hppa64-linux-gnu, m68k-linux-gnu, sh4-linux-gnu, sparc64-linux-gnu exist as targets but are currently broken due to bugs in gcc, qemu, or both)\n* clang 14.0.6\n\nThe following compilers are planned to be tested soon:\n* GCC for hppa64, i686, m68k, mips, sh4, sparc64\n* Clang for aarch64, arm, avr, hexagon, mips, mips64, thumb, wasm32, wasm64\n* Keil / ARM ARMCC on ARM7, Cortex-M0, Cortex-M3, SC000, SC100, SC300\n* Keil C51 and C251 for 8051 and 80251\n* Keil C166 for Infineon C16x and STMicroelectronics ST10\n* Samsung ucc on Calm16 and SecuCalm\n* Open64\n\n## Tested Targets\n### Hosted environments\n* `aarch64-linux-gnu`\n* `alpha-linux-gnu`\n* `amd64-unknown-openbsd7.2`\n* `arm-linux-gnueabi`\n* `hppa-linux-gnu`\n* `m68k-amigaos`\n* `mips64-linux-gnuabi64`\n* `mips-linux-gnu`\n* `powerpc64le-linux-gnu`\n* `powerpc64-linux-gnu`\n* `powerpc-linux-gnu`\n* `riscv64-linux-gnu`\n* `s390x-linux-gnu`\n* `x86-dos` (bcc - Bruce's C Compiler, tested using dosbox)\n* `x86_64-unknown-linux-gnu`\n* `x86_64-apple-darwin` (Mac OS X; run ./configure first to switch aceunit to zsh, see `.github/workflows/clang-macos.yml`)\n* `x86_64-unknown-freebsd13.1`\n* `x86_64-unknown-haiku`\n* `x86_64-unknown-netbsd9.0` (NetBSD 9.3)\n\n\u003e [!NOTE]\n\u003e Users on macOS should either change the interpreter in `bin/aceunit` from `bash` to `zsh` or install a newer `bash`, as `/bin/bash` in macOS is extremely old and does not support the needed constructs.\n\u003e The `./configure.sh` script does exactly that, it looks at your OS and available shells, and patches a supported shell into `bin/aceunit`.\n\u003e The shell script in `bin/aceunit` works for `bash`, `ksh`, and `zsh`, but requires Bash 5 when using `bash`.\n\n\u003e [!NOTE]\n\u003e If you use `bcc` for `x86-dos`, run `aceunit` with the flags `-t nm -b nm86 -s _`.\n\n## How to Build\n(In these instructions, replace `make` with your actual GNU `make` command. This is typically `make` on GNU/Linux systems, and `gmake` on other systems.)\nTo build and run AceUnit, you need a GNU `bash` shell, GNU `make`, and a C compiler with `objdump`, `readelf`, or `nm` to extract symbol tables from object files.\nTo build AceUnit, simply run `make`.\nThis builds and tests AceUnit.\n\nAceUnit defaults to `objdump`.\nOn some BSD, like FreeBSD, `objdump` is not installed by default.\nIf you want to stick to the default, install the `binutils` package (which includes `objdump`).\nAlternatively, you can remove the `objdump.ac` module from `share/aceunit`, or use `-t nm` or `-t readelf` when running `aceunit`.\n\n## How to Install\nIf you want to use AceUnit for testing on your POSIX system, simply run `make \u0026\u0026 sudo make install`.\nThis will install AceUnit into `/usr/local/`.\nYou can override the installation location using the `PREFIX` variable, like this: `sudo make install PREFIX=/opt/aceunit/`.\nThe `PREFIX` variable only has an effect during installation, you do not need to rebuild.\n\nThe same way, you can remove a previous installation by running `sudo make uninstall`.\n\n### How to build with a different compiler.\nBy default, AceUnit will be built with/for the C compiler that your `make` tool uses, usually whatever `cc` is found on the `PATH`.\nIf you want to build and test with a different compiler, you can use `make CC=compilername`, for example, `make CC=clang` or `make CC=armcc`.\n\nYou can also easily cross-compile for multiple targets in parallel.\nThe `Makefile` in `aceunit/lib` can be used from other directories.\nSee `test/cross-hosted/` for examples of how that works.\n\n## Runners\nAceUnit provides different runners for different needs.\nOut of the box, AceUnit comes with 4 runners: Simple, SetJmp, Abort, and Fork.\nAceUnit is well-documented, it should be easy to create your own runner if necessary.\n\n### SimpleRunner\nThe SimpleRunner just executes the tests without any special handling.\nIf a test case fails, the runner stops.\n\nThe SimpleRunner is good to get started and for learning and practicing TDD.\n\nFor real-life projects, the SimpleRunner is less suited.\nAs it will stop at the first error, there will be no information about the total number of test cases and errors.\nBut do not fret, there are other runners.\n\n### SetJmpRunner\nThe SetJmpRunner uses `setjmp()` / `longjmp()` to intercept failed assertion.\nThe `assert()` macro is defined to call `AceUnit_fail()` when the condition fails.\nAnd `AceUnit_fail()` performs a `longjmp()` back.\n\nThis runner works in freestanding environments _as long as `setjmp()`/`longjmp()` are available_.\nAccording to the C standard, freestanding environments are not required to provide `\u003csetjmp.h\u003e`.\nHowever, most freestanding environments do so.\n\n### AbortRunner\nThe AbortRunner is like the SetJmpRunner and additionally has a signal handler to catch the `abort()` signal.\nIf a test case fails by raising `SIGABRT`, the runner will catch it.\nIf you use `\u003cassert.h\u003e` provided by the system/compiler, it will usually call `abort()`, and that will usually raise `SIGABRT`.\n\n### ForkRunner\nThe ForkRunner uses `fork()` to execute test cases in child processes.\nA test case is marked failed if the child ended due to a signal, or if it exited with an exit value other than `EXIT_SUCCESS` (0).\n\n### Writing your own Runner\nIf the runners provided out of the box do not suit you, you can simply write your own.\nJust look at the source code of the existing runners to get inspired.\nThey're simple and should be easy to understand.\n\n## Workflow\n1. Build AceUnit. Skip this step if you've installed AceUnit in your system and you're testing for the same system.\n2. Build your object files as usual.\n3. Build your test object files (can be included in the previous step).\n4. Run `aceunit` on the test object files to generate the fixtures source code.\n5. Build your fixtures object file.\n6. Build a test executable linking the object files together with the aceunit library of your choice.\n7. Run the tests.\n\nHere's an example of how such a Workflow could look like on the command-line:\n```bash\n# Build AceUnit\n$ cd aceunit\n$ make\n# Build your object files and test object files\n$ cd ../myproject\n$ cc -I ../aceunit/include/ -c *.c\n# Run aceunit on the test object files to generate the fixtures source code.\n$ ../aceunit/bin/aceunit *_test.o \u003etestcases.c\n# Build your fixtures object file.\n$ cc -I ../aceunit/include/ -c testcases.c\n# Build a test executable linking the object files together with the aceunit library of your choice.\n$ cc *.o ../aceunit/lib/libaceunit-abort.a\n# Run the tests\n$ ./a.out\nAceUnit: 2 test cases, 2 successful, 0 failed.\n```\n\nHere's an example of a `Makefile` that implements such a workflow:\n```Makefile\nACEUNIT_HOME=../aceunit\nACEUNIT_LIBRARY=$(ACEUNIT_HOME)/lib/libaceunit-abort.a\nCPPFLAGS+=-I $(ACEUNIT_HOME)/include\n\n.PHONY: all\nall: test\n\n.PHONY: test\ntest: leapyear_test\n\t./$^\n\nleapyear_test: leapyear_test.o leapyear.o testcases.o $(ACEUNIT_LIBRARY)\n\n$(ACEUNIT_LIBRARY):\n\t$(MAKE) -C $(dir $(ACEUNIT_LIBRARY))\n\ntestcases.c: leapyear_test.o\n\t$(ACEUNIT_HOME)/bin/aceunit $^ \u003e$@\n\n.PHONY: clean\nclean::\n\t$(RM) *.[adios] *.bc leapyear_test testcases.c\n```\n\n## Assertion/Failure Features\nThere are multiple ways how you can make a test-case fail.\nThe following table shows which type of assertion is supported by which type of runner.\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eAssertion\u003c/th\u003e                                       \u003cth\u003eSimpleRunner\u003c/th\u003e\u003cth\u003eSetJmpRunner\u003c/th\u003e\u003cth\u003eAbortRunner\u003c/th\u003e\u003cth\u003eForkRunner\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode\u003e\u0026lt;stdlib.h\u0026gt; longjmp()\u003c/code\u003e\u003c/td\u003e         \u003ctd\u003eno\u003c/td\u003e          \u003ctd\u003eyes\u003c/td\u003e         \u003ctd\u003eyes\u003c/td\u003e        \u003ctd\u003eno\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode\u003e\u0026lt;assert.h\u0026gt; assert()\u003c/code\u003e\u003c/td\u003e          \u003ctd\u003estop\u003c/td\u003e        \u003ctd\u003eno\u003c/td\u003e          \u003ctd\u003eyes\u003c/td\u003e        \u003ctd\u003eyes\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode\u003e\u0026lt;stdlib.h\u0026gt; abort()\u003c/code\u003e\u003c/td\u003e           \u003ctd\u003estop\u003c/td\u003e        \u003ctd\u003eno\u003c/td\u003e          \u003ctd\u003eyes\u003c/td\u003e        \u003ctd\u003eyes\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode\u003e\u0026lt;stdlib.h\u0026gt; exit()\u003c/code\u003e\u003c/td\u003e            \u003ctd\u003estop\u003c/td\u003e        \u003ctd\u003eno\u003c/td\u003e          \u003ctd\u003eno\u003c/td\u003e         \u003ctd\u003eyes\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode\u003e\u0026lt;AceUnit.h\u0026gt; assert()\u003c/code\u003e\u003c/td\u003e         \u003ctd\u003estop\u003c/td\u003e        \u003ctd\u003eyes\u003c/td\u003e         \u003ctd\u003eyes\u003c/td\u003e        \u003ctd\u003eyes\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eabnormal test case termination (like \u003ccode\u003eSIGSEGV\u003c/code\u003e)\u003c/td\u003e\u003ctd\u003eno\u003c/td\u003e          \u003ctd\u003eno\u003c/td\u003e          \u003ctd\u003eno\u003c/td\u003e         \u003ctd\u003eyes\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\nLegend:\n* \"no\" means that this runner doesn't support the specified assertion type.\n  This means that this assertion type will not result in a test case fail.\n  It also means that the test execution will be aborted.\n  For example, using `exit(1)` will simply abort test execution for all runners except for the _ForkRunner_.\n* \"yes\" means that this runner supports the specified assertion type.\n  The assertion will result in a test case fail.\n  And the runner will continue execution with the next test case.\n* \"stop\" means that this runner supports the specified assertion type.\n  The assertion will result in a test case fail.\n  However, the runner will _not_ continue execution with the next test case but instead stop.\n\nThe _ForkRunner_ does not support `longjmp()` as there is no need for this.\nUsing `longjmp()` for assertions in a test case only serves the purpose of implementing a kind of exception handling in the absence of proper exception handling.\nThe _ForkRunner_ uses POSIX `fork()` for exception handling, so using `longjmp()` or catching `SIGABORT` as a workaround to have exception handling in C is not required.\n\n## Test Fixtures\n\n## What is different from previous versions?\nThe whole code has been rewritten from scratch, test-driven and with ease-of-use on mind.\nThe nomenclature has been updated to match that of JUnit5.\nThe generator has been changed from a Java program to a shell script.\nAlso, the generator no longer works on the source file, which is fragile.\nInstead, the generator uses tools like `objdump`, `nm`, or `readelf` to extract the symbol table and thus introspect the code to discover fixtures and test cases.\n\n## Trouble Shooting\n\n### Error about `declare`\nIf you see the following error:\n```\n./aceunit: line 3: declare: -g: invalid option\n```\nIt means that you're running the aceunit shell script with an unsupported shell.\nAceUnit requires Bash 5, ksh, or zsh 5.\nIf you're using macOS, open the `aceunit` shell script and replace `#!/usr/bin/env bash` with `#!/usr/bin/env zsh`.\nYou can either do that replacement yourself, or you can use the `./configure.sh` shell script to do that.\n\n## Glossary\n\n\u003cdl\u003e\n\u003cdt\u003eAfterAll\u003c/dt\u003e\u003cdd\u003eA function that AceUnit shall run once after it runs any of the test cases of a fixture.\u003c/dd\u003e\n\u003cdt\u003eAfterEach\u003cdt\u003e\u003cdd\u003eA function that AceUnit shall run after each of the test cases of a fixture.\u003c/dd\u003e\n\u003cdt\u003eAssertion\u003c/dt\u003e\u003cdd\u003eA piece of code that verifies expectations inside a test function, and if the expectation isn't met, aborts the test case and reports back to the runner.\u003c/dd\u003e\n\u003cdt\u003eBeforeAll\u003c/dt\u003e\u003cdd\u003eA function that AceUnit shall run once before it runs any of the test cases of a fixture.\u003c/dd\u003e\n\u003cdt\u003eBeforeEach\u003cdt\u003e\u003cdd\u003eA function that AceUnit shall run before each of the test cases of a fixture.\u003c/dd\u003e\n\u003cdt\u003eFixture\u003c/dt\u003e\u003cdd\u003eAn object file with test cases.\u003c/dd\u003e\n\u003cdt\u003eRunner\u003c/dt\u003e\u003cdd\u003eThe part of AceUnit that executes test functions by calling them.\u003c/dd\u003e\n\u003cdt\u003eTest Case\u003c/dt\u003e\u003cdd\u003eA function that AceUnit should execute as a test case.\u003c/dd\u003e\n\u003cdt\u003eTest Function\u003cdt\u003e\u003cdd\u003eAny of these: AfterAll, AfterEach, BeforeAll, BeforeEach, Test Case.\u003c/dd\u003e\n\u003c/dl\u003e\n\n## Dropped Features\nThe previous versions of AceUnit had a number of features that have been deliberately dropped to keep things simple:\n\u003cdl\u003e\n\u003cdt\u003eAnnotation-style processing\u003c/dt\u003e\n\u003cdd\u003e\n    Previous versions of AceUnit used annotation-style processing like \u003ccode\u003eA_Test\u003c/code\u003e, \u003ccode\u003eA_BeforeClass\u003c/code\u003e, and so on.\n    This was a bit fragile and required an extra parser.\n    Annotations will come back once C has annotations.\n    They're on the way, give it a few more years.\n    This also made it possible to get rid of \u003cem\u003eJava\u003c/em\u003e for the generator and replace it with a simple shell script.\n\u003c/dd\u003e\n\u003cdt\u003eMultiple fixture methods\u003c/dt\u003e\n\u003cdd\u003e\n    Previous versions of AceUnit allowed for multiple setup and teardown functions per fixture.\n    I don't think this was really used.\n    This has been dropped to save a bit of memory and to make things less complicated.\n\u003c/dd\u003e\n\u003c/dl\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristianhujer%2Faceunit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristianhujer%2Faceunit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristianhujer%2Faceunit/lists"}