changeset 407:e6f972e04519

tests: don't use automatic feature
author David Demelier <markand@malikania.fr>
date Wed, 06 Apr 2022 12:09:25 +0200
parents 107fc5c77df2
children 0ea90751a62d
files src/libmlk-core/core/vfs.h tests/CMakeLists.txt tests/test-action-script.c tests/test-action.c tests/test-character.c tests/test-color.c tests/test-drawable.c tests/test-error.c tests/test-map.c tests/test-save-quest.c tests/test-save.c tests/test-state.c tests/test-tileset.c tests/test-util.c tests/test-vfs-directory.c tests/test-vfs-zip.c tests/test.h
diffstat 17 files changed, 391 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/src/libmlk-core/core/vfs.h	Sun Apr 03 08:05:30 2022 +0200
+++ b/src/libmlk-core/core/vfs.h	Wed Apr 06 12:09:25 2022 +0200
@@ -19,6 +19,8 @@
 #ifndef MLK_CORE_VFS_H
 #define MLK_CORE_VFS_H
 
+#include <stddef.h>
+
 #include "core.h"
 
 struct vfs_file;
--- a/tests/CMakeLists.txt	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/CMakeLists.txt	Wed Apr 06 12:09:25 2022 +0200
@@ -44,4 +44,8 @@
 	target_compile_definitions(test-${t} PRIVATE DIRECTORY="${tests_SOURCE_DIR}/assets")
 	set_target_properties(test-${t} PROPERTIES FOLDER tests)
 	source_group("" FILES test-${t}.c)
+
+	if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
+		target_compile_options(test-${t} PRIVATE -Wno-unused-parameter)
+	endif ()
 endforeach ()
--- a/tests/test-action-script.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-action-script.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,12 +16,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/action.h>
 #include <core/event.h>
 #include <core/script.h>
 
+#include "test.h"
+
 struct invokes {
 	int handle;
 	int update;
@@ -85,7 +85,7 @@
 	((struct invokes *)act->data)->finish++;
 }
 
-RX_TEST_CASE(basics, init)
+TEST_DECL(basics_init)
 {
 	struct script sc;
 
@@ -95,7 +95,7 @@
 	RX_UINT_REQUIRE_EQUAL(sc.cur, 0U);
 }
 
-RX_TEST_CASE(basics, append)
+TEST_DECL(basics_append)
 {
 	struct action act[3] = {0};
 	struct script sc = {0};
@@ -121,7 +121,7 @@
 	script_finish(&sc);
 }
 
-RX_TEST_CASE(basics, handle)
+TEST_DECL(basics_handle)
 {
 	struct {
 		struct invokes inv;
@@ -131,7 +131,7 @@
 		{ .act = INIT(&table[1].inv, my_update_true)    },
 		{ .act = INIT(&table[2].inv, my_update_false)   }
 	};
-	
+
 	struct script sc = {0};
 
 	RX_REQUIRE(script_append(&sc, &table[0].act) == 0);
@@ -197,7 +197,7 @@
 	RX_INT_REQUIRE_EQUAL(table[2].inv.finish, 0);
 }
 
-RX_TEST_CASE(basics, update)
+TEST_DECL(basics_update)
 {
 	struct {
 		struct invokes inv;
@@ -207,7 +207,7 @@
 		{ .act = INIT(&table[1].inv, my_update_true)    },
 		{ .act = INIT(&table[2].inv, my_update_false)   }
 	};
-	
+
 	struct script sc = {0};
 
 	RX_REQUIRE(script_append(&sc, &table[0].act) == 0);
@@ -290,7 +290,7 @@
 	RX_INT_REQUIRE_EQUAL(table[2].inv.finish, 0);
 }
 
-RX_TEST_CASE(basics, draw)
+TEST_DECL(basics_draw)
 {
 	struct {
 		struct invokes inv;
@@ -300,7 +300,7 @@
 		{ .act = INIT(&table[1].inv, my_update_true)    },
 		{ .act = INIT(&table[2].inv, my_update_false)   }
 	};
-	
+
 	struct script sc = {0};
 
 	RX_REQUIRE(script_append(&sc, &table[0].act) == 0);
@@ -366,7 +366,7 @@
 	RX_INT_REQUIRE_EQUAL(table[2].inv.finish, 0);
 }
 
-RX_TEST_CASE(basics, finish)
+TEST_DECL(basics_finish)
 {
 	struct {
 		struct invokes inv;
@@ -376,7 +376,7 @@
 		{ .act = INIT(&table[1].inv, my_update_true)    },
 		{ .act = INIT(&table[2].inv, my_update_false)   }
 	};
-	
+
 	struct script sc = {0};
 
 	RX_REQUIRE(script_append(&sc, &table[0].act) == 0);
@@ -405,7 +405,7 @@
 	RX_INT_REQUIRE_EQUAL(table[2].inv.finish, 1);
 }
 
-RX_TEST_CASE(action, simple)
+TEST_DECL(action_simple)
 {
 	struct {
 		struct invokes inv;
@@ -415,7 +415,7 @@
 		{ .act = INIT(&table[1].inv, my_update_true)    },
 		{ .act = INIT(&table[2].inv, my_update_false)   }
 	};
-	
+
 	struct script sc = {0};
 	struct action act;
 
@@ -529,8 +529,18 @@
 	RX_INT_REQUIRE_EQUAL(table[2].inv.finish, 1);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "init", basics_init),
+	TEST_DEF("basics", "append", basics_append),
+	TEST_DEF("basics", "handle", basics_handle),
+	TEST_DEF("basics", "update", basics_update),
+	TEST_DEF("basics", "draw", basics_draw),
+	TEST_DEF("basics", "finish", basics_finish),
+	TEST_DEF("action", "simple", action_simple)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-action.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-action.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,12 +16,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/action.h>
 #include <core/action-stack.h>
 #include <core/event.h>
 
+#include "test.h"
+
 struct invokes {
 	int handle;
 	int update;
@@ -87,7 +87,7 @@
 	((struct invokes *)act->data)->finish = 1;
 }
 
-RX_TEST_CASE(basics, handle)
+TEST_DECL(basics_handle)
 {
 	struct invokes inv = {0};
 	struct action act = INIT(&inv, my_update_true);
@@ -101,7 +101,7 @@
 	RX_REQUIRE(!inv.finish);
 }
 
-RX_TEST_CASE(basics, update)
+TEST_DECL(basics_update)
 {
 	struct {
 		struct invokes inv;
@@ -128,7 +128,7 @@
 	RX_REQUIRE(!table[1].inv.finish);
 }
 
-RX_TEST_CASE(basics, draw)
+TEST_DECL(basics_draw)
 {
 	struct invokes inv = {0};
 	struct action act = INIT(&inv, my_update_true);
@@ -142,7 +142,7 @@
 	RX_REQUIRE(!inv.finish);
 }
 
-RX_TEST_CASE(basics, end)
+TEST_DECL(basics_end)
 {
 	struct invokes inv = {0};
 	struct action act = INIT(&inv, my_update_true);
@@ -156,7 +156,7 @@
 	RX_REQUIRE(!inv.finish);
 }
 
-RX_TEST_CASE(basics, finish)
+TEST_DECL(basics_finish)
 {
 	struct invokes inv = {0};
 	struct action act = INIT(&inv, my_update_true);
@@ -170,7 +170,7 @@
 	RX_REQUIRE(inv.finish);
 }
 
-RX_TEST_CASE(stack, add)
+TEST_DECL(stack_add)
 {
 	struct action *actions[10];
 	struct action_stack st = {0};
@@ -188,7 +188,7 @@
 	RX_INT_REQUIRE_EQUAL(action_stack_add(&st, &act), -1);
 }
 
-RX_TEST_CASE(stack, handle)
+TEST_DECL(stack_handle)
 {
 	struct {
 		int called;
@@ -213,7 +213,7 @@
 	RX_REQUIRE(table[2].called);
 }
 
-RX_TEST_CASE(stack, update)
+TEST_DECL(stack_update)
 {
 	struct {
 		struct invokes inv;
@@ -292,7 +292,7 @@
 	RX_PTR_REQUIRE_EQUAL(st.actions[1], NULL);
 	RX_PTR_REQUIRE_EQUAL(st.actions[4], NULL);
 	RX_PTR_REQUIRE_EQUAL(st.actions[5], NULL);
-	
+
 	/*
 	 * Now make all actions to return 1 and check if it cleans the stack.
 	 */
@@ -311,7 +311,76 @@
 	RX_PTR_REQUIRE_EQUAL(st.actions[6], NULL);
 }
 
-RX_TEST_CASE(stack, finish)
+TEST_DECL(stack_draw)
+{
+	struct {
+		struct invokes inv;
+		struct action act;
+	} table[] = {
+		{ .act = INIT(&table[0], my_update_false)       },
+		{ .act = INIT(&table[1], my_update_true)        },
+		{ .act = INIT(&table[2], my_update_false)       },
+		{ .act = INIT(&table[3], my_update_false)       },
+		{ .act = INIT(&table[4], my_update_true)        },
+		{ .act = INIT(&table[5], my_update_true)        },
+		{ .act = INIT(&table[6], my_update_false)	},
+	};
+
+	struct action *actions[10];
+	struct action_stack st = {0};
+
+	action_stack_init(&st, actions, 10);
+	action_stack_add(&st, &table[0].act);
+	action_stack_add(&st, &table[1].act);
+	action_stack_add(&st, &table[2].act);
+	action_stack_add(&st, &table[3].act);
+	action_stack_add(&st, &table[4].act);
+	action_stack_add(&st, &table[5].act);
+	action_stack_add(&st, &table[6].act);
+	action_stack_draw(&st);
+
+	RX_REQUIRE(!table[0].inv.handle);
+	RX_REQUIRE(!table[1].inv.handle);
+	RX_REQUIRE(!table[2].inv.handle);
+	RX_REQUIRE(!table[3].inv.handle);
+	RX_REQUIRE(!table[4].inv.handle);
+	RX_REQUIRE(!table[5].inv.handle);
+	RX_REQUIRE(!table[6].inv.handle);
+
+	RX_REQUIRE(!table[0].inv.update);
+	RX_REQUIRE(!table[1].inv.update);
+	RX_REQUIRE(!table[2].inv.update);
+	RX_REQUIRE(!table[3].inv.update);
+	RX_REQUIRE(!table[4].inv.update);
+	RX_REQUIRE(!table[5].inv.update);
+	RX_REQUIRE(!table[6].inv.update);
+
+	RX_REQUIRE(table[0].inv.draw);
+	RX_REQUIRE(table[1].inv.draw);
+	RX_REQUIRE(table[2].inv.draw);
+	RX_REQUIRE(table[3].inv.draw);
+	RX_REQUIRE(table[4].inv.draw);
+	RX_REQUIRE(table[5].inv.draw);
+	RX_REQUIRE(table[6].inv.draw);
+
+	RX_REQUIRE(!table[0].inv.end);
+	RX_REQUIRE(!table[1].inv.end);
+	RX_REQUIRE(!table[2].inv.end);
+	RX_REQUIRE(!table[3].inv.end);
+	RX_REQUIRE(!table[4].inv.end);
+	RX_REQUIRE(!table[5].inv.end);
+	RX_REQUIRE(!table[6].inv.end);
+
+	RX_REQUIRE(!table[0].inv.finish);
+	RX_REQUIRE(!table[1].inv.finish);
+	RX_REQUIRE(!table[2].inv.finish);
+	RX_REQUIRE(!table[3].inv.finish);
+	RX_REQUIRE(!table[4].inv.finish);
+	RX_REQUIRE(!table[5].inv.finish);
+	RX_REQUIRE(!table[6].inv.finish);
+}
+
+TEST_DECL(stack_finish)
 {
 	struct {
 		struct invokes inv;
@@ -342,8 +411,21 @@
 	RX_REQUIRE(table[0].inv.finish);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "handle", basics_handle),
+	TEST_DEF("basics", "update", basics_update),
+	TEST_DEF("basics", "draw", basics_draw),
+	TEST_DEF("basics", "end", basics_end),
+	TEST_DEF("basics", "finish", basics_finish),
+	TEST_DEF("stack", "add", stack_add),
+	TEST_DEF("stack", "handle", stack_handle),
+	TEST_DEF("stack", "update", stack_update),
+	TEST_DEF("stack", "draw", stack_draw),
+	TEST_DEF("stack", "finish", stack_finish)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-character.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-character.c	Wed Apr 06 12:09:25 2022 +0200
@@ -19,26 +19,24 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <rexo.h>
-
 #include <rpg/character.h>
 #include <rpg/save.h>
 
-RX_SET_UP(setup)
+#include "test.h"
+
+RX_SET_UP(basics_setup)
 {
 	remove("test.db");
 
 	return RX_SUCCESS;
 }
 
-RX_TEAR_DOWN(teardown)
+RX_TEAR_DOWN(basics_teardown)
 {
 	remove("test.db");
 }
 
-RX_FIXTURE(basics_fixture, void *, .set_up = setup, .tear_down = teardown);
-
-RX_TEST_CASE(test, save_simple, .fixture = basics_fixture)
+TEST_DECL(basics_load)
 {
 	struct save db;
 	struct character ch = {
@@ -75,8 +73,12 @@
 	RX_INT_REQUIRE_EQUAL(ch.luckbonus, 1004);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF_FIX("basics", "load", basics_load, void *, basics_setup, basics_teardown)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-color.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-color.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,37 +16,45 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/color.h>
 
-RX_TEST_CASE(basics, red)
+#include "test.h"
+
+TEST_DECL(basics_red)
 {
 	RX_INT_REQUIRE_EQUAL(COLOR_R(0xa3000000), 163);
 }
 
-RX_TEST_CASE(basics, green)
+TEST_DECL(basics_green)
 {
 	RX_INT_REQUIRE_EQUAL(COLOR_G(0x00130000), 19);
 }
 
-RX_TEST_CASE(basics, blue)
+TEST_DECL(basics_blue)
 {
 	RX_INT_REQUIRE_EQUAL(COLOR_B(0x0000ee00), 238);
 }
 
-RX_TEST_CASE(basics, alpha)
+TEST_DECL(basics_alpha)
 {
 	RX_INT_REQUIRE_EQUAL(COLOR_A(0x000000ff), 255);
 }
 
-RX_TEST_CASE(basics, simple)
+TEST_DECL(basics_simple)
 {
 	RX_UINT_REQUIRE_EQUAL(COLOR_HEX(170, 187, 204, 238), 0xaabbccee);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "red", basics_red),
+	TEST_DEF("basics", "green", basics_green),
+	TEST_DEF("basics", "blue", basics_blue),
+	TEST_DEF("basics", "alpha", basics_alpha),
+	TEST_DEF("basics", "simple", basics_simple)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-drawable.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-drawable.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,12 +16,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/drawable.h>
 #include <core/drawable-stack.h>
 #include <core/event.h>
 
+#include "test.h"
+
 struct invokes {
 	int update;
 	int draw;
@@ -75,7 +75,7 @@
 	((struct invokes *)dw->data)->finish = 1;
 }
 
-RX_TEST_CASE(basics, update)
+TEST_DECL(basics_update)
 {
 	struct {
 		struct invokes inv;
@@ -100,7 +100,7 @@
 	RX_REQUIRE(!table[1].inv.finish);
 }
 
-RX_TEST_CASE(basics, draw)
+TEST_DECL(basics_draw)
 {
 	struct invokes inv = {0};
 	struct drawable dw = INIT(&inv, my_update_true);
@@ -113,7 +113,7 @@
 	RX_REQUIRE(!inv.finish);
 }
 
-RX_TEST_CASE(basics, end)
+TEST_DECL(basics_end)
 {
 	struct invokes inv = {0};
 	struct drawable dw = INIT(&inv, my_update_true);
@@ -126,7 +126,7 @@
 	RX_REQUIRE(!inv.finish);
 }
 
-RX_TEST_CASE(basics, finish)
+TEST_DECL(basics_finish)
 {
 	struct invokes inv = {0};
 	struct drawable dw = INIT(&inv, my_update_true);
@@ -139,7 +139,7 @@
 	RX_REQUIRE(inv.finish);
 }
 
-RX_TEST_CASE(stack, add)
+TEST_DECL(stack_add)
 {
 	struct drawable *drawables[10];
 	struct drawable_stack st = {0};
@@ -157,7 +157,7 @@
 	RX_INT_REQUIRE_EQUAL(drawable_stack_add(&st, &dw), -1);
 }
 
-RX_TEST_CASE(stack, update)
+TEST_DECL(stack_update)
 {
 	struct {
 		struct invokes inv;
@@ -228,7 +228,7 @@
 	RX_PTR_REQUIRE_EQUAL(st.objects[1], NULL);
 	RX_PTR_REQUIRE_EQUAL(st.objects[4], NULL);
 	RX_PTR_REQUIRE_EQUAL(st.objects[5], NULL);
-	
+
 	/*
 	 * Now make all actions to return 1 and check if it cleans the stack.
 	 */
@@ -247,7 +247,68 @@
 	RX_PTR_REQUIRE_EQUAL(st.objects[6], NULL);
 }
 
-RX_TEST_CASE(stack, finish)
+TEST_DECL(stack_draw)
+{
+	struct {
+		struct invokes inv;
+		struct drawable dw;
+	} table[] = {
+		{ .dw = INIT(&table[0], my_update_false)       },
+		{ .dw = INIT(&table[1], my_update_true)        },
+		{ .dw = INIT(&table[2], my_update_false)       },
+		{ .dw = INIT(&table[3], my_update_false)       },
+		{ .dw = INIT(&table[4], my_update_true)        },
+		{ .dw = INIT(&table[5], my_update_true)        },
+		{ .dw = INIT(&table[6], my_update_false)	},
+	};
+
+	struct drawable *drawables[10];
+	struct drawable_stack st = {0};
+
+	drawable_stack_init(&st, drawables, 10);
+	drawable_stack_add(&st, &table[0].dw);
+	drawable_stack_add(&st, &table[1].dw);
+	drawable_stack_add(&st, &table[2].dw);
+	drawable_stack_add(&st, &table[3].dw);
+	drawable_stack_add(&st, &table[4].dw);
+	drawable_stack_add(&st, &table[5].dw);
+	drawable_stack_add(&st, &table[6].dw);
+	drawable_stack_draw(&st);
+
+	RX_REQUIRE(!table[0].inv.update);
+	RX_REQUIRE(!table[1].inv.update);
+	RX_REQUIRE(!table[2].inv.update);
+	RX_REQUIRE(!table[3].inv.update);
+	RX_REQUIRE(!table[4].inv.update);
+	RX_REQUIRE(!table[5].inv.update);
+	RX_REQUIRE(!table[6].inv.update);
+
+	RX_REQUIRE(table[0].inv.draw);
+	RX_REQUIRE(table[1].inv.draw);
+	RX_REQUIRE(table[2].inv.draw);
+	RX_REQUIRE(table[3].inv.draw);
+	RX_REQUIRE(table[4].inv.draw);
+	RX_REQUIRE(table[5].inv.draw);
+	RX_REQUIRE(table[6].inv.draw);
+
+	RX_REQUIRE(!table[0].inv.end);
+	RX_REQUIRE(!table[1].inv.end);
+	RX_REQUIRE(!table[2].inv.end);
+	RX_REQUIRE(!table[3].inv.end);
+	RX_REQUIRE(!table[4].inv.end);
+	RX_REQUIRE(!table[5].inv.end);
+	RX_REQUIRE(!table[6].inv.end);
+
+	RX_REQUIRE(!table[0].inv.finish);
+	RX_REQUIRE(!table[1].inv.finish);
+	RX_REQUIRE(!table[2].inv.finish);
+	RX_REQUIRE(!table[3].inv.finish);
+	RX_REQUIRE(!table[4].inv.finish);
+	RX_REQUIRE(!table[5].inv.finish);
+	RX_REQUIRE(!table[6].inv.finish);
+}
+
+TEST_DECL(stack_finish)
 {
 	struct {
 		struct invokes inv;
@@ -276,8 +337,19 @@
 	RX_REQUIRE(table[0].inv.finish);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "update", basics_update),
+	TEST_DEF("basics", "draw", basics_draw),
+	TEST_DEF("basics", "end", basics_end),
+	TEST_DEF("basics", "finish", basics_finish),
+	TEST_DEF("stack", "add", stack_add),
+	TEST_DEF("stack", "update", stack_update),
+	TEST_DEF("stack", "draw", stack_draw),
+	TEST_DEF("stack", "finish", stack_finish)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-error.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-error.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,18 +16,22 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/error.h>
 
-RX_TEST_CASE(basics, simple)
+#include "test.h"
+
+TEST_DECL(basics_simple)
 {
 	errorf("Failed: %d", 123);
 	RX_STR_REQUIRE_EQUAL("Failed: 123", error());
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "simple", basics_simple)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-map.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-map.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,8 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/core.h>
 #include <core/error.h>
 #include <core/panic.h>
@@ -27,7 +25,9 @@
 #include <rpg/map-file.h>
 #include <rpg/map.h>
 
-RX_TEST_CASE(test, basics_sample)
+#include "test.h"
+
+TEST_DECL(basics_sample)
 {
 	struct map_file loader = {0};
 	struct map map = {0};
@@ -88,7 +88,7 @@
 	map_file_finish(&loader);
 }
 
-RX_TEST_CASE(test, error_title)
+TEST_DECL(error_title)
 {
 	struct map_file loader = {0};
 	struct map map = {0};
@@ -99,7 +99,7 @@
 	map_file_finish(&loader);
 }
 
-RX_TEST_CASE(test, error_columns)
+TEST_DECL(error_columns)
 {
 	struct map_file loader = {0};
 	struct map map = {0};
@@ -110,7 +110,7 @@
 	map_file_finish(&loader);
 }
 
-RX_TEST_CASE(test, error_rows)
+TEST_DECL(error_rows)
 {
 	struct map_file loader = {0};
 	struct map map = {0};
@@ -121,6 +121,13 @@
 	map_file_finish(&loader);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "sample", basics_sample),
+	TEST_DEF("error", "title", error_title),
+	TEST_DEF("error", "columns", error_columns),
+	TEST_DEF("error", "rows", error_rows)
+};
+
 int
 main(int argc, char **argv)
 {
@@ -133,5 +140,5 @@
 	if (core_init("fr.malikania", "test") < 0 || window_open("test-map", 100, 100) < 0)
 		return 1;
 
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-save-quest.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-save-quest.c	Wed Apr 06 12:09:25 2022 +0200
@@ -18,14 +18,12 @@
 
 #include <stdio.h>
 
-#include <rexo.h>
-
-#include <core/util.h>
-
 #include <rpg/quest.h>
 #include <rpg/save.h>
 
-RX_SET_UP(setup)
+#include "test.h"
+
+RX_SET_UP(basics_setup)
 {
 	if (save_open_path(RX_DATA, "quest.db", SAVE_MODE_WRITE) < 0)
 		return RX_ERROR;
@@ -33,15 +31,13 @@
 	return RX_SUCCESS;
 }
 
-RX_TEAR_DOWN(teardown)
+RX_TEAR_DOWN(basics_teardown)
 {
 	save_finish(RX_DATA);
 	remove("quest.db");
 }
 
-RX_FIXTURE(basics_fixture, struct save, .set_up = setup, .tear_down = teardown);
-
-RX_TEST_CASE(basics, load, .fixture = basics_fixture)
+TEST_DECL(basics_load)
 {
 	struct quest_step steps[] = {
 		{
@@ -72,8 +68,12 @@
 	RX_INT_REQUIRE_EQUAL(steps[1].percent, 50);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF_FIX("basics", "load", basics_load, struct save, basics_setup, basics_teardown)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-save.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-save.c	Wed Apr 06 12:09:25 2022 +0200
@@ -18,20 +18,18 @@
 
 #include <stdio.h>
 
-#include <rexo.h>
-
 #include <rpg/property.h>
 #include <rpg/save.h>
 
-RX_TEAR_DOWN(teardown)
+#include "test.h"
+
+RX_TEAR_DOWN(basics_teardown)
 {
 	remove("1.db");
 	remove("2.db");
 }
 
-RX_FIXTURE(basics_fixture, void *, .tear_down = teardown);
-
-RX_TEST_CASE(open, read, .fixture = basics_fixture)
+TEST_DECL(basics_read)
 {
 	struct save db;
 
@@ -40,7 +38,7 @@
 	save_finish(&db);
 }
 
-RX_TEST_CASE(open, write, .fixture = basics_fixture)
+TEST_DECL(basics_write)
 {
 	struct save db[2] = {0};
 
@@ -132,8 +130,13 @@
 
 #endif
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF_FIX("basics", "read", basics_read, void *, NULL, basics_teardown),
+	TEST_DEF_FIX("basics", "write", basics_write, void *, NULL, basics_teardown)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv)
 }
--- a/tests/test-state.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-state.c	Wed Apr 06 12:09:25 2022 +0200
@@ -18,13 +18,13 @@
 
 #include <string.h>
 
-#include <rexo.h>
-
 #include <core/event.h>
 #include <core/game.h>
 #include <core/state.h>
 #include <core/util.h>
 
+#include "test.h"
+
 struct invokes {
 	unsigned int start;
 	unsigned int handle;
@@ -38,14 +38,14 @@
 
 static struct state *states[16];
 
-RX_SET_UP(setup)
+RX_SET_UP(basics_setup)
 {
 	game_init(states, UTIL_SIZE(states));
 
 	return RX_SUCCESS;
 }
 
-RX_TEAR_DOWN(teardown)
+RX_TEAR_DOWN(basics_teardown)
 {
 	game_quit();
 }
@@ -114,9 +114,7 @@
 	.finish = my_finish \
 }
 
-RX_FIXTURE(basics_fixture, void *, .set_up = setup, .tear_down = teardown);
-
-RX_TEST_CASE(basics, start)
+TEST_DECL(basics_start)
 {
 	struct invokes inv = {0};
 	struct state state = INIT(&inv);
@@ -130,7 +128,7 @@
 	RX_UINT_REQUIRE_EQUAL(inv.finish, 0U);
 }
 
-RX_TEST_CASE(basics, handle)
+TEST_DECL(basics_handle)
 {
 	struct invokes inv = {0};
 	struct state state = INIT(&inv);
@@ -144,7 +142,7 @@
 	RX_UINT_REQUIRE_EQUAL(inv.finish, 0U);
 }
 
-RX_TEST_CASE(basics, update)
+TEST_DECL(basics_update)
 {
 	struct invokes inv = {0};
 	struct state state = INIT(&inv);
@@ -158,7 +156,7 @@
 	RX_UINT_REQUIRE_EQUAL(inv.finish, 0U);
 }
 
-RX_TEST_CASE(basics, draw)
+TEST_DECL(basics_draw)
 {
 	struct invokes inv = {0};
 	struct state state = INIT(&inv);
@@ -172,7 +170,7 @@
 	RX_UINT_REQUIRE_EQUAL(inv.finish, 0U);
 }
 
-RX_TEST_CASE(basics, end)
+TEST_DECL(basics_end)
 {
 	struct invokes inv = {0};
 	struct state state = INIT(&inv);
@@ -186,7 +184,7 @@
 	RX_UINT_REQUIRE_EQUAL(inv.finish, 0U);
 }
 
-RX_TEST_CASE(basics, finish)
+TEST_DECL(basics_finish)
 {
 	struct invokes inv = {0};
 	struct state state = INIT(&inv);
@@ -200,7 +198,7 @@
 	RX_UINT_REQUIRE_EQUAL(inv.finish, 1U);
 }
 
-RX_TEST_CASE(game, game_push, .fixture = basics_fixture)
+TEST_DECL(basics_game)
 {
 	static struct {
 		struct invokes inv;
@@ -323,8 +321,18 @@
 	RX_UINT_REQUIRE_EQUAL(states[1].inv.finish, 1U);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "start", basics_start),
+	TEST_DEF("basics", "handle", basics_handle),
+	TEST_DEF("basics", "update", basics_update),
+	TEST_DEF("basics", "draw", basics_draw),
+	TEST_DEF("basics", "end", basics_end),
+	TEST_DEF("basics", "finish", basics_finish),
+	TEST_DEF_FIX("basics", "game", basics_game, void *, basics_setup, basics_teardown)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-tileset.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-tileset.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,15 +16,15 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/core.h>
 #include <core/window.h>
 
 #include <rpg/tileset-file.h>
 #include <rpg/tileset.h>
 
-RX_TEST_CASE(test, basics_sample)
+#include "test.h"
+
+TEST_DECL(basics_sample)
 {
 	struct tileset_file loader = {0};
 	struct tileset tileset;
@@ -62,7 +62,7 @@
 	tileset_file_finish(&loader);
 }
 
-RX_TEST_CASE(test, error_tilewidth)
+TEST_DECL(error_tilewidth)
 {
 	struct tileset_file loader = {0};
 	struct tileset tileset = {0};
@@ -70,7 +70,7 @@
 	RX_INT_REQUIRE_EQUAL(tileset_file_open(&loader, &tileset, DIRECTORY "/maps/error-tilewidth.tileset"), -1);
 }
 
-RX_TEST_CASE(test, error_tileheight)
+TEST_DECL(error_tileheight)
 {
 	struct tileset_file loader = {0};
 	struct tileset tileset = {0};
@@ -78,7 +78,7 @@
 	RX_INT_REQUIRE_EQUAL(tileset_file_open(&loader, &tileset, DIRECTORY "/maps/error-tileheight.tileset"), -1);
 }
 
-RX_TEST_CASE(test, error_image)
+TEST_DECL(error_image)
 {
 	struct tileset_file loader = {0};
 	struct tileset tileset = {0};
@@ -86,11 +86,18 @@
 	RX_INT_REQUIRE_EQUAL(tileset_file_open(&loader, &tileset, DIRECTORY "/maps/error-image.tileset"), -1);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "sample", basics_sample),
+	TEST_DEF("error", "tilewidth", error_tilewidth),
+	TEST_DEF("error", "tileheight", error_tileheight),
+	TEST_DEF("error", "image", error_image),
+};
+
 int
 main(int argc, char **argv)
 {
 	if (core_init("fr.malikania", "test") < 0 || window_open("test-tileset", 100, 100) < 0)
 		return 1;
 
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-util.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-util.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,11 +16,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/util.h>
 
-RX_TEST_CASE(nrand, simple)
+#include "test.h"
+
+TEST_DECL(test_nrand)
 {
 	int found[10] = {0};
 
@@ -39,8 +39,12 @@
 	RX_REQUIRE(!found[9]);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF("basics", "nrand", test_nrand)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-vfs-directory.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-vfs-directory.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,11 +16,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/vfs-directory.h>
 #include <core/vfs.h>
 
+#include "test.h"
+
 RX_SET_UP(setup)
 {
 	vfs_directory(RX_DATA, DIRECTORY "/vfs/directory");
@@ -33,9 +33,7 @@
 	vfs_finish(RX_DATA);
 }
 
-RX_FIXTURE(basics_fixture, struct vfs, .set_up = setup, .tear_down = teardown);
-
-RX_TEST_CASE(basics, read, .fixture = basics_fixture)
+TEST_DECL(basics_read)
 {
 	struct vfs_file file;
 	char data[256] = {0};
@@ -45,15 +43,20 @@
 	RX_STR_REQUIRE_EQUAL(data, "Hello World!\n");
 }
 
-RX_TEST_CASE(basics, notfound, .fixture = basics_fixture)
+TEST_DECL(error_notfound)
 {
 	struct vfs_file file;
 
 	RX_INT_REQUIRE_EQUAL(vfs_open(RX_DATA, &file, "notfound.txt", "r"), -1);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF_FIX("basics", "read", basics_read, struct vfs, setup, teardown),
+	TEST_DEF_FIX("error", "notfound", error_notfound, struct vfs, setup, teardown)
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- a/tests/test-vfs-zip.c	Sun Apr 03 08:05:30 2022 +0200
+++ b/tests/test-vfs-zip.c	Wed Apr 06 12:09:25 2022 +0200
@@ -16,11 +16,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <rexo.h>
-
 #include <core/vfs-zip.h>
 #include <core/vfs.h>
 
+#include "test.h"
+
 RX_SET_UP(setup)
 {
 	if (vfs_zip(RX_DATA, DIRECTORY "/vfs/data.zip", "r") < 0)
@@ -34,9 +34,7 @@
 	vfs_finish(RX_DATA);
 }
 
-RX_FIXTURE(basics_fixture, struct vfs, .set_up = setup, .tear_down = teardown);
-
-RX_TEST_CASE(basics, read, .fixture = basics_fixture)
+TEST_DECL(basics_read)
 {
 	struct vfs_file file;
 	char data[256] = {0};
@@ -46,15 +44,20 @@
 	RX_STR_REQUIRE_EQUAL(data, "Hello from zip file!\n");
 }
 
-RX_TEST_CASE(basics, notfound, .fixture = basics_fixture)
+TEST_DECL(error_notfound)
 {
 	struct vfs_file file;
 
 	RX_INT_REQUIRE_EQUAL(vfs_open(RX_DATA, &file, "notfound.txt", "r"), -1);
 }
 
+static const struct rx_test_case tests[] = {
+	TEST_DEF_FIX("basics", "read", basics_read, struct vfs, setup, teardown),
+	TEST_DEF_FIX("error", "notfound", error_notfound, struct vfs, setup, teardown),
+};
+
 int
 main(int argc, char **argv)
 {
-	return rx_main(0, NULL, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;
+	return TEST_RUN(tests, argc, argv);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test.h	Wed Apr 06 12:09:25 2022 +0200
@@ -0,0 +1,49 @@
+/*
+ * test.h -- basic helpers for rexo
+ *
+ * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <rexo.h>
+
+#include <core/util.h>
+
+#define TEST_DECL(name)                                                 \
+static void                                                             \
+name(struct rx_context *RX_PARAM_CONTEXT, void *RX_PARAM_DATA)
+
+#define TEST_DEF(s, n, f)                                               \
+{                                                                       \
+        .suite_name = s,                                                \
+        .name = n,                                                      \
+        .run = f                                                        \
+}
+
+#define TEST_DEF_FIX(s, n, f, type, up, down)                           \
+{                                                                       \
+        .suite_name = s,                                                \
+        .name = n,                                                      \
+        .run = f,                                                       \
+        .config.fixture = {                                             \
+                .size = sizeof (type),                                  \
+                .config = {                                             \
+                        .set_up = up,                                   \
+                        .tear_down = down                               \
+                }                                                       \
+        }                                                               \
+}
+
+#define TEST_RUN(tests, argc, argv)                                     \
+        rx_main(UTIL_SIZE(tests), tests, argc, (const char **)argv) == RX_SUCCESS ? 0 : 1;