#include "pch.h" #include "TestHelpers.h" #include using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace UnitTestsCommonUtils { TEST_CLASS(SerializedTests) { public: // Basic Read tests TEST_METHOD(Read_DefaultState_ReturnsDefaultValue) { Serialized s; int value = -1; s.Read([&value](const int& v) { value = v; }); Assert::AreEqual(0, value); // Default constructed int is 0 } TEST_METHOD(Read_StringType_ReturnsEmpty) { Serialized s; std::string value = "initial"; s.Read([&value](const std::string& v) { value = v; }); Assert::AreEqual(std::string(""), value); } // Basic Access tests TEST_METHOD(Access_ModifyValue_ValueIsModified) { Serialized s; s.Access([](int& v) { v = 42; }); int value = 0; s.Read([&value](const int& v) { value = v; }); Assert::AreEqual(42, value); } TEST_METHOD(Access_ModifyString_StringIsModified) { Serialized s; s.Access([](std::string& v) { v = "hello"; }); std::string value; s.Read([&value](const std::string& v) { value = v; }); Assert::AreEqual(std::string("hello"), value); } TEST_METHOD(Access_MultipleModifications_LastValuePersists) { Serialized s; s.Access([](int& v) { v = 1; }); s.Access([](int& v) { v = 2; }); s.Access([](int& v) { v = 3; }); int value = 0; s.Read([&value](const int& v) { value = v; }); Assert::AreEqual(3, value); } // Reset tests TEST_METHOD(Reset_AfterModification_ReturnsDefault) { Serialized s; s.Access([](int& v) { v = 42; }); s.Reset(); int value = -1; s.Read([&value](const int& v) { value = v; }); Assert::AreEqual(0, value); } TEST_METHOD(Reset_String_ReturnsEmpty) { Serialized s; s.Access([](std::string& v) { v = "hello"; }); s.Reset(); std::string value = "initial"; s.Read([&value](const std::string& v) { value = v; }); Assert::AreEqual(std::string(""), value); } // Complex type tests TEST_METHOD(Serialized_VectorType_Works) { Serialized> s; s.Access([](std::vector& v) { v.push_back(1); v.push_back(2); v.push_back(3); }); size_t size = 0; int sum = 0; s.Read([&size, &sum](const std::vector& v) { size = v.size(); for (int i : v) sum += i; }); Assert::AreEqual(static_cast(3), size); Assert::AreEqual(6, sum); } TEST_METHOD(Serialized_MapType_Works) { Serialized> s; s.Access([](std::map& v) { v["one"] = 1; v["two"] = 2; }); int value = 0; s.Read([&value](const std::map& v) { auto it = v.find("two"); if (it != v.end()) { value = it->second; } }); Assert::AreEqual(2, value); } // Thread safety tests TEST_METHOD(ThreadSafety_ConcurrentReads_NoDataRace) { Serialized s; s.Access([](int& v) { v = 42; }); std::atomic readCount{ 0 }; std::vector threads; for (int i = 0; i < 10; ++i) { threads.emplace_back([&s, &readCount]() { for (int j = 0; j < 100; ++j) { s.Read([&readCount](const int& v) { if (v == 42) { readCount++; } }); } }); } for (auto& t : threads) { t.join(); } Assert::AreEqual(1000, readCount.load()); } TEST_METHOD(ThreadSafety_ConcurrentAccessAndRead_NoDataRace) { Serialized s; std::atomic done{ false }; std::atomic accessCount{ 0 }; std::atomic readersReady{ 0 }; std::atomic start{ false }; // Writer thread std::thread writer([&s, &done, &accessCount, &readersReady, &start]() { while (readersReady.load() < 5) { std::this_thread::yield(); } start = true; for (int i = 0; i < 100; ++i) { s.Access([i](int& v) { v = i; }); accessCount++; } done = true; }); // Reader threads std::vector readers; std::atomic readAttempts{ 0 }; for (int i = 0; i < 5; ++i) { readers.emplace_back([&s, &done, &readAttempts, &readersReady, &start]() { readersReady++; while (!start) { std::this_thread::yield(); } while (!done) { s.Read([](const int& v) { // Just read the value (void)v; }); readAttempts++; } }); } writer.join(); for (auto& t : readers) { t.join(); } // Verify all access calls completed Assert::AreEqual(100, accessCount.load()); // Verify reads happened Assert::IsTrue(readAttempts > 0); } // Struct type test TEST_METHOD(Serialized_StructType_Works) { struct TestStruct { int x = 0; std::string name; }; Serialized s; s.Access([](TestStruct& v) { v.x = 10; v.name = "test"; }); int x = 0; std::string name; s.Read([&x, &name](const TestStruct& v) { x = v.x; name = v.name; }); Assert::AreEqual(10, x); Assert::AreEqual(std::string("test"), name); } TEST_METHOD(Reset_StructType_ResetsToDefault) { struct TestStruct { int x = 0; std::string name; }; Serialized s; s.Access([](TestStruct& v) { v.x = 10; v.name = "test"; }); s.Reset(); int x = -1; std::string name = "not empty"; s.Read([&x, &name](const TestStruct& v) { x = v.x; name = v.name; }); Assert::AreEqual(0, x); Assert::AreEqual(std::string(""), name); } }; }