From 82921c2321be5cb9f890b981ca01d53e6ea9cab3 Mon Sep 17 00:00:00 2001 From: Vemake Date: Wed, 24 Jul 2019 21:46:35 +0800 Subject: [PATCH 01/21] Update Makefile --- Makefile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5416740..add2e4c 100644 --- a/Makefile +++ b/Makefile @@ -33,18 +33,16 @@ example_no_suite: example_no_suite.o example_no_runner: example_no_runner.o example_shuffle: example_shuffle.o -example_cpp: example_cpp.cpp +example_trunc: greatest.h + +example_cpp: example_cpp.cpp greatest.h ${CXX} -o $@ example_cpp.cpp ${CPPFLAGS} ${LDFLAGS} -%.o: %.c +%.o: %.c greatest.h Makefile ${CC} -c -o $@ ${CFLAGS} $< %: %.o ${CC} -o $@ ${LDFLAGS} $^ -*.o: Makefile -*.o: greatest.h - clean: rm -f ${PROGRAMS_C} ${PROGRAMS_CPP} *.o *.core - From 85019d6c31fa5f9b06f17952ad22d9385a6b5375 Mon Sep 17 00:00:00 2001 From: Thodoris Sotiropoulos Date: Wed, 1 Jan 2020 13:23:40 +0200 Subject: [PATCH 02/21] Fix fault in Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 5416740..ef1c207 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ example: example.o example_suite.o example_no_suite: example_no_suite.o example_no_runner: example_no_runner.o example_shuffle: example_shuffle.o +example_trunc: example_trunc.o example_cpp: example_cpp.cpp ${CXX} -o $@ example_cpp.cpp ${CPPFLAGS} ${LDFLAGS} From cf2cfa6f6202f72c71d825e4714342393fd86163 Mon Sep 17 00:00:00 2001 From: Maxwell Bernstein Date: Sat, 29 Aug 2020 23:10:52 -0700 Subject: [PATCH 03/21] Add ASSERT_NE I often find myself wanting to check a result is non-`NULL`. This patch adds `ASSERT_NE` so that it is simple to write `ASSERT_NE(result, NULL)`, for example. --- example.c | 7 +++++++ greatest.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/example.c b/example.c index 13af484..320ca20 100644 --- a/example.c +++ b/example.c @@ -30,6 +30,12 @@ TEST expect_equal(void) { PASS(); } +TEST expect_not_equal(void) { + int i = 9; + ASSERT_NE(10, i); + PASS(); +} + TEST expect_str_equal(void) { const char *foo1 = "foo1"; ASSERT_STR_EQ("foo2", foo1); @@ -279,6 +285,7 @@ SUITE(suite) { printf("\nThis should fail:\n"); RUN_TEST(expect_str_equal); printf("\nThis should pass:\n"); + RUN_TEST(expect_not_equal); RUN_TEST(expect_strn_equal); printf("\nThis should fail:\n"); RUN_TEST(expect_boxed_int_equal); diff --git a/greatest.h b/greatest.h index fd4fe24..5d548c2 100644 --- a/greatest.h +++ b/greatest.h @@ -434,6 +434,8 @@ typedef enum greatest_test_res { GREATEST_ASSERT_FALSEm(#COND, COND) #define GREATEST_ASSERT_EQ(EXP, GOT) \ GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) +#define GREATEST_ASSERT_NE(EXP, GOT) \ + GREATEST_ASSERT_NEm(#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) \ @@ -480,6 +482,13 @@ typedef enum greatest_test_res { if ((EXP) != (GOT)) { GREATEST_FAILm(MSG); } \ } while (0) +/* Fail if EXP == GOT (equality comparison by !=). */ +#define GREATEST_ASSERT_NEm(MSG, EXP, GOT) \ + do { \ + greatest_info.assertions++; \ + if ((EXP) == (GOT)) { GREATEST_FAILm(MSG); } \ + } while (0) + /* Fail if EXP != GOT (equality comparison by ==). * Warning: FMT, EXP, and GOT will be evaluated more * than once on failure. */ @@ -1177,6 +1186,7 @@ greatest_run_info greatest_info #define ASSERTm GREATEST_ASSERTm #define ASSERT_FALSE GREATEST_ASSERT_FALSE #define ASSERT_EQ GREATEST_ASSERT_EQ +#define ASSERT_NE GREATEST_ASSERT_NE #define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T @@ -1186,6 +1196,7 @@ greatest_run_info greatest_info #define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ #define ASSERT_FALSEm GREATEST_ASSERT_FALSEm #define ASSERT_EQm GREATEST_ASSERT_EQm +#define ASSERT_NEm GREATEST_ASSERT_NEm #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm From 83948150c71362a786dbd660223fe9ab505fb15a Mon Sep 17 00:00:00 2001 From: Maxwell Bernstein Date: Wed, 2 Sep 2020 23:42:03 -0700 Subject: [PATCH 04/21] Rename _NE to _NEQ --- example.c | 2 +- greatest.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example.c b/example.c index 320ca20..47a142c 100644 --- a/example.c +++ b/example.c @@ -32,7 +32,7 @@ TEST expect_equal(void) { TEST expect_not_equal(void) { int i = 9; - ASSERT_NE(10, i); + ASSERT_NEQ(10, i); PASS(); } diff --git a/greatest.h b/greatest.h index 5d548c2..270578e 100644 --- a/greatest.h +++ b/greatest.h @@ -434,8 +434,8 @@ typedef enum greatest_test_res { GREATEST_ASSERT_FALSEm(#COND, COND) #define GREATEST_ASSERT_EQ(EXP, GOT) \ GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) -#define GREATEST_ASSERT_NE(EXP, GOT) \ - GREATEST_ASSERT_NEm(#EXP " == " #GOT, EXP, GOT) +#define GREATEST_ASSERT_NEQ(EXP, GOT) \ + GREATEST_ASSERT_NEQm(#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) \ @@ -483,7 +483,7 @@ typedef enum greatest_test_res { } while (0) /* Fail if EXP == GOT (equality comparison by !=). */ -#define GREATEST_ASSERT_NEm(MSG, EXP, GOT) \ +#define GREATEST_ASSERT_NEQm(MSG, EXP, GOT) \ do { \ greatest_info.assertions++; \ if ((EXP) == (GOT)) { GREATEST_FAILm(MSG); } \ @@ -1186,7 +1186,7 @@ greatest_run_info greatest_info #define ASSERTm GREATEST_ASSERTm #define ASSERT_FALSE GREATEST_ASSERT_FALSE #define ASSERT_EQ GREATEST_ASSERT_EQ -#define ASSERT_NE GREATEST_ASSERT_NE +#define ASSERT_NEQ GREATEST_ASSERT_NEQ #define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T @@ -1196,7 +1196,7 @@ greatest_run_info greatest_info #define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ #define ASSERT_FALSEm GREATEST_ASSERT_FALSEm #define ASSERT_EQm GREATEST_ASSERT_EQm -#define ASSERT_NEm GREATEST_ASSERT_NEm +#define ASSERT_NEQm GREATEST_ASSERT_NEQm #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm From a1f4d8a7c16d395089d1f208006dc3bb28b50332 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 11:03:38 -0400 Subject: [PATCH 05/21] CHANGELOG.md: Add new, empty section for future 1.5.0 release. --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b57ec85..af36924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # greatest Changes By Release +## v1.5.0 - 2020-xx-xx + +### API Changes + +None. + + +### Bug Fixes + +None. + + +### Other Improvements + +None. + + ## v1.4.2 - 2019-03-24 ### API Changes From c293ddb4baf7f2236e46add86716e827714b3faf Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 11:10:39 -0400 Subject: [PATCH 06/21] Change default: `GREATEST_USE_LONGJMP` is now 0, to suppress warning. Closes #87. --- CHANGELOG.md | 5 ++++- Makefile | 4 ++-- greatest.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af36924..8b0bb99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ ### API Changes -None. +Changed default: `GREATEST_USE_LONGJMP` now defaults to 0. This eliminates +a warning about variables that can possibly become stale/corrupt in the +presence of `longjmp`. Since `GREATEST_FAIL_WITH_LONGJMP` isn't frequently +used, it should probably be opt-in. ### Bug Fixes diff --git a/Makefile b/Makefile index add2e4c..6bb08a0 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,8 @@ PROGRAMS_CPP= example_cpp # Uncomment to demo c99 parametric testing. #CFLAGS += -std=c99 -# Uncomment to disable setjmp()/longjmp(). -#CFLAGS += -DGREATEST_USE_LONGJMP=0 +# Uncomment to enable setjmp()/longjmp(). +#CFLAGS += -DGREATEST_USE_LONGJMP=1 # Uncomment to disable clock() / time.h. #CFLAGS += -DGREATEST_USE_TIME=0 diff --git a/greatest.h b/greatest.h index fd4fe24..1326bf6 100644 --- a/greatest.h +++ b/greatest.h @@ -119,7 +119,7 @@ int main(int argc, char **argv) { /* Set to 0 to disable all use of setjmp/longjmp. */ #ifndef GREATEST_USE_LONGJMP -#define GREATEST_USE_LONGJMP 1 +#define GREATEST_USE_LONGJMP 0 #endif /* Make it possible to replace fprintf with another From f4d87723ec3a66153a88f44b5d82392c0a62544a Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 11:32:41 -0400 Subject: [PATCH 07/21] Makefile: Further minor fixes for incremental rebuilding. --- CHANGELOG.md | 5 ++++- Makefile | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b0bb99..6a060cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,10 @@ used, it should probably be opt-in. ### Bug Fixes -None. +Makefile: Fix targets so all files are rebuilt when `greatest.h` or the +`Makefile` are modified, but without potentially breaking the build due +to including `greatest.h` as a linker argument to `example_trunc` (which +could happen with clang). (Thanks vemakereporter.) ### Other Improvements diff --git a/Makefile b/Makefile index 6bb08a0..24c1881 100644 --- a/Makefile +++ b/Makefile @@ -32,15 +32,19 @@ example: example.o example_suite.o example_no_suite: example_no_suite.o example_no_runner: example_no_runner.o example_shuffle: example_shuffle.o +example_trunc: example_trunc.o -example_trunc: greatest.h +*.o: greatest.h Makefile -example_cpp: example_cpp.cpp greatest.h +example_cpp: example_cpp.cpp greatest.h Makefile ${CXX} -o $@ example_cpp.cpp ${CPPFLAGS} ${LDFLAGS} -%.o: %.c greatest.h Makefile +%.o: %.c ${CC} -c -o $@ ${CFLAGS} $< +%.o: %.cpp + ${CXX} -c -o $@ ${CPPFLAGS} $< + %: %.o ${CC} -o $@ ${LDFLAGS} $^ From 9658f8b157b98677bda70906f9c34e1bae2ec53e Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 11:33:21 -0400 Subject: [PATCH 08/21] .gitignore: example_cpp --- .gitignore | 1 + CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bee8170..159eeef 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ example_no_runner example_random example_shuffle example_trunc +example_cpp *.o diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a060cb..96a2052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ could happen with clang). (Thanks vemakereporter.) ### Other Improvements -None. +Added built `example_cpp` executable to `.gitignore`. ## v1.4.2 - 2019-03-24 From a210f1230aadbd9e8cbe67c523751e2f920ca61a Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 11:44:12 -0400 Subject: [PATCH 09/21] Guard against nested `RUN_TEST` calls. Set a flag for when a test is actually running and explicitly ignore calls to RUN_TEST from inside another test, with a warning message. Closes #97. --- CHANGELOG.md | 2 ++ example.c | 7 +++++++ greatest.h | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96a2052..fa31a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ Makefile: Fix targets so all files are rebuilt when `greatest.h` or the to including `greatest.h` as a linker argument to `example_trunc` (which could happen with clang). (Thanks vemakereporter.) +Calls to `GREATEST_RUN_TEST` from inside another test are now ignored. + ### Other Improvements diff --git a/example.c b/example.c index 13af484..29de404 100644 --- a/example.c +++ b/example.c @@ -255,6 +255,12 @@ TEST extra_slow_test(void) { PASS(); } +TEST nested_RUN_TEST(void) { + printf("This nested RUN_TEST call should not trigger an infinite loop...\n"); + RUN_TEST(nested_RUN_TEST); + PASS(); +} + static void trace_setup(void *arg) { printf("-- in setup callback\n"); teardown_was_called = 0; @@ -359,6 +365,7 @@ SUITE(suite) { RUN_TEST(expect_enum_equal_only_evaluates_args_once); RUN_TEST(extra_slow_test); + RUN_TEST(nested_RUN_TEST); } TEST standalone_test(void) { diff --git a/greatest.h b/greatest.h index 1326bf6..4747260 100644 --- a/greatest.h +++ b/greatest.h @@ -232,7 +232,8 @@ struct greatest_prng { typedef struct greatest_run_info { unsigned char flags; unsigned char verbosity; - unsigned char pad_0[2]; + unsigned char running_test; /* guard for nested RUN_TEST calls */ + unsigned char pad_0[1]; unsigned int tests_run; /* total test count */ @@ -734,9 +735,14 @@ int greatest_test_pre(const char *name) { \ goto clear; /* don't run this test yet */ \ } \ } \ + if (g->running_test) { \ + fprintf(stderr, "Error: Test run inside another test.\n"); \ + return 0; \ + } \ GREATEST_SET_TIME(g->suite.pre_test); \ if (g->setup) { g->setup(g->setup_udata); } \ p->count_run++; \ + g->running_test = 1; \ return 1; /* test should be run */ \ } else { \ goto clear; /* skipped */ \ @@ -795,6 +801,7 @@ void greatest_test_post(int res) { \ greatest_info.teardown(udata); \ } \ \ + greatest_info.running_test = 0; \ if (res <= GREATEST_TEST_RES_FAIL) { \ greatest_do_fail(); \ } else if (res >= GREATEST_TEST_RES_SKIP) { \ From 13fc3d43f32c7372f4f92a51527b8f44beaf4166 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 12:05:40 -0400 Subject: [PATCH 10/21] Add `greatest_set_exact_name_match()` / `-e` flag. Closes #84. --- CHANGELOG.md | 4 ++++ README.md | 9 ++++++++- greatest.h | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa31a09..64503c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ a warning about variables that can possibly become stale/corrupt in the presence of `longjmp`. Since `GREATEST_FAIL_WITH_LONGJMP` isn't frequently used, it should probably be opt-in. +Added `greatest_set_exact_name_match()` / `-e` flag, which changes the +name-based filtering from substring to exact match. Note that filtering +on an exact suite name will not skip tests run outside of any suite. + ### Bug Fixes diff --git a/README.md b/README.md index 7329c0b..ca1b5ed 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,11 @@ also contain "slow": The string matching includes optional test name suffixes. +The `greatest_set_exact_name_match()` function and corresponding `-e` +command line runner flag can be used to only run tests and/or suites +whose names exactly match the name filter(s). Note: exact-match suite +filtering by name will not skip tests that are run outside of any suite. + ## Available Assertions @@ -350,7 +355,7 @@ The function should have a return type of `enum greatest_test_res`. Test runners build with the following command line options: - Usage: (test_runner) [-hlfav] [-s SUITE] [-t TEST] [-x EXCLUDE] + Usage: (test_runner) [-hlfave] [-s SUITE] [-t TEST] [-x EXCLUDE] -h, --help print this Help -l List suites and tests, then exit (dry run) -f Stop runner after first failure @@ -358,6 +363,7 @@ Test runners build with the following command line options: -v Verbose output -s SUITE only run suite w/ name containing substring SUITE -t TEST only run test w/ name containing substring TEST + -e only run exact name match for -s or -t -x EXCLUDE exclude tests containing string substring EXCLUDE Any arguments after `--` will be ignored. @@ -383,6 +389,7 @@ The command line flags above have corresponding functions: - `greatest_stop_at_first_fail()` - `greatest_abort_on_fail()` - `greatest_list_only()` +- `greatest_set_exact_name_match()` - `greatest_set_suite_filter(const char *filter)` - `greatest_set_test_filter(const char *filter)` - `greatest_set_test_exclude(const char *filter)` diff --git a/greatest.h b/greatest.h index 4747260..faeb2c9 100644 --- a/greatest.h +++ b/greatest.h @@ -233,7 +233,7 @@ typedef struct greatest_run_info { unsigned char flags; unsigned char verbosity; unsigned char running_test; /* guard for nested RUN_TEST calls */ - unsigned char pad_0[1]; + unsigned char exact_name_match; unsigned int tests_run; /* total test count */ @@ -322,6 +322,7 @@ int greatest_all_passed(void); void greatest_set_suite_filter(const char *filter); void greatest_set_test_filter(const char *filter); void greatest_set_test_exclude(const char *filter); +void greatest_set_exact_name_match(void); void greatest_stop_at_first_fail(void); void greatest_abort_on_fail(void); void greatest_list_only(void); @@ -690,6 +691,9 @@ static int greatest_name_match(const char *name, const char *filter, \ size_t offset = 0; \ size_t filter_len = filter ? strlen(filter) : 0; \ if (filter_len == 0) { return res_if_none; } /* no filter */ \ + if (greatest_info.exact_name_match && strlen(name) != filter_len) { \ + return 0; /* ignore substring matches */ \ + } \ while (name[offset] != '\0') { \ if (name[offset] == filter[0]) { \ if (0 == strncmp(&name[offset], filter, filter_len)) { \ @@ -902,7 +906,7 @@ int greatest_do_assert_equal_t(const void *expd, const void *got, \ \ static void greatest_usage(const char *name) { \ GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Usage: %s [-hlfav] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ + "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ " -h, --help print this Help\n" \ " -l List suites and tests, then exit (dry run)\n" \ " -f Stop runner after first failure\n" \ @@ -910,6 +914,7 @@ static void greatest_usage(const char *name) { \ " -v Verbose output\n" \ " -s SUITE only run suites containing substring SUITE\n" \ " -t TEST only run tests containing substring TEST\n" \ + " -e only run exact name match for -s or -t\n" \ " -x EXCLUDE exclude tests containing substring EXCLUDE\n", \ name); \ } \ @@ -929,6 +934,8 @@ static void greatest_parse_options(int argc, char **argv) { \ greatest_set_test_filter(argv[i + 1]); i++; break; \ case 'x': /* test name exclusion */ \ greatest_set_test_exclude(argv[i + 1]); i++; break; \ + case 'e': /* exact name match */ \ + greatest_set_exact_name_match(); break; \ case 'f': /* first fail flag */ \ greatest_stop_at_first_fail(); break; \ case 'a': /* abort() on fail flag */ \ @@ -969,6 +976,10 @@ void greatest_set_suite_filter(const char *filter) { \ greatest_info.suite_filter = filter; \ } \ \ +void greatest_set_exact_name_match(void) { \ + greatest_info.exact_name_match = 1; \ +} \ + \ void greatest_stop_at_first_fail(void) { \ greatest_set_flag(GREATEST_FLAG_FIRST_FAIL); \ } \ From 7757805ba29772bdfd21d3b45f72fd42f935b798 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 12:27:53 -0400 Subject: [PATCH 11/21] List `greatest_get_verbosity()` in README.md. Closes #91. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ca1b5ed..543aede 100644 --- a/README.md +++ b/README.md @@ -393,6 +393,7 @@ The command line flags above have corresponding functions: - `greatest_set_suite_filter(const char *filter)` - `greatest_set_test_filter(const char *filter)` - `greatest_set_test_exclude(const char *filter)` +- `greatest_get_verbosity()` - `greatest_set_verbosity(unsigned int verbosity)` From 8ac09a344eb9a91945e087f9f4aceb5aa43147ed Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 12:42:40 -0400 Subject: [PATCH 12/21] README.md: Add to Basic Usage section. This expands on a couple things that people have found confusing. Closes #95, #93, #85. --- CHANGELOG.md | 3 +++ README.md | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64503c4..0c62b30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,9 @@ Calls to `GREATEST_RUN_TEST` from inside another test are now ignored. Added built `example_cpp` executable to `.gitignore`. +Expanded on the role of `RUN_TEST`, `RUN_TEST1`, `RUN_TESTp`, +`PASS`, `SKIP`, and `FAIL` in the README. + ## v1.4.2 - 2019-03-24 diff --git a/README.md b/README.md index 543aede..952cf0e 100644 --- a/README.md +++ b/README.md @@ -114,19 +114,39 @@ Total: 1 test (47 ticks, 0.000 sec), 3 assertions Pass: 1, fail: 0, skip: 0. ``` +Tests are run with `RUN_TEST(test_name)`, which can be called directly +from the test runner's `main` function or grouped into suites (which are +run with `RUN_SUITE(suite_name)`). (Calls to `RUN_TEST` from inside +another test are ignored.) + +Test cases can be run with arguments: `RUN_TEST1(test_name, arg)` passes +a single argument, and if C99 features are supported, then +`RUN_TESTp(test_name, ...)` uses `__VA_ARGS__` to run a test case with +one or mare arguments. `greatest_set_test_suffix` sets a name suffix, so +output from the test runner can include info about arguments. + Test cases should call assertions and then end with `PASS()`, `SKIP()`, `FAIL()`, or their custom message variants (e.g. `SKIPm("TODO");`). If there are any test failures, the test runner will return 1, otherwise it will return 0. (Skips do not cause the test runner to report failure.) +`PASS()`, `SKIP()`, `FAIL()`, and their custom message variants are +macros that updating internal bookkeeping and then returning and enum +value, such as `GREATEST_TEST_RES_FAIL`. They all `return` from the +current test case function. + `PASS()`/`PASSm("msg")` prints as a dot when verbosity is zero, or the test name and custom message (if any) with verbosity >= 1. `FAIL()`/`FAILm("msg")` always prints "FAIL test_name: msg file:line". -`SKIP()`/`SKIPm("msg")` prints as an 's' when verbosity is zero, or -the test name and custom message (if any) with verbosity >= 1. +`SKIP()`/`SKIPm("msg")` prints as an 's' when verbosity is zero, or the +test name and custom message (if any) with verbosity >= 1. Because skips +are not treated as a failure by the test runner, they can be used to +skip test cases that aren't relevant in a particular build or +environment, a way to temporarily disable broken tests, or as a sort of +todo list for tests and functionality under active development. Tests and suites are just functions, so normal C scoping rules apply. For example, a test or suite named "main" will have a name collision. From f4db11e9b451ef06a6d1968b3ee9546fe5945076 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 12:48:04 -0400 Subject: [PATCH 13/21] README.md: Other minor changes. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 952cf0e..d1ec0d6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A testing system for C, contained in 1 header file. -## Key Features +## Key Features and Project Goals - **Small, Portable, Lightweight** @@ -149,7 +149,7 @@ environment, a way to temporarily disable broken tests, or as a sort of todo list for tests and functionality under active development. Tests and suites are just functions, so normal C scoping rules apply. -For example, a test or suite named "main" will have a name collision. +For example, a test or suite named `main` will have a name collision. (For more examples, look at `example.c` and `example_suite.c`.) From 77b19d84fcaa8520bab04881f34cd0e2e9207e1c Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 14:29:14 -0400 Subject: [PATCH 14/21] CHANGELOG.md: Update to note theosotr's Makefile PR. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c62b30..811e04b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ on an exact suite name will not skip tests run outside of any suite. Makefile: Fix targets so all files are rebuilt when `greatest.h` or the `Makefile` are modified, but without potentially breaking the build due to including `greatest.h` as a linker argument to `example_trunc` (which -could happen with clang). (Thanks vemakereporter.) +could happen with clang). (Thanks @vemakereporter, @theosotr.) Calls to `GREATEST_RUN_TEST` from inside another test are now ignored. From fc8054b4a67b67eee9a99674e818f7771b5b15d9 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 14:34:53 -0400 Subject: [PATCH 15/21] Mention `ASSERT_NEQ` in README.md and CHANGELOG.md. --- CHANGELOG.md | 2 ++ README.md | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 811e04b..f5ccd15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ Added `greatest_set_exact_name_match()` / `-e` flag, which changes the name-based filtering from substring to exact match. Note that filtering on an exact suite name will not skip tests run outside of any suite. +Added `GREATEST_ASSERT_NEQ`. (Thanks @tekknolagi.) + ### Bug Fixes diff --git a/README.md b/README.md index d1ec0d6..d1a733c 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,11 @@ differ, use `ASSERT_EQ_FMT`. To compare with custom equality test and print functions, use `ASSERT_EQUAL_T` instead. +### `ASSERT_NEQ(EXPECTED, ACTUAL)` + +Assert that `EXPECTED != ACTUAL`. + + ### `ASSERT_EQ_FMT(EXPECTED, ACTUAL, FORMAT)` Assert that `EXPECTED == ACTUAL`. If they are not equal, print their From c9a4a1782ca56c39fb01ac5936763644432fe361 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 14:45:14 -0400 Subject: [PATCH 16/21] Eliminate warning for implicit fallthrough. When built with clang and `-Weverything`, `GREATEST_MAIN_DEFS()` can produce a warning for `-Wimplicit-fallthrough`. Rearrange the case labels to make the fallthrough explicit. --- CHANGELOG.md | 3 +++ greatest.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5ccd15..ef3be12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ Added built `example_cpp` executable to `.gitignore`. Expanded on the role of `RUN_TEST`, `RUN_TEST1`, `RUN_TESTp`, `PASS`, `SKIP`, and `FAIL` in the README. +Addressed a `-Wimplicit-fallthrough` warning when building with clang +using `-Weverything`. + ## v1.4.2 - 2019-03-24 diff --git a/greatest.h b/greatest.h index 469abd1..261a506 100644 --- a/greatest.h +++ b/greatest.h @@ -955,13 +955,13 @@ static void greatest_parse_options(int argc, char **argv) { \ greatest_info.verbosity++; break; \ case 'h': /* help */ \ greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ + default: \ case '-': \ if (0 == strncmp("--help", argv[i], 6)) { \ greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ } else if (0 == strncmp("--", argv[i], 2)) { \ return; /* ignore following arguments */ \ - } /* fall through */ \ - default: \ + } \ GREATEST_FPRINTF(GREATEST_STDOUT, \ "Unknown argument '%s'\n", argv[i]); \ greatest_usage(argv[0]); \ From d9d0029016616ce034e54500631805209941daee Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 7 Sep 2020 14:47:38 -0400 Subject: [PATCH 17/21] Fix CLI test runner handling for unknown arguments starting with `--`. Previously anything besides `--help` was handled the same way as `--`; instead of printing an error for an unknown argument, it skipped processing all remaining arguments. --- CHANGELOG.md | 4 ++++ greatest.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef3be12..bb03198 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ could happen with clang). (Thanks @vemakereporter, @theosotr.) Calls to `GREATEST_RUN_TEST` from inside another test are now ignored. +Other flags starting with `--` besides `--help` (print help) and `--` +(ignore rest of ARGV) now produce an "Unknown argument" message; +previously they were unintentionally handled like `--`. + ### Other Improvements diff --git a/greatest.h b/greatest.h index 261a506..ec4a99d 100644 --- a/greatest.h +++ b/greatest.h @@ -959,7 +959,7 @@ static void greatest_parse_options(int argc, char **argv) { \ case '-': \ if (0 == strncmp("--help", argv[i], 6)) { \ greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ - } else if (0 == strncmp("--", argv[i], 2)) { \ + } else if (0 == strcmp("--", argv[i])) { \ return; /* ignore following arguments */ \ } \ GREATEST_FPRINTF(GREATEST_STDOUT, \ From b082166c69e426b25380d30037909de3277e2bf3 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 15 Feb 2021 16:11:00 -0500 Subject: [PATCH 18/21] Add assertions for (> >= < <=): _GT, _GTE, _LT, _LTE. These all attempt to construct a reasonable default failure message, and otherwise fall through to custom message versions of their respective assertions. This increases the SLOCCount size to over 1000 LOC. --- CHANGELOG.md | 6 +++++- README.md | 20 +++++++++++++++++++ example.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ greatest.h | 35 +++++++++++++++++++++++--------- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb03198..e7ab243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,11 @@ Added `greatest_set_exact_name_match()` / `-e` flag, which changes the name-based filtering from substring to exact match. Note that filtering on an exact suite name will not skip tests run outside of any suite. -Added `GREATEST_ASSERT_NEQ`. (Thanks @tekknolagi.) +Added `GREATEST_ASSERT_NEQ` and `GREATEST_ASSERT_NEQm`. (Thanks @tekknolagi.) + +Added `GREATEST_ASSERT_GT`, `GREATEST_ASSERT_GTE`, `GREATEST_ASSERT_LT`, +and `GREATEST_ASSERT_LTE`, along with their custom message (`m`) +variants. ### Bug Fixes diff --git a/README.md b/README.md index d1a733c..f1ba127 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,26 @@ and print functions, use `ASSERT_EQUAL_T` instead. Assert that `EXPECTED != ACTUAL`. +### `ASSERT_GT(EXPECTED, ACTUAL)` + +Assert that `EXPECTED > ACTUAL`. + + +### `ASSERT_GTE(EXPECTED, ACTUAL)` + +Assert that `EXPECTED >= ACTUAL`. + + +### `ASSERT_LT(EXPECTED, ACTUAL)` + +Assert that `EXPECTED < ACTUAL`. + + +### `ASSERT_LTE(EXPECTED, ACTUAL)` + +Assert that `EXPECTED <= ACTUAL`. + + ### `ASSERT_EQ_FMT(EXPECTED, ACTUAL, FORMAT)` Assert that `EXPECTED == ACTUAL`. If they are not equal, print their diff --git a/example.c b/example.c index 5430864..f6f4d2b 100644 --- a/example.c +++ b/example.c @@ -267,6 +267,54 @@ TEST nested_RUN_TEST(void) { PASS(); } +TEST eq_pass_and_fail(void) { + const int x = 1, y = 2; + ASSERT_EQ(x, x); + ASSERT_EQm("y == y", y, y); + ASSERT_EQ(x, y); + PASS(); +} + +TEST neq_pass_and_fail(void) { + const int x = 1, y = 2; + ASSERT_NEQm("x != y", x, y); + ASSERT_NEQ(x, x); + PASS(); +} + +TEST gt_pass_and_fail(void) { + const int x = 1, y = 2; + ASSERT_GTm("y > x", y, x); + ASSERT_GT(x, x); + PASS(); +} + +TEST gte_pass_and_fail(void) { + const int x = 1, y = 2, z = 3;; + ASSERT_GTE(z, y); + ASSERT_GTE(y, x); + ASSERT_GTE(z, x); + ASSERT_GTEm("y >= y", y, y); + ASSERT_GTE(y, z); + PASS(); +} + +TEST lt_pass_and_fail(void) { + const int x = 1, y = 2; + ASSERT_LTm("x < y", x, y); + ASSERT_LT(x, x); + PASS(); +} + +TEST lte_pass_and_fail(void) { + const int x = 1, y = 2, z = 3;; + ASSERT_LTE(y, z); + ASSERT_LTEm("x <= y", x, y); + ASSERT_LTE(x, x); + ASSERT_LTE(z, x); + PASS(); +} + static void trace_setup(void *arg) { printf("-- in setup callback\n"); teardown_was_called = 0; @@ -373,6 +421,14 @@ SUITE(suite) { RUN_TEST(extra_slow_test); RUN_TEST(nested_RUN_TEST); + + printf("\nThese next several tests should also fail:\n"); + RUN_TEST(eq_pass_and_fail); + RUN_TEST(neq_pass_and_fail); + RUN_TEST(gt_pass_and_fail); + RUN_TEST(gte_pass_and_fail); + RUN_TEST(lt_pass_and_fail); + RUN_TEST(lte_pass_and_fail); } TEST standalone_test(void) { diff --git a/greatest.h b/greatest.h index ec4a99d..a2b00ee 100644 --- a/greatest.h +++ b/greatest.h @@ -438,6 +438,14 @@ typedef enum greatest_test_res { GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) #define GREATEST_ASSERT_NEQ(EXP, GOT) \ GREATEST_ASSERT_NEQm(#EXP " == " #GOT, EXP, GOT) +#define GREATEST_ASSERT_GT(EXP, GOT) \ + GREATEST_ASSERT_GTm(#EXP " <= " #GOT, EXP, GOT) +#define GREATEST_ASSERT_GTE(EXP, GOT) \ + GREATEST_ASSERT_GTEm(#EXP " < " #GOT, EXP, GOT) +#define GREATEST_ASSERT_LT(EXP, GOT) \ + GREATEST_ASSERT_LTm(#EXP " >= " #GOT, EXP, GOT) +#define GREATEST_ASSERT_LTE(EXP, GOT) \ + GREATEST_ASSERT_LTEm(#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) \ @@ -477,19 +485,20 @@ typedef enum greatest_test_res { if ((COND)) { GREATEST_FAILm(MSG); } \ } while (0) -/* Fail if EXP != GOT (equality comparison by ==). */ -#define GREATEST_ASSERT_EQm(MSG, EXP, GOT) \ +/* Internal macro for relational assertions */ +#define GREATEST__REL(REL, MSG, EXP, GOT) \ do { \ greatest_info.assertions++; \ - if ((EXP) != (GOT)) { GREATEST_FAILm(MSG); } \ + if (!((EXP) REL (GOT))) { GREATEST_FAILm(MSG); } \ } while (0) -/* Fail if EXP == GOT (equality comparison by !=). */ -#define GREATEST_ASSERT_NEQm(MSG, EXP, GOT) \ - do { \ - greatest_info.assertions++; \ - if ((EXP) == (GOT)) { GREATEST_FAILm(MSG); } \ - } while (0) +/* Fail if EXP is not ==, !=, >, <, >=, or <= to GOT. */ +#define GREATEST_ASSERT_EQm(MSG,E,G) GREATEST__REL(==, MSG,E,G) +#define GREATEST_ASSERT_NEQm(MSG,E,G) GREATEST__REL(!=, MSG,E,G) +#define GREATEST_ASSERT_GTm(MSG,E,G) GREATEST__REL(>, MSG,E,G) +#define GREATEST_ASSERT_GTEm(MSG,E,G) GREATEST__REL(>=, MSG,E,G) +#define GREATEST_ASSERT_LTm(MSG,E,G) GREATEST__REL(<, MSG,E,G) +#define GREATEST_ASSERT_LTEm(MSG,E,G) GREATEST__REL(<=, MSG,E,G) /* Fail if EXP != GOT (equality comparison by ==). * Warning: FMT, EXP, and GOT will be evaluated more @@ -1205,6 +1214,10 @@ greatest_run_info greatest_info #define ASSERT_FALSE GREATEST_ASSERT_FALSE #define ASSERT_EQ GREATEST_ASSERT_EQ #define ASSERT_NEQ GREATEST_ASSERT_NEQ +#define ASSERT_GT GREATEST_ASSERT_GT +#define ASSERT_GTE GREATEST_ASSERT_GTE +#define ASSERT_LT GREATEST_ASSERT_LT +#define ASSERT_LTE GREATEST_ASSERT_LTE #define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T @@ -1215,6 +1228,10 @@ greatest_run_info greatest_info #define ASSERT_FALSEm GREATEST_ASSERT_FALSEm #define ASSERT_EQm GREATEST_ASSERT_EQm #define ASSERT_NEQm GREATEST_ASSERT_NEQm +#define ASSERT_GTm GREATEST_ASSERT_GTm +#define ASSERT_GTEm GREATEST_ASSERT_GTEm +#define ASSERT_LTm GREATEST_ASSERT_LTm +#define ASSERT_LTEm GREATEST_ASSERT_LTEm #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm From 50ffe66f85dc211c6772e3c8997f3a0b704a8f8b Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 15 Feb 2021 16:20:50 -0500 Subject: [PATCH 19/21] example_trunc.c: No need to disable GREATEST_USE_LONGJUMP now. --- example_trunc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/example_trunc.c b/example_trunc.c index 40de137..a081694 100644 --- a/example_trunc.c +++ b/example_trunc.c @@ -1,9 +1,6 @@ /* Make the buffer size VERY small, to check truncation */ #define GREATEST_TESTNAME_BUF_SIZE 8 -/* Disable longjmp, since it isn't used here. */ -#define GREATEST_USE_LONGJMP 0 - #include "greatest.h" TEST t(void) { From 4c262e055bd268a7d67c79a70eb328512de07b4c Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 15 Feb 2021 16:21:52 -0500 Subject: [PATCH 20/21] greatest.h: Minor changes for self-imposed LOC limit. The GT, GTE, LT, LTE operators brought it over 1000 LOC, make small whitespace changes to bring it back under 1000. This totally artifical and self-imposed constraint has guided greatests's evolution so far, and I would rather keep it. --- greatest.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/greatest.h b/greatest.h index a2b00ee..8454ff3 100644 --- a/greatest.h +++ b/greatest.h @@ -906,9 +906,7 @@ static void greatest_run_suite(greatest_suite_cb *suite_cb, \ int greatest_do_assert_equal_t(const void *expd, const void *got, \ greatest_type_info *type_info, void *udata) { \ int eq = 0; \ - if (type_info == NULL || type_info->equal == NULL) { \ - return 0; \ - } \ + if (type_info == NULL || type_info->equal == NULL) { return 0; } \ eq = type_info->equal(expd, got, udata); \ if (!eq) { \ if (type_info->print != NULL) { \ @@ -1040,8 +1038,7 @@ void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ greatest_info.setup_udata = udata; \ } \ \ -void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, \ - void *udata) { \ +void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) { \ greatest_info.teardown = cb; \ greatest_info.teardown_udata = udata; \ } \ @@ -1060,8 +1057,7 @@ static int greatest_string_printf_cb(const void *t, void *udata) { \ } \ \ greatest_type_info greatest_type_info_string = { \ - greatest_string_equal_cb, \ - greatest_string_printf_cb, \ + greatest_string_equal_cb, greatest_string_printf_cb, \ }; \ \ static int greatest_memory_equal_cb(const void *expd, const void *got, \ @@ -1179,8 +1175,7 @@ void GREATEST_PRINT_REPORT(void) { \ } \ \ greatest_type_info greatest_type_info_memory = { \ - greatest_memory_equal_cb, \ - greatest_memory_printf_cb, \ + greatest_memory_equal_cb, greatest_memory_printf_cb, \ }; \ \ greatest_run_info greatest_info From fbbf9818ec72578289716bf6002b11fd25185e02 Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Mon, 15 Feb 2021 16:27:23 -0500 Subject: [PATCH 21/21] Bump version to 1.5.0. Ten years, wow. --- CHANGELOG.md | 2 +- greatest.h | 8 ++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7ab243..47f37ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # greatest Changes By Release -## v1.5.0 - 2020-xx-xx +## v1.5.0 - 2021-02-15 ### API Changes diff --git a/greatest.h b/greatest.h index 8454ff3..af0c053 100644 --- a/greatest.h +++ b/greatest.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019 Scott Vokes + * Copyright (c) 2011-2021 Scott Vokes * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,10 +21,10 @@ extern "C" { #endif -/* 1.4.2 */ +/* 1.5.0 */ #define GREATEST_VERSION_MAJOR 1 -#define GREATEST_VERSION_MINOR 4 -#define GREATEST_VERSION_PATCH 2 +#define GREATEST_VERSION_MINOR 5 +#define GREATEST_VERSION_PATCH 0 /* A unit testing system for C, contained in 1 file. * It doesn't use dynamic allocation or depend on anything diff --git a/package.json b/package.json index 9bfa61d..944ba3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "greatest", - "version": "v1.4.2", + "version": "v1.5.0", "repo": "silentbicycle/greatest", "src": ["greatest.h"], "description": "A C testing library in 1 file. No dependencies, no dynamic allocation.",