From 0ad658fa324e53fd1256e5a1d72b34f4b0266b9a Mon Sep 17 00:00:00 2001
From: Joseph Walton-Rivers <joseph@walton-rivers.uk>
Date: Sat, 23 Jul 2022 14:17:43 +0100
Subject: [PATCH] add unit tests for hash functions

---
 CMakeLists.txt                |  6 ++-
 include/fggl/util/guid.hpp    |  3 ++
 tests/CMakeLists.txt          | 19 ++++----
 tests/testfggl/CMakeLists.txt | 12 ++---
 tests/testfggl/util/guid.cpp  | 85 +++++++++++++++++++++++++++++++++++
 5 files changed, 110 insertions(+), 15 deletions(-)
 create mode 100644 tests/testfggl/util/guid.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f1687da..b130c84 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,6 +6,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED YES)
 
 option(FGGL_CONAN "Should we use conan to find missing dependencies?" OFF)
 option(FGGL_EXAMPLES "Should we build examples or just the library" ON)
+option(FGGL_TESTS "Should we enable the testing suite?" ON)
 option(FGGL_DOCS "Should we build documentation?" ON)
 
 set(CONAN_BUILD_TYPE "Debug")
@@ -68,7 +69,10 @@ target_compile_options( ${PROJECT_NAME} PRIVATE -Wall -Wpedantic -Wextra -Wodr -
 set_property(TARGET fggl PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
 
 # extras
-#add_subdirectory(tests)
+if (FGGL_TESTS)
+	add_subdirectory(tests)
+endif()
+
 if (FGGL_EXAMPLES)
   add_subdirectory(demo)
   target_compile_options( demo PRIVATE -Wall -Wextra -Wodr -Wdouble-promotion -fno-strict-aliasing -fno-strict-overflow )
diff --git a/include/fggl/util/guid.hpp b/include/fggl/util/guid.hpp
index 1c66d8d..a4ac1e8 100644
--- a/include/fggl/util/guid.hpp
+++ b/include/fggl/util/guid.hpp
@@ -14,6 +14,7 @@
 
 //
 // Created by webpigeon on 23/07/22.
+// See http://www.isthe.com/chongo/tech/comp/fnv/
 //
 
 #ifndef FGGL_UTIL_GUID_HPP
@@ -38,6 +39,7 @@ namespace fggl::util {
 	 * @return the hashed value
 	 */
 	constexpr uint32_t hash_fnv1a_32(const char* str) {
+		assert(str != nullptr);
 		uint32_t hash = FNV_OFFSET_BASIS_32;
 		for (int i = 0; str[i] != '\0'; i++) {
 			hash = hash ^ str[i];
@@ -53,6 +55,7 @@ namespace fggl::util {
 	 * @return the hashed value
 	 */
 	constexpr uint64_t hash_fnv1a_64(const char* str) {
+		assert(str != nullptr);
 		uint64_t hash = FNV_OFFSET_BASIS_64;
 		for (int i = 0; str[i] != '\0'; i++) {
 			hash = hash ^ str[i];
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2ea02a9..7cf6ffe 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,16 +1,17 @@
 find_package(Threads REQUIRED)
 
 # GTest Dependency
-find_package(GTest)
+find_package( GTest REQUIRED )
 if ( NOT GTest_FOUND )
-include(FetchContent)
-FetchContent_Declare(
-  googletest
-  URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip
-)
-# For Windows: Prevent overriding the parent project's compiler/linker settings
-set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
-FetchContent_MakeAvailable(googletest)
+    message(NOTICE "GTest not found, installing...")
+    include(FetchContent)
+    FetchContent_Declare(
+      googletest
+      URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip
+    )
+    # For Windows: Prevent overriding the parent project's compiler/linker settings
+    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+    FetchContent_MakeAvailable(googletest)
 endif ()
 
 add_subdirectory(testfggl)
diff --git a/tests/testfggl/CMakeLists.txt b/tests/testfggl/CMakeLists.txt
index 284b79c..13fa77d 100644
--- a/tests/testfggl/CMakeLists.txt
+++ b/tests/testfggl/CMakeLists.txt
@@ -1,11 +1,12 @@
 enable_testing()
 
 add_executable( fggl_test
-	#	TestFggl.cpp
-	ecs/ecs.cpp
-	ecs3/ecs.cpp
-	math/types.cpp
-        ecs3/easing.cpp
+	TestFggl.cpp
+#	ecs/ecs.cpp
+#	ecs3/ecs.cpp
+#	ecs3/easing.cpp
+#	math/types.cpp
+	util/guid.cpp
 )
 target_include_directories(fggl_test
 	PUBLIC
@@ -14,6 +15,7 @@ target_include_directories(fggl_test
 
 target_link_libraries(fggl_test
 	fggl
+	gtest
 	gtest_main
 	gmock
 )
diff --git a/tests/testfggl/util/guid.cpp b/tests/testfggl/util/guid.cpp
new file mode 100644
index 0000000..0d2baa9
--- /dev/null
+++ b/tests/testfggl/util/guid.cpp
@@ -0,0 +1,85 @@
+/*
+ * This file is part of FGGL.
+ *
+ * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * FGGL 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with FGGL.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//
+// Created by webpigeon on 23/07/22.
+//
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "fggl/util/guid.hpp"
+
+namespace {
+	// expect blank (0-width) strings to be the offset basis
+	TEST(UtilHash32, Empty) {
+		auto value = fggl::util::hash_fnv1a_32("");
+		EXPECT_EQ( fggl::util::FNV_OFFSET_BASIS_32, value );
+	}
+
+	TEST(UtilHash64, Empty) {
+		auto value = fggl::util::hash_fnv1a_64("");
+		EXPECT_EQ( fggl::util::FNV_OFFSET_BASIS_64, value );
+	}
+
+	// expect single characters to work correctly
+	TEST(UtilHash32, SingleChar) {
+		auto value = fggl::util::hash_fnv1a_32("a");
+		EXPECT_EQ( 0xe40c292c, value );
+	}
+
+	TEST(UtilHash64, SingleChar) {
+		auto value = fggl::util::hash_fnv1a_64("a");
+		EXPECT_EQ( 0xaf63dc4c8601ec8c, value );
+	}
+
+	// expect hello world to known values
+
+	TEST(UtilHash32, HelloWorld) {
+		auto value = fggl::util::hash_fnv1a_32("Hello World");
+		EXPECT_EQ( 0xb3902527, value );
+	}
+
+	TEST(UtilHash64, HelloWorld) {
+		auto value = fggl::util::hash_fnv1a_64("Hello World");
+		EXPECT_EQ( 0x3d58dee72d4e0c27, value );
+	}
+
+	// expect scoped (::) notation to work correctly
+
+	TEST(UtilHash32, Scoped) {
+		auto value = fggl::util::hash_fnv1a_32("fggl::test::scoped");
+		EXPECT_EQ( 0x27fd4589, value );
+	}
+
+	TEST(UtilHash64, Scoped) {
+		auto value = fggl::util::hash_fnv1a_64("fggl::test::scoped");
+		EXPECT_EQ( 0xd2929655f3b0cf49, value );
+	}
+
+	// sanity checks
+
+	TEST(UtilHash32, RepeatsAreEqual) {
+		auto value = fggl::util::hash_fnv1a_32("fggl::test::scoped");
+		auto value2 = fggl::util::hash_fnv1a_32("fggl::test::scoped");
+		EXPECT_EQ( value, value2 );
+	}
+
+	TEST(UtilHash64, RepeatsAreEqual) {
+		auto value = fggl::util::hash_fnv1a_64("fggl::test::scoped");
+		auto value2 = fggl::util::hash_fnv1a_64("fggl::test::scoped");
+		EXPECT_EQ( value, value2 );
+	}
+
+}
-- 
GitLab