changeset 311:f10fd1293a7e

core: fix states + tests
author David Demelier <markand@malikania.fr>
date Thu, 09 Sep 2021 13:57:54 +0200
parents b271a0e8ce52
children 4ea0f035f712
files GNUmakefile libmlk-core/core/game.c libmlk-core/core/game.h tests/test-state.c
diffstat 4 files changed, 161 insertions(+), 140 deletions(-) [+]
line wrap: on
line diff
--- a/GNUmakefile	Mon Sep 06 09:56:59 2021 +0200
+++ b/GNUmakefile	Thu Sep 09 13:57:54 2021 +0200
@@ -385,7 +385,7 @@
 ${LIBMLK_CORE_OBJS}: config.h
 
 ${LIBMLK_CORE}: INCS += ${SDL2_INCS}
-${LIBMLK_CORE}: ${LIBMLK_CORE_OBJS} ${LIBMLK_CORE_MO}
+${LIBMLK_CORE}: ${LIBMLK_SQLITE} ${LIBMLK_CORE_OBJS} ${LIBMLK_CORE_MO}
 	${CMD.ar}
 
 libmlk-core-pot:
@@ -398,7 +398,7 @@
 ${LIBMLK_UI_ASTS}: ${MLK_BCC}
 ${LIBMLK_UI_OBJS}: ${LIBMLK_UI_ASTS} config.h
 
-${LIBMLK_UI}: ${LIBMLK_UI_OBJS} ${LIBMLK_UI_MO}
+${LIBMLK_UI}: ${LIBMLK_CORE} ${LIBMLK_UI_OBJS} ${LIBMLK_UI_MO}
 	${CMD.ar}
 
 libmlk-ui-pot:
@@ -411,7 +411,7 @@
 ${LIBMLK_RPG_ASTS}: ${MLK_BCC}
 ${LIBMLK_RPG_OBJS}: ${LIBMLK_RPG_ASTS} config.h
 
-${LIBMLK_RPG}: ${LIBMLK_RPG_OBJS} ${LIBMLK_RPG_MO}
+${LIBMLK_RPG}: ${LIBMLK_UI} ${LIBMLK_RPG_OBJS} ${LIBMLK_RPG_MO}
 	${CMD.ar}
 
 libmlk-rpg-pot:
@@ -424,7 +424,7 @@
 ${LIBMLK_ADVENTURE_ASTS}: ${MLK_BCC}
 ${LIBMLK_ADVENTURE_OBJS}: ${LIBMLK_ADVENTURE_ASTS} config.h
 
-${LIBMLK_ADVENTURE}: ${LIBMLK_ADVENTURE_OBJS} ${LIBMLK_ADVENTURE_MO}
+${LIBMLK_ADVENTURE}: ${LIBMLK_RPG} ${LIBMLK_ADVENTURE_OBJS} ${LIBMLK_ADVENTURE_MO}
 	${CMD.ar}
 
 libmlk-adventure-pot:
--- a/libmlk-core/core/game.c	Mon Sep 06 09:56:59 2021 +0200
+++ b/libmlk-core/core/game.c	Thu Sep 09 13:57:54 2021 +0200
@@ -33,6 +33,14 @@
 };
 
 void
+game_init(void)
+{
+	memset(&game, 0, sizeof (game));
+
+	game.state = &game.states[0];
+}
+
+void
 game_push(struct state *state)
 {
 	assert(state);
@@ -54,6 +62,8 @@
 	state_end(*game.state);
 	state_finish(*game.state);
 
+	*game.state = NULL;
+
 	if (game.state != &game.states[0])
 		state_resume(*--game.state);
 }
@@ -117,9 +127,10 @@
 void
 game_quit(void)
 {
-	for (size_t i = 0; i < UTIL_SIZE(game.states); ++i)
+	for (size_t i = 0; i < UTIL_SIZE(game.states); ++i) {
 		if (game.states[i])
 			state_finish(game.states[i]);
 
-	*game.state = NULL;
+		game.states[i] = NULL;
+	}
 }
--- a/libmlk-core/core/game.h	Mon Sep 06 09:56:59 2021 +0200
+++ b/libmlk-core/core/game.h	Thu Sep 09 13:57:54 2021 +0200
@@ -39,6 +39,9 @@
 CORE_BEGIN_DECLS
 
 void
+game_init(void);
+
+void
 game_push(struct state *);
 
 void
--- a/tests/test-state.c	Mon Sep 06 09:56:59 2021 +0200
+++ b/tests/test-state.c	Thu Sep 09 13:57:54 2021 +0200
@@ -30,6 +30,8 @@
 	unsigned int handle;
 	unsigned int update;
 	unsigned int draw;
+	unsigned int suspend;
+	unsigned int resume;
 	unsigned int end;
 	unsigned int finish;
 };
@@ -41,6 +43,18 @@
 }
 
 static void
+setup(void *data)
+{
+	game_init();
+}
+
+static void
+cleanup(void *data)
+{
+	game_quit();
+}
+
+static void
 my_start(struct state *state)
 {
 	((struct invokes *)state->data)->start++;
@@ -69,6 +83,18 @@
 }
 
 static void
+my_suspend(struct state *state)
+{
+	((struct invokes *)state->data)->suspend++;
+}
+
+static void
+my_resume(struct state *state)
+{
+	((struct invokes *)state->data)->resume++;
+}
+
+static void
 my_end(struct state *state)
 {
 	((struct invokes *)state->data)->end++;
@@ -86,6 +112,8 @@
 	.handle = my_handle, \
 	.update = my_update, \
 	.draw = my_draw, \
+	.suspend = my_suspend, \
+	.resume = my_resume, \
 	.end = my_end, \
 	.finish = my_finish \
 }
@@ -202,158 +230,137 @@
 	GREATEST_RUN_TEST(basics_finish);
 }
 
-static void
-switch_startup(void *data)
+GREATEST_TEST
+test_game_push(void)
 {
-	memset(data, 0, sizeof (game));
-}
-
-GREATEST_TEST
-switch_quick_1(void)
-{
-	struct {
+	static struct {
 		struct invokes inv;
 		struct state state;
-	} table[2] = {
-		{ .state = INIT(&table[0]) },
-		{ .state = INIT(&table[1]) }
-	};
-
-	/*
-	 * When set to 1, switching quickly state will immediately set the
-	 * current state to the specified one and call start on it. However,
-	 * if there was already a planned state, it is finished immediately.
-	 */
-	game_push(&table[0].state);
-
-	GREATEST_ASSERT_EQ(table[0].inv.start, 1);
-	GREATEST_ASSERT_EQ(table[0].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.finish, 0);
-
-	GREATEST_ASSERT_EQ(table[1].inv.start, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.finish, 0);
-
-	/* Switch from [0] to [1] quickly, [0] should be closed immediately. */
-	zero(&table[0].inv);
-	game_push(&table[1].state);
-
-	GREATEST_ASSERT_EQ(table[0].inv.start, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.end, 1);
-	GREATEST_ASSERT_EQ(table[0].inv.finish, 1);
-
-	GREATEST_ASSERT_EQ(table[1].inv.start, 1);
-	GREATEST_ASSERT_EQ(table[1].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.finish, 0);
-	
-	GREATEST_PASS();
-}
-
-GREATEST_TEST
-switch_quick_0(void)
-{
-	struct {
-		struct invokes inv;
-		struct state state;
-	} table[2] = {
-		{ .state = INIT(&table[0]) },
-		{ .state = INIT(&table[1]) }
+	} states[] = {
+		{ .state = INIT(&states[0].inv) },
+		{ .state = INIT(&states[1].inv) }
 	};
 
-	game_push(&table[0].state);
-
-	GREATEST_ASSERT_EQ(table[0].inv.start, 1);
-	GREATEST_ASSERT_EQ(table[0].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.finish, 0);
+	/* 0 becomes active and should start. */
+	game_push(&states[0].state);
+	GREATEST_ASSERT_EQ(states[0].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.handle, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.update, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.draw, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.suspend, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.finish, 0U);
 
-	GREATEST_ASSERT_EQ(table[1].inv.start, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.finish, 0);
+	/* Put some event, update and drawing. */
+	game_handle(&(union event) { .type = EVENT_QUIT });
+	game_update(100);
+	game_update(100);
+	game_draw();
+	game_draw();
+	game_draw();
+	GREATEST_ASSERT_EQ(states[0].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.handle, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.update, 2U);
+	GREATEST_ASSERT_EQ(states[0].inv.draw, 3U);
+	GREATEST_ASSERT_EQ(states[0].inv.suspend, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.finish, 0U);
 
-	/*
-	 * Switch from [0] to [1] quickly, this should do nothing as it should
-	 * be done on the next game_update call instead.
-	 */
-	zero(&table[0].inv);
-	game_push(&table[1].state);
+	/* Switch to state 1, 0 must be suspended. */
+	game_push(&states[1].state);
+	GREATEST_ASSERT_EQ(states[0].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.handle, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.update, 2U);
+	GREATEST_ASSERT_EQ(states[0].inv.draw, 3U);
+	GREATEST_ASSERT_EQ(states[0].inv.suspend, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.finish, 0U);
 
-	GREATEST_ASSERT_EQ(table[0].inv.start, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.finish, 0);
+	GREATEST_ASSERT_EQ(states[1].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[1].inv.handle, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.update, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.draw, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.suspend, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.finish, 0U);
 
-	GREATEST_ASSERT_EQ(table[1].inv.start, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.finish, 0);
-	
-	GREATEST_PASS();
-}
+	/* Update a little this state. */
+	game_update(10);
+	game_update(10);
+	game_update(10);
+	game_update(10);
+	GREATEST_ASSERT_EQ(states[0].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.handle, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.update, 2U);
+	GREATEST_ASSERT_EQ(states[0].inv.draw, 3U);
+	GREATEST_ASSERT_EQ(states[0].inv.suspend, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.finish, 0U);
 
-GREATEST_TEST
-switch_invoke(void)
-{
-	struct {
-		struct invokes inv;
-		struct state state;
-	} table[2] = {
-		{ .state = INIT(&table[0]) },
-		{ .state = INIT(&table[1]) }
-	};
+	GREATEST_ASSERT_EQ(states[1].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[1].inv.handle, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.update, 4U);
+	GREATEST_ASSERT_EQ(states[1].inv.draw, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.suspend, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.finish, 0U);
+
+	/* Pop it, it should be finalized through end and finish. */
+	game_pop();
 
-	/* Start with 0. */
-	game_push(&table[0].state);
+	GREATEST_ASSERT_EQ(states[0].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.handle, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.update, 2U);
+	GREATEST_ASSERT_EQ(states[0].inv.draw, 3U);
+	GREATEST_ASSERT_EQ(states[0].inv.suspend, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.resume, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.end, 0U);
+	GREATEST_ASSERT_EQ(states[0].inv.finish, 0U);
 
-	/* Ask to switch to 1. */
-	zero(&table[0].inv);
-	game_push(&table[1].state);
-	game_update(0);
+	GREATEST_ASSERT_EQ(states[1].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[1].inv.handle, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.update, 4U);
+	GREATEST_ASSERT_EQ(states[1].inv.draw, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.suspend, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.end, 1U);
+	GREATEST_ASSERT_EQ(states[1].inv.finish, 1U);
 
-	GREATEST_ASSERT_EQ(table[0].inv.start, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.update, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[0].inv.end, 1);
-	GREATEST_ASSERT_EQ(table[0].inv.finish, 1);
+	/* Pop this state as well. */
+	game_pop();
 
-	GREATEST_ASSERT_EQ(table[1].inv.start, 1);
-	GREATEST_ASSERT_EQ(table[1].inv.handle, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.update, 1);
-	GREATEST_ASSERT_EQ(table[1].inv.draw, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.end, 0);
-	GREATEST_ASSERT_EQ(table[1].inv.finish, 0);
+	GREATEST_ASSERT_EQ(states[0].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.handle, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.update, 2U);
+	GREATEST_ASSERT_EQ(states[0].inv.draw, 3U);
+	GREATEST_ASSERT_EQ(states[0].inv.suspend, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.resume, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.end, 1U);
+	GREATEST_ASSERT_EQ(states[0].inv.finish, 1U);
+
+	GREATEST_ASSERT_EQ(states[1].inv.start, 1U);
+	GREATEST_ASSERT_EQ(states[1].inv.handle, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.update, 4U);
+	GREATEST_ASSERT_EQ(states[1].inv.draw, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.suspend, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.resume, 0U);
+	GREATEST_ASSERT_EQ(states[1].inv.end, 1U);
+	GREATEST_ASSERT_EQ(states[1].inv.finish, 1U);
 
 	GREATEST_PASS();
 }
 
-GREATEST_SUITE(suite_switch)
+GREATEST_SUITE(suite_game)
 {
-	GREATEST_SET_SETUP_CB(switch_startup, &game);
-	GREATEST_RUN_TEST(switch_quick_1);
-	GREATEST_RUN_TEST(switch_quick_0);
-	GREATEST_RUN_TEST(switch_invoke);
+	GREATEST_SET_SETUP_CB(setup, NULL);
+	GREATEST_SET_TEARDOWN_CB(cleanup, NULL);
+	GREATEST_RUN_TEST(test_game_push);
 }
 
 GREATEST_MAIN_DEFS();
@@ -363,6 +370,6 @@
 {
 	GREATEST_MAIN_BEGIN();
 	GREATEST_RUN_SUITE(suite_basics);
-	GREATEST_RUN_SUITE(suite_switch);
+	GREATEST_RUN_SUITE(suite_game);
 	GREATEST_MAIN_END();
 }