From 7da79cf1e24fbc58e0ff2e498a7f3d189a51cbd6 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 18 Dec 2012 16:54:23 -0500 Subject: Improve the unit test macro API a bit. --- libdimension/tests/polynomial.c | 39 ++++++++++++------- libdimension/tests/tests.h | 84 ++++++++++++++++++++++++++++++----------- libdimension/tests/unit-test.c | 20 +++++++++- 3 files changed, 105 insertions(+), 38 deletions(-) diff --git a/libdimension/tests/polynomial.c b/libdimension/tests/polynomial.c index 8fd34df..208edf9 100644 --- a/libdimension/tests/polynomial.c +++ b/libdimension/tests/polynomial.c @@ -25,7 +25,7 @@ #include "tests.h" /* poly[] = 2*(x + 1)*(x - 1.2345)*(x - 2.3456)*(x - 5)*(x - 100) */ -const double poly[6] = { +static const double poly[6] = { [5] = 2.0, [4] = -215.1602, [3] = 1540.4520864, @@ -34,24 +34,35 @@ const double poly[6] = { [0] = 2895.6432, }; -DMNSN_TEST("polynomial", finds_positive_roots) +static double roots[5]; +static size_t nroots; + +#define DMNSN_CLOSE_ENOUGH 1.0e-6 + +DMNSN_TEST_SETUP(polynomial) { - double x[5]; - size_t n = dmnsn_polynomial_solve(poly, 5, x); - ck_assert_int_eq(n, 4); + nroots = dmnsn_polynomial_solve(poly, 5, roots); } -DMNSN_END_TEST -DMNSN_TEST("polynomial", accurate_roots) +DMNSN_TEST(polynomial, finds_positive_roots) { - double x[5]; - size_t n = dmnsn_polynomial_solve(poly, 5, x); + ck_assert_int_eq(nroots, 4); +} - for (size_t i = 0; i < n; ++i) { - double evmin = dmnsn_polynomial_evaluate(poly, 5, x[i] - dmnsn_epsilon); - double ev = dmnsn_polynomial_evaluate(poly, 5, x[i]); - double evmax = dmnsn_polynomial_evaluate(poly, 5, x[i] + dmnsn_epsilon); +DMNSN_TEST(polynomial, local_min_roots) +{ + for (size_t i = 0; i < nroots; ++i) { + double evmin = dmnsn_polynomial_evaluate(poly, 5, roots[i] - dmnsn_epsilon); + double ev = dmnsn_polynomial_evaluate(poly, 5, roots[i]); + double evmax = dmnsn_polynomial_evaluate(poly, 5, roots[i] + dmnsn_epsilon); ck_assert(fabs(ev) < fabs(evmin) && fabs(ev) < fabs(evmax)); } } -DMNSN_END_TEST + +DMNSN_TEST(polynomial, accurate_roots) +{ + for (size_t i = 0; i < nroots; ++i) { + double ev = dmnsn_polynomial_evaluate(poly, 5, roots[i]); + ck_assert(fabs(ev) < DMNSN_CLOSE_ENOUGH); + } +} diff --git a/libdimension/tests/tests.h b/libdimension/tests/tests.h index 3009164..0b8bfce 100644 --- a/libdimension/tests/tests.h +++ b/libdimension/tests/tests.h @@ -31,43 +31,81 @@ extern "C" { /** @internal Map to known test cases from their names. */ extern dmnsn_dictionary* dmnsn_test_cases; +/** @internal Get the test case with the given name, possibly creating it. */ +TCase *dmnsn_get_test_case(const char* name); + /** @internal Default test fixture. */ void dmnsn_test_setup(void); /** @internal Default test fixture. */ void dmnsn_test_teardown(void); /** - * Mark the beginning of a test. + * Defines a test. * @param[in] tcase The name of the test case for this test. * @param[in] test The name of the test itself. */ -#define DMNSN_TEST(tcase, test) \ - static void dmnsn_test_##test(int _i); \ +#define DMNSN_TEST(tcase, test) \ + DMNSN_TEST_IMPL(#tcase, tcase##_test_##test) + +#define DMNSN_TEST_IMPL(tcase, test) \ + DMNSN_TEST_IMPL2(tcase, \ + dmnsn_##test, \ + dmnsn_##test##_impl, \ + dmnsn_add_##test) + +#define DMNSN_TEST_IMPL2(tcase, test, test_impl, add_test) \ + static void test(int _i); \ + static void test_impl(int _i); \ + \ + __attribute__((constructor)) \ + static void \ + add_test(void) \ + { \ + TCase *tc = dmnsn_get_test_case(tcase); \ + tcase_add_test(tc, test); \ + } \ + \ + START_TEST(test) \ + { \ + test_impl(_i); \ + } \ + END_TEST \ + \ + static void \ + test_impl(int _i) + +/** + * Defines the setup method for a test case. + * @param[in] tcase The name of the test case. + */ +#define DMNSN_TEST_SETUP(tcase) \ + DMNSN_TEST_FIXTURE(#tcase, tcase##_test_fixture_setup, true) + +/** + * Defines the teardown method for a test case. + * @param[in] tcase The name of the test case. + */ +#define DMNSN_TEST_TEARDOWN(tcase) \ + DMNSN_TEST_FIXTURE(#tcase, tcase##_test_fixture_teardown, false) + +#define DMNSN_TEST_FIXTURE(tcase, fixture, is_setup) \ + DMNSN_TEST_FIXTURE2(tcase, dmnsn_##fixture, dmnsn_add_##fixture, is_setup) + +#define DMNSN_TEST_FIXTURE2(tcase, fixture, add_fixture, is_setup) \ + static void fixture(void); \ \ __attribute__((constructor)) \ - static void dmnsn_add_test_##test(void) \ + static void \ + add_fixture(void) \ { \ - if (dmnsn_test_cases == NULL) { \ - dmnsn_test_cases = dmnsn_new_dictionary(sizeof(TCase *)); \ - } \ - \ - TCase *tc; \ - TCase **tcp = dmnsn_dictionary_at(dmnsn_test_cases, tcase); \ - if (tcp == NULL) { \ - tc = tcase_create(tcase); \ - tcase_add_checked_fixture(tc, dmnsn_test_setup, dmnsn_test_teardown); \ - dmnsn_dictionary_insert(dmnsn_test_cases, tcase, &tc); \ - } else { \ - tc = *tcp; \ - } \ - \ - tcase_add_test(tc, dmnsn_test_##test); \ + TCase *tc = dmnsn_get_test_case(tcase); \ + tcase_add_checked_fixture(tc, \ + is_setup ? fixture : NULL, \ + !is_setup ? fixture : NULL); \ } \ \ - START_TEST(dmnsn_test_##test) - -/** Mark the end of a test. */ -#define DMNSN_END_TEST END_TEST + static void \ + fixture(void) /* * Test canvas diff --git a/libdimension/tests/unit-test.c b/libdimension/tests/unit-test.c index a15c960..d6d256e 100644 --- a/libdimension/tests/unit-test.c +++ b/libdimension/tests/unit-test.c @@ -26,6 +26,24 @@ dmnsn_dictionary *dmnsn_test_cases = NULL; +TCase * +dmnsn_get_test_case(const char* name) +{ + if (!dmnsn_test_cases) { + dmnsn_test_cases = dmnsn_new_dictionary(sizeof(TCase *)); + } + + TCase **tcp = dmnsn_dictionary_at(dmnsn_test_cases, name); + if (tcp) { + return *tcp; + } + + TCase *tc = tcase_create(name); + tcase_add_checked_fixture(tc, dmnsn_test_setup, dmnsn_test_teardown); + dmnsn_dictionary_insert(dmnsn_test_cases, name, &tc); + return tc; +} + void dmnsn_test_setup(void) { @@ -53,7 +71,7 @@ dmnsn_test_suite() { dmnsn_suite = suite_create("Dimension"); - if (dmnsn_test_cases != NULL) { + if (dmnsn_test_cases) { dmnsn_dictionary_apply(dmnsn_test_cases, dmnsn_add_test_cases); } -- cgit v1.2.3