/ src / common / UnitTests-CommonUtils / Serialized.Tests.cpp
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  }