1035 lines · 53.1 KB · C
RawDownload
/* * Copyright (c) 2011-2016 Scott Vokes <vokes.s@gmail.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef GREATEST_H#define GREATEST_H #ifdef __cplusplusextern "C" {#endif /* 1.2.1 */#define GREATEST_VERSION_MAJOR 1#define GREATEST_VERSION_MINOR 2#define GREATEST_VERSION_PATCH 1 /* A unit testing system for C, contained in 1 file. * It doesn't use dynamic allocation or depend on anything * beyond ANSI C89. * * An up-to-date version can be found at: *     https://github.com/silentbicycle/greatest/ */  /********************************************************************* * Minimal test runner template *********************************************************************/#if 0 #include "greatest.h" TEST foo_should_foo(void) {    PASS();} static void setup_cb(void *data) {    printf("setup callback for each test case\n");} static void teardown_cb(void *data) {    printf("teardown callback for each test case\n");} SUITE(suite) {    /* Optional setup/teardown callbacks which will be run before/after     * every test case. If using a test suite, they will be cleared when     * the suite finishes. */    SET_SETUP(setup_cb, voidp_to_callback_data);    SET_TEARDOWN(teardown_cb, voidp_to_callback_data);     RUN_TEST(foo_should_foo);} /* Add definitions that need to be in the test runner's main file. */GREATEST_MAIN_DEFS(); /* Set up, run suite(s) of tests, report pass/fail/skip stats. */int run_tests(void) {    GREATEST_INIT();            /* init. greatest internals */    /* List of suites to run (if any). */    RUN_SUITE(suite);     /* Tests can also be run directly, without using test suites. */    RUN_TEST(foo_should_foo);     GREATEST_PRINT_REPORT();          /* display results */    return greatest_all_passed();} /* main(), for a standalone command-line test runner. * This replaces run_tests above, and adds command line option * handling and exiting with a pass/fail status. */int main(int argc, char **argv) {    GREATEST_MAIN_BEGIN();      /* init & parse command-line args */    RUN_SUITE(suite);    GREATEST_MAIN_END();        /* display results */} #endif/*********************************************************************/  #include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h> /*********** * Options * ***********/ /* Default column width for non-verbose output. */#ifndef GREATEST_DEFAULT_WIDTH#define GREATEST_DEFAULT_WIDTH 72#endif /* FILE *, for test logging. */#ifndef GREATEST_STDOUT#define GREATEST_STDOUT stdout#endif /* Remove GREATEST_ prefix from most commonly used symbols? */#ifndef GREATEST_USE_ABBREVS#define GREATEST_USE_ABBREVS 1#endif /* Set to 0 to disable all use of setjmp/longjmp. */#ifndef GREATEST_USE_LONGJMP#define GREATEST_USE_LONGJMP 1#endif #if GREATEST_USE_LONGJMP#include <setjmp.h>#endif /* Set to 0 to disable all use of time.h / clock(). */#ifndef GREATEST_USE_TIME#define GREATEST_USE_TIME 1#endif #if GREATEST_USE_TIME#include <time.h>#endif /* Floating point type, for ASSERT_IN_RANGE. */#ifndef GREATEST_FLOAT#define GREATEST_FLOAT double#define GREATEST_FLOAT_FMT "%g"#endif /********* * Types * *********/ /* Info for the current running suite. */typedef struct greatest_suite_info {    unsigned int tests_run;    unsigned int passed;    unsigned int failed;    unsigned int skipped; #if GREATEST_USE_TIME    /* timers, pre/post running suite and individual tests */    clock_t pre_suite;    clock_t post_suite;    clock_t pre_test;    clock_t post_test;#endif} greatest_suite_info; /* Type for a suite function. */typedef void (greatest_suite_cb)(void); /* Types for setup/teardown callbacks. If non-NULL, these will be run * and passed the pointer to their additional data. */typedef void (greatest_setup_cb)(void *udata);typedef void (greatest_teardown_cb)(void *udata); /* Type for an equality comparison between two pointers of the same type. * Should return non-0 if equal, otherwise 0. * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */typedef int greatest_equal_cb(const void *exp, const void *got, void *udata); /* Type for a callback that prints a value pointed to by T. * Return value has the same meaning as printf's. * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */typedef int greatest_printf_cb(const void *t, void *udata); /* Callbacks for an arbitrary type; needed for type-specific * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/typedef struct greatest_type_info {    greatest_equal_cb *equal;    greatest_printf_cb *print;} greatest_type_info; typedef struct greatest_memory_cmp_env {    const unsigned char *exp;    const unsigned char *got;    size_t size;} greatest_memory_cmp_env; /* Callbacks for string and raw memory types. */extern greatest_type_info greatest_type_info_string;extern greatest_type_info greatest_type_info_memory; typedef enum {    GREATEST_FLAG_FIRST_FAIL = 0x01,    GREATEST_FLAG_LIST_ONLY = 0x02} greatest_flag_t; /* Struct containing all test runner state. */typedef struct greatest_run_info {    unsigned char flags;    unsigned char verbosity;    unsigned int tests_run;     /* total test count */     /* overall pass/fail/skip counts */    unsigned int passed;    unsigned int failed;    unsigned int skipped;    unsigned int assertions;     /* currently running test suite */    greatest_suite_info suite;     /* info to print about the most recent failure */    const char *fail_file;    unsigned int fail_line;    const char *msg;     /* current setup/teardown hooks and userdata */    greatest_setup_cb *setup;    void *setup_udata;    greatest_teardown_cb *teardown;    void *teardown_udata;     /* formatting info for ".....s...F"-style output */    unsigned int col;    unsigned int width;     /* only run a specific suite or test */    const char *suite_filter;    const char *test_filter; #if GREATEST_USE_TIME    /* overall timers */    clock_t begin;    clock_t end;#endif #if GREATEST_USE_LONGJMP    jmp_buf jump_dest;#endif} greatest_run_info; struct greatest_report_t {    /* overall pass/fail/skip counts */    unsigned int passed;    unsigned int failed;    unsigned int skipped;    unsigned int assertions;}; /* Global var for the current testing context. * Initialized by GREATEST_MAIN_DEFS(). */extern greatest_run_info greatest_info; /* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */typedef const char *greatest_enum_str_fun(int value); /********************** * Exported functions * **********************/ /* These are used internally by greatest. */void greatest_do_pass(const char *name);void greatest_do_fail(const char *name);void greatest_do_skip(const char *name);int greatest_pre_test(const char *name);void greatest_post_test(const char *name, int res);void greatest_usage(const char *name);int greatest_do_assert_equal_t(const void *exp, const void *got,    greatest_type_info *type_info, void *udata); /* These are part of the public greatest API. */void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata);void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata);int greatest_all_passed(void);void greatest_set_test_filter(const char *name);void greatest_set_suite_filter(const char *name);void greatest_get_report(struct greatest_report_t *report);unsigned int greatest_get_verbosity(void);void greatest_set_verbosity(unsigned int verbosity);void greatest_set_flag(greatest_flag_t flag);  /********************* Language Support *********************/ /* If __VA_ARGS__ (C99) is supported, allow parametric testing* without needing to manually manage the argument struct. */#if __STDC_VERSION__ >= 19901L || _MSC_VER >= 1800#define GREATEST_VA_ARGS#endif  /********** * Macros * **********/ /* Define a suite. */#define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) /* Declare a suite, provided by another compilation unit. */#define GREATEST_SUITE_EXTERN(NAME) void NAME(void) /* Start defining a test function. * The arguments are not included, to allow parametric testing. */#define GREATEST_TEST static enum greatest_test_res /* PASS/FAIL/SKIP result from a test. Used internally. */typedef enum greatest_test_res {    GREATEST_TEST_RES_PASS = 0,    GREATEST_TEST_RES_FAIL = -1,    GREATEST_TEST_RES_SKIP = 1} greatest_test_res; /* Run a suite. */#define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) /* Run a test in the current suite. */#define GREATEST_RUN_TEST(TEST)                                         \    do {                                                                \        if (greatest_pre_test(#TEST) == 1) {                            \            enum greatest_test_res res = GREATEST_SAVE_CONTEXT();       \            if (res == GREATEST_TEST_RES_PASS) {                        \                res = TEST();                                           \            }                                                           \            greatest_post_test(#TEST, res);                             \        } else if (GREATEST_LIST_ONLY()) {                              \            fprintf(GREATEST_STDOUT, "  %s\n", #TEST);                  \        }                                                               \    } while (0) /* Ignore a test, don't warn about it being unused. */#define GREATEST_IGNORE_TEST(TEST) (void)TEST /* Run a test in the current suite with one void * argument, * which can be a pointer to a struct with multiple arguments. */#define GREATEST_RUN_TEST1(TEST, ENV)                                   \    do {                                                                \        if (greatest_pre_test(#TEST) == 1) {                            \            int res = TEST(ENV);                                        \            greatest_post_test(#TEST, res);                             \        } else if (GREATEST_LIST_ONLY()) {                              \            fprintf(GREATEST_STDOUT, "  %s\n", #TEST);                  \        }                                                               \    } while (0) #ifdef GREATEST_VA_ARGS#define GREATEST_RUN_TESTp(TEST, ...)                                   \    do {                                                                \        if (greatest_pre_test(#TEST) == 1) {                            \            int res = TEST(__VA_ARGS__);                                \            greatest_post_test(#TEST, res);                             \        } else if (GREATEST_LIST_ONLY()) {                              \            fprintf(GREATEST_STDOUT, "  %s\n", #TEST);                  \        }                                                               \    } while (0)#endif  /* Check if the test runner is in verbose mode. */#define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0)#define GREATEST_LIST_ONLY()                                            \    (greatest_info.flags & GREATEST_FLAG_LIST_ONLY)#define GREATEST_FIRST_FAIL()                                           \    (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL)#define GREATEST_FAILURE_ABORT()                                        \    (greatest_info.suite.failed > 0 && GREATEST_FIRST_FAIL()) /* Message-less forms of tests defined below. */#define GREATEST_PASS() GREATEST_PASSm(NULL)#define GREATEST_FAIL() GREATEST_FAILm(NULL)#define GREATEST_SKIP() GREATEST_SKIPm(NULL)#define GREATEST_ASSERT(COND)                                           \    GREATEST_ASSERTm(#COND, COND)#define GREATEST_ASSERT_OR_LONGJMP(COND)                                \    GREATEST_ASSERT_OR_LONGJMPm(#COND, COND)#define GREATEST_ASSERT_FALSE(COND)                                     \    GREATEST_ASSERT_FALSEm(#COND, COND)#define GREATEST_ASSERT_EQ(EXP, GOT)                                    \    GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT)#define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT)                           \    GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT)#define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL)                         \    GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL)#define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA)             \    GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA)#define GREATEST_ASSERT_STR_EQ(EXP, GOT)                                \    GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT)#define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE)                         \    GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE)#define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE)                          \    GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE)#define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR)                     \    GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) /* The following forms take an additional message argument first, * to be displayed by the test runner. */ /* Fail if a condition is not true, with message. */#define GREATEST_ASSERTm(MSG, COND)                                     \    do {                                                                \        greatest_info.assertions++;                                     \        if (!(COND)) { GREATEST_FAILm(MSG); }                           \    } while (0) /* Fail if a condition is not true, longjmping out of test. */#define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND)                          \    do {                                                                \        greatest_info.assertions++;                                     \        if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); }              \    } while (0) /* Fail if a condition is not false, with message. */#define GREATEST_ASSERT_FALSEm(MSG, COND)                               \    do {                                                                \        greatest_info.assertions++;                                     \        if ((COND)) { GREATEST_FAILm(MSG); }                            \    } while (0) /* Fail if EXP != GOT (equality comparison by ==). */#define GREATEST_ASSERT_EQm(MSG, EXP, GOT)                              \    do {                                                                \        greatest_info.assertions++;                                     \        if ((EXP) != (GOT)) { GREATEST_FAILm(MSG); }                    \    } while (0) /* Fail if EXP != GOT (equality comparison by ==). * Warning: EXP and GOT will be evaluated more than once on failure. */#define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT)                     \    do {                                                                \        const char *greatest_FMT = ( FMT );                             \        greatest_info.assertions++;                                     \        if ((EXP) != (GOT)) {                                           \            fprintf(GREATEST_STDOUT, "\nExpected: ");                   \            fprintf(GREATEST_STDOUT, greatest_FMT, EXP);                \            fprintf(GREATEST_STDOUT, "\n     Got: ");                   \            fprintf(GREATEST_STDOUT, greatest_FMT, GOT);                \            fprintf(GREATEST_STDOUT, "\n");                             \            GREATEST_FAILm(MSG);                                        \        }                                                               \    } while (0) /* Fail if EXP is not equal to GOT, printing enum IDs. */#define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR)               \    do {                                                                \        int greatest_EXP = (int)(EXP);                                  \        int greatest_GOT = (int)(GOT);                                  \        greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR;            \        if (greatest_EXP != greatest_GOT) {                             \            fprintf(GREATEST_STDOUT, "\nExpected: %s",                  \                greatest_ENUM_STR(greatest_EXP));                       \            fprintf(GREATEST_STDOUT, "\n     Got: %s\n",                \                greatest_ENUM_STR(greatest_GOT));                       \            GREATEST_FAILm(MSG);                                        \        }                                                               \    } while (0)                                                         \ /* Fail if GOT not in range of EXP +|- TOL. */#define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL)                   \    do {                                                                \        GREATEST_FLOAT greatest_EXP = (EXP);                            \        GREATEST_FLOAT greatest_GOT = (GOT);                            \        GREATEST_FLOAT greatest_TOL = (TOL);                            \        greatest_info.assertions++;                                     \        if ((greatest_EXP > greatest_GOT &&                             \                greatest_EXP - greatest_GOT > greatest_TOL) ||          \            (greatest_EXP < greatest_GOT &&                             \                greatest_GOT - greatest_EXP > greatest_TOL)) {          \            fprintf(GREATEST_STDOUT,                                    \                "\nExpected: " GREATEST_FLOAT_FMT                       \                " +/- " GREATEST_FLOAT_FMT                              \                "\n     Got: " GREATEST_FLOAT_FMT                       \                "\n",                                                   \                greatest_EXP, greatest_TOL, greatest_GOT);              \            GREATEST_FAILm(MSG);                                        \        }                                                               \    } while (0) /* Fail if EXP is not equal to GOT, according to strcmp. */#define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT)                          \    do {                                                                \        GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT,                         \            &greatest_type_info_string, NULL);                          \    } while (0)                                                         \ /* Fail if EXP is not equal to GOT, according to strcmp. */#define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE)                   \    do {                                                                \        size_t size = SIZE;                                             \        GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT,                         \            &greatest_type_info_string, &size);                         \    } while (0)                                                         \ 

Lines 1–500 of 1035.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t