diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/geometry/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/geometry/geometry.c | 71 | ||||
-rw-r--r-- | src/geometry/geometry.h | 20 | ||||
-rw-r--r-- | src/geometry/geometry.test.c | 49 | ||||
-rw-r--r-- | src/test/lily-test.c | 366 | ||||
-rw-r--r-- | src/test/lily-test.h | 837 | ||||
-rw-r--r-- | src/test/test.c | 7 | ||||
-rw-r--r-- | src/test/test.h | 13 | ||||
-rw-r--r-- | src/transform/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/transform/transform.c | 170 | ||||
-rw-r--r-- | src/transform/transform.h | 26 | ||||
-rw-r--r-- | src/transform/transform.test.c | 316 | ||||
-rw-r--r-- | src/util/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/util/util.c | 23 | ||||
-rw-r--r-- | src/util/util.h | 6 | ||||
-rw-r--r-- | src/util/util.test.c | 61 |
17 files changed, 760 insertions, 1233 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78cf520..bb8aa82 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,10 +6,8 @@ target_link_libraries(kalmia ezxml) if (KALMIA_BUILD_TESTS) target_sources( kalmia-tests PUBLIC - test/lily-test.c test/test.c ) endif() -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/transform) -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/geometry) +add_subdirectory(util) diff --git a/src/geometry/CMakeLists.txt b/src/geometry/CMakeLists.txt deleted file mode 100644 index e1a0995..0000000 --- a/src/geometry/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -project(kalmia) - -target_sources(kalmia PUBLIC geometry.c) - -if (KALMIA_BUILD_TESTS) - target_sources(kalmia-tests PUBLIC geometry.test.c) -endif() diff --git a/src/geometry/geometry.c b/src/geometry/geometry.c deleted file mode 100644 index be9ce25..0000000 --- a/src/geometry/geometry.c +++ /dev/null @@ -1,71 +0,0 @@ -#include <string.h> -#include <stdlib.h> - -#include <kalmia.h> -#include <ezxml.h> -#include "geometry.h" - - -static int copy_str(char **dest, const char *src) -{ - if (src == NULL) { - *dest = NULL; - return 0; - } - - size_t len = strlen(src)+1; - *dest = malloc(len * sizeof(char)); - if (*dest == NULL) - return -1; - strncpy(*dest, src, len); - return 0; -} - - -ka_float_array_t * kai_parse_float_array(ezxml_t tag) -{ - if (strcmp(ezxml_name(tag), "float_array") != 0) { - /* wrong tag type */ - return NULL; - } - - /* allocate struct */ - ka_float_array_t *a = malloc(sizeof(ka_float_array_t)); - if (a == NULL) return NULL; - - /* inspect attributes */ - const char *count_str = ezxml_attr(tag, "count"); - a->count = strtol(count_str, NULL, 10); - - const char *id_str = ezxml_attr(tag, "id"); - if (copy_str(&(a->id), id_str) < 0) { - free(a); - return NULL; - } - - /* parse data */ - a->array = malloc(a->count * sizeof(ka_real_t)); - if (a->array == NULL) { - free(a->id); - free(a); - return NULL; - } - - char *data = ezxml_txt(tag); - char *end; - int i; - for (i=0; i<a->count; i++) { - a->array[i] = KA_STR_TO_REAL(data, &end); - data = end; - } - - return a; -} - - -void kai_free_float_array(ka_float_array_t *a) -{ - free(a->array); - free(a->id); - free(a); -} diff --git a/src/geometry/geometry.h b/src/geometry/geometry.h deleted file mode 100644 index 971bd1b..0000000 --- a/src/geometry/geometry.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef KALMIA_GEOMETRY_H -#define KALMIA_GEOMETRY_H - -#include <kalmia.h> -#include <ezxml.h> - -typedef struct { - char *id; - size_t count; - ka_real_t *array; -} ka_float_array_t; - - -/* allocate a new float array and parse an xml tag into it */ -ka_float_array_t * kai_parse_float_array(ezxml_t tag); - -/* free a loaded float array */ -void kai_free_float_array(ka_float_array_t *array); - -#endif diff --git a/src/geometry/geometry.test.c b/src/geometry/geometry.test.c deleted file mode 100644 index f400540..0000000 --- a/src/geometry/geometry.test.c +++ /dev/null @@ -1,49 +0,0 @@ -#include <string.h> -#include <math.h> -#include <kalmia.h> -#include "test/test.h" -#include "geometry.h" - - -void parse_float_array(); - - -void suite_geometry() -{ - lily_run_test(parse_float_array); -} - - -void parse_float_array() -{ - char str[1024]; - strncpy( - str, - "<float_array id=\"box-Pos-array\" count=\"24\">\n" - " -0.5 0.5 0.5\n" - " 0.5 0.5 0.5\n" - " -0.5 -0.5 0.5\n" - " 0.5 -0.5 0.5\n" - " -0.5 0.5 -0.5\n" - " 0.5 0.5 -0.5\n" - " -0.5 -0.5 -0.5\n" - " 0.5 -0.5 -0.5\n" - "</float_array>\n", - 1024 - ); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_float_array_t *a = kai_parse_float_array(tag); - ezxml_free(tag); - - lily_assert_not_null(a); - lily_assert_string_equal(a->id, "box-Pos-array"); - lily_assert_int_equal(a->count, 24); - - int i; - for (i=0; i<24; i++) { - lily_assert_float_equal(fabs(a->array[i]), 0.5, 1e-3); - } - - kai_free_float_array(a); -} diff --git a/src/test/lily-test.c b/src/test/lily-test.c deleted file mode 100644 index 30f96d5..0000000 --- a/src/test/lily-test.c +++ /dev/null @@ -1,366 +0,0 @@ -/**************************************************************** - * - * ======== lily-test ======== - * - * a midsize C unit testing library - * copyright (c) 2022 kate swanson (sanine) - * - * This is anti-capitalist software, released for free use by individuals and - * organizations that do not operate by capitalist principles. - * - * Permission is hereby granted, free of charge, to any person or - * organization (the "User") obtaining a copy of this software and associated - * documentation files (the "Software"), to use, copy, modify, merge, - * distribute, and/or sell copies of the Software, subject to the following - * conditions: - * - * 1. The above copyright notice and this permission notice shall be included - * in all copies or modified versions of the Software. - * - * 2. The User is one of the following: - * a. An individual person, laboring for themselves - * b. A non-profit organization - * c. An educational institution - * d. An organization that seeks shared profit for all of its members, and - * allows non-members to set the cost of their labor - * - * 3. If the User is an organization with owners, then all owners are workers - * and all workers are owners with equal equity and/or equal vote. - * - * 4. If the User is an organization, then the User is not law enforcement or - * military, or working for or under either. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT EXPRESS OR IMPLIED WARRANTY OF - * ANY KIND, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * https://anticapitalist.software/ - * https://sanine.net - * - ****************************************************************/ - - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include "lily-test.h" - -struct lily_globals_t _lily_globals = { {0}, 0, NULL, "" }; - -/* run an individual test */ -void _lily_run_test(const char *name, lily_test_t test) -{ - printf(" %s: ", name); - - _lily_globals.error_msg = NULL; - _lily_globals.error_location = ""; - int val = setjmp(_lily_globals.env); - - if (val) { - /* test failed */ - printf("FAIL - %s (%s)\n", - _lily_globals.error_msg, - _lily_globals.error_location); - free(_lily_globals.error_msg); /* error message was allocated! */ - return; - } - - test(); - - /* test succeeded */ - printf("OK\n"); -} - -/* run a suite */ -void _lily_run_suite(const char *name, lily_test_t suite) -{ - printf("=== %s ===\n", name); - suite(); - printf("\n"); -} - - -/* ======== ASSERTIONS ======== */ - -static void _lily_assert_msg(bool statement, const char *location, - const char *format_string, va_list args) -{ - if (statement) { - va_end(args); - return; // no error, return - } - - _lily_globals.error_location = location; - - va_list args_len; - va_copy(args_len, args); - size_t length = vsnprintf(NULL, 0, format_string, args_len); - va_end(args_len); - - if (_lily_globals.error_msg_len < length+1 || - _lily_globals.error_msg == NULL) { - if (_lily_globals.error_msg != NULL) - free(_lily_globals.error_msg); - - char *msg = malloc((length+2) * sizeof(char)); - - if (msg == NULL) { - fprintf(stderr, "WARNING: failed to allocate memory for failed test message!\n"); - _lily_globals.error_msg = NULL; - va_end(args); - longjmp(_lily_globals.env, 1); - return; - } - else { - _lily_globals.error_msg = msg; - _lily_globals.error_msg_len = length+1; - } - } - - vsnprintf(_lily_globals.error_msg, length+1, format_string, args); - - va_end(args); - longjmp(_lily_globals.env, 1); -} - - -void lily_assert_msg(bool statement, const char *location, - const char *format_string, ...) -{ - va_list args; - va_start(args, format_string); - // _lily_assert_msg may long jump, so it takes calls va_end(args) for you - _lily_assert_msg(statement, location, format_string, args); -} - - -void _lily_assert_true(const char *statement, bool value, const char *location) -{ - lily_assert_msg(value, location, - "%s is not true", - statement); -} - - -void _lily_assert_false(const char *statement, bool value, const char *location) -{ - lily_assert_msg(!value, location, - "%s is not false", - statement); -} - - -void _lily_assert_not_null(const char *name, void *ptr, const char *location) -{ - lily_assert_msg(ptr != NULL, location, - "%s is NULL", - name); -} - - -void _lily_assert_null(const char *name, void *ptr, const char *location) -{ - lily_assert_msg(ptr == NULL, location, - "%s (%p) is not NULL", - name, ptr); -} - - -void _lily_assert_ptr_equal(const char *name_a, const char *name_b, - void *a, void *b, const char *location) -{ - lily_assert_msg(a == b, location, - "%s (%p) is not equal to %s (%p)", - name_a, a, name_b, b); -} - - -void _lily_assert_ptr_not_equal(const char *name_a, const char *name_b, - void *a, void *b, const char *location) -{ - lily_assert_msg(a != b, location, - "%s (%p) is equal to %s", - name_a, a, name_b); -} - - -void _lily_assert_int_equal(const char *name_a, const char *name_b, - intmax_t a, intmax_t b, const char *location) -{ - lily_assert_msg(a == b, location, - "%s (%d) is not equal to %s (%d)", - name_a, a, name_b, b); -} - - -void _lily_assert_int_not_equal(const char *name_a, const char *name_b, - intmax_t a, intmax_t b, const char *location) -{ - lily_assert_msg(a != b, location, - "%s (%d) is equal to %s", - name_a, a, name_b); -} - - -void _lily_assert_float_equal(const char *name_a, const char *name_b, - double a, double b, double epsilon, const char *location) -{ - lily_assert_msg(fabs(a - b) <= epsilon, location, - "%s (%f) is not equal to %s (%f) (epsilon: %f)", - name_a, a, name_b, b, epsilon); -} - - -void _lily_assert_float_not_equal(const char *name_a, const char *name_b, - double a, double b, double epsilon, const char *location) -{ - lily_assert_msg(fabs(a - b) > epsilon, location, - "%s (%f) is equal to %s (%f) (epsilon: %f)", - name_a, a, name_b, b, epsilon); -} - - -void _lily_assert_string_equal(const char *name_a, const char *name_b, - char *a, char *b, const char *location) -{ - lily_assert_msg(strcmp(a, b) == 0, location, - "%s ('%s') is not equal to %s ('%s')", - name_a, a, name_b, b); -} - - -void _lily_assert_string_not_equal(const char *name_a, const char *name_b, - char *a, char *b, const char *location) -{ - lily_assert_msg(strcmp(a, b) != 0, location, - "%s ('%s') is equal to %s", - name_a, a, name_b); -} - - -void _lily_assert_memory_equal(const char *name_a, const char *name_b, - void *a, void *b, size_t size, const char *location) -{ - lily_assert_msg(memcmp(a, b, size) == 0, location, - "%s and %s contain different data", name_a, name_b); -} - - -void _lily_assert_memory_not_equal(const char *name_a, const char *name_b, - void *a, void *b, size_t size, const char *location) -{ - lily_assert_msg(memcmp(a, b, size) == 0, location, - "%s contains the same data s %s", name_a, name_b); -} - - -/* ======== MOCKS ======== */ - -lily_queue_t* lily_queue_create() -{ - const size_t size = 256 * sizeof(uint8_t); - - lily_queue_t *q = malloc(sizeof(lily_queue_t)); - q->buf_size = size; - q->buf = malloc(size); - q->front = q->buf; - q->back = q->front; - - return q; -} - - -void lily_queue_destroy(lily_queue_t *q) -{ - free(q->buf); - free(q); -} - - -void _lily_enqueue(lily_queue_t *q, size_t size, uint8_t *data) -{ - size_t used = q->back - q->buf; - size_t remaining = q->buf_size - used; - - if (remaining < size) { - /* re-allocate bigger buffer */ - size_t size_new = 2 * q->buf_size; - uint8_t *buf_new = realloc(q->buf, size_new); - if (buf_new == NULL) { - fprintf(stderr, "failed to allocated %lu bytes for queue %p!\n", - size_new, q); - return; - } - q->buf = buf_new; - } - - memcpy(q->back, data, size); - q->back += size; -} - - -void _lily_dequeue(lily_queue_t *q, size_t size, uint8_t *ptr) -{ - size_t dist = q->back - q->front; - if (dist < size) { - fprintf(stderr, "attempted to read %lu bytes out of queue %p, " - "which has %lu bytes presently queued\n", size, q, dist); - return; - } - - memcpy(ptr, q->front, size); - q->front += size; -} - - -lily_mock_t * lily_mock_create() -{ - lily_mock_t *m = malloc(sizeof(lily_mock_t)); - m->n_calls = 0; - m->arguments = lily_queue_create(); - m->values = lily_queue_create(); - return m; -} - -void lily_mock_destroy(lily_mock_t *m) -{ - lily_queue_destroy(m->arguments); - lily_queue_destroy(m->values); - free(m); -} - -void lily_mock_use(lily_mock_t **m) -{ - if (*m != NULL) lily_mock_destroy(*m); - *m = lily_mock_create(); -} - -void _lily_mock_call(lily_mock_t *m, struct lily_mock_arg_t *args, size_t n_args) -{ - m->n_calls += 1; - - for (int i=0; i<n_args; i++) { - _lily_enqueue(m->arguments, args[i].size, args[i].var); - } -} - -void _lily_get_call(lily_mock_t *m, - struct lily_mock_arg_t *args, - size_t n_args, - unsigned int call_num) -{ - size_t stride = 0; - for (int i=0; i<n_args; i++) { - stride += args[i].size; - } - - m->arguments->front = m->arguments->buf + (call_num * stride); - for (int i=0; i<n_args; i++) { - _lily_dequeue(m->arguments, args[i].size, args[i].var); - } -} diff --git a/src/test/lily-test.h b/src/test/lily-test.h index b5f380c..8b1d9ad 100644 --- a/src/test/lily-test.h +++ b/src/test/lily-test.h @@ -11,7 +11,8 @@ * Permission is hereby granted, free of charge, to any person or * organization (the "User") obtaining a copy of this software and associated * documentation files (the "Software"), to use, copy, modify, merge, - * distribute, and/or sell copies of the Software, subject to the following conditions: + * distribute, and/or sell copies of the Software, subject to the following + * conditions: * * 1. The above copyright notice and this permission notice shall be included * in all copies or modified versions of the Software. @@ -45,7 +46,7 @@ #ifndef LILY_TEST_H #define LILY_TEST_H -#define LILY_VERSION_MAJOR 1 +#define LILY_VERSION_MAJOR 2 #define LILY_VERSION_MINOR 0 #define LILY_VERSION_PATCH 0 @@ -53,211 +54,667 @@ #include <stddef.h> #include <stdint.h> #include <setjmp.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <math.h> #define STR_IMP(x) #x #define STR(x) STR_IMP(x) /* define SOURCE_PATH_SIZE to strip away the - leading parts of the full compilation path */ + leading parts of the full compilation path */ #ifndef SOURCE_PATH_SIZE #define LILY_LOCATION (__FILE__ ":" STR(__LINE__)) #else #define LILY_LOCATION ((__FILE__ ":" STR(__LINE__)) + SOURCE_PATH_SIZE) #endif -/** a few nasty globals that make everything clean for the end user */ -struct lily_globals_t { - jmp_buf env; - size_t error_msg_len; - char *error_msg; - const char *error_location; -}; -extern struct lily_globals_t _lily_globals; - -typedef void (*lily_test_t)(void); - -/** run a single test */ -#define lily_run_test(test) _lily_run_test(#test, test) -void _lily_run_test(const char *name, lily_test_t test); - -/** run a suite */ -#define lily_run_suite(suite) _lily_run_suite(#suite, suite) -void _lily_run_suite(const char *name, lily_test_t suite); - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * assertions - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -/** basic assertion function, mostly used by the other assertions */ -void lily_assert_msg(bool statement, const char *location, - const char *format_string, ...); - -#define lily_assert_true(statement) _lily_assert_true(#statement, statement, LILY_LOCATION) -void _lily_assert_true(const char *statement, bool value, const char *location); - - -#define lily_assert_false(statement) _lily_assert_false(#statement, statement, LILY_LOCATION) -void _lily_assert_false(const char *statement, bool value, const char *location); - - -#define lily_assert_not_null(ptr) _lily_assert_not_null(#ptr, ptr, LILY_LOCATION) -void _lily_assert_not_null(const char *name, void *ptr, const char *location); - - -#define lily_assert_null(ptr) _lily_assert_null(#ptr, ptr, LILY_LOCATION) -void _lily_assert_null(const char *name, void *ptr, const char *location); - - -#define lily_assert_ptr_equal(a, b) _lily_assert_ptr_equal(#a, #b, a, b, LILY_LOCATION) -void _lily_assert_ptr_equal(const char *name_a, const char *name_b, - void *a, void *b, const char *location); - - -#define lily_assert_ptr_not_equal(a, b) _lily_assert_ptr_not_equal(#a, #b, a, b, LILY_LOCATION) -void _lily_assert_ptr_not_equal(const char *name_a, const char *name_b, - void *a, void *b, const char *location); - - -#define lily_assert_int_equal(a, b) _lily_assert_int_equal(#a, #b, a, b, LILY_LOCATION) -void _lily_assert_int_equal(const char *name_a, const char *name_b, - intmax_t a, intmax_t b, const char *location); - - -#define lily_assert_int_not_equal(a, b) _lily_assert_int_not_equal(#a, #b, a, b, LILY_LOCATION) -void _lily_assert_int_not_equal(const char *name_a, const char *name_b, - intmax_t a, intmax_t b, const char *location); - -#define lily_assert_float_equal(a, b, epsilon) \ - _lily_assert_float_equal(#a, #b, a, b, epsilon, LILY_LOCATION) -void _lily_assert_float_equal(const char *name_a, const char *name_b, - double a, double b, double epsilon, const char *location); - - -#define lily_assert_float_not_equal(a, b, epsilon) \ - _lily_assert_float_not_equal(#a, #b, a, b, epsilon, LILY_LOCATION) -void _lily_assert_float_not_equal(const char *name_a, const char *name_b, - double a, double b, double epsilon, const char *location); - - -#define lily_assert_string_equal(a, b) _lily_assert_string_equal(#a, #b, a, b, LILY_LOCATION) -void _lily_assert_string_equal(const char *name_a, const char *name_b, - char *a, char *b, const char *location); - - -#define lily_assert_string_not_equal(a, b) _lily_assert_string_not_equal(#a, #b, a, b, LILY_LOCATION) -void _lily_assert_string_not_equal(const char *name_a, const char *name_b, - char *a, char *b, const char *location); - - -#define lily_assert_memory_equal(a, b, size) \ - _lily_assert_memory_equal(#a, #b, a, b, size, LILY_LOCATION) -void _lily_assert_memory_equal(const char *name_a, const char *name_b, - void *a, void *b, size_t size, const char *location); - - -#define lily_assert_memory_not_equal(a, b, size) \ - _lily_assert_memory_not_equal(#a, #b, a, b, size, LILY_LOCATION) -void _lily_assert_memory_not_equal(const char *name_a, const char *name_b, - void *a, void *b, size_t size, const char *location); - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * mocks - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - -/** queue structure capable of containing arbitrary data */ -typedef struct lily_queue_t { - size_t buf_size; - uint8_t *buf; - uint8_t *front, *back; -} lily_queue_t; +/* self-location macro */ +#ifndef LILY_TEST_H_LOCATION +#define LILY_TEST_H_LOCATION "lily-test.h" +#endif -/** create a queue */ -lily_queue_t* lily_queue_create(); +/* counter macros */ +#define LILY_HEX_(x) 0x##x +#define LILY_HEX(x) LILY_HEX_(x) +#define LILY_COUNTER_POS_0 0 +#define LILY_COUNTER_POS_1 0 +#define LILY_COUNTER_POS_2 0 +#define LILY_COUNTER__(a, b, c) 0x##a##b##c +#define LILY_COUNTER_(a, b, c) LILY_COUNTER__(a, b, c) +#define LILY_COUNTER LILY_COUNTER_(LILY_COUNTER_POS_2, LILY_COUNTER_POS_1, LILY_COUNTER_POS_0) + +/* automatic registration macros */ +typedef struct lily_ll_node_t { + struct lily_ll_node_t *next; + void (*f)(); +} lily_ll_node_t; +#define LILY_FILE_BEGIN(unique_id) \ +static lily_ll_node_t lily_ll_last = { NULL, NULL }; \ +static void file_runner(); \ +void (*unique_id)() = file_runner; + +#define LILY_LIST_HEAD lily_ll_last +#define LILY_LIST_NEXT lily_ll_last +#define LILY_PUSH_TEST() LILY_TEST_H_LOCATION +#define LILY_REGISTER_TESTS() LILY_TEST_H_LOCATION + +#define LILY_CAT_(x, y) x##y +#define LILY_CAT(x, y) LILY_CAT_(x, y) +#define LILY_ANON(x) LILY_CAT(x, LILY_COUNTER) +#define LILY_ANON_WRAP LILY_ANON(LILY_WRAP_) +#define LILY_ANON_FUNC LILY_ANON(LILY_FUNCTION_) +#define LILY_ANON_NODE LILY_ANON(LILY_NODE_) +#define LILY_ANON_DESC LILY_ANON(LILY_DESCRIPTION_) + +#define LILY_TEST_(wrap, f, desc_str, description) \ +static void f(); \ +static void wrap() \ +{ \ + lily_g.test_name = description; \ + f(); \ +} \ +static void f() + +#define LILY_TEST(description) LILY_TEST_(LILY_ANON_WRAP, LILY_ANON_FUNC, LILY_ANON_DESC, description) + +/* assertions */ +typedef struct lily_test_msg_t { + struct lily_test_msg_t *next; + char *msg; + const char *location; +} lily_test_msg_t; +void lily_msg_destroy(lily_test_msg_t *m); + +void lily_info(const char *location, const char *fmt, ...); +#define LILY_INFO_(location, ...) \ + lily_info(location, __VA_ARGS__) +#define LILY_INFO(...) LILY_INFO_(LILY_LOCATION, __VA_ARGS__) +#define INFO(...) LILY_INFO(__VA_ARGS__) + +void lily_check(int x, const char *location, const char *fmt, ...); +#define LILY_CHECK_(str, x, location) \ + lily_check(x, location, "CHECK failed: %s", str) +#define LILY_CHECK(x) LILY_CHECK_(STR(x), x, LILY_LOCATION) +#define CHECK(x) LILY_CHECK(x) + +#define LILY_CHECK_CMP_(x, y, xstr, ystr, cmp, cmpstr, fmt) \ + lily_check(x cmp y, LILY_LOCATION, \ + "CHECK failed: %s " cmpstr " %s\n %s = " fmt "\n %s = " fmt,\ + xstr, ystr, xstr, x, ystr, y) +#define LILY_CHECK_CMP(x, cmp, y, fmt) LILY_CHECK_CMP_(x, y, #x, #y, cmp, #cmp, fmt) + +/* check comparision assertions */ +#define CHECK_EQ(x, y, fmt) LILY_CHECK_CMP(x, ==, y, fmt) +#define CHECK_NEQ(x, y, fmt) LILY_CHECK_CMP(x, !=, y, fmt) +#define CHECK_LT(x, y, fmt) LILY_CHECK_CMP(x, <, y, fmt) +#define CHECK_LE(x, y, fmt) LILY_CHECK_CMP(x, <=, y, fmt) +#define CHECK_GT(x, y, fmt) LILY_CHECK_CMP(x, >, y, fmt) +#define CHECK_GE(x, y, fmt) LILY_CHECK_CMP(x, >=, y, fmt) + +#define LILY_CHECK_EQF(x, y, xstr, ystr, fmt) \ + lily_check(fabs(x-y) < lily_g.epsilon, LILY_LOCATION, \ + "CHECK failed: %s == %s\n %s = " fmt "\n %s = " fmt "\n epsilon: %f", \ + xstr, ystr, xstr, x, ystr, y, lily_g.epsilon) +#define CHECK_EQF(x, y, fmt) LILY_CHECK_EQF(x, y, #x, #y, fmt) + +#define LILY_CHECK_EQS(x, y, xstr, ystr) \ + lily_check(strcmp(x, y) == 0, LILY_LOCATION, \ + "CHECK failed: %s == %s\n %s = \"%s\"\n %s = \"%s\"", \ + xstr, ystr, xstr, x, ystr, y) +#define CHECK_EQS(x, y) LILY_CHECK_EQS(x, y, #x, #y) + + +void lily_require(int x, const char *location, const char *fmt, ...); +#define LILY_REQUIRE_(str, x, location) \ + lily_require(x, location, "REQUIRE failed: %s", str) +#define LILY_REQUIRE(x) LILY_REQUIRE_(STR(x), x, LILY_LOCATION) +#define REQUIRE(x) LILY_REQUIRE(x) + +#define LILY_REQUIRE_CMP_(x, y, xstr, ystr, cmp, cmpstr, fmt) \ + lily_require(x cmp y, LILY_LOCATION, \ + "REQUIRE failed: %s " cmpstr " %s\n %s = " fmt "\n %s = " fmt,\ + xstr, ystr, xstr, x, ystr, y) +#define LILY_REQUIRE_CMP(x, cmp, y, fmt) LILY_REQUIRE_CMP_(x, y, #x, #y, cmp, #cmp, fmt) + +/* require comparison assertions */ +#define REQUIRE_EQ(x, y, fmt) LILY_REQUIRE_CMP(x, ==, y, fmt) +#define REQUIRE_NEQ(x, y, fmt) LILY_REQUIRE_CMP(x, !=, y, fmt) +#define REQUIRE_LT(x, y, fmt) LILY_REQUIRE_CMP(x, <, y, fmt) +#define REQUIRE_LE(x, y, fmt) LILY_REQUIRE_CMP(x, <=, y, fmt) +#define REQUIRE_GT(x, y, fmt) LILY_REQUIRE_CMP(x, >, y, fmt) +#define REQUIRE_GE(x, y, fmt) LILY_REQUIRE_CMP(x, >=, y, fmt) + +#define LILY_REQUIRE_EQF(x, y, xstr, ystr, fmt) \ + lily_require(fabs(x-y) < lily_g.epsilon, LILY_LOCATION, \ + "REQUIRE failed: %s == %s\n %s = " fmt "\n %s = " fmt "\n epsilon: %f", \ + xstr, ystr, xstr, x, ystr, y, lily_g.epsilon) +#define REQUIRE_EQF(x, y, fmt) LILY_REQUIRE_EQF(x, y, #x, #y, fmt) + +#define LILY_REQUIRE_EQS(x, y, xstr, ystr) \ + lily_require(strcmp(x, y) == 0, LILY_LOCATION, \ + "REQUIRE failed: %s == %s\n %s = \"%s\"\n %s = \"%s\"", \ + xstr, ystr, xstr, x, ystr, y) +#define REQUIRE_EQS(x, y) LILY_REQUIRE_EQS(x, y, #x, #y) + + +void lily_begin(); +void lily_finish(); +void lily_run_test(void (*test)()); +void lily_set_epsilon(double epsilon); + + +struct lily_global_t { + int failed; + jmp_buf env; + const char *test_name; + lily_test_msg_t HEAD; + lily_test_msg_t *TAIL; + int n_assertions; + int n_assertions_failed; + int n_tests; + int n_tests_failed; + double epsilon; +} extern lily_g; + +#ifdef LILY_IMPLEMENTATION +struct lily_global_t lily_g; + +lily_test_msg_t *lily_msg_create(const char *location, const char *fmt, va_list args) +{ + lily_test_msg_t *m = malloc(sizeof(lily_test_msg_t)); + if (m == NULL) { + return NULL; + } + m->next = NULL; + m->location = location; + + va_list args_len; + va_copy(args_len, args); + size_t len = vsnprintf(NULL, 0, fmt, args_len) + 1; + va_end(args_len); + + m->msg = malloc(len * sizeof(char)); + if (m->msg == NULL) { + free(m); + return NULL; + } + vsnprintf(m->msg, len, fmt, args); + + return m; +} + +void lily_msg_destroy(lily_test_msg_t *m) +{ + if (m == NULL) { + /* ignore */ + return; + } + + if (m->next != NULL) { + // destroy the whole chain + lily_msg_destroy(m->next); + } + + free(m->msg); + free(m); +} + + +void lily_run_test(void (*test)()) +{ + lily_g.n_tests += 1; + lily_g.HEAD.next = NULL; + lily_g.TAIL = &(lily_g.HEAD); + lily_g.failed = 0; + int jumped = setjmp(lily_g.env); + + if (!jumped) { + test(); + } + + if (lily_g.failed) { + lily_g.n_tests_failed += 1; + printf("================================================================================\n"); + printf("test \"%s\" failed!\n\n", lily_g.test_name); + lily_test_msg_t *n = lily_g.HEAD.next; + while(n != NULL) { + printf(" %s\n [%s]\n\n", n->msg, n->location); + n = n->next; + } + lily_msg_destroy(lily_g.HEAD.next); + } +} + + +void lily_info(const char *location, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + lily_test_msg_t *m = lily_msg_create(location, fmt, args); + va_end(args); + + lily_g.TAIL->next = m; + lily_g.TAIL = m; +} + +void lily_check(int x, const char *location, const char *fmt, ...) +{ + lily_g.n_assertions += 1; + if (!x) { + // assertion failed + lily_g.n_assertions_failed += 1; + + va_list args; + va_start(args, fmt); + lily_test_msg_t *m = lily_msg_create(location, fmt, args); + va_end(args); + + lily_g.TAIL->next = m; + lily_g.TAIL = m; + lily_g.failed = 1; + } +} + + +void lily_require(int x, const char *location, const char *fmt, ...) +{ + lily_g.n_assertions += 1; + if (!x) { + // assertion failed + lily_g.n_assertions_failed += 1; + + va_list args; + va_start(args, fmt); + lily_test_msg_t *m = lily_msg_create(location, fmt, args); + va_end(args); + + lily_g.TAIL->next = m; + lily_g.TAIL = m; + lily_g.failed = 1; + + /* longjump out of test */ + longjmp(lily_g.env, 1); + } +} + + +void lily_begin() +{ + lily_g.n_tests = 0; + lily_g.n_tests_failed = 0; + lily_g.n_assertions_failed = 0; + lily_g.n_assertions_failed = 0; + lily_g.epsilon = 1e-3; + + printf("================================================================================\n"); + printf("lily-test version %d.%d.%d\n", LILY_VERSION_MAJOR, LILY_VERSION_MINOR, LILY_VERSION_PATCH); +} + + +void lily_finish() +{ + printf("================================================================================\n"); + printf("ran %d tests (%d failed)\n", + lily_g.n_tests, lily_g.n_tests_failed); + printf("checked %d asserts (%d failed)\n", + lily_g.n_assertions, lily_g.n_assertions_failed); +} + + +void lily_set_epsilon(double epsilon) +{ + lily_g.epsilon = epsilon; +} +#endif -/** destroy a queue */ -void lily_queue_destroy(lily_queue_t *q); +/* ifdef LILY_TEST_H */ +#else +/* counter incrementing */ +/* this counter can count up to 4096, but it should be pretty trivial to extend it more or less arbitrarily far */ +/* to increment the counter, just #define LILY_COUNTER_INCREMENT and then include this file again */ +#ifdef LILY_COUNTER_INCREMENT +#undef LILY_COUNTER_INCREMENT + /* ones position */ +# if LILY_HEX(LILY_COUNTER_POS_0) == 0 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 1 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 1 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 2 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 2 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 3 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 3 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 4 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 4 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 5 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 5 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 6 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 6 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 7 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 7 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 8 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 8 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 9 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 9 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 a +# elif LILY_HEX(LILY_COUNTER_POS_0) == 10 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 b +# elif LILY_HEX(LILY_COUNTER_POS_0) == 11 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 c +# elif LILY_HEX(LILY_COUNTER_POS_0) == 12 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 d +# elif LILY_HEX(LILY_COUNTER_POS_0) == 13 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 e +# elif LILY_HEX(LILY_COUNTER_POS_0) == 14 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 f +# elif LILY_HEX(LILY_COUNTER_POS_0) == 15 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 0 + /* sixteens position */ +# if LILY_HEX(LILY_COUNTER_POS_1) == 0 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 1 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 1 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 2 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 2 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 3 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 3 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 4 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 4 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 5 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 5 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 6 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 6 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 7 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 7 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 8 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 8 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 9 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 9 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 a +# elif LILY_HEX(LILY_COUNTER_POS_1) == 10 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 b +# elif LILY_HEX(LILY_COUNTER_POS_1) == 11 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 c +# elif LILY_HEX(LILY_COUNTER_POS_1) == 12 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 d +# elif LILY_HEX(LILY_COUNTER_POS_1) == 13 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 e +# elif LILY_HEX(LILY_COUNTER_POS_1) == 14 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 f +# elif LILY_HEX(LILY_COUNTER_POS_1) == 15 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 0 + /* 256s position */ +# if LILY_HEX(LILY_COUNTER_POS_2) == 0 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 1 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 1 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 2 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 2 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 3 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 3 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 4 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 4 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 5 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 5 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 6 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 6 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 7 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 7 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 8 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 8 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 9 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 9 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 a +# elif LILY_HEX(LILY_COUNTER_POS_2) == 10 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 b +# elif LILY_HEX(LILY_COUNTER_POS_2) == 11 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 c +# elif LILY_HEX(LILY_COUNTER_POS_2) == 12 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 d +# elif LILY_HEX(LILY_COUNTER_POS_2) == 13 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 e +# elif LILY_HEX(LILY_COUNTER_POS_2) == 14 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 f +# elif LILY_HEX(LILY_COUNTER_POS_2) == 15 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 0 +# endif +# endif +# endif + +#elif defined(LILY_COUNTER_DECREMENT) +#undef LILY_COUNTER_DECREMENT + /* ones position */ +# if LILY_HEX(LILY_COUNTER_POS_0) == 15 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 e +# elif LILY_HEX(LILY_COUNTER_POS_0) == 14 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 d +# elif LILY_HEX(LILY_COUNTER_POS_0) == 13 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 c +# elif LILY_HEX(LILY_COUNTER_POS_0) == 12 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 b +# elif LILY_HEX(LILY_COUNTER_POS_0) == 11 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 a +# elif LILY_HEX(LILY_COUNTER_POS_0) == 10 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 9 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 9 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 8 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 8 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 7 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 7 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 6 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 6 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 5 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 5 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 4 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 4 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 3 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 3 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 2 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 2 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 1 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 1 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 0 +# elif LILY_HEX(LILY_COUNTER_POS_0) == 0 +# undef LILY_COUNTER_POS_0 +# define LILY_COUNTER_POS_0 f + /* sixteens position */ +# if LILY_HEX(LILY_COUNTER_POS_1) == 15 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 e +# elif LILY_HEX(LILY_COUNTER_POS_1) == 14 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 d +# elif LILY_HEX(LILY_COUNTER_POS_1) == 13 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 c +# elif LILY_HEX(LILY_COUNTER_POS_1) == 12 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 b +# elif LILY_HEX(LILY_COUNTER_POS_1) == 11 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 a +# elif LILY_HEX(LILY_COUNTER_POS_1) == 10 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 9 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 9 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 8 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 8 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 7 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 7 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 6 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 6 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 5 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 5 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 4 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 4 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 3 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 3 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 2 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 2 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 1 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 1 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 0 +# elif LILY_HEX(LILY_COUNTER_POS_1) == 0 +# undef LILY_COUNTER_POS_1 +# define LILY_COUNTER_POS_1 f + /* 256s position */ +# if LILY_HEX(LILY_COUNTER_POS_2) == 15 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 e +# elif LILY_HEX(LILY_COUNTER_POS_2) == 14 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 d +# elif LILY_HEX(LILY_COUNTER_POS_2) == 13 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 c +# elif LILY_HEX(LILY_COUNTER_POS_2) == 12 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 b +# elif LILY_HEX(LILY_COUNTER_POS_2) == 11 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 a +# elif LILY_HEX(LILY_COUNTER_POS_2) == 10 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 9 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 9 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 8 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 8 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 7 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 7 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 6 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 6 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 5 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 5 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 4 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 4 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 3 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 3 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 2 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 2 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 1 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 1 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 0 +# elif LILY_HEX(LILY_COUNTER_POS_2) == 0 +# undef LILY_COUNTER_POS_2 +# define LILY_COUNTER_POS_2 f +# endif +# endif +# endif + + +#elif defined(LILY_FILE_END) +/* ending a file */ + +/* LILY_LIST_HEAD is one too high, so we decrement */ +#define LILY_COUNTER_DECREMENT +#include LILY_TEST_H_LOCATION + +void file_runner() +{ + lily_ll_node_t *n = &LILY_LIST_HEAD; + while (n->next != NULL) { + lily_run_test(n->f); + n = n->next; + } +} -/** enqueue a value - * - * q - the queue to append to - * type - the type of the value to append - * value - the value to append - */ -#define lily_enqueue(q, type, value) \ - do { \ - type _var = value; \ - _lily_enqueue(q, sizeof(type), (uint8_t*)(&_var)); \ - } while(0) -void _lily_enqueue(lily_queue_t *q, size_t size, uint8_t *data); - - -/** pop a value from the queue - * - * q - the queue to pop from - * type - the type of the value to pop - * ptr - the location to store the popped value - */ -#define lily_dequeue(q, type, ptr) \ - _lily_dequeue(q, sizeof(type), (uint8_t*) ptr) -void _lily_dequeue(lily_queue_t *q, size_t size, uint8_t *ptr); - - -struct lily_mock_arg_t { - size_t size; - void *var; +#else +/* register new test */ + +static lily_ll_node_t LILY_ANON_NODE = { +#define LILY_COUNTER_DECREMENT +#include LILY_TEST_H_LOCATION + &LILY_LIST_HEAD, +#define LILY_COUNTER_INCREMENT +#include LILY_TEST_H_LOCATION + LILY_ANON_WRAP, }; +#undef LILY_LIST_HEAD +#define LILY_LIST_HEAD LILY_ANON_NODE +#define LILY_COUNTER_INCREMENT +#include LILY_TEST_H_LOCATION -#define LILY_NARGS(args) (sizeof(args)/sizeof(struct lily_mock_arg_t)) - -/** structure to store data for mock functions */ -typedef struct lily_mock_t { - unsigned int n_calls; - lily_queue_t *arguments; - lily_queue_t *values; -} lily_mock_t; - -/** setup mock function storage */ -lily_mock_t * lily_mock_create(); -/** tear down mock function storage */ -void lily_mock_destroy(lily_mock_t *m); -/** automatically re-create mock function storage */ -void lily_mock_use(lily_mock_t **m); - -/** store a call to a mock function */ -#define lily_mock_store_call(m, args) \ - _lily_mock_call(m, args, LILY_NARGS(args)) -/* lily_mock_call is deprecated!! do not use it in new programs */ -#define lily_mock_call(m, args) \ - _lily_mock_call(m, args, LILY_NARGS(args)) -void _lily_mock_call(lily_mock_t *m, struct lily_mock_arg_t *args, size_t n_args); - -/** retrieve a call to a mock function */ -#define lily_mock_get_call(m, args, call_num) \ - _lily_get_call(m, args, LILY_NARGS(args), call_num) -/* lily_get_call is deprecated!! do not use it in new programs */ -#define lily_get_call(m, args, call_num) \ - _lily_get_call(m, args, LILY_NARGS(args), call_num) -void _lily_get_call(lily_mock_t *m, - struct lily_mock_arg_t *args, - size_t n_args, - unsigned int call_num); - -/** store a value in a mock structure */ -#define lily_store_value(m, type, value) \ - lily_enqueue(m->values, type, value) -/** retrieve a value from a mock structure */ -#define lily_get_value(m, type, ptr) \ - lily_dequeue(m->values, type, ptr) +#endif #endif diff --git a/src/test/test.c b/src/test/test.c index c97f325..7d71fbb 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1,7 +1,12 @@ +#define LILY_IMPLEMENTATION #include "test.h" int main() { - RUN_TESTS(); + lily_begin(); + #define X(test) test(); + TESTS + #undef X + lily_finish(); return 0; } diff --git a/src/test/test.h b/src/test/test.h index b50fda5..f8d07c9 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -1,17 +1,16 @@ #ifndef KALMIA_TEST_H #define KALMIA_TEST_H +#define LILY_TEST_H_LOCATION <test/lily-test.h> #include "lily-test.h" -void suite_transform(); -void suite_geometry(); +#define TESTS \ + X(util_suite) \ -#define RUN_TESTS() \ - do { \ - lily_run_suite(suite_transform); \ - lily_run_suite(suite_geometry); \ - } while (0) +#define X(test) extern void (*test)(); +TESTS +#undef X #endif diff --git a/src/transform/CMakeLists.txt b/src/transform/CMakeLists.txt deleted file mode 100644 index cf9e78a..0000000 --- a/src/transform/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -project(kalmia) - -target_sources(kalmia PUBLIC transform.c) - -if (KALMIA_BUILD_TESTS) - target_sources(kalmia-tests PUBLIC transform.test.c) -endif() diff --git a/src/transform/transform.c b/src/transform/transform.c deleted file mode 100644 index b0f6dc9..0000000 --- a/src/transform/transform.c +++ /dev/null @@ -1,170 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include <kalmia.h> -#include <ezxml.h> -#include "transform.h" - - -#define TWO_PI 6.2831853071796f - - -int kai_identity(ka_matrix_t *m) -{ - memset(*m, 0, sizeof(ka_matrix_t)); - (*m)[0] = 1.0f; - (*m)[5] = 1.0f; - (*m)[10] = 1.0f; - (*m)[15] = 1.0f; - - return 0; -} - - -int kai_multiply(ka_matrix_t *dest, ka_matrix_t A, ka_matrix_t B) -{ - ka_matrix_t C; - memset(C, 0, sizeof(ka_matrix_t)); - - int i, j, k; - int a_ind, b_ind, c_ind; - for (i=0; i<4; i++) { - for (j=0; j<4; j++) { - c_ind = (4*i) + j; - for (k=0; k<4; k++) { - a_ind = (4*i) + k; - b_ind = (4*k) + j; - C[c_ind] += A[a_ind] * B[b_ind]; - } - } - } - - memcpy(*dest, C, sizeof(ka_matrix_t)); - return 0; -} - - -int kai_parse_matrix(ka_matrix_t *m, ezxml_t tag) -{ - if (strcmp("matrix", ezxml_name(tag)) != 0) - return -1; - - char *str = ezxml_txt(tag); - char *end; - int i; - for (i=0; i<16; i++) { - (*m)[i] = strtod(str, &end); - str = end; - } - - return 0; -} - - -int kai_parse_rotate(ka_matrix_t *m, ezxml_t tag) -{ - if (strcmp("rotate", ezxml_name(tag)) != 0) - return -1; - - char *str = ezxml_txt(tag); - char *end; - int i; - double rot[4]; - for (i=0; i<4; i++) { - rot[i] = strtod(str, &end); - str = end; - } - - double x, y, z, angle; - x = rot[0]; - y = rot[1]; - z = rot[2]; - angle = rot[3]; - - /* normalize length */ - double axis_len = (x*x) + (y*y) + (z*z); - axis_len = sqrt(axis_len); - x /= axis_len; - y /= axis_len; - z /= axis_len; - - /* convert angle to radians */ - angle *= TWO_PI / 360; - - /* compute rotation matrix entries */ - double co = cos(angle); - double unco = 1 - co; - double si = sin(angle); - - (*m)[0] = (x*x*unco) + co; - (*m)[1] = (x*y*unco) - (z*si); - (*m)[2] = (x*z*unco) + (y*si); - (*m)[3] = 0.0f; - (*m)[4] = (y*x*unco) + (z*si); - (*m)[5] = (y*y*unco) + co; - (*m)[6] = (y*z*unco) - (x*si); - (*m)[7] = 0.0f; - (*m)[8] = (z*x*unco) - (y*si); - (*m)[9] = (z*y*unco) + (x*si); - (*m)[10] = (z*z*unco) + co; - (*m)[11] = 0.0f; - (*m)[12] = 0.0f; - (*m)[13] = 0.0f; - (*m)[14] = 0.0f; - (*m)[15] = 1.0f; - - return 0; -} - - -int kai_parse_scale(ka_matrix_t *m, ezxml_t tag) -{ - if (strcmp("scale", ezxml_name(tag)) != 0) - return -1; - - char *str = ezxml_txt(tag); - char *end; - int i; - double scale[3]; - for (i=0; i<3; i++) { - scale[i] = strtod(str, &end); - str = end; - } - - memset(*m, 0, 16*sizeof(double)); - (*m)[0] = scale[0]; - (*m)[5] = scale[1]; - (*m)[10] = scale[2]; - (*m)[15] = 1.0f; - - return 0; -} - - -int kai_parse_translate(ka_matrix_t *m, ezxml_t tag) -{ - if (strcmp("translate", ezxml_name(tag)) != 0) - return -1; - - char *str = ezxml_txt(tag); - char *end; - int i; - double move[3]; - for (i=0; i<3; i++) { - move[i] = strtod(str, &end); - str = end; - } - - memset(*m, 0, sizeof(ka_matrix_t)); - - (*m)[0] = 1.0f; - (*m)[3] = move[0]; - (*m)[5] = 1.0f; - (*m)[7] = move[1]; - (*m)[10] = 1.0f; - (*m)[11] = move[2]; - (*m)[15] = 1.0f; - - return 0; -} diff --git a/src/transform/transform.h b/src/transform/transform.h deleted file mode 100644 index db582ac..0000000 --- a/src/transform/transform.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef KALMIA_TRANSLATE_H -#define KALMIA_TRANSLATE_H - -#include <kalmia.h> -#include <ezxml.h> - - -/* fill a ka_matrix_t with the identity matrix */ -int kai_identity(ka_matrix_t *m); - -/* multiply two matrices together */ -int kai_multiply(ka_matrix_t *dest, ka_matrix_t A, ka_matrix_t B); - -/* parse a <matrix> tag into a ka_matrix_t */ -int kai_parse_matrix(ka_matrix_t *m, ezxml_t tag); - -/* parse a <rotate> tag into a ka_matrix_t */ -int kai_parse_rotate(ka_matrix_t *m, ezxml_t tag); - -/* parse a <scale> tag into a ka_matrix_t */ -int kai_parse_scale(ka_matrix_t *m, ezxml_t tag); - -/* parse a <translate> tag into a ka_matrix_t */ -int kai_parse_translate(ka_matrix_t *m, ezxml_t tag); - -#endif diff --git a/src/transform/transform.test.c b/src/transform/transform.test.c deleted file mode 100644 index 4b1e329..0000000 --- a/src/transform/transform.test.c +++ /dev/null @@ -1,316 +0,0 @@ -#include <string.h> -#include <kalmia.h> -#include "test/test.h" -#include "transform.h" - -void create_identity(); -void multiply(); - -void parse_matrix_fail_nonmatrix(); -void parse_identity(); - -void parse_rotate_fail(); -void parse_rotate(); - -void parse_scale_fail(); -void parse_scale(); - -void parse_translate_fail(); -void parse_translate(); - - -void suite_transform() -{ - lily_run_test(create_identity); - lily_run_test(multiply); - lily_run_test(parse_matrix_fail_nonmatrix); - lily_run_test(parse_identity); - lily_run_test(parse_rotate_fail); - lily_run_test(parse_rotate); - lily_run_test(parse_scale_fail); - lily_run_test(parse_scale); - lily_run_test(parse_translate_fail); - lily_run_test(parse_translate); -} - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* ======== basic ======== */ - -void create_identity() -{ - ka_matrix_t mat; - mat[0] = 100; - int rc = kai_identity(&mat); - lily_assert_true(rc == 0); - - lily_assert_float_equal(mat[0], 1.0f, 1e-3); - lily_assert_float_equal(mat[1], 0.0f, 1e-3); - lily_assert_float_equal(mat[2], 0.0f, 1e-3); - lily_assert_float_equal(mat[3], 0.0f, 1e-3); - lily_assert_float_equal(mat[4], 0.0f, 1e-3); - lily_assert_float_equal(mat[5], 1.0f, 1e-3); - lily_assert_float_equal(mat[6], 0.0f, 1e-3); - lily_assert_float_equal(mat[7], 0.0f, 1e-3); - lily_assert_float_equal(mat[8], 0.0f, 1e-3); - lily_assert_float_equal(mat[9], 0.0f, 1e-3); - lily_assert_float_equal(mat[10], 1.0f, 1e-3); - lily_assert_float_equal(mat[11], 0.0f, 1e-3); - lily_assert_float_equal(mat[12], 0.0f, 1e-3); - lily_assert_float_equal(mat[13], 0.0f, 1e-3); - lily_assert_float_equal(mat[14], 0.0f, 1e-3); - lily_assert_float_equal(mat[15], 1.0f, 1e-3); -} - - -void multiply() -{ - ka_matrix_t A = { - 2.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 3.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - - ka_matrix_t B = { - 0.0f, 3.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 2.0f, 2.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - - int rc = kai_multiply(&A, A, B); - lily_assert_true(rc == 0); - - lily_assert_float_equal(A[0], 0.0f, 1e-3); - lily_assert_float_equal(A[1], 8.0f, 1e-3); - lily_assert_float_equal(A[2], 2.0f, 1e-3); - lily_assert_float_equal(A[3], 0.0f, 1e-3); - - lily_assert_float_equal(A[4], 3.0f, 1e-3); - lily_assert_float_equal(A[5], 0.0f, 1e-3); - lily_assert_float_equal(A[6], 3.0f, 1e-3); - lily_assert_float_equal(A[7], 0.0f, 1e-3); - - lily_assert_float_equal(A[8], 0.0f, 1e-3); - lily_assert_float_equal(A[9], 2.0f, 1e-3); - lily_assert_float_equal(A[10], 2.0f, 1e-3); - lily_assert_float_equal(A[11], 0.0f, 1e-3); - - lily_assert_float_equal(A[12], 0.0f, 1e-3); - lily_assert_float_equal(A[13], 0.0f, 1e-3); - lily_assert_float_equal(A[14], 0.0f, 1e-3); - lily_assert_float_equal(A[15], 1.0f, 1e-3); -} - - -/* ======== matrix ======== */ -void parse_matrix_fail_nonmatrix() -{ - char str[128]; - strncpy(str, "<nonmatrix></nonmatrix>", 128); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - int rc = kai_parse_matrix(&mat, tag); - lily_assert_true(rc != 0); - - ezxml_free(tag); -} - - -void parse_identity() -{ - char str[512]; - strncpy( - str, - "<matrix>\n" - " 1 0 0 0\n" - " 0 1 0 0\n" - " 0 0 1 0\n" - " 0 0 0 1\n" - "</matrix>", - 512 - ); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - mat[0] = 100; - int rc = kai_parse_matrix(&mat, tag); - lily_assert_true(rc == 0); - ezxml_free(tag); - - lily_assert_float_equal(mat[0], 1.0f, 1e-3); - lily_assert_float_equal(mat[1], 0.0f, 1e-3); - lily_assert_float_equal(mat[2], 0.0f, 1e-3); - lily_assert_float_equal(mat[3], 0.0f, 1e-3); - lily_assert_float_equal(mat[4], 0.0f, 1e-3); - lily_assert_float_equal(mat[5], 1.0f, 1e-3); - lily_assert_float_equal(mat[6], 0.0f, 1e-3); - lily_assert_float_equal(mat[7], 0.0f, 1e-3); - lily_assert_float_equal(mat[8], 0.0f, 1e-3); - lily_assert_float_equal(mat[9], 0.0f, 1e-3); - lily_assert_float_equal(mat[10], 1.0f, 1e-3); - lily_assert_float_equal(mat[11], 0.0f, 1e-3); - lily_assert_float_equal(mat[12], 0.0f, 1e-3); - lily_assert_float_equal(mat[13], 0.0f, 1e-3); - lily_assert_float_equal(mat[14], 0.0f, 1e-3); - lily_assert_float_equal(mat[15], 1.0f, 1e-3); -} - - -/* ======== rotate ======== */ -void parse_rotate_fail() -{ - char str[128]; - strncpy(str, "<non></non>", 128); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - int rc = kai_parse_rotate(&mat, tag); - lily_assert_true(rc != 0); - - ezxml_free(tag); -} - - -void parse_rotate() -{ - char str[512]; - strncpy( - str, - "<rotate>\n" - " 0 1 0 90.0\n" - "</rotate>", - 512 - ); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - mat[0] = 100; - int rc = kai_parse_rotate(&mat, tag); - lily_assert_true(rc == 0); - ezxml_free(tag); - - lily_assert_float_equal(mat[0], 0.0f, 1e-3); - lily_assert_float_equal(mat[1], 0.0f, 1e-3); - lily_assert_float_equal(mat[2], 1.0f, 1e-3); - lily_assert_float_equal(mat[3], 0.0f, 1e-3); - lily_assert_float_equal(mat[4], 0.0f, 1e-3); - lily_assert_float_equal(mat[5], 1.0f, 1e-3); - lily_assert_float_equal(mat[6], 0.0f, 1e-3); - lily_assert_float_equal(mat[7], 0.0f, 1e-3); - lily_assert_float_equal(mat[8], -1.0f, 1e-3); - lily_assert_float_equal(mat[9], 0.0f, 1e-3); - lily_assert_float_equal(mat[10], 0.0f, 1e-3); - lily_assert_float_equal(mat[11], 0.0f, 1e-3); - lily_assert_float_equal(mat[12], 0.0f, 1e-3); - lily_assert_float_equal(mat[13], 0.0f, 1e-3); - lily_assert_float_equal(mat[14], 0.0f, 1e-3); - lily_assert_float_equal(mat[15], 1.0f, 1e-3); -} - - -/* ======== scale ======== */ -void parse_scale_fail() -{ - char str[128]; - strncpy(str, "<non></non>", 128); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - int rc = kai_parse_scale(&mat, tag); - lily_assert_true(rc != 0); - - ezxml_free(tag); -} - - -void parse_scale() -{ - char str[512]; - strncpy( - str, - "<scale>\n" - " 10 5 -1\n" - "</scale>", - 512 - ); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - mat[0] = 100; - int rc = kai_parse_scale(&mat, tag); - lily_assert_true(rc == 0); - ezxml_free(tag); - - lily_assert_float_equal(mat[0], 10.0f, 1e-3); - lily_assert_float_equal(mat[1], 0.0f, 1e-3); - lily_assert_float_equal(mat[2], 0.0f, 1e-3); - lily_assert_float_equal(mat[3], 0.0f, 1e-3); - lily_assert_float_equal(mat[4], 0.0f, 1e-3); - lily_assert_float_equal(mat[5], 5.0f, 1e-3); - lily_assert_float_equal(mat[6], 0.0f, 1e-3); - lily_assert_float_equal(mat[7], 0.0f, 1e-3); - lily_assert_float_equal(mat[8], 0.0f, 1e-3); - lily_assert_float_equal(mat[9], 0.0f, 1e-3); - lily_assert_float_equal(mat[10],-1.0f, 1e-3); - lily_assert_float_equal(mat[11], 0.0f, 1e-3); - lily_assert_float_equal(mat[12], 0.0f, 1e-3); - lily_assert_float_equal(mat[13], 0.0f, 1e-3); - lily_assert_float_equal(mat[14], 0.0f, 1e-3); - lily_assert_float_equal(mat[15], 1.0f, 1e-3); -} - - -/* ======== translate ======== */ -void parse_translate_fail() -{ - char str[128]; - strncpy(str, "<non></non>", 128); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - int rc = kai_parse_translate(&mat, tag); - lily_assert_true(rc != 0); - - ezxml_free(tag); -} - - -void parse_translate() -{ - char str[512]; - strncpy( - str, - "<translate>\n" - " 10 5 -1\n" - "</translate>", - 512 - ); - ezxml_t tag = ezxml_parse_str(str, strlen(str)); - - ka_matrix_t mat; - mat[0] = 100; - int rc = kai_parse_translate(&mat, tag); - lily_assert_true(rc == 0); - ezxml_free(tag); - - lily_assert_float_equal(mat[0], 1.0f, 1e-3); - lily_assert_float_equal(mat[1], 0.0f, 1e-3); - lily_assert_float_equal(mat[2], 0.0f, 1e-3); - lily_assert_float_equal(mat[3], 10.0f, 1e-3); - lily_assert_float_equal(mat[4], 0.0f, 1e-3); - lily_assert_float_equal(mat[5], 1.0f, 1e-3); - lily_assert_float_equal(mat[6], 0.0f, 1e-3); - lily_assert_float_equal(mat[7], 5.0f, 1e-3); - lily_assert_float_equal(mat[8], 0.0f, 1e-3); - lily_assert_float_equal(mat[9], 0.0f, 1e-3); - lily_assert_float_equal(mat[10], 1.0f, 1e-3); - lily_assert_float_equal(mat[11],-1.0f, 1e-3); - lily_assert_float_equal(mat[12], 0.0f, 1e-3); - lily_assert_float_equal(mat[13], 0.0f, 1e-3); - lily_assert_float_equal(mat[14], 0.0f, 1e-3); - lily_assert_float_equal(mat[15], 1.0f, 1e-3); -} diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt new file mode 100644 index 0000000..dc18b39 --- /dev/null +++ b/src/util/CMakeLists.txt @@ -0,0 +1,10 @@ +project(kalmia) + +target_sources(kalmia PUBLIC util.c) + +if (KALMIA_BUILD_TESTS) + target_sources( + kalmia-tests PUBLIC + util.test.c + ) +endif() diff --git a/src/util/util.c b/src/util/util.c new file mode 100644 index 0000000..c77b3f4 --- /dev/null +++ b/src/util/util.c @@ -0,0 +1,23 @@ +#include <kalmia.h> +#include <stdint.h> +#include <stdio.h> + + +void *kai_expand_array(void **array, size_t *count, size_t element_size) +{ + size_t new_count = *count + 1; + size_t new_size = element_size * new_count; + /* cast to uint8_t so we can do pointer arithmetic */ + uint8_t *new_array = realloc(*array, new_size); + if (new_array == NULL) { + fprintf(stderr, "[kalmia] ERROR: failed to add %ul bytes to %ul-byte array!\n", + element_size, element_size * *count); + return NULL; + } + + void *new_element = new_array + (*count * element_size); + + *array = new_array; + *count = new_count; + return new_element; +} diff --git a/src/util/util.h b/src/util/util.h new file mode 100644 index 0000000..c2f01eb --- /dev/null +++ b/src/util/util.h @@ -0,0 +1,6 @@ +#ifndef KALMIA_UTIL_H +#define KALMIA_UTIL_H + +void * kai_expand_array(void **array, size_t *len, size_t element_size); + +#endif diff --git a/src/util/util.test.c b/src/util/util.test.c new file mode 100644 index 0000000..9f64085 --- /dev/null +++ b/src/util/util.test.c @@ -0,0 +1,61 @@ +#include <test/test.h> +#include "util.h" + +LILY_FILE_BEGIN(util_suite) + + +LILY_TEST("expand NULL array") +{ + size_t count = 0; + int *array = NULL; + + int *first = kai_expand_array((void**) &array, &count, sizeof(int)); + + CHECK_NEQ(first, NULL, "%p"); + CHECK_NEQ(array, NULL, "%p"); + CHECK_EQ(first, array, "%p"); + CHECK_EQ(count, 1, "%d"); + + int *second = kai_expand_array((void**) &array, &count, sizeof(int)); + + CHECK_NEQ(second, NULL, "%p"); + CHECK_EQ(second, array+1, "%p"); + CHECK_EQ(count, 2, "%d"); + + free(array); +} +#include LILY_PUSH_TEST() + + +struct test100 { + int value; + const char *str; +}; + +LILY_TEST("expand array 100 times") +{ + size_t count = 0; + struct test100 *array = NULL; + + const char *str = "hello, world!"; + + for (int i=0; i<100; i++) { + struct test100 *element = kai_expand_array((void**) &array, &count, sizeof(struct test100)); + element->value = i; + element->str = str; + } + + CHECK_EQ(count, 100, "%ul"); + + for (int i=0; i<100; i++) { + CHECK_EQ(array[i].value, i, "%d"); + CHECK_EQ(array[i].str, str, "%p"); + } + + free(array); +} +#include LILY_PUSH_TEST() + + +#define LILY_FILE_END +#include LILY_REGISTER_TESTS() |