Serialized.Tests.cpp
1 #include "pch.h" 2 #include "TestHelpers.h" 3 #include <serialized.h> 4 5 using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 7 namespace UnitTestsCommonUtils 8 { 9 TEST_CLASS(SerializedTests) 10 { 11 public: 12 // Basic Read tests 13 TEST_METHOD(Read_DefaultState_ReturnsDefaultValue) 14 { 15 Serialized<int> s; 16 int value = -1; 17 s.Read([&value](const int& v) { 18 value = v; 19 }); 20 Assert::AreEqual(0, value); // Default constructed int is 0 21 } 22 23 TEST_METHOD(Read_StringType_ReturnsEmpty) 24 { 25 Serialized<std::string> s; 26 std::string value = "initial"; 27 s.Read([&value](const std::string& v) { 28 value = v; 29 }); 30 Assert::AreEqual(std::string(""), value); 31 } 32 33 // Basic Access tests 34 TEST_METHOD(Access_ModifyValue_ValueIsModified) 35 { 36 Serialized<int> s; 37 s.Access([](int& v) { 38 v = 42; 39 }); 40 41 int value = 0; 42 s.Read([&value](const int& v) { 43 value = v; 44 }); 45 Assert::AreEqual(42, value); 46 } 47 48 TEST_METHOD(Access_ModifyString_StringIsModified) 49 { 50 Serialized<std::string> s; 51 s.Access([](std::string& v) { 52 v = "hello"; 53 }); 54 55 std::string value; 56 s.Read([&value](const std::string& v) { 57 value = v; 58 }); 59 Assert::AreEqual(std::string("hello"), value); 60 } 61 62 TEST_METHOD(Access_MultipleModifications_LastValuePersists) 63 { 64 Serialized<int> s; 65 s.Access([](int& v) { v = 1; }); 66 s.Access([](int& v) { v = 2; }); 67 s.Access([](int& v) { v = 3; }); 68 69 int value = 0; 70 s.Read([&value](const int& v) { 71 value = v; 72 }); 73 Assert::AreEqual(3, value); 74 } 75 76 // Reset tests 77 TEST_METHOD(Reset_AfterModification_ReturnsDefault) 78 { 79 Serialized<int> s; 80 s.Access([](int& v) { v = 42; }); 81 s.Reset(); 82 83 int value = -1; 84 s.Read([&value](const int& v) { 85 value = v; 86 }); 87 Assert::AreEqual(0, value); 88 } 89 90 TEST_METHOD(Reset_String_ReturnsEmpty) 91 { 92 Serialized<std::string> s; 93 s.Access([](std::string& v) { v = "hello"; }); 94 s.Reset(); 95 96 std::string value = "initial"; 97 s.Read([&value](const std::string& v) { 98 value = v; 99 }); 100 Assert::AreEqual(std::string(""), value); 101 } 102 103 // Complex type tests 104 TEST_METHOD(Serialized_VectorType_Works) 105 { 106 Serialized<std::vector<int>> s; 107 s.Access([](std::vector<int>& v) { 108 v.push_back(1); 109 v.push_back(2); 110 v.push_back(3); 111 }); 112 113 size_t size = 0; 114 int sum = 0; 115 s.Read([&size, &sum](const std::vector<int>& v) { 116 size = v.size(); 117 for (int i : v) sum += i; 118 }); 119 120 Assert::AreEqual(static_cast<size_t>(3), size); 121 Assert::AreEqual(6, sum); 122 } 123 124 TEST_METHOD(Serialized_MapType_Works) 125 { 126 Serialized<std::map<std::string, int>> s; 127 s.Access([](std::map<std::string, int>& v) { 128 v["one"] = 1; 129 v["two"] = 2; 130 }); 131 132 int value = 0; 133 s.Read([&value](const std::map<std::string, int>& v) { 134 auto it = v.find("two"); 135 if (it != v.end()) { 136 value = it->second; 137 } 138 }); 139 140 Assert::AreEqual(2, value); 141 } 142 143 // Thread safety tests 144 TEST_METHOD(ThreadSafety_ConcurrentReads_NoDataRace) 145 { 146 Serialized<int> s; 147 s.Access([](int& v) { v = 42; }); 148 149 std::atomic<int> readCount{ 0 }; 150 std::vector<std::thread> threads; 151 152 for (int i = 0; i < 10; ++i) 153 { 154 threads.emplace_back([&s, &readCount]() { 155 for (int j = 0; j < 100; ++j) 156 { 157 s.Read([&readCount](const int& v) { 158 if (v == 42) { 159 readCount++; 160 } 161 }); 162 } 163 }); 164 } 165 166 for (auto& t : threads) 167 { 168 t.join(); 169 } 170 171 Assert::AreEqual(1000, readCount.load()); 172 } 173 174 TEST_METHOD(ThreadSafety_ConcurrentAccessAndRead_NoDataRace) 175 { 176 Serialized<int> s; 177 std::atomic<bool> done{ false }; 178 std::atomic<int> accessCount{ 0 }; 179 std::atomic<int> readersReady{ 0 }; 180 std::atomic<bool> start{ false }; 181 182 // Writer thread 183 std::thread writer([&s, &done, &accessCount, &readersReady, &start]() { 184 while (readersReady.load() < 5) 185 { 186 std::this_thread::yield(); 187 } 188 start = true; 189 for (int i = 0; i < 100; ++i) 190 { 191 s.Access([i](int& v) { 192 v = i; 193 }); 194 accessCount++; 195 } 196 done = true; 197 }); 198 199 // Reader threads 200 std::vector<std::thread> readers; 201 std::atomic<int> readAttempts{ 0 }; 202 203 for (int i = 0; i < 5; ++i) 204 { 205 readers.emplace_back([&s, &done, &readAttempts, &readersReady, &start]() { 206 readersReady++; 207 while (!start) 208 { 209 std::this_thread::yield(); 210 } 211 while (!done) 212 { 213 s.Read([](const int& v) { 214 // Just read the value 215 (void)v; 216 }); 217 readAttempts++; 218 } 219 }); 220 } 221 222 writer.join(); 223 for (auto& t : readers) 224 { 225 t.join(); 226 } 227 228 // Verify all access calls completed 229 Assert::AreEqual(100, accessCount.load()); 230 // Verify reads happened 231 Assert::IsTrue(readAttempts > 0); 232 } 233 234 // Struct type test 235 TEST_METHOD(Serialized_StructType_Works) 236 { 237 struct TestStruct 238 { 239 int x = 0; 240 std::string name; 241 }; 242 243 Serialized<TestStruct> s; 244 s.Access([](TestStruct& v) { 245 v.x = 10; 246 v.name = "test"; 247 }); 248 249 int x = 0; 250 std::string name; 251 s.Read([&x, &name](const TestStruct& v) { 252 x = v.x; 253 name = v.name; 254 }); 255 256 Assert::AreEqual(10, x); 257 Assert::AreEqual(std::string("test"), name); 258 } 259 260 TEST_METHOD(Reset_StructType_ResetsToDefault) 261 { 262 struct TestStruct 263 { 264 int x = 0; 265 std::string name; 266 }; 267 268 Serialized<TestStruct> s; 269 s.Access([](TestStruct& v) { 270 v.x = 10; 271 v.name = "test"; 272 }); 273 s.Reset(); 274 275 int x = -1; 276 std::string name = "not empty"; 277 s.Read([&x, &name](const TestStruct& v) { 278 x = v.x; 279 name = v.name; 280 }); 281 282 Assert::AreEqual(0, x); 283 Assert::AreEqual(std::string(""), name); 284 } 285 }; 286 }