Git fork

t/unit-tests: update clar to fcbed04

Update clar to fcbed04 (Merge pull request #123 from
pks-gitlab/pks-sandbox-ubsan, 2025-09-10). The most significant changes
since the last version include:

- Fixed platform support for HP-UX.

- Fixes for how clar handles the `-q` flag.

- A couple of leak fixes for reported clar errors.

- A new `cl_invoke()` function that retains line information.

- New infrastructure to create temporary directories.

- Improved printing of error messages so that all lines are now
properly indented.

- Proper selftests for the clar.

Most of these changes are somewhat irrelevant to us, but neither do we
have to adjust to any of these changes, either. What _is_ interesting to
us though is especially the fixed support for HP-UX, and eventually we
may also want to use `cl_invoke()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
e7f04f65 c44beea4

+1311 -238
+17 -1
t/unit-tests/clar/.github/workflows/ci.yml
··· 13 13 platform: 14 14 - os: ubuntu-latest 15 15 generator: Unix Makefiles 16 + - os: ubuntu-latest 17 + generator: Unix Makefiles 18 + env: 19 + CC: "clang" 20 + CFLAGS: "-fsanitize=leak" 16 21 - os: macos-latest 17 22 generator: Unix Makefiles 18 23 - os: windows-latest ··· 21 26 generator: MSYS Makefiles 22 27 - os: windows-latest 23 28 generator: MinGW Makefiles 29 + fail-fast: false 24 30 25 31 runs-on: ${{ matrix.platform.os }} 26 32 33 + env: 34 + CC: ${{matrix.platform.env.CC}} 35 + CFLAGS: ${{matrix.platform.env.CFLAGS}} 36 + 27 37 steps: 28 38 - name: Check out 29 39 uses: actions/checkout@v2 30 40 - name: Build 41 + shell: bash 31 42 run: | 32 43 mkdir build 33 44 cd build 34 45 cmake .. -G "${{matrix.platform.generator}}" 35 - cmake --build . 46 + cmake --build . --verbose 47 + - name: Test 48 + shell: bash 49 + run: | 50 + cd build 51 + CTEST_OUTPUT_ON_FAILURE=1 ctest --build-config Debug
+12 -1
t/unit-tests/clar/CMakeLists.txt
··· 1 + include(CheckFunctionExists) 2 + 1 3 cmake_minimum_required(VERSION 3.16..3.29) 2 4 3 5 project(clar LANGUAGES C) 4 6 5 - option(BUILD_TESTS "Build test executable" ON) 7 + option(BUILD_EXAMPLE "Build the example." ON) 8 + 9 + check_function_exists(realpath CLAR_HAS_REALPATH) 10 + if(CLAR_HAS_REALPATH) 11 + add_compile_definitions(-DCLAR_HAS_REALPATH) 12 + endif() 6 13 7 14 add_library(clar INTERFACE) 8 15 target_sources(clar INTERFACE ··· 24 31 include(CTest) 25 32 if(BUILD_TESTING) 26 33 add_subdirectory(test) 34 + endif() 35 + 36 + if(BUILD_EXAMPLE) 37 + add_subdirectory(example) 27 38 endif() 28 39 endif()
+20 -17
t/unit-tests/clar/README.md
··· 26 26 ~~~~ sh 27 27 $ mkdir tests 28 28 $ cp -r $CLAR_ROOT/clar* tests 29 - $ cp $CLAR_ROOT/test/clar_test.h tests 30 - $ cp $CLAR_ROOT/test/main.c.sample tests/main.c 29 + $ cp $CLAR_ROOT/example/*.c tests 31 30 ~~~~ 32 31 33 32 - **One: Write some tests** ··· 147 146 148 147 1. copy the Clar boilerplate to your test directory 149 148 2. copy (and probably modify) the sample `main.c` (from 150 - `$CLAR_PATH/test/main.c.sample`) 149 + `$CLAR_PATH/example/main.c`) 151 150 3. run the Clar mixer (a.k.a. `generate.py`) to scan your test directory and 152 151 write out the test suite metadata. 153 152 4. compile your test files and the Clar boilerplate into a single test ··· 159 158 the `clar.c` and `clar.h` files, plus the code in the `clar/` subdirectory. 160 159 You should not need to edit these files. 161 160 162 - The sample `main.c` (i.e. `$CLAR_PATH/test/main.c.sample`) file invokes 161 + The sample `main.c` (i.e. `$CLAR_PATH/example/main.c`) file invokes 163 162 `clar_test(argc, argv)` to run the tests. Usually, you will edit this file 164 163 to perform any framework specific initialization and teardown that you need. 165 164 ··· 251 250 252 251 - `cl_fixture(const char *)`: Gets the full path to a fixture file. 253 252 254 - Please do note that these methods are *always* available whilst running a 255 - test, even when calling auxiliary/static functions inside the same file. 253 + ### Auxiliary / helper functions 256 254 257 - It's strongly encouraged to perform test assertions in auxiliary methods, 258 - instead of returning error values. This is considered good Clar style. 255 + The clar API is always available while running a test, even when calling 256 + "auxiliary" (helper) functions. 257 + 258 + You're encouraged to perform test assertions in those auxiliary 259 + methods, instead of returning error values. This is considered good 260 + Clar style. _However_, when you do this, you need to call `cl_invoke` 261 + to preserve the current state; this ensures that failures are reported 262 + as coming from the actual test, instead of the auxiliary method. 259 263 260 264 Style Example: 261 265 ··· 310 314 311 315 void test_example__a_test_with_auxiliary_methods(void) 312 316 { 313 - check_string("foo"); 314 - check_string("bar"); 317 + cl_invoke(check_string("foo")); 318 + cl_invoke(check_string("bar")); 315 319 } 316 320 ~~~~ 317 321 318 322 About Clar 319 323 ========== 320 324 321 - Clar has been written from scratch by [Vicent Martí](https://github.com/vmg), 322 - to replace the old testing framework in [libgit2][libgit2]. 323 - 324 - Do you know what languages are *in* on the SF startup scene? Node.js *and* 325 - Latin. Follow [@vmg](https://www.twitter.com/vmg) on Twitter to 326 - receive more lessons on word etymology. You can be hip too. 327 - 325 + Clar was originally written by [Vicent Martí](https://github.com/vmg), 326 + to replace the old testing framework in [libgit2][libgit2]. It is 327 + currently maintained by [Edward Thomson](https://github.com/ethomson), 328 + and used by the [libgit2][libgit2] and [git][git] projects, amongst 329 + others. 328 330 329 331 [libgit2]: https://github.com/libgit2/libgit2 332 + [git]: https://github.com/git/git
+108 -41
t/unit-tests/clar/clar.c
··· 79 79 # else 80 80 # define p_snprintf snprintf 81 81 # endif 82 + 83 + # define localtime_r(timer, buf) (localtime_s(buf, timer) == 0 ? buf : NULL) 82 84 #else 83 85 # include <sys/wait.h> /* waitpid(2) */ 84 86 # include <unistd.h> ··· 150 152 151 153 enum cl_output_format output_format; 152 154 153 - int report_errors_only; 154 155 int exit_on_error; 155 156 int verbosity; 156 157 ··· 163 164 164 165 struct clar_report *reports; 165 166 struct clar_report *last_report; 167 + 168 + const char *invoke_file; 169 + const char *invoke_func; 170 + size_t invoke_line; 166 171 167 172 void (*local_cleanup)(void *); 168 173 void *local_cleanup_payload; ··· 199 204 static void clar_print_onabort(const char *msg, ...); 200 205 201 206 /* From clar_sandbox.c */ 202 - static void clar_unsandbox(void); 203 - static void clar_sandbox(void); 207 + static void clar_tempdir_init(void); 208 + static void clar_tempdir_shutdown(void); 209 + static int clar_sandbox_create(const char *suite_name, const char *test_name); 210 + static int clar_sandbox_cleanup(void); 204 211 205 212 /* From summary.h */ 206 213 static struct clar_summary *clar_summary_init(const char *filename); ··· 304 311 305 312 CL_TRACE(CL_TRACE__TEST__BEGIN); 306 313 314 + clar_sandbox_create(suite->name, test->name); 315 + 307 316 _clar.last_report->start = time(NULL); 308 317 clar_time_now(&start); 309 318 ··· 328 337 if (_clar.local_cleanup != NULL) 329 338 _clar.local_cleanup(_clar.local_cleanup_payload); 330 339 340 + clar__clear_invokepoint(); 341 + 331 342 if (cleanup->ptr != NULL) 332 343 cleanup->ptr(); 344 + 345 + clar_sandbox_cleanup(); 333 346 334 347 CL_TRACE(CL_TRACE__TEST__END); 335 348 ··· 339 352 _clar.local_cleanup = NULL; 340 353 _clar.local_cleanup_payload = NULL; 341 354 342 - if (_clar.report_errors_only) { 343 - clar_report_errors(_clar.last_report); 344 - } else { 345 - clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status); 346 - } 355 + clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status); 347 356 } 348 357 349 358 static void ··· 360 369 if (_clar.exit_on_error && _clar.total_errors) 361 370 return; 362 371 363 - if (!_clar.report_errors_only) 364 - clar_print_onsuite(suite->name, ++_clar.suites_ran); 372 + clar_print_onsuite(suite->name, ++_clar.suites_ran); 365 373 366 374 _clar.active_suite = suite->name; 367 375 _clar.active_test = NULL; ··· 428 436 printf(" -iname Include the suite with `name`\n"); 429 437 printf(" -xname Exclude the suite with `name`\n"); 430 438 printf(" -v Increase verbosity (show suite names)\n"); 431 - printf(" -q Only report tests that had an error\n"); 439 + printf(" -q Decrease verbosity, inverse to -v\n"); 432 440 printf(" -Q Quit as soon as a test fails\n"); 433 441 printf(" -t Display results in tap format\n"); 434 442 printf(" -l Print suite names\n"); 435 443 printf(" -r[filename] Write summary file (to the optional filename)\n"); 436 - exit(-1); 444 + exit(1); 437 445 } 438 446 439 447 static void ··· 441 449 { 442 450 int i; 443 451 444 - /* Verify options before execute */ 445 452 for (i = 1; i < argc; ++i) { 446 453 char *argument = argv[i]; 447 454 448 - if (argument[0] != '-' || argument[1] == '\0' 449 - || strchr("sixvqQtlr", argument[1]) == NULL) { 455 + if (argument[0] != '-' || argument[1] == '\0') 450 456 clar_usage(argv[0]); 451 - } 452 - } 453 - 454 - for (i = 1; i < argc; ++i) { 455 - char *argument = argv[i]; 456 457 457 458 switch (argument[1]) { 458 459 case 's': ··· 465 466 argument += offset; 466 467 arglen = strlen(argument); 467 468 468 - if (arglen == 0) 469 - clar_usage(argv[0]); 469 + if (arglen == 0) { 470 + if (i + 1 == argc) 471 + clar_usage(argv[0]); 472 + 473 + argument = argv[++i]; 474 + arglen = strlen(argument); 475 + } 470 476 471 477 for (j = 0; j < _clar_suite_count; ++j) { 472 478 suitelen = strlen(_clar_suites[j].name); ··· 482 488 continue; 483 489 484 490 ++found; 485 - 486 - if (!exact) 487 - _clar.verbosity = MAX(_clar.verbosity, 1); 488 491 489 492 switch (action) { 490 493 case 's': { ··· 517 520 518 521 if (!found) 519 522 clar_abort("No suite matching '%s' found.\n", argument); 523 + 520 524 break; 521 525 } 522 526 523 527 case 'q': 524 - _clar.report_errors_only = 1; 528 + if (argument[2] != '\0') 529 + clar_usage(argv[0]); 530 + 531 + _clar.verbosity--; 525 532 break; 526 533 527 534 case 'Q': 535 + if (argument[2] != '\0') 536 + clar_usage(argv[0]); 537 + 528 538 _clar.exit_on_error = 1; 529 539 break; 530 540 531 541 case 't': 542 + if (argument[2] != '\0') 543 + clar_usage(argv[0]); 544 + 532 545 _clar.output_format = CL_OUTPUT_TAP; 533 546 break; 534 547 535 548 case 'l': { 536 549 size_t j; 550 + 551 + if (argument[2] != '\0') 552 + clar_usage(argv[0]); 553 + 537 554 printf("Test suites (use -s<name> to run just one):\n"); 538 555 for (j = 0; j < _clar_suite_count; ++j) 539 556 printf(" %3d: %s\n", (int)j, _clar_suites[j].name); ··· 542 559 } 543 560 544 561 case 'v': 562 + if (argument[2] != '\0') 563 + clar_usage(argv[0]); 564 + 545 565 _clar.verbosity++; 546 566 break; 547 567 548 568 case 'r': 549 569 _clar.write_summary = 1; 550 570 free(_clar.summary_filename); 571 + 551 572 if (*(argument + 2)) { 552 573 if ((_clar.summary_filename = strdup(argument + 2)) == NULL) 553 574 clar_abort("Failed to allocate summary filename.\n"); 554 575 } else { 555 576 _clar.summary_filename = NULL; 556 577 } 578 + 557 579 break; 558 580 559 581 default: 560 - clar_abort("Unexpected commandline argument '%s'.\n", 561 - argument[1]); 582 + clar_usage(argv[0]); 562 583 } 563 584 } 564 585 } ··· 591 612 if (_clar.write_summary) 592 613 _clar.summary = clar_summary_init(_clar.summary_filename); 593 614 594 - clar_sandbox(); 615 + clar_tempdir_init(); 595 616 } 596 617 597 618 int ··· 623 644 _clar.total_errors 624 645 ); 625 646 626 - clar_unsandbox(); 647 + clar_tempdir_shutdown(); 627 648 628 649 if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0) 629 650 clar_abort("Failed to write the summary file '%s: %s.\n", ··· 635 656 } 636 657 637 658 for (report = _clar.reports; report; report = report_next) { 659 + struct clar_error *error, *error_next; 660 + 661 + for (error = report->errors; error; error = error_next) { 662 + free(error->description); 663 + error_next = error->next; 664 + free(error); 665 + } 666 + 638 667 report_next = report->next; 639 668 free(report); 640 669 } ··· 660 689 clar_print_onabort( 661 690 "Fatal error: a cleanup method raised an exception.\n"); 662 691 clar_report_errors(_clar.last_report); 663 - exit(-1); 692 + exit(1); 664 693 } 665 694 666 695 CL_TRACE(CL_TRACE__TEST__LONGJMP); ··· 695 724 696 725 _clar.last_report->last_error = error; 697 726 698 - error->file = file; 699 - error->function = function; 700 - error->line_number = line; 727 + error->file = _clar.invoke_file ? _clar.invoke_file : file; 728 + error->function = _clar.invoke_func ? _clar.invoke_func : function; 729 + error->line_number = _clar.invoke_line ? _clar.invoke_line : line; 701 730 error->error_msg = error_msg; 702 731 703 732 if (description != NULL && ··· 754 783 p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)", 755 784 s1, s2, pos); 756 785 } else { 757 - p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2); 786 + const char *q1 = s1 ? "'" : ""; 787 + const char *q2 = s2 ? "'" : ""; 788 + s1 = s1 ? s1 : "NULL"; 789 + s2 = s2 ? s2 : "NULL"; 790 + p_snprintf(buf, sizeof(buf), "%s%s%s != %s%s%s", 791 + q1, s1, q1, q2, s2, q2); 758 792 } 759 793 } 760 794 } ··· 767 801 if (!is_equal) { 768 802 if (s1 && s2) { 769 803 int pos; 770 - for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos) 804 + for (pos = 0; pos < len && s1[pos] == s2[pos]; ++pos) 771 805 /* find differing byte offset */; 772 806 p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)", 773 807 len, s1, len, s2, pos); 774 808 } else { 775 - p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2); 809 + const char *q1 = s1 ? "'" : ""; 810 + const char *q2 = s2 ? "'" : ""; 811 + s1 = s1 ? s1 : "NULL"; 812 + s2 = s2 ? s2 : "NULL"; 813 + p_snprintf(buf, sizeof(buf), "%s%.*s%s != %s%.*s%s", 814 + q1, len, s1, q1, q2, len, s2, q2); 776 815 } 777 816 } 778 817 } ··· 790 829 p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)", 791 830 wcs1, wcs2, pos); 792 831 } else { 793 - p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2); 832 + const char *q1 = wcs1 ? "'" : ""; 833 + const char *q2 = wcs2 ? "'" : ""; 834 + wcs1 = wcs1 ? wcs1 : L"NULL"; 835 + wcs2 = wcs2 ? wcs2 : L"NULL"; 836 + p_snprintf(buf, sizeof(buf), "%s%ls%s != %s%ls%s", 837 + q1, wcs1, q1, q2, wcs2, q2); 794 838 } 795 839 } 796 840 } ··· 803 847 if (!is_equal) { 804 848 if (wcs1 && wcs2) { 805 849 int pos; 806 - for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos) 850 + for (pos = 0; pos < len && wcs1[pos] == wcs2[pos]; ++pos) 807 851 /* find differing byte offset */; 808 852 p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)", 809 853 len, wcs1, len, wcs2, pos); 810 854 } else { 811 - p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2); 855 + const char *q1 = wcs1 ? "'" : ""; 856 + const char *q2 = wcs2 ? "'" : ""; 857 + wcs1 = wcs1 ? wcs1 : L"NULL"; 858 + wcs2 = wcs2 ? wcs2 : L"NULL"; 859 + p_snprintf(buf, sizeof(buf), "%s%.*ls%s != %s%.*ls%s", 860 + q1, len, wcs1, q1, q2, len, wcs2, q2); 812 861 } 813 862 } 814 863 } ··· 826 875 void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *); 827 876 is_equal = (p1 == p2); 828 877 if (!is_equal) 829 - p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2); 878 + p_snprintf(buf, sizeof(buf), "0x%"PRIxPTR" != 0x%"PRIxPTR, 879 + (uintptr_t)p1, (uintptr_t)p2); 830 880 } 831 881 else { 832 882 int i1 = va_arg(args, int), i2 = va_arg(args, int); ··· 848 898 { 849 899 _clar.local_cleanup = cleanup; 850 900 _clar.local_cleanup_payload = opaque; 901 + } 902 + 903 + void clar__set_invokepoint( 904 + const char *file, 905 + const char *func, 906 + size_t line) 907 + { 908 + _clar.invoke_file = file; 909 + _clar.invoke_func = func; 910 + _clar.invoke_line = line; 911 + } 912 + 913 + void clar__clear_invokepoint(void) 914 + { 915 + _clar.invoke_file = NULL; 916 + _clar.invoke_func = NULL; 917 + _clar.invoke_line = 0; 851 918 } 852 919 853 920 #include "clar/sandbox.h"
+62 -21
t/unit-tests/clar/clar.h
··· 8 8 #define __CLAR_TEST_H__ 9 9 10 10 #include <stdlib.h> 11 + #include <limits.h> 12 + 13 + #if defined(_WIN32) && defined(CLAR_WIN32_LONGPATHS) 14 + # define CLAR_MAX_PATH 4096 15 + #elif defined(_WIN32) 16 + # define CLAR_MAX_PATH MAX_PATH 17 + #else 18 + # define CLAR_MAX_PATH PATH_MAX 19 + #endif 20 + 21 + #ifndef CLAR_SELFTEST 22 + # define CLAR_CURRENT_FILE __FILE__ 23 + # define CLAR_CURRENT_LINE __LINE__ 24 + # define CLAR_CURRENT_FUNC __func__ 25 + #else 26 + # define CLAR_CURRENT_FILE "file" 27 + # define CLAR_CURRENT_LINE 42 28 + # define CLAR_CURRENT_FUNC "func" 29 + #endif 11 30 12 31 enum cl_test_status { 13 32 CL_TEST_OK, ··· 30 49 int clar_test(int argc, char *argv[]); 31 50 32 51 const char *clar_sandbox_path(void); 52 + const char *clar_tempdir_path(void); 33 53 34 54 void cl_set_cleanup(void (*cleanup)(void *), void *opaque); 35 55 void cl_fs_cleanup(void); ··· 84 104 #endif 85 105 86 106 /** 107 + * Invoke a helper function, which itself will use `cl_assert` 108 + * constructs. This will preserve the stack information of the 109 + * current call point, so that function name and line number 110 + * information is shown from the line of the test, instead of 111 + * the helper function. 112 + */ 113 + #define cl_invoke(expr) \ 114 + do { \ 115 + clar__set_invokepoint(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE); \ 116 + expr; \ 117 + clar__clear_invokepoint(); \ 118 + } while(0) 119 + 120 + /** 87 121 * Assertion macros with explicit error message 88 122 */ 89 - #define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 1) 90 - #define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 1) 91 - #define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 1) 123 + #define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Function call failed: " #expr, desc, 1) 124 + #define cl_must_fail_(expr, desc) clar__assert((expr) < 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expected function call to fail: " #expr, desc, 1) 125 + #define cl_assert_(expr, desc) clar__assert((expr) != 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expression is not true: " #expr, desc, 1) 92 126 93 127 /** 94 128 * Check macros with explicit error message 95 129 */ 96 - #define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 0) 97 - #define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 0) 98 - #define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 0) 130 + #define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Function call failed: " #expr, desc, 0) 131 + #define cl_check_fail_(expr, desc) clar__assert((expr) < 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expected function call to fail: " #expr, desc, 0) 132 + #define cl_check_(expr, desc) clar__assert((expr) != 0, CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Expression is not true: " #expr, desc, 0) 99 133 100 134 /** 101 135 * Assertion macros with no error message ··· 114 148 /** 115 149 * Forced failure/warning 116 150 */ 117 - #define cl_fail(desc) clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1) 118 - #define cl_warning(desc) clar__fail(__FILE__, __func__, __LINE__, "Warning during test execution:", desc, 0) 151 + #define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1) 152 + #define cl_warning(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Warning during test execution:", desc, 0) 119 153 120 154 #define cl_skip() clar__skip() 121 155 122 156 /** 123 157 * Typed assertion macros 124 158 */ 125 - #define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2)) 126 - #define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2)) 159 + #define cl_assert_equal_s(s1,s2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2)) 160 + #define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2)) 127 161 128 - #define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2)) 129 - #define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2)) 162 + #define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2)) 163 + #define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2)) 130 164 131 - #define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len)) 132 - #define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len)) 165 + #define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len)) 166 + #define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len)) 133 167 134 - #define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len)) 135 - #define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len)) 168 + #define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len)) 169 + #define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len)) 136 170 137 - #define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) 138 - #define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2)) 139 - #define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2)) 171 + #define cl_assert_equal_i(i1,i2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) 172 + #define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2)) 173 + #define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2)) 140 174 141 - #define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__func__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0)) 175 + #define cl_assert_equal_b(b1,b2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0)) 142 176 143 - #define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__func__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2)) 177 + #define cl_assert_equal_p(p1,p2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2)) 144 178 145 179 void clar__skip(void); 146 180 ··· 169 203 int should_abort, 170 204 const char *fmt, 171 205 ...); 206 + 207 + void clar__set_invokepoint( 208 + const char *file, 209 + const char *func, 210 + size_t line); 211 + 212 + void clar__clear_invokepoint(void); 172 213 173 214 #endif
+3 -3
t/unit-tests/clar/clar/fixtures.h
··· 2 2 static const char * 3 3 fixture_path(const char *base, const char *fixture_name) 4 4 { 5 - static char _path[4096]; 5 + static char _path[CLAR_MAX_PATH]; 6 6 size_t root_len; 7 7 8 8 root_len = strlen(base); ··· 28 28 29 29 void cl_fixture_sandbox(const char *fixture_name) 30 30 { 31 - fs_copy(cl_fixture(fixture_name), _clar_path); 31 + fs_copy(cl_fixture(fixture_name), clar_sandbox_path()); 32 32 } 33 33 34 34 const char *cl_fixture_basename(const char *fixture_name) ··· 45 45 46 46 void cl_fixture_cleanup(const char *fixture_name) 47 47 { 48 - fs_rm(fixture_path(_clar_path, cl_fixture_basename(fixture_name))); 48 + fs_rm(fixture_path(clar_sandbox_path(), cl_fixture_basename(fixture_name))); 49 49 } 50 50 #endif
+14 -15
t/unit-tests/clar/clar/fs.h
··· 8 8 9 9 #ifdef _WIN32 10 10 11 - #ifdef CLAR_WIN32_LONGPATHS 12 - # define CLAR_MAX_PATH 4096 13 - #else 14 - # define CLAR_MAX_PATH MAX_PATH 15 - #endif 16 - 17 11 #define RM_RETRY_COUNT 5 18 12 #define RM_RETRY_DELAY 10 19 13 ··· 296 290 cl_fs_cleanup(void) 297 291 { 298 292 #ifdef CLAR_FIXTURE_PATH 299 - fs_rm(fixture_path(_clar_path, "*")); 293 + fs_rm(fixture_path(clar_tempdir_path(), "*")); 300 294 #else 301 295 ((void)fs_copy); /* unused */ 302 296 #endif ··· 371 365 fs_copydir_helper(const char *source, const char *dest, int dest_mode) 372 366 { 373 367 DIR *source_dir; 374 - struct dirent *d; 375 368 376 369 mkdir(dest, dest_mode); 377 370 378 371 cl_assert_(source_dir = opendir(source), "Could not open source dir"); 379 - for (;;) { 372 + while (1) { 373 + struct dirent *d; 380 374 char *child; 381 375 382 376 errno = 0; 383 - if ((d = readdir(source_dir)) == NULL) 377 + d = readdir(source_dir); 378 + if (!d) 384 379 break; 380 + 385 381 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 386 382 continue; 387 383 ··· 479 475 fs_rmdir_helper(const char *path) 480 476 { 481 477 DIR *dir; 482 - struct dirent *d; 483 478 484 479 cl_assert_(dir = opendir(path), "Could not open dir"); 485 - for (;;) { 480 + 481 + while (1) { 482 + struct dirent *d; 486 483 char *child; 487 484 488 485 errno = 0; 489 - if ((d = readdir(dir)) == NULL) 486 + d = readdir(dir); 487 + if (!d) 490 488 break; 489 + 491 490 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 492 491 continue; 493 492 ··· 524 523 void 525 524 cl_fs_cleanup(void) 526 525 { 527 - clar_unsandbox(); 528 - clar_sandbox(); 526 + clar_tempdir_shutdown(); 527 + clar_tempdir_init(); 529 528 } 530 529 #endif
+45 -15
t/unit-tests/clar/clar/print.h
··· 3 3 static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names) 4 4 { 5 5 (void)test_count; 6 + 7 + if (_clar.verbosity < 0) 8 + return; 9 + 6 10 printf("Loaded %d suites: %s\n", (int)suite_count, suite_names); 7 11 printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n"); 8 12 } ··· 13 17 (void)suite_count; 14 18 (void)error_count; 15 19 16 - printf("\n\n"); 20 + if (_clar.verbosity >= 0) 21 + printf("\n\n"); 17 22 clar_report_all(); 18 23 } 19 24 25 + 26 + static void clar_print_indented(const char *str, int indent) 27 + { 28 + const char *bol, *eol; 29 + 30 + for (bol = str; *bol; bol = eol) { 31 + eol = strchr(bol, '\n'); 32 + if (eol) 33 + eol++; 34 + else 35 + eol = bol + strlen(bol); 36 + printf("%*s%.*s", indent, "", (int)(eol - bol), bol); 37 + } 38 + putc('\n', stdout); 39 + } 40 + 20 41 static void clar_print_clap_error(int num, const struct clar_report *report, const struct clar_error *error) 21 42 { 22 43 printf(" %d) Failure:\n", num); ··· 27 48 error->file, 28 49 error->line_number); 29 50 30 - printf(" %s\n", error->error_msg); 51 + clar_print_indented(error->error_msg, 2); 31 52 32 53 if (error->description != NULL) 33 - printf(" %s\n", error->description); 54 + clar_print_indented(error->description, 2); 34 55 35 56 printf("\n"); 36 57 fflush(stdout); ··· 40 61 { 41 62 (void)test_name; 42 63 (void)test_number; 64 + 65 + if (_clar.verbosity < 0) 66 + return; 43 67 44 68 if (_clar.verbosity > 1) { 45 69 printf("%s::%s: ", suite_name, test_name); ··· 47 71 switch (status) { 48 72 case CL_TEST_OK: printf("ok\n"); break; 49 73 case CL_TEST_FAILURE: printf("fail\n"); break; 50 - case CL_TEST_SKIP: printf("skipped"); break; 51 - case CL_TEST_NOTRUN: printf("notrun"); break; 74 + case CL_TEST_SKIP: printf("skipped\n"); break; 75 + case CL_TEST_NOTRUN: printf("notrun\n"); break; 52 76 } 53 77 } else { 54 78 switch (status) { ··· 64 88 65 89 static void clar_print_clap_onsuite(const char *suite_name, int suite_index) 66 90 { 91 + if (_clar.verbosity < 0) 92 + return; 67 93 if (_clar.verbosity == 1) 68 94 printf("\n%s", suite_name); 69 95 ··· 127 153 case CL_TEST_FAILURE: 128 154 printf("not ok %d - %s::%s\n", test_number, suite_name, test_name); 129 155 130 - printf(" ---\n"); 131 - printf(" reason: |\n"); 132 - printf(" %s\n", error->error_msg); 156 + if (_clar.verbosity >= 0) { 157 + printf(" ---\n"); 158 + printf(" reason: |\n"); 159 + clar_print_indented(error->error_msg, 6); 133 160 134 - if (error->description) 135 - printf(" %s\n", error->description); 161 + if (error->description) 162 + clar_print_indented(error->description, 6); 136 163 137 - printf(" at:\n"); 138 - printf(" file: '"); print_escaped(error->file); printf("'\n"); 139 - printf(" line: %" PRIuMAX "\n", error->line_number); 140 - printf(" function: '%s'\n", error->function); 141 - printf(" ---\n"); 164 + printf(" at:\n"); 165 + printf(" file: '"); print_escaped(error->file); printf("'\n"); 166 + printf(" line: %" PRIuMAX "\n", error->line_number); 167 + printf(" function: '%s'\n", error->function); 168 + printf(" ---\n"); 169 + } 142 170 143 171 break; 144 172 case CL_TEST_SKIP: ··· 152 180 153 181 static void clar_print_tap_onsuite(const char *suite_name, int suite_index) 154 182 { 183 + if (_clar.verbosity < 0) 184 + return; 155 185 printf("# start of suite %d: %s\n", suite_index, suite_name); 156 186 } 157 187
+179 -47
t/unit-tests/clar/clar/sandbox.h
··· 2 2 #include <sys/syslimits.h> 3 3 #endif 4 4 5 - static char _clar_path[4096 + 1]; 5 + /* 6 + * The tempdir is the temporary directory for the entirety of the clar 7 + * process execution. The sandbox is an individual temporary directory 8 + * for the execution of an individual test. Sandboxes are deleted 9 + * entirely after test execution to avoid pollution across tests. 10 + */ 11 + 12 + static char _clar_tempdir[CLAR_MAX_PATH]; 13 + static size_t _clar_tempdir_len; 14 + 15 + static char _clar_sandbox[CLAR_MAX_PATH]; 6 16 7 17 static int 8 18 is_valid_tmp_path(const char *path) ··· 15 25 if (!S_ISDIR(st.st_mode)) 16 26 return 0; 17 27 18 - return (access(path, W_OK) == 0); 28 + if (access(path, W_OK) != 0) 29 + return 0; 30 + 31 + return (strlen(path) < CLAR_MAX_PATH); 19 32 } 20 33 21 34 static int ··· 31 44 32 45 for (i = 0; i < var_count; ++i) { 33 46 const char *env = getenv(env_vars[i]); 47 + 34 48 if (!env) 35 49 continue; 36 50 37 51 if (is_valid_tmp_path(env)) { 38 - #ifdef __APPLE__ 39 - if (length >= PATH_MAX && realpath(env, buffer) != NULL) 40 - return 0; 41 - #endif 42 52 strncpy(buffer, env, length - 1); 43 53 buffer[length - 1] = '\0'; 44 54 return 0; ··· 47 57 48 58 /* If the environment doesn't say anything, try to use /tmp */ 49 59 if (is_valid_tmp_path("/tmp")) { 50 - #ifdef __APPLE__ 51 - if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL) 52 - return 0; 53 - #endif 54 60 strncpy(buffer, "/tmp", length - 1); 55 61 buffer[length - 1] = '\0'; 56 62 return 0; 57 63 } 58 64 59 65 #else 60 - DWORD env_len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length); 61 - if (env_len > 0 && env_len < (DWORD)length) 66 + DWORD len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length); 67 + if (len > 0 && len < (DWORD)length) 62 68 return 0; 63 69 64 - if (GetTempPath((DWORD)length, buffer)) 70 + len = GetTempPath((DWORD)length, buffer); 71 + if (len > 0 && len < (DWORD)length) 65 72 return 0; 66 73 #endif 67 74 ··· 75 82 return -1; 76 83 } 77 84 78 - static void clar_unsandbox(void) 85 + static int canonicalize_tmp_path(char *buffer) 86 + { 87 + #ifdef _WIN32 88 + char tmp[CLAR_MAX_PATH], *p; 89 + DWORD ret; 90 + 91 + ret = GetFullPathName(buffer, CLAR_MAX_PATH, tmp, NULL); 92 + 93 + if (ret == 0 || ret > CLAR_MAX_PATH) 94 + return -1; 95 + 96 + ret = GetLongPathName(tmp, buffer, CLAR_MAX_PATH); 97 + 98 + if (ret == 0 || ret > CLAR_MAX_PATH) 99 + return -1; 100 + 101 + /* normalize path to POSIX forward slashes */ 102 + for (p = buffer; *p; p++) 103 + if (*p == '\\') 104 + *p = '/'; 105 + 106 + return 0; 107 + #elif defined(CLAR_HAS_REALPATH) 108 + char tmp[CLAR_MAX_PATH]; 109 + 110 + if (realpath(buffer, tmp) == NULL) 111 + return -1; 112 + 113 + strcpy(buffer, tmp); 114 + return 0; 115 + #else 116 + (void)buffer; 117 + return 0; 118 + #endif 119 + } 120 + 121 + static void clar_tempdir_shutdown(void) 79 122 { 80 - if (_clar_path[0] == '\0') 123 + if (_clar_tempdir[0] == '\0') 81 124 return; 82 125 83 126 cl_must_pass(chdir("..")); 84 127 85 - fs_rm(_clar_path); 128 + fs_rm(_clar_tempdir); 86 129 } 87 130 88 - static int build_sandbox_path(void) 131 + static int build_tempdir_path(void) 89 132 { 90 133 #ifdef CLAR_TMPDIR 91 134 const char path_tail[] = CLAR_TMPDIR "_XXXXXX"; ··· 95 138 96 139 size_t len; 97 140 98 - if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0) 141 + if (find_tmp_path(_clar_tempdir, sizeof(_clar_tempdir)) < 0 || 142 + canonicalize_tmp_path(_clar_tempdir) < 0) 99 143 return -1; 100 144 101 - len = strlen(_clar_path); 145 + len = strlen(_clar_tempdir); 102 146 103 - #ifdef _WIN32 104 - { /* normalize path to POSIX forward slashes */ 105 - size_t i; 106 - for (i = 0; i < len; ++i) { 107 - if (_clar_path[i] == '\\') 108 - _clar_path[i] = '/'; 109 - } 110 - } 111 - #endif 147 + if (len + strlen(path_tail) + 2 > CLAR_MAX_PATH) 148 + return -1; 112 149 113 - if (_clar_path[len - 1] != '/') { 114 - _clar_path[len++] = '/'; 115 - } 150 + if (_clar_tempdir[len - 1] != '/') 151 + _clar_tempdir[len++] = '/'; 116 152 117 - strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len); 153 + strncpy(_clar_tempdir + len, path_tail, sizeof(_clar_tempdir) - len); 118 154 119 155 #if defined(__MINGW32__) 120 - if (_mktemp(_clar_path) == NULL) 156 + if (_mktemp(_clar_tempdir) == NULL) 121 157 return -1; 122 158 123 - if (mkdir(_clar_path, 0700) != 0) 159 + if (mkdir(_clar_tempdir, 0700) != 0) 124 160 return -1; 125 161 #elif defined(_WIN32) 126 - if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0) 162 + if (_mktemp_s(_clar_tempdir, sizeof(_clar_tempdir)) != 0) 127 163 return -1; 128 164 129 - if (mkdir(_clar_path, 0700) != 0) 165 + if (mkdir(_clar_tempdir, 0700) != 0) 130 166 return -1; 131 - #elif defined(__sun) || defined(__TANDEM) 132 - if (mktemp(_clar_path) == NULL) 167 + #elif defined(__sun) || defined(__TANDEM) || defined(__hpux) 168 + if (mktemp(_clar_tempdir) == NULL) 133 169 return -1; 134 170 135 - if (mkdir(_clar_path, 0700) != 0) 171 + if (mkdir(_clar_tempdir, 0700) != 0) 136 172 return -1; 137 173 #else 138 - if (mkdtemp(_clar_path) == NULL) 174 + if (mkdtemp(_clar_tempdir) == NULL) 139 175 return -1; 140 176 #endif 141 177 178 + _clar_tempdir_len = strlen(_clar_tempdir); 142 179 return 0; 143 180 } 144 181 145 - static void clar_sandbox(void) 182 + static void clar_tempdir_init(void) 183 + { 184 + if (_clar_tempdir[0] == '\0' && build_tempdir_path() < 0) 185 + clar_abort("Failed to build tempdir path.\n"); 186 + 187 + if (chdir(_clar_tempdir) != 0) 188 + clar_abort("Failed to change into tempdir '%s': %s.\n", 189 + _clar_tempdir, strerror(errno)); 190 + 191 + #if !defined(CLAR_SANDBOX_TEST_NAMES) && defined(_WIN32) 192 + srand(clock() ^ (unsigned int)time(NULL) ^ GetCurrentProcessId() ^ GetCurrentThreadId()); 193 + #elif !defined(CLAR_SANDBOX_TEST_NAMES) 194 + srand(clock() ^ time(NULL) ^ ((unsigned)getpid() << 16)); 195 + #endif 196 + } 197 + 198 + static void append(char *dst, const char *src) 199 + { 200 + char *d; 201 + const char *s; 202 + 203 + for (d = dst; *d; d++) 204 + ; 205 + 206 + for (s = src; *s; d++, s++) 207 + if (*s == ':') 208 + *d = '_'; 209 + else 210 + *d = *s; 211 + 212 + *d = '\0'; 213 + } 214 + 215 + static int clar_sandbox_create(const char *suite_name, const char *test_name) 216 + { 217 + #ifndef CLAR_SANDBOX_TEST_NAMES 218 + char alpha[] = "0123456789abcdef"; 219 + int num = rand(); 220 + #endif 221 + 222 + cl_assert(_clar_sandbox[0] == '\0'); 223 + 224 + /* 225 + * We may want to use test names as sandbox directory names for 226 + * readability, _however_ on platforms with restrictions for short 227 + * file / folder names (eg, Windows), this may be too long. 228 + */ 229 + #ifdef CLAR_SANDBOX_TEST_NAMES 230 + cl_assert(strlen(_clar_tempdir) + strlen(suite_name) + strlen(test_name) + 3 < CLAR_MAX_PATH); 231 + 232 + strcpy(_clar_sandbox, _clar_tempdir); 233 + _clar_sandbox[_clar_tempdir_len] = '/'; 234 + _clar_sandbox[_clar_tempdir_len + 1] = '\0'; 235 + 236 + append(_clar_sandbox, suite_name); 237 + append(_clar_sandbox, "__"); 238 + append(_clar_sandbox, test_name); 239 + #else 240 + ((void)suite_name); 241 + ((void)test_name); 242 + ((void)append); 243 + 244 + cl_assert(strlen(_clar_tempdir) + 9 < CLAR_MAX_PATH); 245 + 246 + strcpy(_clar_sandbox, _clar_tempdir); 247 + _clar_sandbox[_clar_tempdir_len] = '/'; 248 + 249 + _clar_sandbox[_clar_tempdir_len + 1] = alpha[(num & 0xf0000000) >> 28]; 250 + _clar_sandbox[_clar_tempdir_len + 2] = alpha[(num & 0x0f000000) >> 24]; 251 + _clar_sandbox[_clar_tempdir_len + 3] = alpha[(num & 0x00f00000) >> 20]; 252 + _clar_sandbox[_clar_tempdir_len + 4] = alpha[(num & 0x000f0000) >> 16]; 253 + _clar_sandbox[_clar_tempdir_len + 5] = alpha[(num & 0x0000f000) >> 12]; 254 + _clar_sandbox[_clar_tempdir_len + 6] = alpha[(num & 0x00000f00) >> 8]; 255 + _clar_sandbox[_clar_tempdir_len + 7] = alpha[(num & 0x000000f0) >> 4]; 256 + _clar_sandbox[_clar_tempdir_len + 8] = alpha[(num & 0x0000000f) >> 0]; 257 + _clar_sandbox[_clar_tempdir_len + 9] = '\0'; 258 + #endif 259 + 260 + if (mkdir(_clar_sandbox, 0700) != 0) 261 + return -1; 262 + 263 + if (chdir(_clar_sandbox) != 0) 264 + return -1; 265 + 266 + return 0; 267 + } 268 + 269 + static int clar_sandbox_cleanup(void) 146 270 { 147 - if (_clar_path[0] == '\0' && build_sandbox_path() < 0) 148 - clar_abort("Failed to build sandbox path.\n"); 271 + cl_assert(_clar_sandbox[0] != '\0'); 149 272 150 - if (chdir(_clar_path) != 0) 151 - clar_abort("Failed to change into sandbox directory '%s': %s.\n", 152 - _clar_path, strerror(errno)); 273 + if (chdir(_clar_tempdir) != 0) 274 + return -1; 275 + 276 + fs_rm(_clar_sandbox); 277 + _clar_sandbox[0] = '\0'; 278 + 279 + return 0; 280 + } 281 + 282 + const char *clar_tempdir_path(void) 283 + { 284 + return _clar_tempdir; 153 285 } 154 286 155 287 const char *clar_sandbox_path(void) 156 288 { 157 - return _clar_path; 289 + return _clar_sandbox; 158 290 }
+3 -2
t/unit-tests/clar/clar/summary.h
··· 23 23 int idn, const char *name, time_t timestamp, 24 24 int test_count, int fail_count, int error_count) 25 25 { 26 - struct tm *tm = localtime(&timestamp); 26 + struct tm tm; 27 27 char iso_dt[20]; 28 28 29 - if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", tm) == 0) 29 + localtime_r(&timestamp, &tm); 30 + if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", &tm) == 0) 30 31 return -1; 31 32 32 33 return fprintf(summary->fp, "\t<testsuite"
+28
t/unit-tests/clar/example/CMakeLists.txt
··· 1 + find_package(Python COMPONENTS Interpreter REQUIRED) 2 + 3 + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" 4 + COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}" 5 + DEPENDS main.c example.c 6 + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 7 + ) 8 + 9 + add_executable(example) 10 + set_target_properties(example PROPERTIES 11 + C_STANDARD 90 12 + C_STANDARD_REQUIRED ON 13 + C_EXTENSIONS OFF 14 + ) 15 + target_sources(example PRIVATE 16 + main.c 17 + example.c 18 + "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" 19 + ) 20 + target_compile_definitions(example PRIVATE) 21 + target_compile_options(example PRIVATE 22 + $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall> 23 + ) 24 + target_include_directories(example PRIVATE 25 + "${CMAKE_SOURCE_DIR}" 26 + "${CMAKE_CURRENT_BINARY_DIR}" 27 + ) 28 + target_link_libraries(example clar)
+6
t/unit-tests/clar/example/example.c
··· 1 + #include "clar.h" 2 + 3 + void test_example__simple_assert(void) 4 + { 5 + cl_assert_equal_i(1, 1); 6 + }
+27 -12
t/unit-tests/clar/test/CMakeLists.txt
··· 1 + add_subdirectory(selftest_suite) 2 + 1 3 find_package(Python COMPONENTS Interpreter REQUIRED) 2 4 3 5 add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" 4 6 COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}" 5 - DEPENDS main.c sample.c clar_test.h 7 + DEPENDS main.c selftest.c 6 8 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 7 9 ) 8 10 9 - add_executable(clar_test) 10 - set_target_properties(clar_test PROPERTIES 11 + add_executable(selftest) 12 + set_target_properties(selftest PROPERTIES 11 13 C_STANDARD 90 12 14 C_STANDARD_REQUIRED ON 13 15 C_EXTENSIONS OFF ··· 15 17 16 18 # MSVC generates all kinds of warnings. We may want to fix these in the future 17 19 # and then unconditionally treat warnings as errors. 18 - if(NOT MSVC) 19 - set_target_properties(clar_test PROPERTIES 20 + if (NOT MSVC) 21 + set_target_properties(selftest PROPERTIES 20 22 COMPILE_WARNING_AS_ERROR ON 21 23 ) 22 24 endif() 23 25 24 - target_sources(clar_test PRIVATE 26 + target_sources(selftest PRIVATE 25 27 main.c 26 - sample.c 28 + selftest.c 27 29 "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" 28 30 ) 29 - target_compile_definitions(clar_test PRIVATE 30 - CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/" 31 + target_compile_definitions(selftest PRIVATE 32 + CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/expected/" 31 33 ) 32 - target_compile_options(clar_test PRIVATE 34 + target_compile_options(selftest PRIVATE 33 35 $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall> 34 36 ) 35 - target_include_directories(clar_test PRIVATE 37 + target_include_directories(selftest PRIVATE 36 38 "${CMAKE_SOURCE_DIR}" 37 39 "${CMAKE_CURRENT_BINARY_DIR}" 38 40 ) 39 - target_link_libraries(clar_test clar) 41 + target_link_libraries(selftest clar) 42 + 43 + add_test(NAME build_selftest_suite 44 + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest_suite 45 + ) 46 + set_tests_properties(build_selftest_suite PROPERTIES FIXTURES_SETUP clar_test_fixture) 47 + 48 + add_test(NAME build_selftest 49 + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --target selftest 50 + ) 51 + set_tests_properties(build_selftest PROPERTIES FIXTURES_SETUP clar_test_fixture) 52 + 53 + add_test(NAME selftest COMMAND "${CMAKE_CURRENT_BINARY_DIR}/selftest" "$<TARGET_FILE:selftest_suite>") 54 + set_tests_properties(selftest PROPERTIES FIXTURES_REQUIRED clar_test_fixture)
-16
t/unit-tests/clar/test/clar_test.h
··· 1 - /* 2 - * Copyright (c) Vicent Marti. All rights reserved. 3 - * 4 - * This file is part of clar, distributed under the ISC license. 5 - * For full terms see the included COPYING file. 6 - */ 7 - #ifndef __CLAR_TEST__ 8 - #define __CLAR_TEST__ 9 - 10 - /* Import the standard clar helper functions */ 11 - #include "clar.h" 12 - 13 - /* Your custom shared includes / defines here */ 14 - extern int global_test_counter; 15 - 16 - #endif
+12
t/unit-tests/clar/test/expected/help
··· 1 + Usage: selftest [options] 2 + 3 + Options: 4 + -sname Run only the suite with `name` (can go to individual test name) 5 + -iname Include the suite with `name` 6 + -xname Exclude the suite with `name` 7 + -v Increase verbosity (show suite names) 8 + -q Decrease verbosity, inverse to -v 9 + -Q Quit as soon as a test fails 10 + -t Display results in tap format 11 + -l Print suite names 12 + -r[filename] Write summary file (to the optional filename)
+49
t/unit-tests/clar/test/expected/quiet
··· 1 + 1) Failure: 2 + selftest::suite::1 [file:42] 3 + Function call failed: -1 4 + 5 + 2) Failure: 6 + selftest::suite::2 [file:42] 7 + Expression is not true: 100 == 101 8 + 9 + 3) Failure: 10 + selftest::suite::strings [file:42] 11 + String mismatch: "mismatched" != actual ("this one fails") 12 + 'mismatched' != 'expected' (at byte 0) 13 + 14 + 4) Failure: 15 + selftest::suite::strings_with_length [file:42] 16 + String mismatch: "exactly" != actual ("this one fails") 17 + 'exa' != 'exp' (at byte 2) 18 + 19 + 5) Failure: 20 + selftest::suite::int [file:42] 21 + 101 != value ("extra note on failing test") 22 + 101 != 100 23 + 24 + 6) Failure: 25 + selftest::suite::int_fmt [file:42] 26 + 022 != value 27 + 0022 != 0144 28 + 29 + 7) Failure: 30 + selftest::suite::bool [file:42] 31 + 0 != value 32 + 0 != 1 33 + 34 + 8) Failure: 35 + selftest::suite::ptr [file:42] 36 + Pointer mismatch: p1 != p2 37 + 0x1 != 0x2 38 + 39 + 9) Failure: 40 + selftest::suite::multiline_description [file:42] 41 + Function call failed: -1 42 + description line 1 43 + description line 2 44 + 45 + 10) Failure: 46 + selftest::suite::null_string [file:42] 47 + String mismatch: "expected" != actual ("this one fails") 48 + 'expected' != NULL 49 +
+9
t/unit-tests/clar/test/expected/specific_test
··· 1 + Loaded 1 suites: 2 + Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') 3 + F 4 + 5 + 1) Failure: 6 + selftest::suite::bool [file:42] 7 + 0 != value 8 + 0 != 1 9 +
+8
t/unit-tests/clar/test/expected/stop_on_failure
··· 1 + Loaded 1 suites: 2 + Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') 3 + F 4 + 5 + 1) Failure: 6 + selftest::suite::1 [file:42] 7 + Function call failed: -1 8 +
+2
t/unit-tests/clar/test/expected/suite_names
··· 1 + Test suites (use -s<name> to run just one): 2 + 0: selftest::suite
+45
t/unit-tests/clar/test/expected/summary.xml
··· 1 + <testsuites> 2 + <testsuite id="0" name="selftest" hostname="localhost" timestamp="2024-09-06T10:04:08" tests="8" failures="8" errors="0"> 3 + <testcase name="1" classname="selftest" time="0.00"> 4 + <failure type="assert"><![CDATA[Function call failed: -1 5 + (null)]]></failure> 6 + </testcase> 7 + <testcase name="2" classname="selftest" time="0.00"> 8 + <failure type="assert"><![CDATA[Expression is not true: 100 == 101 9 + (null)]]></failure> 10 + </testcase> 11 + <testcase name="strings" classname="selftest" time="0.00"> 12 + <failure type="assert"><![CDATA[String mismatch: "mismatched" != actual ("this one fails") 13 + 'mismatched' != 'expected' (at byte 0)]]></failure> 14 + </testcase> 15 + <testcase name="strings_with_length" classname="selftest" time="0.00"> 16 + <failure type="assert"><![CDATA[String mismatch: "exactly" != actual ("this one fails") 17 + 'exa' != 'exp' (at byte 2)]]></failure> 18 + </testcase> 19 + <testcase name="int" classname="selftest" time="0.00"> 20 + <failure type="assert"><![CDATA[101 != value ("extra note on failing test") 21 + 101 != 100]]></failure> 22 + </testcase> 23 + <testcase name="int_fmt" classname="selftest" time="0.00"> 24 + <failure type="assert"><![CDATA[022 != value 25 + 0022 != 0144]]></failure> 26 + </testcase> 27 + <testcase name="bool" classname="selftest" time="0.00"> 28 + <failure type="assert"><![CDATA[0 != value 29 + 0 != 1]]></failure> 30 + </testcase> 31 + <testcase name="ptr" classname="selftest" time="0.00"> 32 + <failure type="assert"><![CDATA[Pointer mismatch: p1 != p2 33 + 0x1 != 0x2]]></failure> 34 + </testcase> 35 + <testcase name="multiline_description" classname="selftest" time="0.00"> 36 + <failure type="assert"><![CDATA[Function call failed: −1 37 + description line 1 38 + description line 2]]></failure> 39 + </testcase> 40 + <testcase name="null_string" classname="selftest" time="0.00"> 41 + <failure type="assert"><![CDATA[String mismatch: "expected" != actual ("this one fails") 42 + 'expected' != NULL]]></failure> 43 + </testcase> 44 + </testsuite> 45 + </testsuites>
+54
t/unit-tests/clar/test/expected/summary_with_filename
··· 1 + Loaded 1 suites: 2 + Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') 3 + FFFFFFFFFF 4 + 5 + 1) Failure: 6 + selftest::suite::1 [file:42] 7 + Function call failed: -1 8 + 9 + 2) Failure: 10 + selftest::suite::2 [file:42] 11 + Expression is not true: 100 == 101 12 + 13 + 3) Failure: 14 + selftest::suite::strings [file:42] 15 + String mismatch: "mismatched" != actual ("this one fails") 16 + 'mismatched' != 'expected' (at byte 0) 17 + 18 + 4) Failure: 19 + selftest::suite::strings_with_length [file:42] 20 + String mismatch: "exactly" != actual ("this one fails") 21 + 'exa' != 'exp' (at byte 2) 22 + 23 + 5) Failure: 24 + selftest::suite::int [file:42] 25 + 101 != value ("extra note on failing test") 26 + 101 != 100 27 + 28 + 6) Failure: 29 + selftest::suite::int_fmt [file:42] 30 + 022 != value 31 + 0022 != 0144 32 + 33 + 7) Failure: 34 + selftest::suite::bool [file:42] 35 + 0 != value 36 + 0 != 1 37 + 38 + 8) Failure: 39 + selftest::suite::ptr [file:42] 40 + Pointer mismatch: p1 != p2 41 + 0x1 != 0x2 42 + 43 + 9) Failure: 44 + selftest::suite::multiline_description [file:42] 45 + Function call failed: -1 46 + description line 1 47 + description line 2 48 + 49 + 10) Failure: 50 + selftest::suite::null_string [file:42] 51 + String mismatch: "expected" != actual ("this one fails") 52 + 'expected' != NULL 53 + 54 + written summary file to different.xml
+54
t/unit-tests/clar/test/expected/summary_without_filename
··· 1 + Loaded 1 suites: 2 + Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') 3 + FFFFFFFFFF 4 + 5 + 1) Failure: 6 + selftest::suite::1 [file:42] 7 + Function call failed: -1 8 + 9 + 2) Failure: 10 + selftest::suite::2 [file:42] 11 + Expression is not true: 100 == 101 12 + 13 + 3) Failure: 14 + selftest::suite::strings [file:42] 15 + String mismatch: "mismatched" != actual ("this one fails") 16 + 'mismatched' != 'expected' (at byte 0) 17 + 18 + 4) Failure: 19 + selftest::suite::strings_with_length [file:42] 20 + String mismatch: "exactly" != actual ("this one fails") 21 + 'exa' != 'exp' (at byte 2) 22 + 23 + 5) Failure: 24 + selftest::suite::int [file:42] 25 + 101 != value ("extra note on failing test") 26 + 101 != 100 27 + 28 + 6) Failure: 29 + selftest::suite::int_fmt [file:42] 30 + 022 != value 31 + 0022 != 0144 32 + 33 + 7) Failure: 34 + selftest::suite::bool [file:42] 35 + 0 != value 36 + 0 != 1 37 + 38 + 8) Failure: 39 + selftest::suite::ptr [file:42] 40 + Pointer mismatch: p1 != p2 41 + 0x1 != 0x2 42 + 43 + 9) Failure: 44 + selftest::suite::multiline_description [file:42] 45 + Function call failed: -1 46 + description line 1 47 + description line 2 48 + 49 + 10) Failure: 50 + selftest::suite::null_string [file:42] 51 + String mismatch: "expected" != actual ("this one fails") 52 + 'expected' != NULL 53 + 54 + written summary file to summary.xml
+102
t/unit-tests/clar/test/expected/tap
··· 1 + TAP version 13 2 + # start of suite 1: selftest::suite 3 + not ok 1 - selftest::suite::1 4 + --- 5 + reason: | 6 + Function call failed: -1 7 + at: 8 + file: 'file' 9 + line: 42 10 + function: 'func' 11 + --- 12 + not ok 2 - selftest::suite::2 13 + --- 14 + reason: | 15 + Expression is not true: 100 == 101 16 + at: 17 + file: 'file' 18 + line: 42 19 + function: 'func' 20 + --- 21 + not ok 3 - selftest::suite::strings 22 + --- 23 + reason: | 24 + String mismatch: "mismatched" != actual ("this one fails") 25 + 'mismatched' != 'expected' (at byte 0) 26 + at: 27 + file: 'file' 28 + line: 42 29 + function: 'func' 30 + --- 31 + not ok 4 - selftest::suite::strings_with_length 32 + --- 33 + reason: | 34 + String mismatch: "exactly" != actual ("this one fails") 35 + 'exa' != 'exp' (at byte 2) 36 + at: 37 + file: 'file' 38 + line: 42 39 + function: 'func' 40 + --- 41 + not ok 5 - selftest::suite::int 42 + --- 43 + reason: | 44 + 101 != value ("extra note on failing test") 45 + 101 != 100 46 + at: 47 + file: 'file' 48 + line: 42 49 + function: 'func' 50 + --- 51 + not ok 6 - selftest::suite::int_fmt 52 + --- 53 + reason: | 54 + 022 != value 55 + 0022 != 0144 56 + at: 57 + file: 'file' 58 + line: 42 59 + function: 'func' 60 + --- 61 + not ok 7 - selftest::suite::bool 62 + --- 63 + reason: | 64 + 0 != value 65 + 0 != 1 66 + at: 67 + file: 'file' 68 + line: 42 69 + function: 'func' 70 + --- 71 + not ok 8 - selftest::suite::ptr 72 + --- 73 + reason: | 74 + Pointer mismatch: p1 != p2 75 + 0x1 != 0x2 76 + at: 77 + file: 'file' 78 + line: 42 79 + function: 'func' 80 + --- 81 + not ok 9 - selftest::suite::multiline_description 82 + --- 83 + reason: | 84 + Function call failed: -1 85 + description line 1 86 + description line 2 87 + at: 88 + file: 'file' 89 + line: 42 90 + function: 'func' 91 + --- 92 + not ok 10 - selftest::suite::null_string 93 + --- 94 + reason: | 95 + String mismatch: "expected" != actual ("this one fails") 96 + 'expected' != NULL 97 + at: 98 + file: 'file' 99 + line: 42 100 + function: 'func' 101 + --- 102 + 1..10
+53
t/unit-tests/clar/test/expected/without_arguments
··· 1 + Loaded 1 suites: 2 + Started (test status codes: OK='.' FAILURE='F' SKIPPED='S') 3 + FFFFFFFFFF 4 + 5 + 1) Failure: 6 + selftest::suite::1 [file:42] 7 + Function call failed: -1 8 + 9 + 2) Failure: 10 + selftest::suite::2 [file:42] 11 + Expression is not true: 100 == 101 12 + 13 + 3) Failure: 14 + selftest::suite::strings [file:42] 15 + String mismatch: "mismatched" != actual ("this one fails") 16 + 'mismatched' != 'expected' (at byte 0) 17 + 18 + 4) Failure: 19 + selftest::suite::strings_with_length [file:42] 20 + String mismatch: "exactly" != actual ("this one fails") 21 + 'exa' != 'exp' (at byte 2) 22 + 23 + 5) Failure: 24 + selftest::suite::int [file:42] 25 + 101 != value ("extra note on failing test") 26 + 101 != 100 27 + 28 + 6) Failure: 29 + selftest::suite::int_fmt [file:42] 30 + 022 != value 31 + 0022 != 0144 32 + 33 + 7) Failure: 34 + selftest::suite::bool [file:42] 35 + 0 != value 36 + 0 != 1 37 + 38 + 8) Failure: 39 + selftest::suite::ptr [file:42] 40 + Pointer mismatch: p1 != p2 41 + 0x1 != 0x2 42 + 43 + 9) Failure: 44 + selftest::suite::multiline_description [file:42] 45 + Function call failed: -1 46 + description line 1 47 + description line 2 48 + 49 + 10) Failure: 50 + selftest::suite::null_string [file:42] 51 + String mismatch: "expected" != actual ("this one fails") 52 + 'expected' != NULL 53 +
+13 -28
t/unit-tests/clar/test/main.c
··· 1 - /* 2 - * Copyright (c) Vicent Marti. All rights reserved. 3 - * 4 - * This file is part of clar, distributed under the ISC license. 5 - * For full terms see the included COPYING file. 6 - */ 1 + #include <stdio.h> 2 + #include <string.h> 7 3 8 - #include "clar_test.h" 4 + #include "selftest.h" 9 5 10 - /* 11 - * Sample main() for clar tests. 12 - * 13 - * You should write your own main routine for clar tests that does specific 14 - * setup and teardown as necessary for your application. The only required 15 - * line is the call to `clar_test(argc, argv)`, which will execute the test 16 - * suite. If you want to check the return value of the test application, 17 - * your main() should return the same value returned by clar_test(). 18 - */ 19 - 20 - int global_test_counter = 0; 6 + const char *selftest_binary_path; 21 7 22 8 #ifdef _WIN32 23 9 int __cdecl main(int argc, char *argv[]) ··· 25 11 int main(int argc, char *argv[]) 26 12 #endif 27 13 { 28 - int ret; 29 - 30 - /* Your custom initialization here */ 31 - global_test_counter = 0; 32 - 33 - /* Run the test suite */ 34 - ret = clar_test(argc, argv); 14 + if (argc < 2) { 15 + fprintf(stderr, "usage: %s <selftest-suite-executable> <options>\n", 16 + argv[0]); 17 + exit(1); 18 + } 35 19 36 - /* Your custom cleanup here */ 37 - cl_assert_equal_i(8, global_test_counter); 20 + selftest_binary_path = argv[1]; 21 + memmove(argv + 1, argv + 2, argc - 1); 22 + argc -= 1; 38 23 39 - return ret; 24 + return clar_test(argc, argv); 40 25 }
+1 -1
t/unit-tests/clar/test/main.c.sample t/unit-tests/clar/example/main.c
··· 5 5 * For full terms see the included COPYING file. 6 6 */ 7 7 8 - #include "clar_test.h" 8 + #include "clar.h" 9 9 10 10 /* 11 11 * Minimal main() for clar tests.
t/unit-tests/clar/test/resources/test/file t/unit-tests/clar/test/selftest_suite/resources/test/file
+26 -18
t/unit-tests/clar/test/sample.c t/unit-tests/clar/test/selftest_suite/selftest_suite.c
··· 1 - #include "clar_test.h" 2 1 #include <sys/stat.h> 2 + 3 + #include "clar.h" 3 4 4 5 static int file_size(const char *filename) 5 6 { ··· 10 11 return -1; 11 12 } 12 13 13 - void test_sample__initialize(void) 14 - { 15 - global_test_counter++; 16 - } 17 - 18 - void test_sample__cleanup(void) 14 + void test_selftest_suite__cleanup(void) 19 15 { 20 16 cl_fixture_cleanup("test"); 21 17 22 18 cl_assert(file_size("test/file") == -1); 23 19 } 24 20 25 - void test_sample__1(void) 21 + void test_selftest_suite__1(void) 26 22 { 27 23 cl_assert(1); 28 24 cl_must_pass(0); /* 0 == success */ ··· 30 26 cl_must_pass(-1); /* demonstrate a failing call */ 31 27 } 32 28 33 - void test_sample__2(void) 29 + void test_selftest_suite__2(void) 34 30 { 35 31 cl_fixture_sandbox("test"); 36 32 ··· 39 35 cl_assert(100 == 101); 40 36 } 41 37 42 - void test_sample__strings(void) 38 + void test_selftest_suite__strings(void) 43 39 { 44 40 const char *actual = "expected"; 45 41 cl_assert_equal_s("expected", actual); ··· 47 43 cl_assert_equal_s_("mismatched", actual, "this one fails"); 48 44 } 49 45 50 - void test_sample__strings_with_length(void) 46 + void test_selftest_suite__strings_with_length(void) 51 47 { 52 48 const char *actual = "expected"; 53 49 cl_assert_equal_strn("expected_", actual, 8); ··· 56 52 cl_assert_equal_strn_("exactly", actual, 3, "this one fails"); 57 53 } 58 54 59 - void test_sample__int(void) 55 + void test_selftest_suite__int(void) 60 56 { 61 57 int value = 100; 62 58 cl_assert_equal_i(100, value); 63 59 cl_assert_equal_i_(101, value, "extra note on failing test"); 64 60 } 65 61 66 - void test_sample__int_fmt(void) 62 + void test_selftest_suite__int_fmt(void) 67 63 { 68 64 int value = 100; 69 65 cl_assert_equal_i_fmt(022, value, "%04o"); 70 66 } 71 67 72 - void test_sample__bool(void) 68 + void test_selftest_suite__bool(void) 73 69 { 74 70 int value = 100; 75 71 cl_assert_equal_b(1, value); /* test equality as booleans */ 76 72 cl_assert_equal_b(0, value); 77 73 } 78 74 79 - void test_sample__ptr(void) 75 + void test_selftest_suite__ptr(void) 80 76 { 81 - const char *actual = "expected"; 82 - cl_assert_equal_p(actual, actual); /* pointers to same object */ 83 - cl_assert_equal_p(&actual, actual); 77 + void *p1 = (void *)0x1, *p2 = (void *)0x2; 78 + cl_assert_equal_p(p1, p1); /* pointers to same object */ 79 + cl_assert_equal_p(p1, p2); 80 + } 81 + 82 + void test_selftest_suite__multiline_description(void) 83 + { 84 + cl_must_pass_(-1, "description line 1\ndescription line 2"); 85 + } 86 + 87 + void test_selftest_suite__null_string(void) 88 + { 89 + const char *actual = NULL; 90 + cl_assert_equal_s(actual, actual); 91 + cl_assert_equal_s_("expected", actual, "this one fails"); 84 92 }
+289
t/unit-tests/clar/test/selftest.c
··· 1 + #include <stdarg.h> 2 + #include <stdio.h> 3 + #include <string.h> 4 + #include <sys/stat.h> 5 + 6 + #include "selftest.h" 7 + 8 + #ifdef _WIN32 9 + # define WIN32_LEAN_AND_MEAN 10 + # include <windows.h> 11 + 12 + static char *read_full(HANDLE h, int is_pipe) 13 + { 14 + char *data = NULL; 15 + size_t data_size = 0; 16 + 17 + while (1) { 18 + CHAR buf[4096]; 19 + DWORD bytes_read; 20 + 21 + if (!ReadFile(h, buf, sizeof(buf), &bytes_read, NULL)) { 22 + if (!is_pipe) 23 + cl_fail("Failed reading file handle."); 24 + cl_assert_equal_i(GetLastError(), ERROR_BROKEN_PIPE); 25 + break; 26 + } 27 + if (!bytes_read) 28 + break; 29 + 30 + data = realloc(data, data_size + bytes_read); 31 + cl_assert(data); 32 + memcpy(data + data_size, buf, bytes_read); 33 + data_size += bytes_read; 34 + } 35 + 36 + data = realloc(data, data_size + 1); 37 + cl_assert(data); 38 + data[data_size] = '\0'; 39 + 40 + while (strstr(data, "\r\n")) { 41 + char *ptr = strstr(data, "\r\n"); 42 + memmove(ptr, ptr + 1, strlen(ptr)); 43 + } 44 + 45 + return data; 46 + } 47 + 48 + static char *read_file(const char *path) 49 + { 50 + char *content; 51 + HANDLE file; 52 + 53 + file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, 54 + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 55 + cl_assert(file != INVALID_HANDLE_VALUE); 56 + content = read_full(file, 0); 57 + cl_assert_equal_b(1, CloseHandle(file)); 58 + 59 + return content; 60 + } 61 + 62 + static void run(const char *expected_output_file, int expected_error_code, ...) 63 + { 64 + SECURITY_ATTRIBUTES security_attributes = { 0 }; 65 + PROCESS_INFORMATION process_info = { 0 }; 66 + STARTUPINFO startup_info = { 0 }; 67 + char cmdline[4096] = { 0 }; 68 + char *expected_output = NULL; 69 + char *output = NULL; 70 + HANDLE stdout_write; 71 + HANDLE stdout_read; 72 + DWORD exit_code; 73 + va_list ap; 74 + 75 + /* 76 + * Assemble command line arguments. In theory we'd have to properly 77 + * quote them. In practice none of our tests actually care. 78 + */ 79 + va_start(ap, expected_error_code); 80 + snprintf(cmdline, sizeof(cmdline), "selftest"); 81 + while (1) { 82 + size_t cmdline_len = strlen(cmdline); 83 + const char *arg; 84 + 85 + arg = va_arg(ap, const char *); 86 + if (!arg) 87 + break; 88 + 89 + cl_assert(cmdline_len + strlen(arg) < sizeof(cmdline)); 90 + snprintf(cmdline + cmdline_len, sizeof(cmdline) - cmdline_len, 91 + " %s", arg); 92 + } 93 + va_end(ap); 94 + 95 + /* 96 + * Create a pipe that we will use to read data from the child process. 97 + * The writing side needs to be inheritable such that the child can use 98 + * it as stdout and stderr. The reading side should only be used by the 99 + * parent. 100 + */ 101 + security_attributes.nLength = sizeof(security_attributes); 102 + security_attributes.bInheritHandle = TRUE; 103 + cl_assert_equal_b(1, CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0)); 104 + cl_assert_equal_b(1, SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)); 105 + 106 + /* 107 + * Create the child process with our pipe. 108 + */ 109 + startup_info.cb = sizeof(startup_info); 110 + startup_info.hStdError = stdout_write; 111 + startup_info.hStdOutput = stdout_write; 112 + startup_info.dwFlags |= STARTF_USESTDHANDLES; 113 + cl_assert_equal_b(1, CreateProcess(selftest_binary_path, cmdline, NULL, NULL, TRUE, 114 + 0, NULL, NULL, &startup_info, &process_info)); 115 + cl_assert_equal_b(1, CloseHandle(stdout_write)); 116 + 117 + output = read_full(stdout_read, 1); 118 + cl_assert_equal_b(1, CloseHandle(stdout_read)); 119 + cl_assert_equal_b(1, GetExitCodeProcess(process_info.hProcess, &exit_code)); 120 + 121 + expected_output = read_file(cl_fixture(expected_output_file)); 122 + cl_assert_equal_s(output, expected_output); 123 + cl_assert_equal_i(exit_code, expected_error_code); 124 + 125 + free(expected_output); 126 + free(output); 127 + } 128 + 129 + #else 130 + # include <errno.h> 131 + # include <fcntl.h> 132 + # include <limits.h> 133 + # include <unistd.h> 134 + # include <sys/wait.h> 135 + 136 + static char *read_full(int fd) 137 + { 138 + size_t data_bytes = 0; 139 + char *data = NULL; 140 + 141 + while (1) { 142 + char buf[4096]; 143 + ssize_t n; 144 + 145 + n = read(fd, buf, sizeof(buf)); 146 + if (n < 0) { 147 + if (errno == EAGAIN || errno == EINTR) 148 + continue; 149 + cl_fail("Failed reading from child process."); 150 + } 151 + if (!n) 152 + break; 153 + 154 + data = realloc(data, data_bytes + n); 155 + cl_assert(data); 156 + 157 + memcpy(data + data_bytes, buf, n); 158 + data_bytes += n; 159 + } 160 + 161 + data = realloc(data, data_bytes + 1); 162 + cl_assert(data); 163 + data[data_bytes] = '\0'; 164 + 165 + return data; 166 + } 167 + 168 + static char *read_file(const char *path) 169 + { 170 + char *data; 171 + int fd; 172 + 173 + fd = open(path, O_RDONLY); 174 + if (fd < 0) 175 + cl_fail("Failed reading expected file."); 176 + 177 + data = read_full(fd); 178 + cl_must_pass(close(fd)); 179 + 180 + return data; 181 + } 182 + 183 + static void run(const char *expected_output_file, int expected_error_code, ...) 184 + { 185 + const char *argv[16]; 186 + int pipe_fds[2]; 187 + va_list ap; 188 + pid_t pid; 189 + int i; 190 + 191 + va_start(ap, expected_error_code); 192 + argv[0] = "selftest"; 193 + for (i = 1; ; i++) { 194 + cl_assert(i < sizeof(argv) / sizeof(*argv)); 195 + 196 + argv[i] = va_arg(ap, const char *); 197 + if (!argv[i]) 198 + break; 199 + } 200 + va_end(ap); 201 + 202 + cl_must_pass(pipe(pipe_fds)); 203 + 204 + pid = fork(); 205 + if (!pid) { 206 + if (dup2(pipe_fds[1], STDOUT_FILENO) < 0 || 207 + dup2(pipe_fds[1], STDERR_FILENO) < 0 || 208 + close(0) < 0 || 209 + close(pipe_fds[0]) < 0 || 210 + close(pipe_fds[1]) < 0) 211 + exit(1); 212 + 213 + execv(selftest_binary_path, (char **) argv); 214 + exit(1); 215 + } else if (pid > 0) { 216 + pid_t waited_pid; 217 + char *expected_output, *output; 218 + int stat; 219 + 220 + cl_must_pass(close(pipe_fds[1])); 221 + 222 + output = read_full(pipe_fds[0]); 223 + 224 + waited_pid = waitpid(pid, &stat, 0); 225 + cl_assert_equal_i(pid, waited_pid); 226 + cl_assert(WIFEXITED(stat)); 227 + cl_assert_equal_i(WEXITSTATUS(stat), expected_error_code); 228 + 229 + expected_output = read_file(cl_fixture(expected_output_file)); 230 + cl_assert_equal_s(output, expected_output); 231 + 232 + free(expected_output); 233 + free(output); 234 + } else { 235 + cl_fail("Fork failed."); 236 + } 237 + } 238 + #endif 239 + 240 + void test_selftest__help(void) 241 + { 242 + cl_invoke(run("help", 1, "-h", NULL)); 243 + } 244 + 245 + void test_selftest__without_arguments(void) 246 + { 247 + cl_invoke(run("without_arguments", 10, NULL)); 248 + } 249 + 250 + void test_selftest__specific_test(void) 251 + { 252 + cl_invoke(run("specific_test", 1, "-sselftest::suite::bool", NULL)); 253 + } 254 + 255 + void test_selftest__stop_on_failure(void) 256 + { 257 + cl_invoke(run("stop_on_failure", 1, "-Q", NULL)); 258 + } 259 + 260 + void test_selftest__quiet(void) 261 + { 262 + cl_invoke(run("quiet", 10, "-q", NULL)); 263 + } 264 + 265 + void test_selftest__tap(void) 266 + { 267 + cl_invoke(run("tap", 10, "-t", NULL)); 268 + } 269 + 270 + void test_selftest__suite_names(void) 271 + { 272 + cl_invoke(run("suite_names", 0, "-l", NULL)); 273 + } 274 + 275 + void test_selftest__summary_without_filename(void) 276 + { 277 + struct stat st; 278 + cl_invoke(run("summary_without_filename", 10, "-r", NULL)); 279 + /* The summary contains timestamps, so we cannot verify its contents. */ 280 + cl_must_pass(stat("summary.xml", &st)); 281 + } 282 + 283 + void test_selftest__summary_with_filename(void) 284 + { 285 + struct stat st; 286 + cl_invoke(run("summary_with_filename", 10, "-rdifferent.xml", NULL)); 287 + /* The summary contains timestamps, so we cannot verify its contents. */ 288 + cl_must_pass(stat("different.xml", &st)); 289 + }
+3
t/unit-tests/clar/test/selftest.h
··· 1 + #include "clar.h" 2 + 3 + extern const char *selftest_binary_path;
+40
t/unit-tests/clar/test/selftest_suite/CMakeLists.txt
··· 1 + find_package(Python COMPONENTS Interpreter REQUIRED) 2 + 3 + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" 4 + COMMAND "${Python_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/generate.py" --output "${CMAKE_CURRENT_BINARY_DIR}" 5 + DEPENDS main.c selftest_suite.c 6 + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 7 + ) 8 + 9 + add_executable(selftest_suite) 10 + set_target_properties(selftest_suite PROPERTIES 11 + C_STANDARD 90 12 + C_STANDARD_REQUIRED ON 13 + C_EXTENSIONS OFF 14 + ) 15 + 16 + # MSVC generates all kinds of warnings. We may want to fix these in the future 17 + # and then unconditionally treat warnings as errors. 18 + if(NOT MSVC) 19 + set_target_properties(selftest_suite PROPERTIES 20 + COMPILE_WARNING_AS_ERROR ON 21 + ) 22 + endif() 23 + 24 + target_sources(selftest_suite PRIVATE 25 + main.c 26 + selftest_suite.c 27 + "${CMAKE_CURRENT_BINARY_DIR}/clar.suite" 28 + ) 29 + target_compile_definitions(selftest_suite PRIVATE 30 + CLAR_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/" 31 + CLAR_SELFTEST 32 + ) 33 + target_compile_options(selftest_suite PRIVATE 34 + $<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall> 35 + ) 36 + target_include_directories(selftest_suite PRIVATE 37 + "${CMAKE_SOURCE_DIR}" 38 + "${CMAKE_CURRENT_BINARY_DIR}" 39 + ) 40 + target_link_libraries(selftest_suite clar)
+27
t/unit-tests/clar/test/selftest_suite/main.c
··· 1 + /* 2 + * Copyright (c) Vicent Marti. All rights reserved. 3 + * 4 + * This file is part of clar, distributed under the ISC license. 5 + * For full terms see the included COPYING file. 6 + */ 7 + 8 + #include "clar.h" 9 + 10 + /* 11 + * Selftest main() for clar tests. 12 + * 13 + * You should write your own main routine for clar tests that does specific 14 + * setup and teardown as necessary for your application. The only required 15 + * line is the call to `clar_test(argc, argv)`, which will execute the test 16 + * suite. If you want to check the return value of the test application, 17 + * your main() should return the same value returned by clar_test(). 18 + */ 19 + 20 + #ifdef _WIN32 21 + int __cdecl main(int argc, char *argv[]) 22 + #else 23 + int main(int argc, char *argv[]) 24 + #endif 25 + { 26 + return clar_test(argc, argv); 27 + }