changeset 42:22a09a5ee476

core: add better map check and unit tests
author David Demelier <markand@malikania.fr>
date Wed, 15 Jan 2020 20:33:21 +0100
parents 3996f873a54b
children 291be94202c7
files .hgignore Makefile src/main.c src/map.c src/map.h tests/assets/maps/error-height.map tests/assets/maps/error-tileheight.map tests/assets/maps/error-tilewidth.map tests/assets/maps/error-title.map tests/assets/maps/error-width.map tests/assets/maps/sample-map.map tests/assets/tilesets/sample-map.png tests/test-map.c
diffstat 13 files changed, 277 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Jan 15 13:11:47 2020 +0100
+++ b/.hgignore	Wed Jan 15 20:33:21 2020 +0100
@@ -13,8 +13,9 @@
 \.o$
 ^libmolko\.a$
 ^molko(\.exe)?$
-^tests/test-color$
-^tests/test-error$
+^tests/test-color(\.exe)?$
+^tests/test-error(\.exe)?$
+^tests/test-map(\.exe)?$
 ^tools/molko-map$
 
 # doxygen stuff.
--- a/Makefile	Wed Jan 15 13:11:47 2020 +0100
+++ b/Makefile	Wed Jan 15 20:33:21 2020 +0100
@@ -51,7 +51,8 @@
 JANSSON_LDFLAGS=`pkg-config --libs jansson`
 
 TESTS=          tests/test-color.c \
-                tests/test-error.c
+                tests/test-error.c \
+                tests/test-map.c
 TESTS_INCS=     -I extern/libgreatest -I src ${SDL_CFLAGS}
 TESTS_LIBS=     ${LIB} ${SDL_LDFLAGS} ${LDFLAGS}
 TESTS_OBJS=     ${TESTS:.c=}
--- a/src/main.c	Wed Jan 15 13:11:47 2020 +0100
+++ b/src/main.c	Wed Jan 15 20:33:21 2020 +0100
@@ -36,6 +36,8 @@
 	(void)argc;
 	(void)argv;
 
+#if 0
+
 	struct clock clock;
 	struct map map;
 	struct texture *guy;
@@ -120,7 +122,6 @@
 			}
 		}
 
-		map_move(&map, map.x + dx, map.y + dy);
 		walksprite_update(&ws, elapsed);
 		painter_clear();
 		map_draw(&map);
@@ -128,6 +129,7 @@
 		painter_present();
 		delay(50);
 	}
+#endif
 
 	return 0;
 }
--- a/src/map.c	Wed Jan 15 13:11:47 2020 +0100
+++ b/src/map.c	Wed Jan 15 20:33:21 2020 +0100
@@ -27,6 +27,7 @@
 #include "image.h"
 #include "texture.h"
 #include "sprite.h"
+#include "sys.h"
 #include "painter.h"
 
 #include <SDL.h>
@@ -58,6 +59,7 @@
 
 	amount = map->width * map->height;
 	current = 0;
+
 	if (!(layer->tiles = calloc(amount, sizeof (uint16_t))))
 		return;
 
@@ -69,12 +71,12 @@
 parse_tileset(struct map *map, const char *line)
 {
 	char filename[128 + 1] = { 0 };
-	char path[512] = { 0 };
 
 	sscanf(line, "tileset|%128s", filename);
-	snprintf(path, sizeof (path), "assets/tilesets/%s", filename);
 
-	if (!(map->tileset = image_openf(path)))
+	if (map->tilewidth == 0 || map->tileheight == 0)
+		return;
+	if (!(map->tileset = image_openf(sys_datapath("tilesets/%s", filename))))
 		return;
 
 	sprite_init(&map->sprite, map->tileset, map->tilewidth, map->tileheight);
@@ -99,6 +101,23 @@
 		parse_layer(map, line, fp);
 }
 
+static bool
+check(struct map *map)
+{
+	if (strlen(map->title) == 0)
+		return error_printf("map has no title");
+	if (!map->tileset)
+		return error_printf("unable to open tileset");
+	if (map->width == 0 || map->height == 0)
+		return error_printf("map has null sizes");
+	if (map->tilewidth == 0 || map->tileheight == 0)
+		return error_printf("map has null tile sizes");
+	if (!map->layers[0].tiles || !map->layers[1].tiles)
+		return error_printf("could not allocate data");
+
+	return true;
+}
+
 static void
 draw_layer(struct map *map, const struct map_layer *layer)
 {
@@ -146,10 +165,10 @@
 
 	fclose(fp);
 
-	if (map->width == 0 || map->tilewidth == 0)
-		return error_printf("map width is null");
-	if (map->height == 0 || map->tileheight == 0)
-		return error_printf("map height is null");
+	if (!check(map)) {
+		map_close(map);
+		return false;
+	}
 
 	size_t pw = map->width * map->tilewidth;
 	size_t ph = map->height * map->tileheight;
@@ -161,14 +180,13 @@
 }
 
 void
-map_draw(struct map *map)
+map_draw(struct map *map, int srcx, int srcy)
 {
-	/* TODO: coordinates here */
 	/* TODO: remove window size here */
 	texture_draw_ex(
 		map->picture,
-		map->x,
-		map->y,
+		srcx,
+		srcy,
 		1024,
 		576,
 		0,
@@ -192,13 +210,6 @@
 }
 
 void
-map_view(struct map *map, uint64_t x, uint64_t y)
-{
-	map->x = x;
-	map->y = y;
-}
-
-void
 map_close(struct map *map)
 {
 	assert(map);
@@ -210,4 +221,6 @@
 
 	free(map->layers[0].tiles);
 	free(map->layers[1].tiles);
+
+	memset(&map, 0, sizeof (struct map));
 }
--- a/src/map.h	Wed Jan 15 13:11:47 2020 +0100
+++ b/src/map.h	Wed Jan 15 20:33:21 2020 +0100
@@ -51,8 +51,6 @@
 	struct texture *tileset;        /*!< (RW) Tileset to use */
 	struct texture *picture;        /*!< (RO) Map drawn into a picture */
 	struct sprite sprite;           /*!< (RO) Sprite to render */
-	uint64_t x;
-	uint64_t y;
 	uint16_t width;                 /*!< (RO) Map width in cells */
 	uint16_t height;                /*!< (RO) Map height in cells */
 	uint8_t tilewidth;              /*!< (RO) Pixels per cell (width) */
@@ -77,9 +75,11 @@
  *
  * \pre map != NULL
  * \param map the map to render
+ * \param srcx the x coordinate region
+ * \param srcy the y coordinate region
  */
 void
-map_draw(struct map *map);
+map_draw(struct map *map, int srcx, int srcy);
 
 /**
  * Force map repaint on its texture.
@@ -92,17 +92,6 @@
 map_repaint(struct map *map);
 
 /**
- * Move the origin of the picture rect to view.
- *
- * \param map the map
- * \param x the x coordinate
- * \param y the y coordinate
- * \note This function may adjust the coordinates if needed
- */
-void
-map_view(struct map *map, uint64_t x, uint64_t y);
-
-/**
  * Close the map and its resources.
  *
  * \pre map != NULL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/assets/maps/error-height.map	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,15 @@
+title|This map lacks height
+width|2
+tilewidth|32
+tileheight|16
+tileset|sample-map.png
+layer|background
+0
+1
+2
+3
+layer|foreground
+4
+5
+6
+7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/assets/maps/error-tileheight.map	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,16 @@
+title|This map lacks tileheight
+width|2
+height|2
+tilewidth|32
+tileset|sample-map.png
+layer|background
+0
+1
+2
+3
+layer|foreground
+4
+5
+6
+7
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/assets/maps/error-tilewidth.map	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,16 @@
+title|This map lacks tilewidth
+width|2
+height|2
+tileheight|16
+tileset|sample-map.png
+layer|background
+0
+1
+2
+3
+layer|foreground
+4
+5
+6
+7
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/assets/maps/error-title.map	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,15 @@
+width|2
+height|2
+tilewidth|32
+tileheight|16
+tileset|sample-map.png
+layer|background
+0
+1
+2
+3
+layer|foreground
+4
+5
+6
+7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/assets/maps/error-width.map	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,15 @@
+title|This map lacks width
+height|2
+tilewidth|32
+tileheight|16
+tileset|sample-map.png
+layer|background
+0
+1
+2
+3
+layer|foreground
+4
+5
+6
+7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/assets/maps/sample-map.map	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,16 @@
+title|This is a test map
+width|2
+height|2
+tilewidth|32
+tileheight|16
+tileset|sample-map.png
+layer|background
+0
+1
+2
+3
+layer|foreground
+4
+5
+6
+7
Binary file tests/assets/tilesets/sample-map.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-map.c	Wed Jan 15 20:33:21 2020 +0100
@@ -0,0 +1,142 @@
+/*
+ * test-map.c -- test map routines
+ *
+ * Copyright (c) 2020 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 <greatest.h>
+
+#include <error.h>
+#include <map.h>
+#include <sys.h>
+#include <window.h>
+
+static void
+setup(void *data)
+{
+	(void)data;
+
+	if (!sys_init())
+		error_fatal();
+	if (!window_init("Test map", 100, 100))
+		error_fatal();
+}
+
+static void
+teardown(void *data)
+{
+	(void)data;
+
+	window_close();
+	sys_close();
+}
+
+TEST
+sample(void)
+{
+	struct map map;
+
+	ASSERT(map_open(&map, sys_datapath("maps/sample-map.map")));
+	ASSERT_STR_EQ("This is a test map", map.title);
+	ASSERT_EQ(2, map.width);
+	ASSERT_EQ(2, map.height);
+	ASSERT_EQ(32, map.tilewidth);
+	ASSERT_EQ(16, map.tileheight);
+	ASSERT_EQ(0, map.layers[0].tiles[0]);
+	ASSERT_EQ(1, map.layers[0].tiles[1]);
+	ASSERT_EQ(2, map.layers[0].tiles[2]);
+	ASSERT_EQ(3, map.layers[0].tiles[3]);
+	ASSERT_EQ(4, map.layers[1].tiles[0]);
+	ASSERT_EQ(5, map.layers[1].tiles[1]);
+	ASSERT_EQ(6, map.layers[1].tiles[2]);
+	ASSERT_EQ(7, map.layers[1].tiles[3]);
+	PASS();
+}
+
+TEST
+error_title(void)
+{
+	struct map map;
+
+	ASSERT(!map_open(&map, sys_datapath("maps/error-title.map")));
+	PASS();
+}
+
+TEST
+error_width(void)
+{
+	struct map map;
+
+	ASSERT(!map_open(&map, sys_datapath("maps/error-width.map")));
+	PASS();
+}
+
+TEST
+error_height(void)
+{
+	struct map map;
+
+	ASSERT(!map_open(&map, sys_datapath("maps/error-height.map")));
+	PASS();
+}
+
+TEST
+error_tilewidth(void)
+{
+	struct map map;
+
+	ASSERT(!map_open(&map, sys_datapath("maps/error-tilewidth.map")));
+	PASS();
+}
+
+TEST
+error_tileheight(void)
+{
+	struct map map;
+
+	ASSERT(!map_open(&map, sys_datapath("maps/error-tileheight.map")));
+	PASS();
+}
+
+SUITE(basics)
+{
+	SET_SETUP(setup, NULL);
+	SET_TEARDOWN(teardown, NULL);
+	RUN_TEST(sample);
+}
+
+SUITE(errors)
+{
+	SET_SETUP(setup, NULL);
+	SET_TEARDOWN(teardown, NULL);
+	RUN_TEST(error_title);
+	RUN_TEST(error_width);
+	RUN_TEST(error_height);
+	RUN_TEST(error_tilewidth);
+	RUN_TEST(error_tileheight);
+}
+
+GREATEST_MAIN_DEFS();
+
+int
+main(int argc, char **argv)
+{
+	GREATEST_MAIN_BEGIN();
+	RUN_SUITE(basics);
+	RUN_SUITE(errors);
+	GREATEST_MAIN_END();
+
+	return 0;
+}