#include "piprotectedvariable.h" #include "pistring.h" #include "pithread.h" #include "piliterals_time.h" #include "gtest/gtest.h" #include // Basic functionality tests TEST(PIProtectedVariable_Basic, BasicFunctionality) { // Test basic set/get with different types PIProtectedVariable pvInt; PIProtectedVariable pvDouble; PIProtectedVariable pvString; pvInt.set(123); pvDouble.set(3.14159); pvString.set(PIString("Hello, World!")); EXPECT_EQ(pvInt.get(), 123); EXPECT_DOUBLE_EQ(pvDouble.get(), 3.14159); EXPECT_EQ(pvString.get(), PIString("Hello, World!")); // Test operator= pvInt = 999; EXPECT_EQ(pvInt.get(), 999); // Test getRef() with Pointer struct TestStruct { int x = 10; int y = 20; int getValue() const { return x + y; } }; PIProtectedVariable pvStruct; auto ptr = pvStruct.getRef(); EXPECT_EQ(ptr->x, 10); EXPECT_EQ(ptr->y, 20); EXPECT_EQ(ptr->getValue(), 30); // Modify through pointer *ptr = TestStruct(); ptr->x = 100; EXPECT_EQ(pvStruct.get().x, 100); // Test for Pointer pvInt.set(42); auto ptr1 = pvInt.getRef(); EXPECT_EQ(*ptr1, 42); *ptr1 = 55; EXPECT_EQ(*ptr1, 55); auto ptr2 = std::move(ptr1); EXPECT_EQ(*ptr2, 55); *ptr2 = 100; EXPECT_EQ(*ptr2, 100); auto ptr3 = pvInt.getRef(); EXPECT_EQ(*ptr3, 100); *ptr3 = 333; EXPECT_EQ(*ptr3, 333); EXPECT_EQ(pvInt.get(), 333); } // Thread safety tests TEST(PIProtectedVariable_ThreadSafety, ConcurrentReadWrite) { PIProtectedVariable pv; std::atomic writeCount(0); std::atomic readCount(0); std::atomic invalidReads(0); const int NUM_ITERATIONS = 1000; const int NUM_WRITERS = 10; const int NUM_READERS = 20; const int TOTAL_WRITES = NUM_WRITERS * NUM_ITERATIONS; // Collect thread handles for joining PIVector threads; // Create writer threads for (int i = 0; i < NUM_WRITERS; ++i) { threads.push_back(new PIThread([&pv, &writeCount]() { for (int j = 0; j < NUM_ITERATIONS; ++j) { auto val = pv.getRef(); (*val)++; auto val2 = pv.getRef(); writeCount++; ASSERT_EQ(writeCount, *val2); } })); } // Create reader threads for (int i = 0; i < NUM_READERS; ++i) { threads.push_back(new PIThread([&pv, &invalidReads, &readCount]() { for (int j = 0; j < NUM_ITERATIONS; ++j) { auto val = pv.get(); readCount++; // Value should always be in valid range [0, TOTAL_WRITES] if (val < 0 || val > TOTAL_WRITES) { invalidReads++; } } })); } threads.forEach([](PIThread * & t) {t->startOnce();}); threads.forEach([](PIThread * & t) {t->waitForFinish(2_s);}); piDeleteAll(threads); // Verify results EXPECT_EQ(writeCount, TOTAL_WRITES); EXPECT_EQ(readCount, NUM_READERS * NUM_ITERATIONS); EXPECT_EQ(invalidReads, 0) << "All reads should return valid values in range [0, " << TOTAL_WRITES << "]"; // Final value should be TOTAL_WRITES int finalVal = pv.get(); EXPECT_EQ(finalVal, TOTAL_WRITES); }