diff --git a/.gitignore b/.gitignore
index 0a25736..547e49a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,8 +11,9 @@ latex/
*.so
*.la
*.a
-drow-engine
-main
+/drow-engine
+/main
+/test
# junk
core
diff --git a/Makefile b/Makefile
index 093b938..8d46141 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
all:
$(MAKE) -C src all
+test:
+ $(MAKE) -C src test
+
doc:
doxygen
@@ -9,7 +12,7 @@ doc-pdf: doc
clean:
$(MAKE) -C src clean
- rm -rf drown-engine
+ rm -rf drown-engine test
install:
$(MAKE) -C install
@@ -18,4 +21,4 @@ uninstall:
$(MAKE) -C uninstall
-.PHONY: all doc doc-pdf clean install uninstall
+.PHONY: all doc doc-pdf clean install test uninstall
diff --git a/src/Makefile b/src/Makefile
index d7cf6c5..1a252af 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -16,7 +16,7 @@ endif
TARGET = drow-engine
HEADERS = err.h common.h print.h filereader.h gl_draw.h vector.h half_edge.h
-OBJECTS = main.o print.o filereader.o gl_draw.o vector.o half_edge.o
+OBJECTS = print.o filereader.o gl_draw.o vector.o half_edge.o
INCS = -I.
CFLAGS += $(shell $(PKG_CONFIG) --cflags gl glu glib-2.0)
@@ -37,8 +37,16 @@ INSTALL_LIBDIR = $(PREFIX)/$(LIBDIR)
all: $(TARGET)
-$(TARGET): $(HEADERS) $(OBJECTS)
- $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o ../$(TARGET) $(OBJECTS) $(LDFLAGS) $(LIBS)
+drow-engine.a: $(OBJECTS)
+ $(AR) rcu $@ $^
+
+test: drow-engine.a
+ $(MAKE) -C test
+
+$(TARGET): $(HEADERS) drow-engine.a main.o
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) \
+ -o ../$(TARGET) \
+ main.o drow-engine.a $(LDFLAGS) $(LIBS)
install: $(TARGET)
$(INSTALL_DIR) "$(DESTDIR)$(INSTALL_BINDIR)"
@@ -48,7 +56,8 @@ uninstall:
rm "$(DESTDIR)$(INSTALL_BINDIR)/$(TARGET)"
clean:
- rm -f *.o $(TARGET) core vgcore*
+ $(MAKE) -C test clean
+ rm -f *.o drow-engine.a $(TARGET) core vgcore*
-.PHONY: all clean install uninstall
+.PHONY: all clean install test uninstall
diff --git a/src/test/Makefile b/src/test/Makefile
new file mode 100644
index 0000000..d731ae6
--- /dev/null
+++ b/src/test/Makefile
@@ -0,0 +1,52 @@
+# compiler, tools
+CC = clang
+PKG_CONFIG ?= pkg-config
+
+# flags
+CFLAGS ?= -march=native -O2 -pipe
+CFLAGS += -std=c99 -pedantic -Wall -Wextra -Werror -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function
+ifeq ($(shell $(CC) -v 2>&1 | grep 'gcc version' &>/dev/null && echo 1),1)
+CFLAGS += -Wno-unused-but-set-variable
+endif
+LDFLAGS ?= -Wl,-O1 -Wl,--as-needed -Wl,--hash-style=gnu
+
+ifndef NODEBUG
+CFLAGS += -O0 -g3
+endif
+
+TARGET = test
+HEADERS = cunit.h
+OBJECTS = cunit.o cunit_filereader.o cunit_half_edge.o
+INCS = -I. -I..
+
+CFLAGS += $(shell $(PKG_CONFIG) --cflags gl glu glib-2.0)
+LIBS = $(shell $(PKG_CONFIG) --libs gl glu glib-2.0) -lglut -lm -lcunit
+CPPFLAGS += -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED -D_GNU_SOURCE
+
+# install variables
+INSTALL = install
+INSTALL_BIN = install -m755
+INSTALL_DIR = install -d
+PREFIX = /usr/local
+LIBDIR = lib64
+INSTALL_BINDIR = $(PREFIX)/bin
+INSTALL_LIBDIR = $(PREFIX)/$(LIBDIR)
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -c $*.c
+
+all: $(TARGET)
+
+drow-engine.a:
+ $(MAKE) -C .. $@
+
+$(TARGET): $(HEADERS) $(OBJECTS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o ../../$(TARGET) \
+ $(OBJECTS) ../drow-engine.a $(LDFLAGS) $(LIBS)
+
+clean:
+ rm -f *.o $(TARGET) core vgcore*
+
+
+.PHONY: all clean drow-engine.a install uninstall
+
diff --git a/src/test/cunit.c b/src/test/cunit.c
new file mode 100644
index 0000000..95a89b4
--- /dev/null
+++ b/src/test/cunit.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2011-2014 hasufell
+ *
+ * This file is part of a hasufell project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "cunit.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+int init_suite(void)
+{
+ return 0;
+}
+
+int clean_suite(void)
+{
+ return 0;
+}
+
+int main(void)
+{
+ CU_pSuite pSuite = NULL;
+ int my_stderr;
+
+ /* initialize the CUnit test registry */
+ if (CUE_SUCCESS != CU_initialize_registry())
+ return CU_get_error();
+
+ /* add a suite to the registry */
+ pSuite = CU_add_suite("filereader tests",
+ init_suite,
+ clean_suite);
+ if (NULL == pSuite) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ /* add the tests to the suite */
+ if (
+ (NULL == CU_add_test(pSuite, "test1 reading plain text file",
+ test_read_text_file1)) ||
+ (NULL == CU_add_test(pSuite, "test2 reading plain text file",
+ test_read_text_file2)) ||
+ (NULL == CU_add_test(pSuite, "test3 reading plain text file",
+ test_read_text_file3)) ||
+ (NULL == CU_add_test(pSuite, "test4 reading plain text file",
+ test_read_text_file4)) ||
+ (NULL == CU_add_test(pSuite, "test1 reading obj file",
+ test_read_obj_file1)) ||
+ (NULL == CU_add_test(pSuite, "test2 reading obj file",
+ test_read_obj_file2)) ||
+ (NULL == CU_add_test(pSuite, "test3 reading obj file",
+ test_read_obj_file3))
+
+ ) {
+
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ /* add a suite to the registry */
+ pSuite = CU_add_suite("half edge tests",
+ init_suite,
+ clean_suite);
+ if (NULL == pSuite) {
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ /* add the tests to the suite */
+ if (
+ (NULL == CU_add_test(pSuite, "test1 parsing .obj",
+ test_parse_obj1)) ||
+ (NULL == CU_add_test(pSuite, "test2 parsing .obj",
+ test_parse_obj2)) ||
+ (NULL == CU_add_test(pSuite, "test3 parsing .obj",
+ test_parse_obj3)) ||
+ (NULL == CU_add_test(pSuite, "test4 parsing .obj",
+ test_parse_obj4))
+ ) {
+
+ CU_cleanup_registry();
+ return CU_get_error();
+ }
+
+ /* save stderr stream and close it */
+ my_stderr = dup(STDERR_FILENO);
+ close(STDERR_FILENO);
+
+ /* Run all tests using the basic interface */
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ printf("\n");
+ CU_basic_show_failures(CU_get_failure_list());
+ printf("\n\n");
+
+ /* Clean up registry and return */
+ CU_cleanup_registry();
+
+ /* restore stderr stream */
+ dup2(my_stderr, STDERR_FILENO);
+
+ return CU_get_error();
+}
diff --git a/src/test/cunit.h b/src/test/cunit.h
new file mode 100644
index 0000000..c55e485
--- /dev/null
+++ b/src/test/cunit.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011-2014 hasufell
+ *
+ * This file is part of a hasufell project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/*
+ * filereader tests
+ */
+void test_read_text_file1(void);
+void test_read_text_file2(void);
+void test_read_text_file3(void);
+void test_read_text_file4(void);
+
+void test_read_obj_file1(void);
+void test_read_obj_file2(void);
+void test_read_obj_file3(void);
+
+/*
+ * half_edge tests
+ */
+void test_parse_obj1(void);
+void test_parse_obj2(void);
+void test_parse_obj3(void);
+void test_parse_obj4(void);
diff --git a/src/test/cunit_filereader.c b/src/test/cunit_filereader.c
new file mode 100644
index 0000000..ff3a6fe
--- /dev/null
+++ b/src/test/cunit_filereader.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2011-2014 hasufell
+ *
+ * This file is part of a hasufell project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "filereader.h"
+#include "half_edge.h"
+
+#include
+#include
+#include
+#include
+#include
+
+
+/**
+ * Read a valid text file and compare it with the correct expected
+ * string.
+ */
+void test_read_text_file1(void)
+{
+ char *actual_string = read_file("src/test/test-file.txt"),
+ *expected_string = "This test file is a test file.\n";
+
+
+ CU_ASSERT_PTR_NOT_NULL(actual_string);
+ CU_ASSERT_EQUAL((strcmp(actual_string, expected_string)), 0);
+}
+
+/**
+ * Read a valid text file and compare it with an uncorrect expected
+ * string.
+ */
+void test_read_text_file2(void)
+{
+ char *actual_string = read_file("src/test/test-file.txt"),
+ *expected_string = "foo";
+
+ CU_ASSERT_PTR_NOT_NULL(actual_string);
+ CU_ASSERT_NOT_EQUAL((strcmp(actual_string, expected_string)), 0);
+}
+
+/**
+ * Read an invalid text file.
+ */
+void test_read_text_file3(void)
+{
+ char *actual_string = actual_string = read_file("asd");
+
+ CU_ASSERT_PTR_NULL(actual_string);
+}
+
+/**
+ * Pass NULL to the read_file() function.
+ */
+void test_read_text_file4(void)
+{
+ char *actual_string = actual_string = read_file(NULL);
+
+ CU_ASSERT_PTR_NULL(actual_string);
+}
+
+/**
+ * Read a valid .obj file and test the whole HE_obj structure
+ * for correctness.
+ */
+void test_read_obj_file1(void)
+{
+ HE_obj *obj = read_obj_file("obj/testcube_trans.obj");
+
+ CU_ASSERT_PTR_NOT_NULL(obj);
+
+ CU_ASSERT_EQUAL(obj->vertices[0].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[0].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[0].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[1].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[1].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[1].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[2].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[2].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[2].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[3].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[3].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[3].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[4].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[4].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[4].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[5].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[5].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[5].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[6].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[6].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[6].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[7].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[7].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[7].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vc, 8);
+
+ /*
+ * The following relies on faces always saving the
+ * last listed vertice as their edge member.
+ */
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->fc, 6);
+
+ CU_ASSERT_EQUAL(obj->ec, 24);
+}
+
+/**
+ * Read an invalid .obj file.
+ */
+void test_read_obj_file2(void)
+{
+ HE_obj *obj = read_obj_file("objfoo");
+
+ CU_ASSERT_PTR_NULL(obj);
+}
+
+/**
+ * Pass NULL to read_obj_file().
+ */
+void test_read_obj_file3(void)
+{
+ HE_obj *obj = read_obj_file(NULL);
+
+ CU_ASSERT_PTR_NULL(obj);
+}
diff --git a/src/test/cunit_half_edge.c b/src/test/cunit_half_edge.c
new file mode 100644
index 0000000..810d7c0
--- /dev/null
+++ b/src/test/cunit_half_edge.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2011-2014 hasufell
+ *
+ * This file is part of a hasufell project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "half_edge.h"
+
+#include
+#include
+#include
+#include
+
+/**
+ * Use a valid string representing an .obj file
+ * and test the whole HE_obj structure for correctness.
+ */
+void test_parse_obj1(void)
+{
+ char const * const string = ""
+ "v 9.0 10.0 11.0\n"
+ "v 11.0 10.0 11.0\n"
+ "v 9.0 11.0 11.0\n"
+ "v 11.0 11.0 11.0\n"
+ "v 9.0 11.0 9.0\n"
+ "v 11.0 11.0 9.0\n"
+ "v 9.0 10.0 9.0\n"
+ "v 11.0 10.0 9.0\n"
+ "f 1 2 4 3\n"
+ "f 3 4 6 5\n"
+ "f 5 6 8 7\n"
+ "f 7 8 2 1\n"
+ "f 2 8 6 4\n"
+ "f 7 1 3 5\n";
+
+ HE_obj *obj = parse_obj(string);
+
+ CU_ASSERT_PTR_NOT_NULL(obj);
+
+ CU_ASSERT_EQUAL(obj->vertices[0].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[0].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[0].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[1].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[1].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[1].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[2].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[2].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[2].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[3].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[3].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[3].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[4].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[4].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[4].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[5].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[5].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[5].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[6].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[6].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[6].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[7].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[7].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[7].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vc, 8);
+
+ /*
+ * The following relies on faces always saving the
+ * last listed vertice as their edge member.
+ */
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->fc, 6);
+
+ CU_ASSERT_EQUAL(obj->ec, 24);
+}
+
+/**
+ * Test if the parser correctly ignores comments and other
+ * junk.
+ */
+void test_parse_obj2(void)
+{
+ char const * const string = ""
+ "v 9.0 10.0 11.0\n"
+ "v 11.0 10.0 11.0\n"
+ "v 9.0 11.0 11.0\n"
+ "v 11.0 11.0 11.0\n"
+ "v 9.0 11.0 9.0\n"
+ "v 11.0 11.0 9.0\n"
+ "# blah\n"
+ "v 9.0 10.0 9.0\n"
+ "v 11.0 10.0 9.0\n"
+ "f 1 2 4 3\n"
+ "f 3 4 6 5\n"
+ "kkldsakl sakdjl\n"
+ "f 5 6 8 7\n"
+ "f 7 8 2 1\n"
+ "f 2 8 6 4\n"
+ "f 7 1 3 5\n"
+ "998032lkk\n";
+
+ HE_obj *obj = parse_obj(string);
+
+ CU_ASSERT_PTR_NOT_NULL(obj);
+
+ CU_ASSERT_EQUAL(obj->vertices[0].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[0].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[0].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[1].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[1].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[1].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[2].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[2].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[2].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[3].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[3].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[3].z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[4].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[4].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[4].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[5].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[5].y, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[5].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[6].x, 9.0);
+ CU_ASSERT_EQUAL(obj->vertices[6].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[6].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vertices[7].x, 11.0);
+ CU_ASSERT_EQUAL(obj->vertices[7].y, 10.0);
+ CU_ASSERT_EQUAL(obj->vertices[7].z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->vc, 8);
+
+ /*
+ * The following relies on faces always saving the
+ * last listed vertice as their edge member.
+ */
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[0].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[1].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[2].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[3].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->x, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[4].edge->next->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->y, 10.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->vert->z, 11.0);
+
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->x, 9.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->y, 11.0);
+ CU_ASSERT_EQUAL(obj->faces[5].edge->next->next->next->next->vert->z, 9.0);
+
+ CU_ASSERT_EQUAL(obj->fc, 6);
+
+ CU_ASSERT_EQUAL(obj->ec, 24);
+}
+
+/**
+ * Test if the parser correctly aborts when passed
+ * an empty string.
+ */
+void test_parse_obj3(void)
+{
+ char const * const string = "";
+
+ HE_obj *obj = parse_obj(string);
+
+ CU_ASSERT_PTR_NULL(obj);
+}
+
+/**
+ * Test if the parser correctly aborts when passed
+ * a NULL pointer.
+ */
+void test_parse_obj4(void)
+{
+ HE_obj *obj = parse_obj(NULL);
+
+ CU_ASSERT_PTR_NULL(obj);
+}
diff --git a/src/test/test-file.txt b/src/test/test-file.txt
new file mode 100644
index 0000000..abc2699
--- /dev/null
+++ b/src/test/test-file.txt
@@ -0,0 +1 @@
+This test file is a test file.