summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2023-01-03 23:31:48 -0600
committersanine <sanine.not@pm.me>2023-01-03 23:31:48 -0600
commit13a7c902c051fa8da1e476687c17bb5431d258e1 (patch)
treeec75993aba0b8264f0dffd03eee2191020b206be /src
parente68e6d4e433fe42a0c6df18b2f2d7990b91b7cd6 (diff)
add kai_expand_array
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/geometry/CMakeLists.txt7
-rw-r--r--src/geometry/geometry.c71
-rw-r--r--src/geometry/geometry.h20
-rw-r--r--src/geometry/geometry.test.c49
-rw-r--r--src/test/lily-test.c366
-rw-r--r--src/test/lily-test.h837
-rw-r--r--src/test/test.c7
-rw-r--r--src/test/test.h13
-rw-r--r--src/transform/CMakeLists.txt7
-rw-r--r--src/transform/transform.c170
-rw-r--r--src/transform/transform.h26
-rw-r--r--src/transform/transform.test.c316
-rw-r--r--src/util/CMakeLists.txt10
-rw-r--r--src/util/util.c23
-rw-r--r--src/util/util.h6
-rw-r--r--src/util/util.test.c61
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()