├── .github └── workflows │ └── ci-build.yml ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── examples ├── CMakeLists.txt ├── c-example.c └── cpp-example.cc └── include └── acutest.h /.github/workflows/ci-build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | - pull_request 5 | - push 6 | 7 | jobs: 8 | linux: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Configure 13 | run: cmake -DCMAKE_BUILD_TYPE=Release -G 'Unix Makefiles' . 14 | - name: Build 15 | run: make VERBOSE=1 16 | 17 | windows-32: 18 | runs-on: windows-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: microsoft/setup-msbuild@v1.3.1 22 | - name: Configure 23 | run: cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A Win32 . 24 | - name: Build 25 | run: msbuild.exe acutest.sln /p:Configuration=Release /p:Platform=Win32 26 | 27 | windows-64: 28 | runs-on: windows-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: microsoft/setup-msbuild@v1.3.1 32 | - name: Configure 33 | run: cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 . 34 | - name: Build 35 | run: msbuild.exe acutest.sln /p:Configuration=Release /p:Platform=x64 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.5) 3 | project(Acutest C CXX) 4 | 5 | 6 | set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo MinSizeRel) 7 | if("${CMAKE_BUILD_TYPE}" STREQUAL "") 8 | set(CMAKE_BUILD_TYPE $ENV{CMAKE_BUILD_TYPE}) 9 | 10 | if("${CMAKE_BUILD_TYPE}" STREQUAL "") 11 | set(CMAKE_BUILD_TYPE "Release") 12 | endif() 13 | endif() 14 | 15 | 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 17 | 18 | 19 | if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") 20 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") 21 | elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") 22 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") 23 | elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") 24 | # Specify proper C runtime library: 25 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") 26 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") 27 | set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} /MT") 28 | set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_RELEASE} /MT") 29 | endif() 30 | 31 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 32 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 33 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 35 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 36 | # Specify proper C runtime library: 37 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") 38 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 39 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /MT") 40 | set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_RELEASE} /MT") 41 | endif() 42 | 43 | 44 | add_subdirectory(examples) 45 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | # The MIT License (MIT) 3 | 4 | Copyright © 2013-2019 Martin Mitáš 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the “Software”), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Acutest Readme 3 | 4 | Home: https://github.com/mity/acutest 5 | 6 | 7 | ## What Is Acutest 8 | 9 | Acutest is C/C++ unit testing facility aiming to be as simple as possible, not 10 | to stand in the developer's way and to minimize any external dependencies. 11 | 12 | To achieve that, the complete implementation resides in a single C header file, 13 | and its core depends only on few standard C library functions. 14 | 15 | 16 | ## Overview 17 | 18 | **Main features:** 19 | * Unit tests in C or C++ are supported. 20 | * No need to install/setup/configure any testing framework. Acutest is just 21 | a single header file, `acutest.h`. 22 | * The header provides the program entry point (function `main()`). 23 | * Minimal dependencies: Core features only depend on few standard C headers, 24 | optional features may use more if available on the particular system. 25 | * Trivial interface for writing unit tests: Few preprocessor macros described 26 | further below. 27 | * Rudimentary support for [Test Anything Protocol](https://testanything.org/) 28 | (use `--tap` option). 29 | * Rudimentary support for xUnit-compatible XML output (use `--xml-output=FILE`). 30 | 31 | **C++ specific features:** 32 | * Acutest catches any C++ exception thrown from any unit test function. When 33 | that happens, the given test is considered to fail. 34 | * If the exception is derived from `std::exception`, `what()` is written out 35 | in the error message. 36 | 37 | **Unix/Posix specific features:** 38 | * By default, every unit test is executed as a child process. 39 | * By default, if the output is directed to a terminal, the output is colorized. 40 | * If the system offers Posix timer (`clock_gettime()`), user can measure test 41 | execution times with `--time=real` (same as `--time`) and `--time=cpu`. 42 | 43 | **Linux specific features:** 44 | * If a debugger is detected, the default execution of tests as child processes 45 | is suppressed in order to make the debugging easier. 46 | 47 | **Windows specific features:** 48 | * By default, every unit test is executed as a child process. 49 | * If a debugger is detected, the default execution of tests as child processes 50 | is suppressed in order to make the debugging easier. 51 | * By default, if the output is directed to a terminal, the output is colorized. 52 | * Acutest installs a SEH filter to print out uncaught SEH exceptions. 53 | * User can measure test execution times with `--time`. 54 | 55 | **macOS specific features:** 56 | * If a debugger is detected, the default execution of tests as child processes 57 | is suppressed in order to make the debugging easier. 58 | 59 | Any C/C++ module implementing one or more unit tests and including `acutest.h`, 60 | can be built as a standalone program. We call the resulted binary as a "test 61 | suite" for purposes of this document. The suite is then executed to run the 62 | tests, as specified with its command line options. 63 | 64 | We say any unit test succeeds if and only if: 65 | 1. all condition checks (as described below) called throughout its execution 66 | pass; 67 | 2. the test does not throw any exception (C++ only); and 68 | 3. (on Windows or Unix) the unit test subprocess is not interrupted/terminated 69 | (e.g. by a signal on Unix or SEH on Windows). 70 | 71 | 72 | ## Writing Unit Tests 73 | 74 | ### Basic Use 75 | 76 | To use Acutest, simply include the header file `acutest.h` on the beginning of 77 | the C/C++ source file implementing one or more unit tests. Note the header 78 | provides implementation of the `main()` function. 79 | 80 | ```C 81 | #include "acutest.h" 82 | ``` 83 | 84 | Every test is supposed to be implemented as a function with the following 85 | prototype: 86 | 87 | ```C 88 | void test_example(void); 89 | ``` 90 | 91 | The tests can use some preprocessor macros to validate the test conditions. 92 | They can be used multiple times, and if any of those conditions fails, the 93 | particular test is considered to fail. 94 | 95 | `TEST_CHECK` is the most commonly used testing macro which simply tests a 96 | boolean condition and fails if the condition evaluates to false (or zero). 97 | 98 | For example: 99 | 100 | ```C 101 | void test_example(void) 102 | { 103 | void* mem; 104 | int a, b; 105 | 106 | mem = malloc(10); 107 | TEST_CHECK(mem != NULL); 108 | 109 | mem = realloc(mem, 20); 110 | TEST_CHECK(mem != NULL); 111 | } 112 | ``` 113 | 114 | Note that the tests should be completely independent on each other. Whenever 115 | the test suite is invoked, the user may run any number of tests in the suite, 116 | in any order. Furthermore by default, on platforms where supported, each unit 117 | test is executed as a standalone (sub)process. 118 | 119 | Finally, the test suite source file has to list the unit tests, using the 120 | macro `TEST_LIST`. The list specifies name of each test (it has to be unique) 121 | and pointer to a function implementing the test. I recommend names which are 122 | easy to use on command line: especially avoid space and other special 123 | characters which might require escaping in shell; also avoid dash (`-`) as a 124 | first character of the name, as it could then be interpreted as a command line 125 | option and not as a test name. 126 | 127 | ```C 128 | TEST_LIST = { 129 | { "example", test_example }, 130 | ... 131 | { NULL, NULL } /* zeroed record marking the end of the list */ 132 | }; 133 | ``` 134 | 135 | Note the test list has to be ended with zeroed record. 136 | 137 | For a basic test suites this is more or less all you need to know. However 138 | Acutest provides some more macros which can be useful in some specific 139 | situations. We cover them in the following sub-sections. 140 | 141 | ### Aborting on a Check Failure 142 | 143 | There is a macro `TEST_ASSERT` which is very similar to `TEST_CHECK` but, if it 144 | fails, it aborts execution of the current unit test instantly. 145 | 146 | For example: 147 | 148 | ```C 149 | void test_example(void) 150 | { 151 | void* mem; 152 | int a, b; 153 | 154 | mem = malloc(10); 155 | TEST_ASSERT(mem != NULL); 156 | 157 | mem = realloc(mem, 20); 158 | TEST_ASSERT(mem != NULL); 159 | } 160 | ``` 161 | 162 | The abortion in the case of failure is performed either by calling `abort()` 163 | (if the test is executed as a child process) or via `longjmp()` (if it is not). 164 | 165 | Therefore it should be used only if you understand the costs connected with 166 | such a brutal abortion of the test. Depending on what your unit test does, 167 | it may include unflushed file descriptors, memory leaks, C++ objects destructed 168 | without their destructors being called and more. 169 | 170 | In general, `TEST_CHECK` should be preferred over `TEST_ASSERT`, unless you 171 | know exactly what you do and why you chose `TEST_ASSERT` in some particular 172 | situation. 173 | 174 | ### Testing C++ Exceptions 175 | 176 | For C++, there is an additional macro `TEST_EXCEPTION` for verifying the given 177 | code (typically just a function or a method call) throws the expected type of 178 | exception. 179 | 180 | The check fails if the function does not throw any exception or if it throws 181 | anything incompatible. 182 | 183 | For example: 184 | 185 | ```C++ 186 | void test_example(void) 187 | { 188 | TEST_EXCEPTION(CallSomeFunction(), std::exception); 189 | } 190 | ``` 191 | 192 | ### Richer Failure Diagnosis 193 | 194 | If a condition check fails, it is often useful to provide some additional 195 | information about the situation so the problem is easier to debug. Acutest 196 | provides the macros `TEST_MSG` and `TEST_DUMP` for this purpose. 197 | 198 | The former one outputs any `printf`-like message, the other one outputs a 199 | hexadecimal dump of a provided memory block. 200 | 201 | So for example: 202 | 203 | ```C 204 | void test_example(void) 205 | { 206 | char produced[100]; 207 | char expected[] = "Hello World!"; 208 | 209 | SomeSprintfLikeFunction(produced, "Hello %s!", "world"); 210 | TEST_CHECK(strcmp(produced, expected) == 0); 211 | TEST_MSG("Expected: %s", expected); 212 | TEST_MSG("Produced: %s", produced); 213 | 214 | /* Or, if the function could provide some binary stuff, we might rather 215 | * use TEST_DUMP instead in order to output a hexadecimal dump of the data. 216 | */ 217 | TEST_DUMP("Expected:", expected, strlen(expected)); 218 | TEST_DUMP("Produced:", produced, strlen(produced)); 219 | } 220 | ``` 221 | 222 | Note that both macros output anything only when the most recently checking 223 | macro has failed. In other words, these two are equivalent: 224 | 225 | ```C 226 | if(!TEST_CHECK(some_condition != 0)) 227 | TEST_MSG("some message"); 228 | ``` 229 | 230 | ```C 231 | TEST_CHECK(some_condition != 0); 232 | TEST_MSG("some message"); 233 | ``` 234 | 235 | (Note that `TEST_MSG` requires the compiler with variadic macros support.) 236 | 237 | ### Loops over Test Vectors 238 | 239 | Sometimes, it is useful to design your testing function as a loop over data 240 | providing a collection of test vectors and their respective expected outputs. 241 | For example imagine our unit test is supposed to verify some kind of a hashing 242 | function implementation and we've got a collection of test vectors for it in 243 | the hash specification. 244 | 245 | In such cases, it is very useful to get some name associated with every test 246 | vector and output the name in the output log so that if any check fails, it is 247 | easy to identify the guilty test vector. However, the loop body may execute 248 | dozens of checking macros and so it may be impractical to add such name to 249 | customize every check message in the loop. 250 | 251 | To solve this, Acutest provides the macro `TEST_CASE`. The macro specifies 252 | a string serving as the test vector name. When used, Acutest makes sure that 253 | in the output log the provided name precedes any message from subsequent 254 | condition checks. 255 | 256 | For example, lets assume we are testing `SomeFunction()` which is supposed, 257 | for a given byte array of some size, return another array of bytes in a newly 258 | `malloc`-ed buffer. Then we can do something like this: 259 | 260 | ```C 261 | struct TestVector { 262 | const char* name; 263 | const uint8_t* input; 264 | size_t input_size; 265 | const uint8_t* expected_output; 266 | size_t expected_output_size; 267 | }; 268 | 269 | struct TestVector test_vectors[] = { 270 | /* some data */ 271 | }; 272 | 273 | void test_example(void) 274 | { 275 | int i; 276 | const uint8_t* output; 277 | size_t output_size; 278 | 279 | for(i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) { 280 | struct TestVector* vec = &test_vectors[i]; 281 | 282 | /* Output the name of the tested test vector. */ 283 | TEST_CASE(vec.name); 284 | 285 | /* Now, we can check the function produces what it should for the 286 | * current test vector. If any of the following checking macros 287 | * produces any output (either because the check fails, or because 288 | * high `--verbose` level is used), Acutest also outputs the currently 289 | * tested vector's name. */ 290 | output = SomeFunction(vec->input, vec->input_size, &output_size); 291 | if(TEST_CHECK(output != NULL)) { 292 | TEST_CHECK(output_size == vec->expected_output_size); 293 | TEST_CHECK(memcmp(output, vec->expected_output, output_size) == 0); 294 | free(output); 295 | } 296 | } 297 | } 298 | ``` 299 | 300 | The specified name applies to all checks executed after the use of `TEST_CASE` 301 | * until the unit test ends; or 302 | * until `TEST_CASE` is used again to specify another name; or 303 | * until the name is explicitly reset by using `TEST_CASE` with the `NULL` 304 | as its argument. 305 | 306 | ### Custom Log Messages 307 | 308 | Many of the macros mentioned in the earlier sections have a counterpart which 309 | allows to output a custom messages instead of some default ones. 310 | 311 | All of these have the same name as the aforementioned macros, just with the 312 | underscore suffix added. With the suffix, they then expect `printf`-like string 313 | format and corresponding additional arguments. 314 | 315 | So, for example, instead of the simple checking macros 316 | ```C++ 317 | TEST_CHECK(a == b); 318 | TEST_ASSERT(x < y); 319 | TEST_EXCEPTION(SomeFunction(), std::exception); 320 | ``` 321 | we can use their respective counterparts with a custom messages: 322 | ```C++ 323 | TEST_CHECK_(a == b, "%d is equal to %d", a, b); 324 | TEST_ASSERT_(x < y, "%d is lower than %d", x, y); 325 | TEST_EXCEPTION_(SomeFunction(), std::exception, "SomeFunction() throws std::exception"); 326 | ``` 327 | 328 | You should use some neutral wording for them because, with the command line 329 | option `--verbose`, the messages are logged out even if the respective check 330 | passes successfully. 331 | 332 | (If you need to output some diagnostic information just in the case the check 333 | fails, use the macro `TEST_MSG`. That's exactly its purpose.) 334 | 335 | Similarly, instead of 336 | ```C 337 | TEST_CASE("name"); 338 | ``` 339 | we can use richer 340 | ```C 341 | TEST_CASE_("iteration #%d", 42); 342 | ``` 343 | 344 | However note all of these can only be used if your compiler supports variadic 345 | preprocessor macros. Variadic macros became a standard part of the C language 346 | with C99. 347 | 348 | 349 | ## Building the Test Suite 350 | 351 | When we are done with implementing the tests, we can simply compile it as 352 | a simple C/C++ program. For example, assuming `cc` is your C compiler: 353 | 354 | ```sh 355 | $ cc test_example.c -o test_example 356 | ``` 357 | 358 | 359 | ## Running Unit Tests 360 | 361 | When the test suite is compiled, the resulted testing binary can be used to run 362 | the tests. 363 | 364 | Exit code of the test suite is 0 if all the executed unit tests pass, 1 if any 365 | of them fails, or any other number if an internal error occurs. 366 | 367 | By default (without any command line options), it runs all implemented unit 368 | tests. It can also run only subset of the unit tests as specified on the 369 | command line: 370 | 371 | ```sh 372 | $ ./test_example # Runs all tests in the suite 373 | $ ./test_example test1 test2 # Runs only tests specified 374 | $ ./test_example --exclude test3 # Runs all tests but those specified 375 | ``` 376 | 377 | Note that a single command line argument can select a whole group of test units 378 | because Acutest implements several levels of unit test selection (the 1st one 379 | matching at least one test unit is used): 380 | 381 | 1. *Exact match*: When the argument matches exactly the whole name of a unit 382 | test then just the given test is selected. 383 | 384 | 2. *Word match*: When the argument does not match any complete test name, but 385 | it does match whole word in one or more test names, then all such tests are 386 | selected. 387 | 388 | The following characters are recognized as word delimiters: space ` `, 389 | tabulator `\t`, dash `-`, underscore `_`, slash `/`, dot `.`, comma `,`, 390 | colon `:`, semicolon `;`. 391 | 392 | 3. *Substring match*: If even the word match failed to select any test, then 393 | all tests with a name which contains the argument as its substring are 394 | selected. 395 | 396 | By adopting an appropriate test naming strategy, this allows user to run (or 397 | to skip if `--exclude` is used) easily whole family of related tests with a 398 | single command line argument. 399 | 400 | For example consider test suite `test_example` which implements tests `foo-1`, 401 | `foo-2`, `foomatic`, `bar-1` and `bar-10`: 402 | 403 | ```sh 404 | $ ./test_example bar-1 # Runs only the test 'bar-1' (exact match) 405 | $ ./test_example foo # Runs 'foo-1' and 'foo-2' (word match) 406 | $ ./test_example oo # Runs 'foo-1', 'foo-2' and 'foomatic' (substring match) 407 | $ ./test_example 1 # Runs 'foo-1' and 'bar-1' (word match) 408 | ``` 409 | 410 | You may use `--list` or `-l` to just list all unit tests implemented by the 411 | given test suite: 412 | 413 | ```sh 414 | $ ./test_example --list 415 | ``` 416 | 417 | To see description for all the supported command line options, run the binary 418 | with the option `--help`: 419 | 420 | ```sh 421 | $ ./test_example --help 422 | ``` 423 | 424 | 425 | ## FAQ 426 | 427 | **Q: Wasn't this project known as "CUTest"?** 428 | 429 | **A:** Yes. It has been renamed as the original name was found to be 430 | [too much overloaded](https://github.com/mity/cutest/issues/6). 431 | 432 | 433 | **Q: Do I need to distribute file `README.md` and/or `LICENSE.md`?** 434 | 435 | **A:** No. The header `acutest.h` includes URL to our repo, copyright note and 436 | the MIT license terms inside of it. As long as you leave those intact, we are 437 | completely fine if you only add the header into your project. After all, 438 | the simple use and all-in-one-header nature of it is our primary aim. 439 | 440 | 441 | ## License 442 | 443 | Acutest is covered with MIT license, see the file `LICENSE.md` or beginning of 444 | `acutest.h` for its full text. 445 | 446 | 447 | ## More Information 448 | 449 | The project resides on github: 450 | 451 | * https://github.com/mity/acutest 452 | 453 | You can find the latest version of Acutest there, contribute with enhancements 454 | or report bugs. 455 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | include_directories("${PROJECT_SOURCE_DIR}/include") 3 | 4 | add_executable(c-example c-example.c ../include/acutest.h) 5 | add_executable(cpp-example cpp-example.cc ../include/acutest.h) 6 | -------------------------------------------------------------------------------- /examples/c-example.c: -------------------------------------------------------------------------------- 1 | 2 | #include "acutest.h" 3 | 4 | void 5 | test_tutorial(void) 6 | { 7 | void* mem; 8 | 9 | mem = malloc(10); 10 | TEST_CHECK(mem != NULL); 11 | 12 | mem = realloc(mem, 20); 13 | TEST_CHECK(mem != NULL); 14 | 15 | free(mem); 16 | } 17 | 18 | void 19 | test_fail(void) 20 | { 21 | int a, b; 22 | 23 | /* This condition is designed to fail so you can see what the failed test 24 | * output looks like. */ 25 | a = 1; 26 | b = 2; 27 | TEST_CHECK(a + b == 5); 28 | 29 | /* Here is TEST_CHECK_ in action. */ 30 | TEST_CHECK_(a + b == 5, "%d + %d == 5", a, b); 31 | 32 | /* We may also show more information about the failure. */ 33 | if(!TEST_CHECK(a + b == 5)) { 34 | TEST_MSG("a: %d", a); 35 | TEST_MSG("b: %d", b); 36 | } 37 | 38 | /* The macro TEST_MSG() only outputs something when the preceding 39 | * condition fails, so we can avoid the 'if' statement. */ 40 | TEST_CHECK(a + b == 3); 41 | TEST_MSG("a: %d", a); 42 | TEST_MSG("b: %d", b); 43 | } 44 | 45 | void 46 | test_skip(void) 47 | { 48 | TEST_SKIP("Decided to skip."); 49 | TEST_CHECK(1 == 0); /* ignored check. */ 50 | } 51 | 52 | void 53 | test_bad_skip(void) 54 | { 55 | TEST_CHECK(1 == 1); 56 | TEST_SKIP("Decided to skip."); /* Cannot skip after any TEST_CHECK */ 57 | } 58 | 59 | static void 60 | helper(void) 61 | { 62 | /* Kill the current test with a condition which is never true. */ 63 | TEST_ASSERT(1 == 2); 64 | 65 | /* This never happens because the test is aborted above. */ 66 | TEST_CHECK(1 + 2 == 2 + 1); 67 | } 68 | 69 | void 70 | test_abort(void) 71 | { 72 | helper(); 73 | 74 | /* This test never happens because the test is aborted inside the helper() 75 | * function. */ 76 | TEST_CHECK(1 * 2 == 2 * 1); 77 | } 78 | 79 | void 80 | test_crash(void) 81 | { 82 | int* invalid = ((int*)NULL) + 0xdeadbeef; 83 | 84 | *invalid = 42; 85 | TEST_CHECK_(1 == 1, "This should never execute, due to a write into " 86 | "an invalid address."); 87 | } 88 | 89 | TEST_LIST = { 90 | { "tutorial", test_tutorial }, 91 | { "fail", test_fail }, 92 | { "skip", test_skip }, 93 | { "bad-skip", test_bad_skip }, 94 | { "abort", test_abort }, 95 | { "crash", test_crash }, 96 | { NULL, NULL } 97 | }; 98 | -------------------------------------------------------------------------------- /examples/cpp-example.cc: -------------------------------------------------------------------------------- 1 | #include "acutest.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | class TestException : public std::exception 9 | { 10 | std::string msg_; 11 | 12 | public: 13 | virtual const char* what() const throw() 14 | { return msg_.c_str(); } 15 | 16 | explicit TestException(const std::string& msg) throw() 17 | : msg_(msg) 18 | {} 19 | 20 | virtual ~TestException() throw() 21 | {} 22 | }; 23 | 24 | 25 | enum What { 26 | NO_THROW = 0, 27 | THROW_TEST_EXC, 28 | THROW_INVALID_ARG, 29 | THROW_CHAR_PTR, 30 | THROW_INT 31 | }; 32 | 33 | /* This dummy function represents some code which we want to test. 34 | * As this is written in C++, they can throw exceptions. 35 | */ 36 | static void 37 | some_function(What what, const char* msg = NULL) 38 | { 39 | switch(what) { 40 | case NO_THROW: 41 | /* noop */ 42 | break; 43 | 44 | case THROW_TEST_EXC: 45 | throw TestException(msg != NULL ? msg : "TestException"); 46 | break; 47 | 48 | case THROW_INVALID_ARG: 49 | throw std::invalid_argument(msg != NULL ? msg : "std::invalid_argument"); 50 | break; 51 | 52 | case THROW_CHAR_PTR: 53 | throw msg; 54 | break; 55 | 56 | case THROW_INT: 57 | throw 42; 58 | break; 59 | } 60 | } 61 | 62 | 63 | void test_exception_type(void) 64 | { 65 | /* In C++, we may want to test whether some code throws an expected 66 | * exception type. */ 67 | TEST_EXCEPTION(some_function(THROW_TEST_EXC), TestException); 68 | TEST_EXCEPTION(some_function(THROW_INVALID_ARG), std::invalid_argument); 69 | 70 | /* Naturally, testing for a type the actual exception is derived from, 71 | * is ok too. */ 72 | TEST_EXCEPTION(some_function(THROW_TEST_EXC), std::exception); 73 | TEST_EXCEPTION(some_function(THROW_INVALID_ARG), std::exception); 74 | 75 | /* Fundemental types used as exceptions work too. */ 76 | TEST_EXCEPTION(some_function(THROW_CHAR_PTR), const char*); 77 | TEST_EXCEPTION(some_function(THROW_INT), int); 78 | 79 | /* These checks fail because the given code does not throw an exception 80 | * at all, or throws a different type of exception. */ 81 | TEST_EXCEPTION(some_function(NO_THROW), std::exception); 82 | TEST_EXCEPTION(some_function(THROW_INT), std::exception); 83 | TEST_EXCEPTION(some_function(THROW_INVALID_ARG), TestException); 84 | 85 | /* With TEST_CATCH_EXC_, we may use a custom message. */ 86 | TEST_EXCEPTION_(some_function(THROW_INT), std::exception, "we may use a custom message"); 87 | } 88 | 89 | void test_uncaught_std_exception(void) 90 | { 91 | /* If the test throws unhandled exception, Acutest aborts the test unit 92 | * and considers it a failure. */ 93 | some_function(THROW_TEST_EXC, "Acutest knows how to catch me :-)"); 94 | } 95 | 96 | void test_uncaught_strange_exception(void) 97 | { 98 | /* If the test throws unhandled exception, Acutest aborts the test unit 99 | * and considers it a failure even if it is not derived from std::exception. 100 | */ 101 | some_function(THROW_CHAR_PTR, "Acutest knows how to catch me :-)"); 102 | } 103 | 104 | void test_success(void) 105 | { 106 | /* Do nothing */ 107 | } 108 | 109 | TEST_LIST = { 110 | { "test_exception_type", test_exception_type }, 111 | { "uncaught-std-exception", test_uncaught_std_exception }, 112 | { "uncaught-strange-exception", test_uncaught_strange_exception }, 113 | { "success", test_success }, 114 | { NULL, NULL } 115 | }; 116 | -------------------------------------------------------------------------------- /include/acutest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Acutest -- Another C/C++ Unit Test facility 3 | * 4 | * 5 | * Copyright 2013-2023 Martin Mitáš 6 | * Copyright 2019 Garrett D'Amore 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a 9 | * copy of this software and associated documentation files (the "Software"), 10 | * to deal in the Software without restriction, including without limitation 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | * and/or sell copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 24 | * IN THE SOFTWARE. 25 | */ 26 | 27 | #ifndef ACUTEST_H 28 | #define ACUTEST_H 29 | 30 | 31 | /* Try to auto-detect whether we need to disable C++ exception handling. 32 | * If the detection fails, you may always define TEST_NO_EXCEPTIONS before 33 | * including "acutest.h" manually. */ 34 | #ifdef __cplusplus 35 | #if (__cplusplus >= 199711L && !defined __cpp_exceptions) || \ 36 | ((defined(__GNUC__) || defined(__clang__)) && !defined __EXCEPTIONS) 37 | #ifndef TEST_NO_EXCEPTIONS 38 | #define TEST_NO_EXCEPTIONS 39 | #endif 40 | #endif 41 | #endif 42 | 43 | 44 | /************************ 45 | *** Public interface *** 46 | ************************/ 47 | 48 | /* By default, "acutest.h" provides the main program entry point (function 49 | * main()). However, if the test suite is composed of multiple source files 50 | * which include "acutest.h", then this causes a problem of multiple main() 51 | * definitions. To avoid this problem, #define macro TEST_NO_MAIN in all 52 | * compilation units but one. 53 | */ 54 | 55 | /* Macro to specify list of unit tests in the suite. 56 | * The unit test implementation MUST provide list of unit tests it implements 57 | * with this macro: 58 | * 59 | * TEST_LIST = { 60 | * { "test1_name", test1_func_ptr }, 61 | * { "test2_name", test2_func_ptr }, 62 | * ... 63 | * { NULL, NULL } // zeroed record marking the end of the list 64 | * }; 65 | * 66 | * The list specifies names of each test (must be unique) and pointer to 67 | * a function implementing it. The function does not take any arguments 68 | * and has no return values, i.e. every test function has to be compatible 69 | * with this prototype: 70 | * 71 | * void test_func(void); 72 | * 73 | * Note the list has to be ended with a zeroed record. 74 | */ 75 | #define TEST_LIST const struct acutest_test_ acutest_list_[] 76 | 77 | 78 | /* Macros for testing whether an unit test succeeds or fails. These macros 79 | * can be used arbitrarily in functions implementing the unit tests. 80 | * 81 | * If any condition fails throughout execution of a test, the test fails. 82 | * 83 | * TEST_CHECK takes only one argument (the condition), TEST_CHECK_ allows 84 | * also to specify an error message to print out if the condition fails. 85 | * (It expects printf-like format string and its parameters). The macros 86 | * return non-zero (condition passes) or 0 (condition fails). 87 | * 88 | * That can be useful when more conditions should be checked only if some 89 | * preceding condition passes, as illustrated in this code snippet: 90 | * 91 | * SomeStruct* ptr = allocate_some_struct(); 92 | * if(TEST_CHECK(ptr != NULL)) { 93 | * TEST_CHECK(ptr->member1 < 100); 94 | * TEST_CHECK(ptr->member2 > 200); 95 | * } 96 | */ 97 | #define TEST_CHECK_(cond,...) \ 98 | acutest_check_(!!(cond), __FILE__, __LINE__, __VA_ARGS__) 99 | #define TEST_CHECK(cond) \ 100 | acutest_check_(!!(cond), __FILE__, __LINE__, "%s", #cond) 101 | 102 | 103 | /* These macros are the same as TEST_CHECK_ and TEST_CHECK except that if the 104 | * condition fails, the currently executed unit test is immediately aborted. 105 | * 106 | * That is done either by calling abort() if the unit test is executed as a 107 | * child process; or via longjmp() if the unit test is executed within the 108 | * main Acutest process. 109 | * 110 | * As a side effect of such abortion, your unit tests may cause memory leaks, 111 | * unflushed file descriptors, and other phenomena caused by the abortion. 112 | * 113 | * Therefore you should not use these as a general replacement for TEST_CHECK. 114 | * Use it with some caution, especially if your test causes some other side 115 | * effects to the outside world (e.g. communicating with some server, inserting 116 | * into a database etc.). 117 | */ 118 | #define TEST_ASSERT_(cond,...) \ 119 | do { \ 120 | if(!acutest_check_(!!(cond), __FILE__, __LINE__, __VA_ARGS__)) \ 121 | acutest_abort_(); \ 122 | } while(0) 123 | #define TEST_ASSERT(cond) \ 124 | do { \ 125 | if(!acutest_check_(!!(cond), __FILE__, __LINE__, "%s", #cond)) \ 126 | acutest_abort_(); \ 127 | } while(0) 128 | 129 | 130 | #ifdef __cplusplus 131 | #ifndef TEST_NO_EXCEPTIONS 132 | /* Macros to verify that the code (the 1st argument) throws exception of given 133 | * type (the 2nd argument). (Note these macros are only available in C++.) 134 | * 135 | * TEST_EXCEPTION_ is like TEST_EXCEPTION but accepts custom printf-like 136 | * message. 137 | * 138 | * For example: 139 | * 140 | * TEST_EXCEPTION(function_that_throw(), ExpectedExceptionType); 141 | * 142 | * If the function_that_throw() throws ExpectedExceptionType, the check passes. 143 | * If the function throws anything incompatible with ExpectedExceptionType 144 | * (or if it does not thrown an exception at all), the check fails. 145 | */ 146 | #define TEST_EXCEPTION(code, exctype) \ 147 | do { \ 148 | bool exc_ok_ = false; \ 149 | const char *msg_ = NULL; \ 150 | try { \ 151 | code; \ 152 | msg_ = "No exception thrown."; \ 153 | } catch(exctype const&) { \ 154 | exc_ok_= true; \ 155 | } catch(...) { \ 156 | msg_ = "Unexpected exception thrown."; \ 157 | } \ 158 | acutest_check_(exc_ok_, __FILE__, __LINE__, #code " throws " #exctype);\ 159 | if(msg_ != NULL) \ 160 | acutest_message_("%s", msg_); \ 161 | } while(0) 162 | #define TEST_EXCEPTION_(code, exctype, ...) \ 163 | do { \ 164 | bool exc_ok_ = false; \ 165 | const char *msg_ = NULL; \ 166 | try { \ 167 | code; \ 168 | msg_ = "No exception thrown."; \ 169 | } catch(exctype const&) { \ 170 | exc_ok_= true; \ 171 | } catch(...) { \ 172 | msg_ = "Unexpected exception thrown."; \ 173 | } \ 174 | acutest_check_(exc_ok_, __FILE__, __LINE__, __VA_ARGS__); \ 175 | if(msg_ != NULL) \ 176 | acutest_message_("%s", msg_); \ 177 | } while(0) 178 | #endif /* #ifndef TEST_NO_EXCEPTIONS */ 179 | #endif /* #ifdef __cplusplus */ 180 | 181 | 182 | /* Sometimes it is useful to split execution of more complex unit tests to some 183 | * smaller parts and associate those parts with some names. 184 | * 185 | * This is especially handy if the given unit test is implemented as a loop 186 | * over some vector of multiple testing inputs. Using these macros allow to use 187 | * sort of subtitle for each iteration of the loop (e.g. outputting the input 188 | * itself or a name associated to it), so that if any TEST_CHECK condition 189 | * fails in the loop, it can be easily seen which iteration triggers the 190 | * failure, without the need to manually output the iteration-specific data in 191 | * every single TEST_CHECK inside the loop body. 192 | * 193 | * TEST_CASE allows to specify only single string as the name of the case, 194 | * TEST_CASE_ provides all the power of printf-like string formatting. 195 | * 196 | * Note that the test cases cannot be nested. Starting a new test case ends 197 | * implicitly the previous one. To end the test case explicitly (e.g. to end 198 | * the last test case after exiting the loop), you may use TEST_CASE(NULL). 199 | */ 200 | #define TEST_CASE_(...) acutest_case_(__VA_ARGS__) 201 | #define TEST_CASE(name) acutest_case_("%s", name) 202 | 203 | 204 | /* Maximal output per TEST_CASE call. Longer messages are cut. 205 | * You may define another limit prior including "acutest.h" 206 | */ 207 | #ifndef TEST_CASE_MAXSIZE 208 | #define TEST_CASE_MAXSIZE 64 209 | #endif 210 | 211 | 212 | /* printf-like macro for outputting an extra information about a failure. 213 | * 214 | * Intended use is to output some computed output versus the expected value, 215 | * e.g. like this: 216 | * 217 | * if(!TEST_CHECK(produced == expected)) { 218 | * TEST_MSG("Expected: %d", expected); 219 | * TEST_MSG("Produced: %d", produced); 220 | * } 221 | * 222 | * Note the message is only written down if the most recent use of any checking 223 | * macro (like e.g. TEST_CHECK or TEST_EXCEPTION) in the current test failed. 224 | * This means the above is equivalent to just this: 225 | * 226 | * TEST_CHECK(produced == expected); 227 | * TEST_MSG("Expected: %d", expected); 228 | * TEST_MSG("Produced: %d", produced); 229 | * 230 | * The macro can deal with multi-line output fairly well. It also automatically 231 | * adds a final new-line if there is none present. 232 | */ 233 | #define TEST_MSG(...) acutest_message_(__VA_ARGS__) 234 | 235 | 236 | /* Maximal output per TEST_MSG call. Longer messages are cut. 237 | * You may define another limit prior including "acutest.h" 238 | */ 239 | #ifndef TEST_MSG_MAXSIZE 240 | #define TEST_MSG_MAXSIZE 1024 241 | #endif 242 | 243 | 244 | /* Macro for dumping a block of memory. 245 | * 246 | * Its intended use is very similar to what TEST_MSG is for, but instead of 247 | * generating any printf-like message, this is for dumping raw block of a 248 | * memory in a hexadecimal form: 249 | * 250 | * TEST_CHECK(size_produced == size_expected && 251 | * memcmp(addr_produced, addr_expected, size_produced) == 0); 252 | * TEST_DUMP("Expected:", addr_expected, size_expected); 253 | * TEST_DUMP("Produced:", addr_produced, size_produced); 254 | */ 255 | #define TEST_DUMP(title, addr, size) acutest_dump_(title, addr, size) 256 | 257 | /* Maximal output per TEST_DUMP call (in bytes to dump). Longer blocks are cut. 258 | * You may define another limit prior including "acutest.h" 259 | */ 260 | #ifndef TEST_DUMP_MAXSIZE 261 | #define TEST_DUMP_MAXSIZE 1024 262 | #endif 263 | 264 | 265 | /* Macros for marking the test as SKIPPED. 266 | * Note it can only be used at the beginning of a test, before any other 267 | * checking. 268 | * 269 | * Once used, the best practice is to return from the test routine as soon 270 | * as possible. 271 | */ 272 | #define TEST_SKIP(...) acutest_skip_(__FILE__, __LINE__, __VA_ARGS__) 273 | 274 | 275 | /* Common test initialisation/clean-up 276 | * 277 | * In some test suites, it may be needed to perform some sort of the same 278 | * initialization and/or clean-up in all the tests. 279 | * 280 | * Such test suites may use macros TEST_INIT and/or TEST_FINI prior including 281 | * this header. The expansion of the macro is then used as a body of helper 282 | * function called just before executing every single (TEST_INIT) or just after 283 | * it ends (TEST_FINI). 284 | * 285 | * Examples of various ways how to use the macro TEST_INIT: 286 | * 287 | * #define TEST_INIT my_init_func(); 288 | * #define TEST_INIT my_init_func() // Works even without the semicolon 289 | * #define TEST_INIT setlocale(LC_ALL, NULL); 290 | * #define TEST_INIT { setlocale(LC_ALL, NULL); my_init_func(); } 291 | * 292 | * TEST_FINI is to be used in the same way. 293 | */ 294 | 295 | 296 | /********************** 297 | *** Implementation *** 298 | **********************/ 299 | 300 | /* The unit test files should not rely on anything below. */ 301 | 302 | #include 303 | 304 | /* Enable the use of the non-standard keyword __attribute__ to silence warnings under some compilers */ 305 | #if defined(__GNUC__) || defined(__clang__) 306 | #define ACUTEST_ATTRIBUTE_(attr) __attribute__((attr)) 307 | #else 308 | #define ACUTEST_ATTRIBUTE_(attr) 309 | #endif 310 | 311 | #ifdef __cplusplus 312 | extern "C" { 313 | #endif 314 | 315 | enum acutest_state_ { 316 | ACUTEST_STATE_INITIAL = -4, 317 | ACUTEST_STATE_SELECTED = -3, 318 | ACUTEST_STATE_NEEDTORUN = -2, 319 | 320 | /* By the end all tests should be in one of the following: */ 321 | ACUTEST_STATE_EXCLUDED = -1, 322 | ACUTEST_STATE_SUCCESS = 0, 323 | ACUTEST_STATE_FAILED = 1, 324 | ACUTEST_STATE_SKIPPED = 2 325 | }; 326 | 327 | int acutest_check_(int cond, const char* file, int line, const char* fmt, ...); 328 | void acutest_case_(const char* fmt, ...); 329 | void acutest_message_(const char* fmt, ...); 330 | void acutest_dump_(const char* title, const void* addr, size_t size); 331 | void acutest_abort_(void) ACUTEST_ATTRIBUTE_(noreturn); 332 | #ifdef __cplusplus 333 | } /* extern "C" */ 334 | #endif 335 | 336 | #ifndef TEST_NO_MAIN 337 | 338 | #include 339 | #include 340 | #include 341 | #include 342 | #include 343 | 344 | #if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) 345 | #define ACUTEST_UNIX_ 1 346 | #include 347 | #include 348 | #include 349 | #include 350 | #include 351 | #include 352 | #include 353 | 354 | #if defined CLOCK_PROCESS_CPUTIME_ID && defined CLOCK_MONOTONIC 355 | #define ACUTEST_HAS_POSIX_TIMER_ 1 356 | #endif 357 | #endif 358 | 359 | #if defined(_gnu_linux_) || defined(__linux__) 360 | #define ACUTEST_LINUX_ 1 361 | #include 362 | #include 363 | #endif 364 | 365 | #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) 366 | #define ACUTEST_WIN_ 1 367 | #include 368 | #include 369 | #endif 370 | 371 | #if defined(__APPLE__) 372 | #define ACUTEST_MACOS_ 373 | #include 374 | #include 375 | #include 376 | #include 377 | #include 378 | #endif 379 | 380 | #ifdef __cplusplus 381 | #ifndef TEST_NO_EXCEPTIONS 382 | #include 383 | #endif 384 | #endif 385 | 386 | #ifdef __has_include 387 | #if __has_include() 388 | #include 389 | #endif 390 | #endif 391 | 392 | /* Note our global private identifiers end with '_' to mitigate risk of clash 393 | * with the unit tests implementation. */ 394 | 395 | #ifdef __cplusplus 396 | extern "C" { 397 | #endif 398 | 399 | #ifdef _MSC_VER 400 | /* In the multi-platform code like ours, we cannot use the non-standard 401 | * "safe" functions from Microsoft C lib like e.g. sprintf_s() instead of 402 | * standard sprintf(). Hence, lets disable the warning C4996. */ 403 | #pragma warning(push) 404 | #pragma warning(disable: 4996) 405 | #endif 406 | 407 | 408 | struct acutest_test_ { 409 | const char* name; 410 | void (*func)(void); 411 | }; 412 | 413 | struct acutest_test_data_ { 414 | enum acutest_state_ state; 415 | double duration; 416 | }; 417 | 418 | 419 | extern const struct acutest_test_ acutest_list_[]; 420 | 421 | 422 | static char* acutest_argv0_ = NULL; 423 | static int acutest_list_size_ = 0; 424 | static struct acutest_test_data_* acutest_test_data_ = NULL; 425 | static int acutest_no_exec_ = -1; 426 | static int acutest_no_summary_ = 0; 427 | static int acutest_tap_ = 0; 428 | static int acutest_exclude_mode_ = 0; 429 | static int acutest_worker_ = 0; 430 | static int acutest_worker_index_ = 0; 431 | static int acutest_cond_failed_ = 0; 432 | static FILE *acutest_xml_output_ = NULL; 433 | 434 | static const struct acutest_test_* acutest_current_test_ = NULL; 435 | static int acutest_current_index_ = 0; 436 | static char acutest_case_name_[TEST_CASE_MAXSIZE] = ""; 437 | static int acutest_test_check_count_ = 0; 438 | static int acutest_test_skip_count_ = 0; 439 | static char acutest_test_skip_reason_[256] = ""; 440 | static int acutest_test_already_logged_ = 0; 441 | static int acutest_case_already_logged_ = 0; 442 | static int acutest_verbose_level_ = 2; 443 | static int acutest_test_failures_ = 0; 444 | static int acutest_colorize_ = 0; 445 | static int acutest_timer_ = 0; 446 | 447 | static int acutest_abort_has_jmp_buf_ = 0; 448 | static jmp_buf acutest_abort_jmp_buf_; 449 | 450 | static int 451 | acutest_count_(enum acutest_state_ state) 452 | { 453 | int i, n; 454 | 455 | for(i = 0, n = 0; i < acutest_list_size_; i++) { 456 | if(acutest_test_data_[i].state == state) 457 | n++; 458 | } 459 | 460 | return n; 461 | } 462 | 463 | static void 464 | acutest_cleanup_(void) 465 | { 466 | free((void*) acutest_test_data_); 467 | } 468 | 469 | static void ACUTEST_ATTRIBUTE_(noreturn) 470 | acutest_exit_(int exit_code) 471 | { 472 | acutest_cleanup_(); 473 | exit(exit_code); 474 | } 475 | 476 | 477 | #if defined ACUTEST_WIN_ 478 | typedef LARGE_INTEGER acutest_timer_type_; 479 | static LARGE_INTEGER acutest_timer_freq_; 480 | static acutest_timer_type_ acutest_timer_start_; 481 | static acutest_timer_type_ acutest_timer_end_; 482 | 483 | static void 484 | acutest_timer_init_(void) 485 | { 486 | QueryPerformanceFrequency(´st_timer_freq_); 487 | } 488 | 489 | static void 490 | acutest_timer_get_time_(LARGE_INTEGER* ts) 491 | { 492 | QueryPerformanceCounter(ts); 493 | } 494 | 495 | static double 496 | acutest_timer_diff_(LARGE_INTEGER start, LARGE_INTEGER end) 497 | { 498 | double duration = (double)(end.QuadPart - start.QuadPart); 499 | duration /= (double)acutest_timer_freq_.QuadPart; 500 | return duration; 501 | } 502 | 503 | static void 504 | acutest_timer_print_diff_(void) 505 | { 506 | printf("%.6lf secs", acutest_timer_diff_(acutest_timer_start_, acutest_timer_end_)); 507 | } 508 | #elif defined ACUTEST_HAS_POSIX_TIMER_ 509 | static clockid_t acutest_timer_id_; 510 | typedef struct timespec acutest_timer_type_; 511 | static acutest_timer_type_ acutest_timer_start_; 512 | static acutest_timer_type_ acutest_timer_end_; 513 | 514 | static void 515 | acutest_timer_init_(void) 516 | { 517 | if(acutest_timer_ == 1) 518 | acutest_timer_id_ = CLOCK_MONOTONIC; 519 | else if(acutest_timer_ == 2) 520 | acutest_timer_id_ = CLOCK_PROCESS_CPUTIME_ID; 521 | } 522 | 523 | static void 524 | acutest_timer_get_time_(struct timespec* ts) 525 | { 526 | clock_gettime(acutest_timer_id_, ts); 527 | } 528 | 529 | static double 530 | acutest_timer_diff_(struct timespec start, struct timespec end) 531 | { 532 | return (double)(end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1e9; 533 | } 534 | 535 | static void 536 | acutest_timer_print_diff_(void) 537 | { 538 | printf("%.6lf secs", 539 | acutest_timer_diff_(acutest_timer_start_, acutest_timer_end_)); 540 | } 541 | #else 542 | typedef int acutest_timer_type_; 543 | static acutest_timer_type_ acutest_timer_start_; 544 | static acutest_timer_type_ acutest_timer_end_; 545 | 546 | void 547 | acutest_timer_init_(void) 548 | {} 549 | 550 | static void 551 | acutest_timer_get_time_(int* ts) 552 | { 553 | (void) ts; 554 | } 555 | 556 | static double 557 | acutest_timer_diff_(int start, int end) 558 | { 559 | (void) start; 560 | (void) end; 561 | return 0.0; 562 | } 563 | 564 | static void 565 | acutest_timer_print_diff_(void) 566 | {} 567 | #endif 568 | 569 | #define ACUTEST_COLOR_DEFAULT_ 0 570 | #define ACUTEST_COLOR_RED_ 1 571 | #define ACUTEST_COLOR_GREEN_ 2 572 | #define ACUTEST_COLOR_YELLOW_ 3 573 | #define ACUTEST_COLOR_DEFAULT_INTENSIVE_ 10 574 | #define ACUTEST_COLOR_RED_INTENSIVE_ 11 575 | #define ACUTEST_COLOR_GREEN_INTENSIVE_ 12 576 | #define ACUTEST_COLOR_YELLOW_INTENSIVE_ 13 577 | 578 | static int ACUTEST_ATTRIBUTE_(format (printf, 2, 3)) 579 | acutest_colored_printf_(int color, const char* fmt, ...) 580 | { 581 | va_list args; 582 | char buffer[256]; 583 | int n; 584 | 585 | va_start(args, fmt); 586 | vsnprintf(buffer, sizeof(buffer), fmt, args); 587 | va_end(args); 588 | buffer[sizeof(buffer)-1] = '\0'; 589 | 590 | if(!acutest_colorize_) { 591 | return printf("%s", buffer); 592 | } 593 | 594 | #if defined ACUTEST_UNIX_ 595 | { 596 | const char* col_str; 597 | switch(color) { 598 | case ACUTEST_COLOR_RED_: col_str = "\033[0;31m"; break; 599 | case ACUTEST_COLOR_GREEN_: col_str = "\033[0;32m"; break; 600 | case ACUTEST_COLOR_YELLOW_: col_str = "\033[0;33m"; break; 601 | case ACUTEST_COLOR_RED_INTENSIVE_: col_str = "\033[1;31m"; break; 602 | case ACUTEST_COLOR_GREEN_INTENSIVE_: col_str = "\033[1;32m"; break; 603 | case ACUTEST_COLOR_YELLOW_INTENSIVE_: col_str = "\033[1;33m"; break; 604 | case ACUTEST_COLOR_DEFAULT_INTENSIVE_: col_str = "\033[1m"; break; 605 | default: col_str = "\033[0m"; break; 606 | } 607 | printf("%s", col_str); 608 | n = printf("%s", buffer); 609 | printf("\033[0m"); 610 | return n; 611 | } 612 | #elif defined ACUTEST_WIN_ 613 | { 614 | HANDLE h; 615 | CONSOLE_SCREEN_BUFFER_INFO info; 616 | WORD attr; 617 | 618 | h = GetStdHandle(STD_OUTPUT_HANDLE); 619 | GetConsoleScreenBufferInfo(h, &info); 620 | 621 | switch(color) { 622 | case ACUTEST_COLOR_RED_: attr = FOREGROUND_RED; break; 623 | case ACUTEST_COLOR_GREEN_: attr = FOREGROUND_GREEN; break; 624 | case ACUTEST_COLOR_YELLOW_: attr = FOREGROUND_RED | FOREGROUND_GREEN; break; 625 | case ACUTEST_COLOR_RED_INTENSIVE_: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break; 626 | case ACUTEST_COLOR_GREEN_INTENSIVE_: attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; 627 | case ACUTEST_COLOR_DEFAULT_INTENSIVE_: attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break; 628 | case ACUTEST_COLOR_YELLOW_INTENSIVE_: attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; 629 | default: attr = 0; break; 630 | } 631 | if(attr != 0) 632 | SetConsoleTextAttribute(h, attr); 633 | n = printf("%s", buffer); 634 | SetConsoleTextAttribute(h, info.wAttributes); 635 | return n; 636 | } 637 | #else 638 | n = printf("%s", buffer); 639 | return n; 640 | #endif 641 | } 642 | 643 | static const char* 644 | acutest_basename_(const char* path) 645 | { 646 | const char* name; 647 | 648 | name = strrchr(path, '/'); 649 | if(name != NULL) 650 | name++; 651 | else 652 | name = path; 653 | 654 | #ifdef ACUTEST_WIN_ 655 | { 656 | const char* alt_name; 657 | 658 | alt_name = strrchr(path, '\\'); 659 | if(alt_name != NULL) 660 | alt_name++; 661 | else 662 | alt_name = path; 663 | 664 | if(alt_name > name) 665 | name = alt_name; 666 | } 667 | #endif 668 | 669 | return name; 670 | } 671 | 672 | static void 673 | acutest_begin_test_line_(const struct acutest_test_* test) 674 | { 675 | if(!acutest_tap_) { 676 | if(acutest_verbose_level_ >= 3) { 677 | acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Test %s:\n", test->name); 678 | acutest_test_already_logged_++; 679 | } else if(acutest_verbose_level_ >= 1) { 680 | int n; 681 | char spaces[48]; 682 | 683 | n = acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Test %s... ", test->name); 684 | memset(spaces, ' ', sizeof(spaces)); 685 | if(n < (int) sizeof(spaces)) 686 | printf("%.*s", (int) sizeof(spaces) - n, spaces); 687 | } else { 688 | acutest_test_already_logged_ = 1; 689 | } 690 | } 691 | } 692 | 693 | static void 694 | acutest_finish_test_line_(enum acutest_state_ state) 695 | { 696 | if(acutest_tap_) { 697 | printf("%s %d - %s%s\n", 698 | (state == ACUTEST_STATE_SUCCESS || state == ACUTEST_STATE_SKIPPED) ? "ok" : "not ok", 699 | acutest_current_index_ + 1, 700 | acutest_current_test_->name, 701 | (state == ACUTEST_STATE_SKIPPED) ? " # SKIP" : ""); 702 | 703 | if(state == ACUTEST_STATE_SUCCESS && acutest_timer_) { 704 | printf("# Duration: "); 705 | acutest_timer_print_diff_(); 706 | printf("\n"); 707 | } 708 | } else { 709 | int color; 710 | const char* str; 711 | 712 | switch(state) { 713 | case ACUTEST_STATE_SUCCESS: color = ACUTEST_COLOR_GREEN_INTENSIVE_; str = "OK"; break; 714 | case ACUTEST_STATE_SKIPPED: color = ACUTEST_COLOR_YELLOW_INTENSIVE_; str = "SKIPPED"; break; 715 | case ACUTEST_STATE_FAILED: /* Fall through. */ 716 | default: color = ACUTEST_COLOR_RED_INTENSIVE_; str = "FAILED"; break; 717 | } 718 | 719 | printf("[ "); 720 | acutest_colored_printf_(color, "%s", str); 721 | printf(" ]"); 722 | 723 | if(state == ACUTEST_STATE_SUCCESS && acutest_timer_) { 724 | printf(" "); 725 | acutest_timer_print_diff_(); 726 | } 727 | 728 | printf("\n"); 729 | } 730 | } 731 | 732 | static void 733 | acutest_line_indent_(int level) 734 | { 735 | static const char spaces[] = " "; 736 | int n = level * 2; 737 | 738 | if(acutest_tap_ && n > 0) { 739 | n--; 740 | printf("#"); 741 | } 742 | 743 | while(n > 16) { 744 | printf("%s", spaces); 745 | n -= 16; 746 | } 747 | printf("%.*s", n, spaces); 748 | } 749 | 750 | void ACUTEST_ATTRIBUTE_(format (printf, 3, 4)) 751 | acutest_skip_(const char* file, int line, const char* fmt, ...) 752 | { 753 | va_list args; 754 | size_t reason_len; 755 | 756 | va_start(args, fmt); 757 | vsnprintf(acutest_test_skip_reason_, sizeof(acutest_test_skip_reason_), fmt, args); 758 | va_end(args); 759 | acutest_test_skip_reason_[sizeof(acutest_test_skip_reason_)-1] = '\0'; 760 | 761 | /* Remove final dot, if provided; that collides with our other logic. */ 762 | reason_len = strlen(acutest_test_skip_reason_); 763 | if(acutest_test_skip_reason_[reason_len-1] == '.') 764 | acutest_test_skip_reason_[reason_len-1] = '\0'; 765 | 766 | if(acutest_test_check_count_ > 0) { 767 | acutest_check_(0, file, line, "Cannot skip, already performed some checks"); 768 | return; 769 | } 770 | 771 | if(acutest_verbose_level_ >= 2) { 772 | const char *result_str = "skipped"; 773 | int result_color = ACUTEST_COLOR_YELLOW_; 774 | 775 | if(!acutest_test_already_logged_ && acutest_current_test_ != NULL) 776 | acutest_finish_test_line_(ACUTEST_STATE_SKIPPED); 777 | acutest_test_already_logged_++; 778 | 779 | acutest_line_indent_(1); 780 | 781 | if(file != NULL) { 782 | file = acutest_basename_(file); 783 | printf("%s:%d: ", file, line); 784 | } 785 | 786 | printf("%s... ", acutest_test_skip_reason_); 787 | acutest_colored_printf_(result_color, "%s", result_str); 788 | printf("\n"); 789 | acutest_test_already_logged_++; 790 | } 791 | 792 | acutest_test_skip_count_++; 793 | } 794 | 795 | int ACUTEST_ATTRIBUTE_(format (printf, 4, 5)) 796 | acutest_check_(int cond, const char* file, int line, const char* fmt, ...) 797 | { 798 | const char *result_str; 799 | int result_color; 800 | int verbose_level; 801 | 802 | if(acutest_test_skip_count_) { 803 | /* We've skipped the test. We shouldn't be here: The test implementation 804 | * should have already return before. So lets suppress the following 805 | * output. */ 806 | cond = 1; 807 | goto skip_check; 808 | } 809 | 810 | if(cond) { 811 | result_str = "ok"; 812 | result_color = ACUTEST_COLOR_GREEN_; 813 | verbose_level = 3; 814 | } else { 815 | if(!acutest_test_already_logged_ && acutest_current_test_ != NULL) 816 | acutest_finish_test_line_(ACUTEST_STATE_FAILED); 817 | 818 | acutest_test_failures_++; 819 | acutest_test_already_logged_++; 820 | 821 | result_str = "failed"; 822 | result_color = ACUTEST_COLOR_RED_; 823 | verbose_level = 2; 824 | } 825 | 826 | if(acutest_verbose_level_ >= verbose_level) { 827 | va_list args; 828 | 829 | if(!acutest_case_already_logged_ && acutest_case_name_[0]) { 830 | acutest_line_indent_(1); 831 | acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Case %s:\n", acutest_case_name_); 832 | acutest_test_already_logged_++; 833 | acutest_case_already_logged_++; 834 | } 835 | 836 | acutest_line_indent_(acutest_case_name_[0] ? 2 : 1); 837 | if(file != NULL) { 838 | file = acutest_basename_(file); 839 | printf("%s:%d: ", file, line); 840 | } 841 | 842 | va_start(args, fmt); 843 | vprintf(fmt, args); 844 | va_end(args); 845 | 846 | printf("... "); 847 | acutest_colored_printf_(result_color, "%s", result_str); 848 | printf("\n"); 849 | acutest_test_already_logged_++; 850 | } 851 | 852 | acutest_test_check_count_++; 853 | 854 | skip_check: 855 | acutest_cond_failed_ = (cond == 0); 856 | return !acutest_cond_failed_; 857 | } 858 | 859 | void ACUTEST_ATTRIBUTE_(format (printf, 1, 2)) 860 | acutest_case_(const char* fmt, ...) 861 | { 862 | va_list args; 863 | 864 | if(acutest_verbose_level_ < 2) 865 | return; 866 | 867 | if(acutest_case_name_[0]) { 868 | acutest_case_already_logged_ = 0; 869 | acutest_case_name_[0] = '\0'; 870 | } 871 | 872 | if(fmt == NULL) 873 | return; 874 | 875 | va_start(args, fmt); 876 | vsnprintf(acutest_case_name_, sizeof(acutest_case_name_) - 1, fmt, args); 877 | va_end(args); 878 | acutest_case_name_[sizeof(acutest_case_name_) - 1] = '\0'; 879 | 880 | if(acutest_verbose_level_ >= 3) { 881 | acutest_line_indent_(1); 882 | acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Case %s:\n", acutest_case_name_); 883 | acutest_test_already_logged_++; 884 | acutest_case_already_logged_++; 885 | } 886 | } 887 | 888 | void ACUTEST_ATTRIBUTE_(format (printf, 1, 2)) 889 | acutest_message_(const char* fmt, ...) 890 | { 891 | char buffer[TEST_MSG_MAXSIZE]; 892 | char* line_beg; 893 | char* line_end; 894 | va_list args; 895 | 896 | if(acutest_verbose_level_ < 2) 897 | return; 898 | 899 | /* We allow extra message only when something is already wrong in the 900 | * current test. */ 901 | if(acutest_current_test_ == NULL || !acutest_cond_failed_) 902 | return; 903 | 904 | va_start(args, fmt); 905 | vsnprintf(buffer, TEST_MSG_MAXSIZE, fmt, args); 906 | va_end(args); 907 | buffer[TEST_MSG_MAXSIZE-1] = '\0'; 908 | 909 | line_beg = buffer; 910 | while(1) { 911 | line_end = strchr(line_beg, '\n'); 912 | if(line_end == NULL) 913 | break; 914 | acutest_line_indent_(acutest_case_name_[0] ? 3 : 2); 915 | printf("%.*s\n", (int)(line_end - line_beg), line_beg); 916 | line_beg = line_end + 1; 917 | } 918 | if(line_beg[0] != '\0') { 919 | acutest_line_indent_(acutest_case_name_[0] ? 3 : 2); 920 | printf("%s\n", line_beg); 921 | } 922 | } 923 | 924 | void 925 | acutest_dump_(const char* title, const void* addr, size_t size) 926 | { 927 | static const size_t BYTES_PER_LINE = 16; 928 | size_t line_beg; 929 | size_t truncate = 0; 930 | 931 | if(acutest_verbose_level_ < 2) 932 | return; 933 | 934 | /* We allow extra message only when something is already wrong in the 935 | * current test. */ 936 | if(acutest_current_test_ == NULL || !acutest_cond_failed_) 937 | return; 938 | 939 | if(size > TEST_DUMP_MAXSIZE) { 940 | truncate = size - TEST_DUMP_MAXSIZE; 941 | size = TEST_DUMP_MAXSIZE; 942 | } 943 | 944 | acutest_line_indent_(acutest_case_name_[0] ? 3 : 2); 945 | printf((title[strlen(title)-1] == ':') ? "%s\n" : "%s:\n", title); 946 | 947 | for(line_beg = 0; line_beg < size; line_beg += BYTES_PER_LINE) { 948 | size_t line_end = line_beg + BYTES_PER_LINE; 949 | size_t off; 950 | 951 | acutest_line_indent_(acutest_case_name_[0] ? 4 : 3); 952 | printf("%08lx: ", (unsigned long)line_beg); 953 | for(off = line_beg; off < line_end; off++) { 954 | if(off < size) 955 | printf(" %02x", ((const unsigned char*)addr)[off]); 956 | else 957 | printf(" "); 958 | } 959 | 960 | printf(" "); 961 | for(off = line_beg; off < line_end; off++) { 962 | unsigned char byte = ((const unsigned char*)addr)[off]; 963 | if(off < size) 964 | printf("%c", (iscntrl(byte) ? '.' : byte)); 965 | else 966 | break; 967 | } 968 | 969 | printf("\n"); 970 | } 971 | 972 | if(truncate > 0) { 973 | acutest_line_indent_(acutest_case_name_[0] ? 4 : 3); 974 | printf(" ... (and more %u bytes)\n", (unsigned) truncate); 975 | } 976 | } 977 | 978 | /* This is called just before each test */ 979 | static void 980 | acutest_init_(const char *test_name) 981 | { 982 | #ifdef TEST_INIT 983 | TEST_INIT 984 | ; /* Allow for a single unterminated function call */ 985 | #endif 986 | 987 | /* Suppress any warnings about unused variable. */ 988 | (void) test_name; 989 | } 990 | 991 | /* This is called after each test */ 992 | static void 993 | acutest_fini_(const char *test_name) 994 | { 995 | #ifdef TEST_FINI 996 | TEST_FINI 997 | ; /* Allow for a single unterminated function call */ 998 | #endif 999 | 1000 | /* Suppress any warnings about unused variable. */ 1001 | (void) test_name; 1002 | } 1003 | 1004 | void 1005 | acutest_abort_(void) 1006 | { 1007 | if(acutest_abort_has_jmp_buf_) { 1008 | longjmp(acutest_abort_jmp_buf_, 1); 1009 | } else { 1010 | if(acutest_current_test_ != NULL) 1011 | acutest_fini_(acutest_current_test_->name); 1012 | fflush(stdout); 1013 | fflush(stderr); 1014 | acutest_exit_(ACUTEST_STATE_FAILED); 1015 | } 1016 | } 1017 | 1018 | static void 1019 | acutest_list_names_(void) 1020 | { 1021 | const struct acutest_test_* test; 1022 | 1023 | printf("Unit tests:\n"); 1024 | for(test = ´st_list_[0]; test->func != NULL; test++) 1025 | printf(" %s\n", test->name); 1026 | } 1027 | 1028 | static int 1029 | acutest_name_contains_word_(const char* name, const char* pattern) 1030 | { 1031 | static const char word_delim[] = " \t-_/.,:;"; 1032 | const char* substr; 1033 | size_t pattern_len; 1034 | 1035 | pattern_len = strlen(pattern); 1036 | 1037 | substr = strstr(name, pattern); 1038 | while(substr != NULL) { 1039 | int starts_on_word_boundary = (substr == name || strchr(word_delim, substr[-1]) != NULL); 1040 | int ends_on_word_boundary = (substr[pattern_len] == '\0' || strchr(word_delim, substr[pattern_len]) != NULL); 1041 | 1042 | if(starts_on_word_boundary && ends_on_word_boundary) 1043 | return 1; 1044 | 1045 | substr = strstr(substr+1, pattern); 1046 | } 1047 | 1048 | return 0; 1049 | } 1050 | 1051 | static int 1052 | acutest_select_(const char* pattern) 1053 | { 1054 | int i; 1055 | int n = 0; 1056 | 1057 | /* Try exact match. */ 1058 | for(i = 0; i < acutest_list_size_; i++) { 1059 | if(strcmp(acutest_list_[i].name, pattern) == 0) { 1060 | acutest_test_data_[i].state = ACUTEST_STATE_SELECTED; 1061 | n++; 1062 | break; 1063 | } 1064 | } 1065 | if(n > 0) 1066 | return n; 1067 | 1068 | /* Try word match. */ 1069 | for(i = 0; i < acutest_list_size_; i++) { 1070 | if(acutest_name_contains_word_(acutest_list_[i].name, pattern)) { 1071 | acutest_test_data_[i].state = ACUTEST_STATE_SELECTED; 1072 | n++; 1073 | } 1074 | } 1075 | if(n > 0) 1076 | return n; 1077 | 1078 | /* Try relaxed match. */ 1079 | for(i = 0; i < acutest_list_size_; i++) { 1080 | if(strstr(acutest_list_[i].name, pattern) != NULL) { 1081 | acutest_test_data_[i].state = ACUTEST_STATE_SELECTED; 1082 | n++; 1083 | } 1084 | } 1085 | 1086 | return n; 1087 | } 1088 | 1089 | 1090 | /* Called if anything goes bad in Acutest, or if the unit test ends in other 1091 | * way then by normal returning from its function (e.g. exception or some 1092 | * abnormal child process termination). */ 1093 | static void ACUTEST_ATTRIBUTE_(format (printf, 1, 2)) 1094 | acutest_error_(const char* fmt, ...) 1095 | { 1096 | if(acutest_verbose_level_ == 0) 1097 | return; 1098 | 1099 | if(acutest_verbose_level_ >= 2) { 1100 | va_list args; 1101 | 1102 | acutest_line_indent_(1); 1103 | if(acutest_verbose_level_ >= 3) 1104 | acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "ERROR: "); 1105 | va_start(args, fmt); 1106 | vprintf(fmt, args); 1107 | va_end(args); 1108 | printf("\n"); 1109 | } 1110 | 1111 | if(acutest_verbose_level_ >= 3) { 1112 | printf("\n"); 1113 | } 1114 | } 1115 | 1116 | /* Call directly the given test unit function. */ 1117 | static enum acutest_state_ 1118 | acutest_do_run_(const struct acutest_test_* test, int index) 1119 | { 1120 | enum acutest_state_ state = ACUTEST_STATE_FAILED; 1121 | 1122 | acutest_current_test_ = test; 1123 | acutest_current_index_ = index; 1124 | acutest_test_failures_ = 0; 1125 | acutest_test_already_logged_ = 0; 1126 | acutest_test_check_count_ = 0; 1127 | acutest_test_skip_count_ = 0; 1128 | acutest_cond_failed_ = 0; 1129 | 1130 | #ifdef __cplusplus 1131 | #ifndef TEST_NO_EXCEPTIONS 1132 | try { 1133 | #endif 1134 | #endif 1135 | acutest_init_(test->name); 1136 | acutest_begin_test_line_(test); 1137 | 1138 | /* This is good to do in case the test unit crashes. */ 1139 | fflush(stdout); 1140 | fflush(stderr); 1141 | 1142 | if(!acutest_worker_) { 1143 | acutest_abort_has_jmp_buf_ = 1; 1144 | if(setjmp(acutest_abort_jmp_buf_) != 0) 1145 | goto aborted; 1146 | } 1147 | 1148 | acutest_timer_get_time_(´st_timer_start_); 1149 | test->func(); 1150 | 1151 | aborted: 1152 | acutest_abort_has_jmp_buf_ = 0; 1153 | acutest_timer_get_time_(´st_timer_end_); 1154 | 1155 | if(acutest_test_failures_ > 0) 1156 | state = ACUTEST_STATE_FAILED; 1157 | else if(acutest_test_skip_count_ > 0) 1158 | state = ACUTEST_STATE_SKIPPED; 1159 | else 1160 | state = ACUTEST_STATE_SUCCESS; 1161 | 1162 | if(!acutest_test_already_logged_) 1163 | acutest_finish_test_line_(state); 1164 | 1165 | if(acutest_verbose_level_ >= 3) { 1166 | acutest_line_indent_(1); 1167 | switch(state) { 1168 | case ACUTEST_STATE_SUCCESS: 1169 | acutest_colored_printf_(ACUTEST_COLOR_GREEN_INTENSIVE_, "SUCCESS: "); 1170 | printf("All conditions have passed.\n"); 1171 | 1172 | if(acutest_timer_) { 1173 | acutest_line_indent_(1); 1174 | printf("Duration: "); 1175 | acutest_timer_print_diff_(); 1176 | printf("\n"); 1177 | } 1178 | break; 1179 | 1180 | case ACUTEST_STATE_SKIPPED: 1181 | acutest_colored_printf_(ACUTEST_COLOR_YELLOW_INTENSIVE_, "SKIPPED: "); 1182 | printf("%s.\n", acutest_test_skip_reason_); 1183 | break; 1184 | 1185 | default: 1186 | acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED: "); 1187 | printf("%d condition%s %s failed.\n", 1188 | acutest_test_failures_, 1189 | (acutest_test_failures_ == 1) ? "" : "s", 1190 | (acutest_test_failures_ == 1) ? "has" : "have"); 1191 | break; 1192 | } 1193 | printf("\n"); 1194 | } 1195 | 1196 | #ifdef __cplusplus 1197 | #ifndef TEST_NO_EXCEPTIONS 1198 | } catch(std::exception& e) { 1199 | const char* what = e.what(); 1200 | acutest_check_(0, NULL, 0, "Threw std::exception"); 1201 | if(what != NULL) 1202 | acutest_message_("std::exception::what(): %s", what); 1203 | 1204 | if(acutest_verbose_level_ >= 3) { 1205 | acutest_line_indent_(1); 1206 | acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED: "); 1207 | printf("C++ exception.\n\n"); 1208 | } 1209 | } catch(...) { 1210 | acutest_check_(0, NULL, 0, "Threw an exception"); 1211 | 1212 | if(acutest_verbose_level_ >= 3) { 1213 | acutest_line_indent_(1); 1214 | acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED: "); 1215 | printf("C++ exception.\n\n"); 1216 | } 1217 | } 1218 | #endif 1219 | #endif 1220 | 1221 | acutest_fini_(test->name); 1222 | acutest_case_(NULL); 1223 | acutest_current_test_ = NULL; 1224 | 1225 | return state; 1226 | } 1227 | 1228 | /* Trigger the unit test. If possible (and not suppressed) it starts a child 1229 | * process who calls acutest_do_run_(), otherwise it calls acutest_do_run_() 1230 | * directly. */ 1231 | static void 1232 | acutest_run_(const struct acutest_test_* test, int index, int master_index) 1233 | { 1234 | enum acutest_state_ state = ACUTEST_STATE_FAILED; 1235 | acutest_timer_type_ start, end; 1236 | 1237 | acutest_current_test_ = test; 1238 | acutest_test_already_logged_ = 0; 1239 | acutest_timer_get_time_(&start); 1240 | 1241 | if(!acutest_no_exec_) { 1242 | 1243 | #if defined(ACUTEST_UNIX_) 1244 | 1245 | pid_t pid; 1246 | int exit_code; 1247 | 1248 | /* Make sure the child starts with empty I/O buffers. */ 1249 | fflush(stdout); 1250 | fflush(stderr); 1251 | 1252 | pid = fork(); 1253 | if(pid == (pid_t)-1) { 1254 | acutest_error_("Cannot fork. %s [%d]", strerror(errno), errno); 1255 | } else if(pid == 0) { 1256 | /* Child: Do the test. */ 1257 | acutest_worker_ = 1; 1258 | state = acutest_do_run_(test, index); 1259 | acutest_exit_((int) state); 1260 | } else { 1261 | /* Parent: Wait until child terminates and analyze its exit code. */ 1262 | waitpid(pid, &exit_code, 0); 1263 | if(WIFEXITED(exit_code)) { 1264 | state = (enum acutest_state_) WEXITSTATUS(exit_code); 1265 | } else if(WIFSIGNALED(exit_code)) { 1266 | char tmp[32]; 1267 | const char* signame; 1268 | switch(WTERMSIG(exit_code)) { 1269 | case SIGINT: signame = "SIGINT"; break; 1270 | case SIGHUP: signame = "SIGHUP"; break; 1271 | case SIGQUIT: signame = "SIGQUIT"; break; 1272 | case SIGABRT: signame = "SIGABRT"; break; 1273 | case SIGKILL: signame = "SIGKILL"; break; 1274 | case SIGSEGV: signame = "SIGSEGV"; break; 1275 | case SIGILL: signame = "SIGILL"; break; 1276 | case SIGTERM: signame = "SIGTERM"; break; 1277 | default: snprintf(tmp, sizeof(tmp), "signal %d", WTERMSIG(exit_code)); signame = tmp; break; 1278 | } 1279 | acutest_error_("Test interrupted by %s.", signame); 1280 | } else { 1281 | acutest_error_("Test ended in an unexpected way [%d].", exit_code); 1282 | } 1283 | } 1284 | 1285 | #elif defined(ACUTEST_WIN_) 1286 | 1287 | char buffer[512] = {0}; 1288 | STARTUPINFOA startupInfo; 1289 | PROCESS_INFORMATION processInfo; 1290 | DWORD exitCode; 1291 | 1292 | /* Windows has no fork(). So we propagate all info into the child 1293 | * through a command line arguments. */ 1294 | snprintf(buffer, sizeof(buffer), 1295 | "%s --worker=%d %s --no-exec --no-summary %s --verbose=%d --color=%s -- \"%s\"", 1296 | acutest_argv0_, index, acutest_timer_ ? "--time" : "", 1297 | acutest_tap_ ? "--tap" : "", acutest_verbose_level_, 1298 | acutest_colorize_ ? "always" : "never", 1299 | test->name); 1300 | memset(&startupInfo, 0, sizeof(startupInfo)); 1301 | startupInfo.cb = sizeof(STARTUPINFO); 1302 | if(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) { 1303 | WaitForSingleObject(processInfo.hProcess, INFINITE); 1304 | GetExitCodeProcess(processInfo.hProcess, &exitCode); 1305 | CloseHandle(processInfo.hThread); 1306 | CloseHandle(processInfo.hProcess); 1307 | switch(exitCode) { 1308 | case 0: state = ACUTEST_STATE_SUCCESS; break; 1309 | case 1: state = ACUTEST_STATE_FAILED; break; 1310 | case 2: state = ACUTEST_STATE_SKIPPED; break; 1311 | case 3: acutest_error_("Aborted."); break; 1312 | case 0xC0000005: acutest_error_("Access violation."); break; 1313 | default: acutest_error_("Test ended in an unexpected way [%lu].", exitCode); break; 1314 | } 1315 | } else { 1316 | acutest_error_("Cannot create unit test subprocess [%ld].", GetLastError()); 1317 | } 1318 | 1319 | #else 1320 | 1321 | /* A platform where we don't know how to run child process. */ 1322 | state = acutest_do_run_(test, index); 1323 | 1324 | #endif 1325 | 1326 | } else { 1327 | /* Child processes suppressed through --no-exec. */ 1328 | state = acutest_do_run_(test, index); 1329 | } 1330 | acutest_timer_get_time_(&end); 1331 | 1332 | acutest_current_test_ = NULL; 1333 | 1334 | acutest_test_data_[master_index].state = state; 1335 | acutest_test_data_[master_index].duration = acutest_timer_diff_(start, end); 1336 | } 1337 | 1338 | #if defined(ACUTEST_WIN_) 1339 | /* Callback for SEH events. */ 1340 | static LONG CALLBACK 1341 | acutest_seh_exception_filter_(EXCEPTION_POINTERS *ptrs) 1342 | { 1343 | acutest_check_(0, NULL, 0, "Unhandled SEH exception"); 1344 | acutest_message_("Exception code: 0x%08lx", ptrs->ExceptionRecord->ExceptionCode); 1345 | acutest_message_("Exception address: 0x%p", ptrs->ExceptionRecord->ExceptionAddress); 1346 | 1347 | fflush(stdout); 1348 | fflush(stderr); 1349 | 1350 | return EXCEPTION_EXECUTE_HANDLER; 1351 | } 1352 | #endif 1353 | 1354 | 1355 | #define ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ 0x0001 1356 | #define ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_ 0x0002 1357 | 1358 | #define ACUTEST_CMDLINE_OPTID_NONE_ 0 1359 | #define ACUTEST_CMDLINE_OPTID_UNKNOWN_ (-0x7fffffff + 0) 1360 | #define ACUTEST_CMDLINE_OPTID_MISSINGARG_ (-0x7fffffff + 1) 1361 | #define ACUTEST_CMDLINE_OPTID_BOGUSARG_ (-0x7fffffff + 2) 1362 | 1363 | typedef struct acutest_test_CMDLINE_OPTION_ { 1364 | char shortname; 1365 | const char* longname; 1366 | int id; 1367 | unsigned flags; 1368 | } ACUTEST_CMDLINE_OPTION_; 1369 | 1370 | static int 1371 | acutest_cmdline_handle_short_opt_group_(const ACUTEST_CMDLINE_OPTION_* options, 1372 | const char* arggroup, 1373 | int (*callback)(int /*optval*/, const char* /*arg*/)) 1374 | { 1375 | const ACUTEST_CMDLINE_OPTION_* opt; 1376 | int i; 1377 | int ret = 0; 1378 | 1379 | for(i = 0; arggroup[i] != '\0'; i++) { 1380 | for(opt = options; opt->id != 0; opt++) { 1381 | if(arggroup[i] == opt->shortname) 1382 | break; 1383 | } 1384 | 1385 | if(opt->id != 0 && !(opt->flags & ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_)) { 1386 | ret = callback(opt->id, NULL); 1387 | } else { 1388 | /* Unknown option. */ 1389 | char badoptname[3]; 1390 | badoptname[0] = '-'; 1391 | badoptname[1] = arggroup[i]; 1392 | badoptname[2] = '\0'; 1393 | ret = callback((opt->id != 0 ? ACUTEST_CMDLINE_OPTID_MISSINGARG_ : ACUTEST_CMDLINE_OPTID_UNKNOWN_), 1394 | badoptname); 1395 | } 1396 | 1397 | if(ret != 0) 1398 | break; 1399 | } 1400 | 1401 | return ret; 1402 | } 1403 | 1404 | #define ACUTEST_CMDLINE_AUXBUF_SIZE_ 32 1405 | 1406 | static int 1407 | acutest_cmdline_read_(const ACUTEST_CMDLINE_OPTION_* options, int argc, char** argv, 1408 | int (*callback)(int /*optval*/, const char* /*arg*/)) 1409 | { 1410 | 1411 | const ACUTEST_CMDLINE_OPTION_* opt; 1412 | char auxbuf[ACUTEST_CMDLINE_AUXBUF_SIZE_+1]; 1413 | int after_doubledash = 0; 1414 | int i = 1; 1415 | int ret = 0; 1416 | 1417 | auxbuf[ACUTEST_CMDLINE_AUXBUF_SIZE_] = '\0'; 1418 | 1419 | while(i < argc) { 1420 | if(after_doubledash || strcmp(argv[i], "-") == 0) { 1421 | /* Non-option argument. */ 1422 | ret = callback(ACUTEST_CMDLINE_OPTID_NONE_, argv[i]); 1423 | } else if(strcmp(argv[i], "--") == 0) { 1424 | /* End of options. All the remaining members are non-option arguments. */ 1425 | after_doubledash = 1; 1426 | } else if(argv[i][0] != '-') { 1427 | /* Non-option argument. */ 1428 | ret = callback(ACUTEST_CMDLINE_OPTID_NONE_, argv[i]); 1429 | } else { 1430 | for(opt = options; opt->id != 0; opt++) { 1431 | if(opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) { 1432 | size_t len = strlen(opt->longname); 1433 | if(strncmp(argv[i]+2, opt->longname, len) == 0) { 1434 | /* Regular long option. */ 1435 | if(argv[i][2+len] == '\0') { 1436 | /* with no argument provided. */ 1437 | if(!(opt->flags & ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_)) 1438 | ret = callback(opt->id, NULL); 1439 | else 1440 | ret = callback(ACUTEST_CMDLINE_OPTID_MISSINGARG_, argv[i]); 1441 | break; 1442 | } else if(argv[i][2+len] == '=') { 1443 | /* with an argument provided. */ 1444 | if(opt->flags & (ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ | ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_)) { 1445 | ret = callback(opt->id, argv[i]+2+len+1); 1446 | } else { 1447 | snprintf(auxbuf, sizeof(auxbuf), "--%s", opt->longname); 1448 | ret = callback(ACUTEST_CMDLINE_OPTID_BOGUSARG_, auxbuf); 1449 | } 1450 | break; 1451 | } else { 1452 | continue; 1453 | } 1454 | } 1455 | } else if(opt->shortname != '\0' && argv[i][0] == '-') { 1456 | if(argv[i][1] == opt->shortname) { 1457 | /* Regular short option. */ 1458 | if(opt->flags & ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_) { 1459 | if(argv[i][2] != '\0') 1460 | ret = callback(opt->id, argv[i]+2); 1461 | else if(i+1 < argc) 1462 | ret = callback(opt->id, argv[++i]); 1463 | else 1464 | ret = callback(ACUTEST_CMDLINE_OPTID_MISSINGARG_, argv[i]); 1465 | break; 1466 | } else { 1467 | ret = callback(opt->id, NULL); 1468 | 1469 | /* There might be more (argument-less) short options 1470 | * grouped together. */ 1471 | if(ret == 0 && argv[i][2] != '\0') 1472 | ret = acutest_cmdline_handle_short_opt_group_(options, argv[i]+2, callback); 1473 | break; 1474 | } 1475 | } 1476 | } 1477 | } 1478 | 1479 | if(opt->id == 0) { /* still not handled? */ 1480 | if(argv[i][0] != '-') { 1481 | /* Non-option argument. */ 1482 | ret = callback(ACUTEST_CMDLINE_OPTID_NONE_, argv[i]); 1483 | } else { 1484 | /* Unknown option. */ 1485 | char* badoptname = argv[i]; 1486 | 1487 | if(strncmp(badoptname, "--", 2) == 0) { 1488 | /* Strip any argument from the long option. */ 1489 | char* assignment = strchr(badoptname, '='); 1490 | if(assignment != NULL) { 1491 | size_t len = (size_t)(assignment - badoptname); 1492 | if(len > ACUTEST_CMDLINE_AUXBUF_SIZE_) 1493 | len = ACUTEST_CMDLINE_AUXBUF_SIZE_; 1494 | strncpy(auxbuf, badoptname, len); 1495 | auxbuf[len] = '\0'; 1496 | badoptname = auxbuf; 1497 | } 1498 | } 1499 | 1500 | ret = callback(ACUTEST_CMDLINE_OPTID_UNKNOWN_, badoptname); 1501 | } 1502 | } 1503 | } 1504 | 1505 | if(ret != 0) 1506 | return ret; 1507 | i++; 1508 | } 1509 | 1510 | return ret; 1511 | } 1512 | 1513 | static void 1514 | acutest_help_(void) 1515 | { 1516 | printf("Usage: %s [options] [test...]\n", acutest_argv0_); 1517 | printf("\n"); 1518 | printf("Run the specified unit tests; or if the option '--exclude' is used, run all\n"); 1519 | printf("tests in the suite but those listed. By default, if no tests are specified\n"); 1520 | printf("on the command line, all unit tests in the suite are run.\n"); 1521 | printf("\n"); 1522 | printf("Options:\n"); 1523 | printf(" -X, --exclude Execute all unit tests but the listed ones\n"); 1524 | printf(" --exec[=WHEN] If supported, execute unit tests as child processes\n"); 1525 | printf(" (WHEN is one of 'auto', 'always', 'never')\n"); 1526 | printf(" -E, --no-exec Same as --exec=never\n"); 1527 | #if defined ACUTEST_WIN_ 1528 | printf(" -t, --time Measure test duration\n"); 1529 | #elif defined ACUTEST_HAS_POSIX_TIMER_ 1530 | printf(" -t, --time Measure test duration (real time)\n"); 1531 | printf(" --time=TIMER Measure test duration, using given timer\n"); 1532 | printf(" (TIMER is one of 'real', 'cpu')\n"); 1533 | #endif 1534 | printf(" --no-summary Suppress printing of test results summary\n"); 1535 | printf(" --tap Produce TAP-compliant output\n"); 1536 | printf(" (See https://testanything.org/)\n"); 1537 | printf(" -x, --xml-output=FILE Enable XUnit output to the given file\n"); 1538 | printf(" -l, --list List unit tests in the suite and exit\n"); 1539 | printf(" -v, --verbose Make output more verbose\n"); 1540 | printf(" --verbose=LEVEL Set verbose level to LEVEL:\n"); 1541 | printf(" 0 ... Be silent\n"); 1542 | printf(" 1 ... Output one line per test (and summary)\n"); 1543 | printf(" 2 ... As 1 and failed conditions (this is default)\n"); 1544 | printf(" 3 ... As 1 and all conditions (and extended summary)\n"); 1545 | printf(" -q, --quiet Same as --verbose=0\n"); 1546 | printf(" --color[=WHEN] Enable colorized output\n"); 1547 | printf(" (WHEN is one of 'auto', 'always', 'never')\n"); 1548 | printf(" --no-color Same as --color=never\n"); 1549 | printf(" -h, --help Display this help and exit\n"); 1550 | 1551 | if(acutest_list_size_ < 16) { 1552 | printf("\n"); 1553 | acutest_list_names_(); 1554 | } 1555 | } 1556 | 1557 | static const ACUTEST_CMDLINE_OPTION_ acutest_cmdline_options_[] = { 1558 | { 'X', "exclude", 'X', 0 }, 1559 | { 's', "skip", 'X', 0 }, /* kept for compatibility, use --exclude instead */ 1560 | { 0, "exec", 'e', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, 1561 | { 'E', "no-exec", 'E', 0 }, 1562 | #if defined ACUTEST_WIN_ 1563 | { 't', "time", 't', 0 }, 1564 | { 0, "timer", 't', 0 }, /* kept for compatibility */ 1565 | #elif defined ACUTEST_HAS_POSIX_TIMER_ 1566 | { 't', "time", 't', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, 1567 | { 0, "timer", 't', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, /* kept for compatibility */ 1568 | #endif 1569 | { 0, "no-summary", 'S', 0 }, 1570 | { 0, "tap", 'T', 0 }, 1571 | { 'l', "list", 'l', 0 }, 1572 | { 'v', "verbose", 'v', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, 1573 | { 'q', "quiet", 'q', 0 }, 1574 | { 0, "color", 'c', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, 1575 | { 0, "no-color", 'C', 0 }, 1576 | { 'h', "help", 'h', 0 }, 1577 | { 0, "worker", 'w', ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_ }, /* internal */ 1578 | { 'x', "xml-output", 'x', ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_ }, 1579 | { 0, NULL, 0, 0 } 1580 | }; 1581 | 1582 | static int 1583 | acutest_cmdline_callback_(int id, const char* arg) 1584 | { 1585 | switch(id) { 1586 | case 'X': 1587 | acutest_exclude_mode_ = 1; 1588 | break; 1589 | 1590 | case 'e': 1591 | if(arg == NULL || strcmp(arg, "always") == 0) { 1592 | acutest_no_exec_ = 0; 1593 | } else if(strcmp(arg, "never") == 0) { 1594 | acutest_no_exec_ = 1; 1595 | } else if(strcmp(arg, "auto") == 0) { 1596 | /*noop*/ 1597 | } else { 1598 | fprintf(stderr, "%s: Unrecognized argument '%s' for option --exec.\n", acutest_argv0_, arg); 1599 | fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_); 1600 | acutest_exit_(2); 1601 | } 1602 | break; 1603 | 1604 | case 'E': 1605 | acutest_no_exec_ = 1; 1606 | break; 1607 | 1608 | case 't': 1609 | #if defined ACUTEST_WIN_ || defined ACUTEST_HAS_POSIX_TIMER_ 1610 | if(arg == NULL || strcmp(arg, "real") == 0) { 1611 | acutest_timer_ = 1; 1612 | #ifndef ACUTEST_WIN_ 1613 | } else if(strcmp(arg, "cpu") == 0) { 1614 | acutest_timer_ = 2; 1615 | #endif 1616 | } else { 1617 | fprintf(stderr, "%s: Unrecognized argument '%s' for option --time.\n", acutest_argv0_, arg); 1618 | fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_); 1619 | acutest_exit_(2); 1620 | } 1621 | #endif 1622 | break; 1623 | 1624 | case 'S': 1625 | acutest_no_summary_ = 1; 1626 | break; 1627 | 1628 | case 'T': 1629 | acutest_tap_ = 1; 1630 | break; 1631 | 1632 | case 'l': 1633 | acutest_list_names_(); 1634 | acutest_exit_(0); 1635 | break; 1636 | 1637 | case 'v': 1638 | acutest_verbose_level_ = (arg != NULL ? atoi(arg) : acutest_verbose_level_+1); 1639 | break; 1640 | 1641 | case 'q': 1642 | acutest_verbose_level_ = 0; 1643 | break; 1644 | 1645 | case 'c': 1646 | if(arg == NULL || strcmp(arg, "always") == 0) { 1647 | acutest_colorize_ = 1; 1648 | } else if(strcmp(arg, "never") == 0) { 1649 | acutest_colorize_ = 0; 1650 | } else if(strcmp(arg, "auto") == 0) { 1651 | /*noop*/ 1652 | } else { 1653 | fprintf(stderr, "%s: Unrecognized argument '%s' for option --color.\n", acutest_argv0_, arg); 1654 | fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_); 1655 | acutest_exit_(2); 1656 | } 1657 | break; 1658 | 1659 | case 'C': 1660 | acutest_colorize_ = 0; 1661 | break; 1662 | 1663 | case 'h': 1664 | acutest_help_(); 1665 | acutest_exit_(0); 1666 | break; 1667 | 1668 | case 'w': 1669 | acutest_worker_ = 1; 1670 | acutest_worker_index_ = atoi(arg); 1671 | break; 1672 | case 'x': 1673 | acutest_xml_output_ = fopen(arg, "w"); 1674 | if (!acutest_xml_output_) { 1675 | fprintf(stderr, "Unable to open '%s': %s\n", arg, strerror(errno)); 1676 | acutest_exit_(2); 1677 | } 1678 | break; 1679 | 1680 | case 0: 1681 | if(acutest_select_(arg) == 0) { 1682 | fprintf(stderr, "%s: Unrecognized unit test '%s'\n", acutest_argv0_, arg); 1683 | fprintf(stderr, "Try '%s --list' for list of unit tests.\n", acutest_argv0_); 1684 | acutest_exit_(2); 1685 | } 1686 | break; 1687 | 1688 | case ACUTEST_CMDLINE_OPTID_UNKNOWN_: 1689 | fprintf(stderr, "Unrecognized command line option '%s'.\n", arg); 1690 | fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_); 1691 | acutest_exit_(2); 1692 | break; 1693 | 1694 | case ACUTEST_CMDLINE_OPTID_MISSINGARG_: 1695 | fprintf(stderr, "The command line option '%s' requires an argument.\n", arg); 1696 | fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_); 1697 | acutest_exit_(2); 1698 | break; 1699 | 1700 | case ACUTEST_CMDLINE_OPTID_BOGUSARG_: 1701 | fprintf(stderr, "The command line option '%s' does not expect an argument.\n", arg); 1702 | fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_); 1703 | acutest_exit_(2); 1704 | break; 1705 | } 1706 | 1707 | return 0; 1708 | } 1709 | 1710 | static int 1711 | acutest_under_debugger_(void) 1712 | { 1713 | #ifdef ACUTEST_LINUX_ 1714 | /* Scan /proc/self/status for line "TracerPid: [PID]". If such line exists 1715 | * and the PID is non-zero, we're being debugged. */ 1716 | { 1717 | static const int OVERLAP = 32; 1718 | int fd; 1719 | char buf[512]; 1720 | size_t n_read; 1721 | pid_t tracer_pid = 0; 1722 | 1723 | /* Little trick so that we can treat the 1st line the same as any other 1724 | * and detect line start easily. */ 1725 | buf[0] = '\n'; 1726 | n_read = 1; 1727 | 1728 | fd = open("/proc/self/status", O_RDONLY); 1729 | if(fd != -1) { 1730 | while(1) { 1731 | static const char pattern[] = "\nTracerPid:"; 1732 | const char* field; 1733 | 1734 | while(n_read < sizeof(buf) - 1) { 1735 | ssize_t n; 1736 | 1737 | n = read(fd, buf + n_read, sizeof(buf) - 1 - n_read); 1738 | if(n <= 0) 1739 | break; 1740 | n_read += (size_t)n; 1741 | } 1742 | buf[n_read] = '\0'; 1743 | 1744 | field = strstr(buf, pattern); 1745 | if(field != NULL && field < buf + sizeof(buf) - OVERLAP) { 1746 | tracer_pid = (pid_t) atoi(field + sizeof(pattern) - 1); 1747 | break; 1748 | } 1749 | 1750 | if(n_read == sizeof(buf) - 1) { 1751 | /* Move the tail with the potentially incomplete line we're 1752 | * be looking for to the beginning of the buffer. 1753 | * (The OVERLAP must be large enough so the searched line 1754 | * can fit in completely.) */ 1755 | memmove(buf, buf + sizeof(buf) - 1 - OVERLAP, OVERLAP); 1756 | n_read = OVERLAP; 1757 | } else { 1758 | break; 1759 | } 1760 | } 1761 | 1762 | close(fd); 1763 | 1764 | if(tracer_pid != 0) 1765 | return 1; 1766 | } 1767 | } 1768 | #endif 1769 | 1770 | #ifdef ACUTEST_MACOS_ 1771 | /* See https://developer.apple.com/library/archive/qa/qa1361/_index.html */ 1772 | { 1773 | int mib[4]; 1774 | struct kinfo_proc info; 1775 | size_t size; 1776 | 1777 | mib[0] = CTL_KERN; 1778 | mib[1] = KERN_PROC; 1779 | mib[2] = KERN_PROC_PID; 1780 | mib[3] = getpid(); 1781 | 1782 | size = sizeof(info); 1783 | info.kp_proc.p_flag = 0; 1784 | sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); 1785 | 1786 | if(info.kp_proc.p_flag & P_TRACED) 1787 | return 1; 1788 | } 1789 | #endif 1790 | 1791 | #ifdef ACUTEST_WIN_ 1792 | if(IsDebuggerPresent()) 1793 | return 1; 1794 | #endif 1795 | 1796 | #ifdef RUNNING_ON_VALGRIND 1797 | /* We treat Valgrind as a debugger of sorts. 1798 | * (Macro RUNNING_ON_VALGRIND is provided by , if available.) */ 1799 | if(RUNNING_ON_VALGRIND) 1800 | return 1; 1801 | #endif 1802 | 1803 | return 0; 1804 | } 1805 | 1806 | int 1807 | main(int argc, char** argv) 1808 | { 1809 | int i, index; 1810 | int exit_code = 1; 1811 | 1812 | acutest_argv0_ = argv[0]; 1813 | 1814 | #if defined ACUTEST_UNIX_ 1815 | acutest_colorize_ = isatty(STDOUT_FILENO); 1816 | #elif defined ACUTEST_WIN_ 1817 | #if defined _BORLANDC_ 1818 | acutest_colorize_ = isatty(_fileno(stdout)); 1819 | #else 1820 | acutest_colorize_ = _isatty(_fileno(stdout)); 1821 | #endif 1822 | #else 1823 | acutest_colorize_ = 0; 1824 | #endif 1825 | 1826 | /* Count all test units */ 1827 | acutest_list_size_ = 0; 1828 | for(i = 0; acutest_list_[i].func != NULL; i++) 1829 | acutest_list_size_++; 1830 | 1831 | acutest_test_data_ = (struct acutest_test_data_*)calloc(acutest_list_size_, sizeof(struct acutest_test_data_)); 1832 | if(acutest_test_data_ == NULL) { 1833 | fprintf(stderr, "Out of memory.\n"); 1834 | acutest_exit_(2); 1835 | } 1836 | 1837 | /* Parse options */ 1838 | acutest_cmdline_read_(acutest_cmdline_options_, argc, argv, acutest_cmdline_callback_); 1839 | 1840 | /* Initialize the proper timer. */ 1841 | acutest_timer_init_(); 1842 | 1843 | #if defined(ACUTEST_WIN_) 1844 | SetUnhandledExceptionFilter(acutest_seh_exception_filter_); 1845 | #ifdef _MSC_VER 1846 | _set_abort_behavior(0, _WRITE_ABORT_MSG); 1847 | #endif 1848 | #endif 1849 | 1850 | /* Determine what to run. */ 1851 | if(acutest_count_(ACUTEST_STATE_SELECTED) > 0) { 1852 | enum acutest_state_ if_selected; 1853 | enum acutest_state_ if_unselected; 1854 | 1855 | if(!acutest_exclude_mode_) { 1856 | if_selected = ACUTEST_STATE_NEEDTORUN; 1857 | if_unselected = ACUTEST_STATE_EXCLUDED; 1858 | } else { 1859 | if_selected = ACUTEST_STATE_EXCLUDED; 1860 | if_unselected = ACUTEST_STATE_NEEDTORUN; 1861 | } 1862 | 1863 | for(i = 0; acutest_list_[i].func != NULL; i++) { 1864 | if(acutest_test_data_[i].state == ACUTEST_STATE_SELECTED) 1865 | acutest_test_data_[i].state = if_selected; 1866 | else 1867 | acutest_test_data_[i].state = if_unselected; 1868 | } 1869 | } else { 1870 | /* By default, we want to run all tests. */ 1871 | for(i = 0; acutest_list_[i].func != NULL; i++) 1872 | acutest_test_data_[i].state = ACUTEST_STATE_NEEDTORUN; 1873 | } 1874 | 1875 | /* By default, we want to suppress running tests as child processes if we 1876 | * run just one test, or if we're under debugger: Debugging tests is then 1877 | * so much easier. */ 1878 | if(acutest_no_exec_ < 0) { 1879 | if(acutest_count_(ACUTEST_STATE_NEEDTORUN) <= 1 || acutest_under_debugger_()) 1880 | acutest_no_exec_ = 1; 1881 | else 1882 | acutest_no_exec_ = 0; 1883 | } 1884 | 1885 | if(acutest_tap_) { 1886 | /* TAP requires we know test result ("ok", "not ok") before we output 1887 | * anything about the test, and this gets problematic for larger verbose 1888 | * levels. */ 1889 | if(acutest_verbose_level_ > 2) 1890 | acutest_verbose_level_ = 2; 1891 | 1892 | /* TAP harness should provide some summary. */ 1893 | acutest_no_summary_ = 1; 1894 | 1895 | if(!acutest_worker_) 1896 | printf("1..%d\n", acutest_count_(ACUTEST_STATE_NEEDTORUN)); 1897 | } 1898 | 1899 | index = acutest_worker_index_; 1900 | for(i = 0; acutest_list_[i].func != NULL; i++) { 1901 | if(acutest_test_data_[i].state == ACUTEST_STATE_NEEDTORUN) 1902 | acutest_run_(´st_list_[i], index++, i); 1903 | } 1904 | 1905 | /* Write a summary */ 1906 | if(!acutest_no_summary_ && acutest_verbose_level_ >= 1) { 1907 | int n_run, n_success, n_failed ; 1908 | 1909 | n_run = acutest_list_size_ - acutest_count_(ACUTEST_STATE_EXCLUDED); 1910 | n_success = acutest_count_(ACUTEST_STATE_SUCCESS); 1911 | n_failed = acutest_count_(ACUTEST_STATE_FAILED); 1912 | 1913 | if(acutest_verbose_level_ >= 3) { 1914 | acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Summary:\n"); 1915 | 1916 | printf(" Count of run unit tests: %4d\n", n_run); 1917 | printf(" Count of successful unit tests: %4d\n", n_success); 1918 | printf(" Count of failed unit tests: %4d\n", n_failed); 1919 | } 1920 | 1921 | if(n_failed == 0) { 1922 | acutest_colored_printf_(ACUTEST_COLOR_GREEN_INTENSIVE_, "SUCCESS:"); 1923 | printf(" No unit tests have failed.\n"); 1924 | } else { 1925 | acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED:"); 1926 | printf(" %d of %d unit tests %s failed.\n", 1927 | n_failed, n_run, (n_failed == 1) ? "has" : "have"); 1928 | } 1929 | 1930 | if(acutest_verbose_level_ >= 3) 1931 | printf("\n"); 1932 | } 1933 | 1934 | if (acutest_xml_output_) { 1935 | const char* suite_name = acutest_basename_(argv[0]); 1936 | fprintf(acutest_xml_output_, "\n"); 1937 | fprintf(acutest_xml_output_, "\n", 1938 | suite_name, 1939 | (int)acutest_list_size_, 1940 | acutest_count_(ACUTEST_STATE_FAILED), 1941 | acutest_count_(ACUTEST_STATE_SKIPPED) + acutest_count_(ACUTEST_STATE_EXCLUDED)); 1942 | for(i = 0; acutest_list_[i].func != NULL; i++) { 1943 | struct acutest_test_data_ *details = ´st_test_data_[i]; 1944 | const char* str_state; 1945 | fprintf(acutest_xml_output_, " \n", acutest_list_[i].name, details->duration); 1946 | 1947 | switch(details->state) { 1948 | case ACUTEST_STATE_SUCCESS: str_state = NULL; break; 1949 | case ACUTEST_STATE_EXCLUDED: /* Fall through. */ 1950 | case ACUTEST_STATE_SKIPPED: str_state = ""; break; 1951 | case ACUTEST_STATE_FAILED: /* Fall through. */ 1952 | default: str_state = ""; break; 1953 | } 1954 | 1955 | if(str_state != NULL) 1956 | fprintf(acutest_xml_output_, " %s\n", str_state); 1957 | fprintf(acutest_xml_output_, " \n"); 1958 | } 1959 | fprintf(acutest_xml_output_, "\n"); 1960 | fclose(acutest_xml_output_); 1961 | } 1962 | 1963 | if(acutest_worker_ && acutest_count_(ACUTEST_STATE_EXCLUDED)+1 == acutest_list_size_) { 1964 | /* If we are the child process, we need to propagate the test state 1965 | * without any moderation. */ 1966 | for(i = 0; acutest_list_[i].func != NULL; i++) { 1967 | if(acutest_test_data_[i].state != ACUTEST_STATE_EXCLUDED) { 1968 | exit_code = (int) acutest_test_data_[i].state; 1969 | break; 1970 | } 1971 | } 1972 | } else { 1973 | if(acutest_count_(ACUTEST_STATE_FAILED) > 0) 1974 | exit_code = 1; 1975 | else 1976 | exit_code = 0; 1977 | } 1978 | 1979 | acutest_cleanup_(); 1980 | return exit_code; 1981 | } 1982 | 1983 | 1984 | #endif /* #ifndef TEST_NO_MAIN */ 1985 | 1986 | #ifdef _MSC_VER 1987 | #pragma warning(pop) 1988 | #endif 1989 | 1990 | #ifdef __cplusplus 1991 | } /* extern "C" */ 1992 | #endif 1993 | 1994 | #endif /* #ifndef ACUTEST_H */ 1995 | --------------------------------------------------------------------------------