tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cutest.h (22815B)


      1 /*
      2 * CUTest -- C/C++ Unit Test facility
      3 * <http://github.com/mity/cutest>
      4 *
      5 * Copyright (c) 2013-2017 Martin Mitas
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a
      8 * copy of this software and associated documentation files (the "Software"),
      9 * to deal in the Software without restriction, including without limitation
     10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11 * and/or sell copies of the Software, and to permit persons to whom the
     12 * Software is furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in
     15 * all copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     23 * IN THE SOFTWARE.
     24 */
     25 
     26 #ifndef CUTEST_H__
     27 #define CUTEST_H__
     28 
     29 /************************
     30 *** Public interface ***
     31 ************************/
     32 
     33 /* By default, <cutest.h> provides the main program entry point (function
     34 * main()). However, if the test suite is composed of multiple source files
     35 * which include <cutest.h>, then this causes a problem of multiple main()
     36 * definitions. To avoid this problem, #define macro TEST_NO_MAIN in all
     37 * compilation units but one.
     38 */
     39 
     40 /* Macro to specify list of unit tests in the suite.
     41 * The unit test implementation MUST provide list of unit tests it implements
     42 * with this macro:
     43 *
     44 *   TEST_LIST = {
     45 *       { "test1_name", test1_func_ptr },
     46 *       { "test2_name", test2_func_ptr },
     47 *       ...
     48 *       { 0 }
     49 *   };
     50 *
     51 * The list specifies names of each test (must be unique) and pointer to
     52 * a function implementing it. The function does not take any arguments
     53 * and has no return values, i.e. every test function has tp be compatible
     54 * with this prototype:
     55 *
     56 *   void test_func(void);
     57 */
     58 #define TEST_LIST const struct test__ test_list__[]
     59 
     60 /* Macros for testing whether an unit test succeeds or fails. These macros
     61 * can be used arbitrarily in functions implementing the unit tests.
     62 *
     63 * If any condition fails throughout execution of a test, the test fails.
     64 *
     65 * TEST_CHECK takes only one argument (the condition), TEST_CHECK_ allows
     66 * also to specify an error message to print out if the condition fails.
     67 * (It expects printf-like format string and its parameters). The macros
     68 * return non-zero (condition passes) or 0 (condition fails).
     69 *
     70 * That can be useful when more conditions should be checked only if some
     71 * preceding condition passes, as illustrated in this code snippet:
     72 *
     73 *   SomeStruct* ptr = allocate_some_struct();
     74 *   if(TEST_CHECK(ptr != NULL)) {
     75 *       TEST_CHECK(ptr->member1 < 100);
     76 *       TEST_CHECK(ptr->member2 > 200);
     77 *   }
     78 */
     79 #define TEST_CHECK_(cond, ...)                                                 \
     80    test_check__((cond), __FILE__, __LINE__, __VA_ARGS__)
     81 #define TEST_CHECK(cond) test_check__((cond), __FILE__, __LINE__, "%s", #cond)
     82 
     83 /**********************
     84 *** Implementation ***
     85 **********************/
     86 
     87 /* The unit test files should not rely on anything below. */
     88 
     89 #include <stdarg.h>
     90 #include <stdio.h>
     91 #include <stdlib.h>
     92 #include <string.h>
     93 
     94 #if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__)
     95 #define CUTEST_UNIX__ 1
     96 #include <errno.h>
     97 #include <unistd.h>
     98 #include <sys/types.h>
     99 #include <sys/wait.h>
    100 #include <signal.h>
    101 #endif
    102 
    103 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
    104 #define CUTEST_WIN__ 1
    105 #include <windows.h>
    106 #include <io.h>
    107 #endif
    108 
    109 #ifdef __cplusplus
    110 #include <exception>
    111 #endif
    112 
    113 /* Note our global private identifiers end with '__' to mitigate risk of clash
    114 * with the unit tests implementation. */
    115 
    116 #ifdef __cplusplus
    117 extern "C" {
    118 #endif
    119 
    120 struct test__ {
    121    const char *name;
    122    void (*func)(void);
    123 };
    124 
    125 extern const struct test__ test_list__[];
    126 
    127 int test_check__(int cond, const char *file, int line, const char *fmt, ...);
    128 
    129 #ifndef TEST_NO_MAIN
    130 
    131 static char *test_argv0__ = NULL;
    132 static int test_count__ = 0;
    133 static int test_no_exec__ = 0;
    134 static int test_no_summary__ = 0;
    135 static int test_skip_mode__ = 0;
    136 
    137 static int test_stat_failed_units__ = 0;
    138 static int test_stat_run_units__ = 0;
    139 
    140 static const struct test__ *test_current_unit__ = NULL;
    141 static int test_current_already_logged__ = 0;
    142 static int test_verbose_level__ = 2;
    143 static int test_current_failures__ = 0;
    144 static int test_colorize__ = 0;
    145 
    146 #define CUTEST_COLOR_DEFAULT__ 0
    147 #define CUTEST_COLOR_GREEN__ 1
    148 #define CUTEST_COLOR_RED__ 2
    149 #define CUTEST_COLOR_DEFAULT_INTENSIVE__ 3
    150 #define CUTEST_COLOR_GREEN_INTENSIVE__ 4
    151 #define CUTEST_COLOR_RED_INTENSIVE__ 5
    152 
    153 static size_t test_print_in_color__(int color, const char *fmt, ...)
    154 {
    155    va_list args;
    156    char buffer[256];
    157    size_t n;
    158 
    159    va_start(args, fmt);
    160    vsnprintf(buffer, sizeof(buffer), fmt, args);
    161    va_end(args);
    162    buffer[sizeof(buffer) - 1] = '\0';
    163 
    164    if (!test_colorize__) {
    165        return printf("%s", buffer);
    166    }
    167 
    168 #if defined CUTEST_UNIX__
    169    {
    170        const char *col_str;
    171        switch (color) {
    172        case CUTEST_COLOR_GREEN__:
    173            col_str = "\033[0;32m";
    174            break;
    175        case CUTEST_COLOR_RED__:
    176            col_str = "\033[0;31m";
    177            break;
    178        case CUTEST_COLOR_GREEN_INTENSIVE__:
    179            col_str = "\033[1;32m";
    180            break;
    181        case CUTEST_COLOR_RED_INTENSIVE__:
    182            col_str = "\033[1;30m";
    183            break;
    184        case CUTEST_COLOR_DEFAULT_INTENSIVE__:
    185            col_str = "\033[1m";
    186            break;
    187        default:
    188            col_str = "\033[0m";
    189            break;
    190        }
    191        printf("%s", col_str);
    192        n = printf("%s", buffer);
    193        printf("\033[0m");
    194        return n;
    195    }
    196 #elif defined CUTEST_WIN__
    197    {
    198        HANDLE h;
    199        CONSOLE_SCREEN_BUFFER_INFO info;
    200        WORD attr;
    201 
    202        h = GetStdHandle(STD_OUTPUT_HANDLE);
    203        GetConsoleScreenBufferInfo(h, &info);
    204 
    205        switch (color) {
    206        case CUTEST_COLOR_GREEN__:
    207            attr = FOREGROUND_GREEN;
    208            break;
    209        case CUTEST_COLOR_RED__:
    210            attr = FOREGROUND_RED;
    211            break;
    212        case CUTEST_COLOR_GREEN_INTENSIVE__:
    213            attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
    214            break;
    215        case CUTEST_COLOR_RED_INTENSIVE__:
    216            attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
    217            break;
    218        case CUTEST_COLOR_DEFAULT_INTENSIVE__:
    219            attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED |
    220                   FOREGROUND_INTENSITY;
    221            break;
    222        default:
    223            attr = 0;
    224            break;
    225        }
    226        if (attr != 0)
    227            SetConsoleTextAttribute(h, attr);
    228        n = printf("%s", buffer);
    229        SetConsoleTextAttribute(h, info.wAttributes);
    230        return n;
    231    }
    232 #else
    233    n = printf("%s", buffer);
    234    return n;
    235 #endif
    236 }
    237 
    238 int test_check__(int cond, const char *file, int line, const char *fmt, ...)
    239 {
    240    const char *result_str;
    241    int result_color;
    242    int verbose_level;
    243 
    244    if (cond) {
    245        result_str = "ok";
    246        result_color = CUTEST_COLOR_GREEN__;
    247        verbose_level = 3;
    248    } else {
    249        if (!test_current_already_logged__ && test_current_unit__ != NULL) {
    250            printf("[ ");
    251            test_print_in_color__(CUTEST_COLOR_RED_INTENSIVE__, "FAILED");
    252            printf(" ]\n");
    253        }
    254        result_str = "failed";
    255        result_color = CUTEST_COLOR_RED__;
    256        verbose_level = 2;
    257        test_current_failures__++;
    258        test_current_already_logged__++;
    259    }
    260 
    261    if (test_verbose_level__ >= verbose_level) {
    262        va_list args;
    263 
    264        printf("  ");
    265 
    266        if (file != NULL)
    267            printf("%s:%d: Check ", file, line);
    268 
    269        va_start(args, fmt);
    270        vprintf(fmt, args);
    271        va_end(args);
    272 
    273        printf("... ");
    274        test_print_in_color__(result_color, result_str);
    275        printf("\n");
    276        test_current_already_logged__++;
    277    }
    278 
    279    return (cond != 0);
    280 }
    281 
    282 static void test_list_names__(void)
    283 {
    284    const struct test__ *test;
    285 
    286    printf("Unit tests:\n");
    287    for (test = &test_list__[0]; test->func != NULL; test++)
    288        printf("  %s\n", test->name);
    289 }
    290 
    291 static const struct test__ *test_by_name__(const char *name)
    292 {
    293    const struct test__ *test;
    294 
    295    for (test = &test_list__[0]; test->func != NULL; test++) {
    296        if (strcmp(test->name, name) == 0)
    297            return test;
    298    }
    299 
    300    return NULL;
    301 }
    302 
    303 /* Call directly the given test unit function. */
    304 static int test_do_run__(const struct test__ *test)
    305 {
    306    test_current_unit__ = test;
    307    test_current_failures__ = 0;
    308    test_current_already_logged__ = 0;
    309 
    310    if (test_verbose_level__ >= 3) {
    311        test_print_in_color__(CUTEST_COLOR_DEFAULT_INTENSIVE__, "Test %s:\n",
    312                              test->name);
    313        test_current_already_logged__++;
    314    } else if (test_verbose_level__ >= 1) {
    315        size_t n;
    316        char spaces[32];
    317 
    318        n = test_print_in_color__(CUTEST_COLOR_DEFAULT_INTENSIVE__,
    319                                  "Test %s... ", test->name);
    320        memset(spaces, ' ', sizeof(spaces));
    321        if (n < sizeof(spaces))
    322            printf("%.*s", (int)(sizeof(spaces) - n), spaces);
    323    } else {
    324        test_current_already_logged__ = 1;
    325    }
    326 
    327 #ifdef __cplusplus
    328    try {
    329 #endif
    330 
    331        /* This is good to do for case the test unit e.g. crashes. */
    332        fflush(stdout);
    333        fflush(stderr);
    334 
    335        test->func();
    336 
    337 #ifdef __cplusplus
    338    } catch (std::exception &e) {
    339        const char *what = e.what();
    340        if (what != NULL)
    341            test_check__(0, NULL, 0, "Threw std::exception: %s", what);
    342        else
    343            test_check__(0, NULL, 0, "Threw std::exception");
    344    } catch (...) {
    345        test_check__(0, NULL, 0, "Threw an exception");
    346    }
    347 #endif
    348 
    349    if (test_verbose_level__ >= 3) {
    350        switch (test_current_failures__) {
    351        case 0:
    352            test_print_in_color__(CUTEST_COLOR_GREEN_INTENSIVE__,
    353                                  "  All conditions have passed.\n\n");
    354            break;
    355        case 1:
    356            test_print_in_color__(CUTEST_COLOR_RED_INTENSIVE__,
    357                                  "  One condition has FAILED.\n\n");
    358            break;
    359        default:
    360            test_print_in_color__(CUTEST_COLOR_RED_INTENSIVE__,
    361                                  "  %d conditions have FAILED.\n\n",
    362                                  test_current_failures__);
    363            break;
    364        }
    365    } else if (test_verbose_level__ >= 1 && test_current_failures__ == 0) {
    366        printf("[   ");
    367        test_print_in_color__(CUTEST_COLOR_GREEN_INTENSIVE__, "OK");
    368        printf("   ]\n");
    369    }
    370 
    371    test_current_unit__ = NULL;
    372    return (test_current_failures__ == 0) ? 0 : -1;
    373 }
    374 
    375 #if defined(CUTEST_UNIX__) || defined(CUTEST_WIN__)
    376 /* Called if anything goes bad in cutest, or if the unit test ends in other
    377 * way then by normal returning from its function (e.g. exception or some
    378 * abnormal child process termination). */
    379 static void test_error__(const char *fmt, ...)
    380 {
    381    va_list args;
    382 
    383    if (test_verbose_level__ == 0)
    384        return;
    385 
    386    if (test_verbose_level__ <= 2 && !test_current_already_logged__ &&
    387        test_current_unit__ != NULL) {
    388        printf("[ ");
    389        test_print_in_color__(CUTEST_COLOR_RED_INTENSIVE__, "FAILED");
    390        printf(" ]\n");
    391    }
    392 
    393    if (test_verbose_level__ >= 2) {
    394        test_print_in_color__(CUTEST_COLOR_RED_INTENSIVE__, "  Error: ");
    395        va_start(args, fmt);
    396        vprintf(fmt, args);
    397        va_end(args);
    398        printf("\n");
    399    }
    400 }
    401 #endif
    402 
    403 /* Trigger the unit test. If possible (and not suppressed) it starts a child
    404 * process who calls test_do_run__(), otherwise it calls test_do_run__()
    405 * directly. */
    406 static void test_run__(const struct test__ *test)
    407 {
    408    int failed = 1;
    409 
    410    test_current_unit__ = test;
    411    test_current_already_logged__ = 0;
    412 
    413    if (!test_no_exec__) {
    414 #if defined(CUTEST_UNIX__)
    415 
    416        pid_t pid;
    417        int exit_code;
    418 
    419        pid = fork();
    420        if (pid == (pid_t)-1) {
    421            test_error__("Cannot fork. %s [%d]", strerror(errno), errno);
    422            failed = 1;
    423        } else if (pid == 0) {
    424            /* Child: Do the test. */
    425            failed = (test_do_run__(test) != 0);
    426            exit(failed ? 1 : 0);
    427        } else {
    428            /* Parent: Wait until child terminates and analyze its exit code. */
    429            waitpid(pid, &exit_code, 0);
    430            if (WIFEXITED(exit_code)) {
    431                switch (WEXITSTATUS(exit_code)) {
    432                case 0:
    433                    failed = 0;
    434                    break; /* test has passed. */
    435                case 1:    /* noop */
    436                    break; /* "normal" failure. */
    437                default:
    438                    test_error__("Unexpected exit code [%d]",
    439                                 WEXITSTATUS(exit_code));
    440                }
    441            } else if (WIFSIGNALED(exit_code)) {
    442                char tmp[32];
    443                const char *signame;
    444                switch (WTERMSIG(exit_code)) {
    445                case SIGINT:
    446                    signame = "SIGINT";
    447                    break;
    448                case SIGHUP:
    449                    signame = "SIGHUP";
    450                    break;
    451                case SIGQUIT:
    452                    signame = "SIGQUIT";
    453                    break;
    454                case SIGABRT:
    455                    signame = "SIGABRT";
    456                    break;
    457                case SIGKILL:
    458                    signame = "SIGKILL";
    459                    break;
    460                case SIGSEGV:
    461                    signame = "SIGSEGV";
    462                    break;
    463                case SIGILL:
    464                    signame = "SIGILL";
    465                    break;
    466                case SIGTERM:
    467                    signame = "SIGTERM";
    468                    break;
    469                default:
    470                    snprintf(tmp, sizeof(tmp), "signal %d",
    471                             WTERMSIG(exit_code));
    472                    signame = tmp;
    473                    break;
    474                }
    475                test_error__("Test interrupted by %s", signame);
    476            } else {
    477                test_error__("Test ended in an unexpected way [%d]", exit_code);
    478            }
    479        }
    480 
    481 #elif defined(CUTEST_WIN__)
    482 
    483        char buffer[512] = { 0 };
    484        STARTUPINFOA startupInfo = { 0 };
    485        PROCESS_INFORMATION processInfo;
    486        DWORD exitCode;
    487 
    488        /* Windows has no fork(). So we propagate all info into the child
    489         * through a command line arguments. */
    490        _snprintf(buffer, sizeof(buffer) - 1,
    491                  "%s --no-exec --no-summary --verbose=%d --color=%s -- \"%s\"",
    492                  test_argv0__, test_verbose_level__,
    493                  test_colorize__ ? "always" : "never", test->name);
    494        startupInfo.cb = sizeof(STARTUPINFO);
    495        if (CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL,
    496                           &startupInfo, &processInfo)) {
    497            WaitForSingleObject(processInfo.hProcess, INFINITE);
    498            GetExitCodeProcess(processInfo.hProcess, &exitCode);
    499            CloseHandle(processInfo.hThread);
    500            CloseHandle(processInfo.hProcess);
    501            failed = (exitCode != 0);
    502        } else {
    503            test_error__("Cannot create unit test subprocess [%ld].",
    504                         GetLastError());
    505            failed = 1;
    506        }
    507 
    508 #else
    509 
    510        /* A platform where we don't know how to run child process. */
    511        failed = (test_do_run__(test) != 0);
    512 
    513 #endif
    514 
    515    } else {
    516        /* Child processes suppressed through --no-exec. */
    517        failed = (test_do_run__(test) != 0);
    518    }
    519 
    520    test_current_unit__ = NULL;
    521 
    522    test_stat_run_units__++;
    523    if (failed)
    524        test_stat_failed_units__++;
    525 }
    526 
    527 #if defined(CUTEST_WIN__)
    528 /* Callback for SEH events. */
    529 static LONG CALLBACK test_exception_filter__(EXCEPTION_POINTERS *ptrs)
    530 {
    531    test_error__("Unhandled SEH exception %08lx at %p.",
    532                 ptrs->ExceptionRecord->ExceptionCode,
    533                 ptrs->ExceptionRecord->ExceptionAddress);
    534    fflush(stdout);
    535    fflush(stderr);
    536    return EXCEPTION_EXECUTE_HANDLER;
    537 }
    538 #endif
    539 
    540 static void test_help__(void)
    541 {
    542    printf("Usage: %s [options] [test...]\n", test_argv0__);
    543    printf("Run the specified unit tests; or if the option '--skip' is used, "
    544           "run all\n");
    545    printf("tests in the suite but those listed.  By default, if no tests are "
    546           "specified\n");
    547    printf("on the command line, all unit tests in the suite are run.\n");
    548    printf("\n");
    549    printf("Options:\n");
    550    printf(
    551        "  -s, --skip            Execute all unit tests but the listed ones\n");
    552    printf("      --no-exec         Do not execute unit tests as child "
    553           "processes\n");
    554    printf(
    555        "      --no-summary      Suppress printing of test results summary\n");
    556    printf("  -l, --list            List unit tests in the suite and exit\n");
    557    printf("  -v, --verbose         Enable more verbose output\n");
    558    printf("      --verbose=LEVEL   Set verbose level to LEVEL:\n");
    559    printf("                          0 ... Be silent\n");
    560    printf("                          1 ... Output one line per test (and "
    561           "summary)\n");
    562    printf("                          2 ... As 1 and failed conditions (this "
    563           "is default)\n");
    564    printf("                          3 ... As 1 and all conditions (and "
    565           "extended summary)\n");
    566    printf("      --color=WHEN      Enable colorized output (WHEN is one of "
    567           "'auto', 'always', 'never')\n");
    568    printf("  -h, --help            Display this help and exit\n");
    569    printf("\n");
    570    test_list_names__();
    571 }
    572 
    573 int main(int argc, char **argv)
    574 {
    575    const struct test__ **tests = NULL;
    576    int i, j, n = 0;
    577    int seen_double_dash = 0;
    578 
    579    test_argv0__ = argv[0];
    580 
    581 #if defined CUTEST_UNIX__
    582    test_colorize__ = isatty(STDOUT_FILENO);
    583 #elif defined CUTEST_WIN__
    584    test_colorize__ = _isatty(_fileno(stdout));
    585 #else
    586    test_colorize__ = 0;
    587 #endif
    588 
    589    /* Parse options */
    590    for (i = 1; i < argc; i++) {
    591        if (seen_double_dash || argv[i][0] != '-') {
    592            tests = (const struct test__ **)realloc(
    593                (void *)tests, (n + 1) * sizeof(const struct test__ *));
    594            if (tests == NULL) {
    595                fprintf(stderr, "Out of memory.\n");
    596                exit(2);
    597            }
    598            tests[n] = test_by_name__(argv[i]);
    599            if (tests[n] == NULL) {
    600                fprintf(stderr, "%s: Unrecognized unit test '%s'\n", argv[0],
    601                        argv[i]);
    602                fprintf(stderr, "Try '%s --list' for list of unit tests.\n",
    603                        argv[0]);
    604                exit(2);
    605            }
    606            n++;
    607        } else if (strcmp(argv[i], "--") == 0) {
    608            seen_double_dash = 1;
    609        } else if (strcmp(argv[i], "--help") == 0 ||
    610                   strcmp(argv[i], "-h") == 0) {
    611            test_help__();
    612            exit(0);
    613        } else if (strcmp(argv[i], "--verbose") == 0 ||
    614                   strcmp(argv[i], "-v") == 0) {
    615            test_verbose_level__++;
    616        } else if (strncmp(argv[i], "--verbose=", 10) == 0) {
    617            test_verbose_level__ = atoi(argv[i] + 10);
    618        } else if (strcmp(argv[i], "--color=auto") == 0) {
    619            /* noop (set from above) */
    620        } else if (strcmp(argv[i], "--color=always") == 0 ||
    621                   strcmp(argv[i], "--color") == 0) {
    622            test_colorize__ = 1;
    623        } else if (strcmp(argv[i], "--color=never") == 0) {
    624            test_colorize__ = 0;
    625        } else if (strcmp(argv[i], "--skip") == 0 ||
    626                   strcmp(argv[i], "-s") == 0) {
    627            test_skip_mode__ = 1;
    628        } else if (strcmp(argv[i], "--no-exec") == 0) {
    629            test_no_exec__ = 1;
    630        } else if (strcmp(argv[i], "--no-summary") == 0) {
    631            test_no_summary__ = 1;
    632        } else if (strcmp(argv[i], "--list") == 0 ||
    633                   strcmp(argv[i], "-l") == 0) {
    634            test_list_names__();
    635            exit(0);
    636        } else {
    637            fprintf(stderr, "%s: Unrecognized option '%s'\n", argv[0], argv[i]);
    638            fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
    639            exit(2);
    640        }
    641    }
    642 
    643 #if defined(CUTEST_WIN__)
    644    SetUnhandledExceptionFilter(test_exception_filter__);
    645 #endif
    646 
    647    /* Count all test units */
    648    test_count__ = 0;
    649    for (i = 0; test_list__[i].func != NULL; i++)
    650        test_count__++;
    651 
    652    /* Run the tests */
    653    if (n == 0) {
    654        /* Run all tests */
    655        for (i = 0; test_list__[i].func != NULL; i++)
    656            test_run__(&test_list__[i]);
    657    } else if (!test_skip_mode__) {
    658        /* Run the listed tests */
    659        for (i = 0; i < n; i++)
    660            test_run__(tests[i]);
    661    } else {
    662        /* Run all tests except those listed */
    663        for (i = 0; test_list__[i].func != NULL; i++) {
    664            int want_skip = 0;
    665            for (j = 0; j < n; j++) {
    666                if (tests[j] == &test_list__[i]) {
    667                    want_skip = 1;
    668                    break;
    669                }
    670            }
    671            if (!want_skip)
    672                test_run__(&test_list__[i]);
    673        }
    674    }
    675 
    676    /* Write a summary */
    677    if (!test_no_summary__ && test_verbose_level__ >= 1) {
    678        test_print_in_color__(CUTEST_COLOR_DEFAULT_INTENSIVE__, "\nSummary:\n");
    679 
    680        if (test_verbose_level__ >= 3) {
    681            printf("  Count of all unit tests:     %4d\n", test_count__);
    682            printf("  Count of run unit tests:     %4d\n",
    683                   test_stat_run_units__);
    684            printf("  Count of failed unit tests:  %4d\n",
    685                   test_stat_failed_units__);
    686            printf("  Count of skipped unit tests: %4d\n",
    687                   test_count__ - test_stat_run_units__);
    688        }
    689 
    690        if (test_stat_failed_units__ == 0) {
    691            test_print_in_color__(CUTEST_COLOR_GREEN_INTENSIVE__,
    692                                  "  SUCCESS: All unit tests have passed.\n");
    693        } else {
    694            test_print_in_color__(
    695                CUTEST_COLOR_RED_INTENSIVE__,
    696                "  FAILED: %d of %d unit tests have failed.\n",
    697                test_stat_failed_units__, test_stat_run_units__);
    698        }
    699    }
    700 
    701    if (tests != NULL)
    702        free((void *)tests);
    703 
    704    return (test_stat_failed_units__ == 0) ? 0 : 1;
    705 }
    706 
    707 #endif /* #ifndef TEST_NO_MAIN */
    708 
    709 #ifdef __cplusplus
    710 } /* extern "C" */
    711 #endif
    712 
    713 #endif /* #ifndef CUTEST_H__ */