diff --git a/fggl/util/guid.cpp b/fggl/util/guid.cpp
index 569353daa74538496ab20a0ecd41abcbb2968c78..f2f908a080a174290ee6039470cc789fe88936c0 100644
--- a/fggl/util/guid.cpp
+++ b/fggl/util/guid.cpp
@@ -23,9 +23,13 @@
 #include "fggl/util/guid.hpp"
 
 namespace fggl::util {
-	static std::map<GUID, std::string> guidTable;
+	namespace {
+		std::map<GUID, std::string> guidTable;
+	}
 
 	GUID internString(const char* str) {
+		assert(str != nullptr);
+
 		GUID guid = make_guid(str);
 		auto tableValue = guidTable.find(guid);
 		if (tableValue != guidTable.end()) {
@@ -33,6 +37,7 @@ namespace fggl::util {
 		} else {
 			guidTable[guid] = str;
 		}
+		return guid;
 	}
 
 	std::string guidToString(GUID guid) {
@@ -43,4 +48,15 @@ namespace fggl::util {
 			return "FGGL_UNKNOWN_GUID";
 		}
 	}
+
+}
+
+fggl::util::GUID operator "" _fid(const char* str) {
+	fggl::util::internString(str);
+	return fggl::util::make_guid(str);
+}
+
+fggl::util::GUID operator "" _fid(const char* str, std::size_t) {
+	fggl::util::internString(str);
+	return fggl::util::make_guid(str);
 }
diff --git a/include/fggl/util/guid.hpp b/include/fggl/util/guid.hpp
index a4ac1e805c920998a607d0a643f44e520f9870f1..c9c85b2db090d69700223911214b6ad3b982c683 100644
--- a/include/fggl/util/guid.hpp
+++ b/include/fggl/util/guid.hpp
@@ -68,14 +68,13 @@ namespace fggl::util {
 		return GUID::make(hash_fnv1a_64(str));
 	}
 
-	constexpr GUID operator ""_fid(const char* str) {
-		return make_guid(str);
-	}
-
 	// debug-only functions
 	GUID internString(const char* str);
 	std::string guidToString(GUID guid);
 
 } // namespace fggl::util
 
+fggl::util::GUID operator "" _fid(const char* str);
+fggl::util::GUID operator "" _fid(const char* str, std::size_t);
+
 #endif //FGGL_UTIL_GUID_HPP
diff --git a/include/fggl/util/safety.hpp b/include/fggl/util/safety.hpp
index 18797eab7b97af1fcad579bd366e79fd7ba44380..6a10829c40fc7ee7a07cbfb238f1e442c6f82460 100644
--- a/include/fggl/util/safety.hpp
+++ b/include/fggl/util/safety.hpp
@@ -23,6 +23,16 @@
 
 namespace fggl::util {
 
+	/**
+	 * A type-safe opaque handle.
+	 *
+	 * Lots of low-level libaries we use pass around handles as some primative type. It's fairly easy to accidentally
+	 * mix these up. This wrapper's job is to make sure that mixing up handle types is impossible (and results in
+	 * compiler errors).
+	 *
+	 * @tparam T the underling type of the handle.
+	 * @tparam Tag a unique tag used to identify the handle type.
+	 */
 	template<typename T, typename Tag>
 	struct OpaqueName {
 		private:
diff --git a/tests/testfggl/CMakeLists.txt b/tests/testfggl/CMakeLists.txt
index 13fa77df7212bcac817d883a71ef23e4ae993cb7..589fbb1e84a221193c5cf07ff684bcfcf1b2f44d 100644
--- a/tests/testfggl/CMakeLists.txt
+++ b/tests/testfggl/CMakeLists.txt
@@ -7,6 +7,7 @@ add_executable( fggl_test
 #	ecs3/easing.cpp
 #	math/types.cpp
 	util/guid.cpp
+	util/safety.cpp
 )
 target_include_directories(fggl_test
 	PUBLIC
diff --git a/tests/testfggl/util/guid.cpp b/tests/testfggl/util/guid.cpp
index 0d2baa97f9c69a423a135bf8a6a68b3145254b11..e4dedf7b8280a2c2eceb322f38030adb5120ef2e 100644
--- a/tests/testfggl/util/guid.cpp
+++ b/tests/testfggl/util/guid.cpp
@@ -17,8 +17,6 @@
 //
 
 #include <gtest/gtest.h>
-#include <gmock/gmock.h>
-
 #include "fggl/util/guid.hpp"
 
 namespace {
@@ -69,7 +67,6 @@ namespace {
 	}
 
 	// 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");
@@ -82,4 +79,16 @@ namespace {
 		EXPECT_EQ( value, value2 );
 	}
 
+	// GUID tests
+	TEST(GuidTest, GuidSuffix) {
+		auto guid = fggl::util::make_guid("test");
+		auto guidSuffix = "test"_fid;
+		EXPECT_EQ(guid, guidSuffix);
+	}
+
+	TEST(GuidTest, GuidToString) {
+		fggl::util::GUID guid = fggl::util::internString("test");
+		EXPECT_EQ("test", fggl::util::guidToString(guid));
+	}
+
 }
diff --git a/tests/testfggl/util/safety.cpp b/tests/testfggl/util/safety.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f88475d592ba4951068c5ab4bc04abe5d7042b4c
--- /dev/null
+++ b/tests/testfggl/util/safety.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "fggl/util/safety.hpp"
+
+namespace {
+
+	using TestType = fggl::util::OpaqueName<unsigned int, struct TestTag>;
+
+	TEST(SafetyHandle, CheckZero) {
+		auto v1 = TestType::make(0);
+		auto v2 = TestType::make(0);
+		EXPECT_EQ(v1, v2);
+	}
+
+	TEST(SafetyHandle, CheckValue) {
+		auto v1 = TestType::make(0x12345678);
+		auto v2 = TestType::make(0x12345678);
+		EXPECT_EQ(v1, v2);
+	}
+
+	TEST(SafetyHandle, CheckValueNE) {
+		auto v1 = TestType::make(0x12345678);
+		auto v2 = TestType::make(0x87654321);
+		EXPECT_NE(v1, v2);
+	}
+
+}
\ No newline at end of file