summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2012-12-18 16:54:23 -0500
committerTavian Barnes <tavianator@tavianator.com>2012-12-18 17:02:56 -0500
commit7da79cf1e24fbc58e0ff2e498a7f3d189a51cbd6 (patch)
tree702a05f5cfb2490462c1ce93a44591cfaec5d332
parent330ead5f47a7c4904cc6cecfa36b10d75718f1ff (diff)
downloaddimension-7da79cf1e24fbc58e0ff2e498a7f3d189a51cbd6.tar.xz
Improve the unit test macro API a bit.
-rw-r--r--libdimension/tests/polynomial.c39
-rw-r--r--libdimension/tests/tests.h84
-rw-r--r--libdimension/tests/unit-test.c20
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);
}