Files
Renderive/Kernel/tests/renderive/state/Render_Acquired_State_Strategy_Test.cpp
T
2026-08-16 03:34:17 +08:00

109 lines
5.0 KiB
C++

#include <gtest/gtest.h>
#include <atomic>
#include <cstdint>
#include <memory>
#include <thread>
#include "renderive/state/State_Strategy.hpp"
#include "State_Test_Types.hpp"
struct Render_Acquired_State_Test_State {
int value{};
};
TEST(render_acquired_state_strategy_test, publishes_then_acquires_render_state) {
State_Render_State_Reader render;
Render_Acquired_State_Storage<Render_Acquired_State_Test_State> strategy;
strategy.set<&Render_Acquired_State_Test_State::value>(7);
strategy.publish();
EXPECT_EQ(render.read(strategy).value, 0);
EXPECT_EQ(strategy.acquire_render_state(), 1);
EXPECT_EQ(render.read(strategy).value, 7);
}
TEST(render_acquired_state_strategy_test, returns_render_state_snapshot) {
State_Render_State_Reader render;
Render_Acquired_State_Storage<Render_Acquired_State_Test_State> strategy;
const auto snapshot = render.read(strategy);
strategy.set<&Render_Acquired_State_Test_State::value>(7);
strategy.publish();
strategy.acquire_render_state();
EXPECT_EQ(snapshot.value, 0);
EXPECT_EQ(render.read(strategy).value, 7);
}
struct Multi_State_A {
int value{};
};
struct Multi_State_B {
int value{};
};
struct Multi_State_A_Strategy : Published_State_Storage<Multi_State_A> {};
struct Multi_State_B_Strategy : Published_State_Storage<Multi_State_B> {};
struct Multi_State_Product : Multi_State_A_Strategy, Multi_State_B_Strategy {};
TEST(published_state_strategy_test, supports_named_base_access_in_multiple_inheritance) {
State_Render_State_Reader render;
Multi_State_Product product;
product.Multi_State_A_Strategy::set<&Multi_State_A::value>(3);
product.Multi_State_B_Strategy::set<&Multi_State_B::value>(8);
product.Multi_State_A_Strategy::publish();
product.Multi_State_B_Strategy::publish();
EXPECT_EQ(render.read(static_cast<const Multi_State_A_Strategy&>(product)).value, 3);
EXPECT_EQ(render.read(static_cast<const Multi_State_B_Strategy&>(product)).value, 8);
}
TEST(render_acquired_state_strategy_test, concurrently_acquires_render_revision_without_data_race) {
State_Render_State_Reader render;
Render_Acquired_State_Storage<Render_Acquired_State_Test_State> strategy;
std::atomic<bool> finished{};
auto acquire = [&] {
while (!finished.load(std::memory_order_acquire)) {
strategy.acquire_render_state();
}
strategy.acquire_render_state();
};
std::thread first(acquire);
std::thread second(acquire);
for (int value = 1; value <= 1000; ++value) {
strategy.set<&Render_Acquired_State_Test_State::value>(value);
strategy.publish();
}
finished.store(true, std::memory_order_release);
first.join();
second.join();
EXPECT_EQ(strategy.acquire_render_state(), 1000);
EXPECT_EQ(render.read(strategy).value, 1000);
}
struct Render_Acquired_State_Throwing_Assignment_State {
int first{};
int second{};
Render_Acquired_State_Throwing_Assignment_State() = default;
Render_Acquired_State_Throwing_Assignment_State(int first, int second) : first(first), second(second) {}
Render_Acquired_State_Throwing_Assignment_State(const Render_Acquired_State_Throwing_Assignment_State&) = default;
Render_Acquired_State_Throwing_Assignment_State(Render_Acquired_State_Throwing_Assignment_State&&) noexcept = default;
Render_Acquired_State_Throwing_Assignment_State& operator=(const Render_Acquired_State_Throwing_Assignment_State& other) {
first = other.first;
if (throw_on_copy_assignment) {
throw std::runtime_error("state assignment failed");
}
second = other.second;
return *this;
}
Render_Acquired_State_Throwing_Assignment_State& operator=(Render_Acquired_State_Throwing_Assignment_State&&) noexcept = default;
inline static bool throw_on_copy_assignment{};
};
TEST(render_acquired_state_strategy_test, failed_publish_keeps_published_revision_and_render_state_unchanged) {
State_Render_State_Reader render;
using Strategy = Render_Acquired_State_Storage<Render_Acquired_State_Throwing_Assignment_State>;
Render_Acquired_State_Throwing_Assignment_State::throw_on_copy_assignment = false;
Strategy strategy(Render_Acquired_State_Throwing_Assignment_State(1, 2));
strategy.set<&Render_Acquired_State_Throwing_Assignment_State::first>(10);
strategy.set<&Render_Acquired_State_Throwing_Assignment_State::second>(20);
Render_Acquired_State_Throwing_Assignment_State::throw_on_copy_assignment = true;
EXPECT_THROW(strategy.publish(), std::runtime_error);
Render_Acquired_State_Throwing_Assignment_State::throw_on_copy_assignment = false;
EXPECT_EQ(strategy.state_revision(), 0);
EXPECT_EQ(strategy.acquire_render_state(), 0);
EXPECT_EQ(render.read(strategy).first, 1);
EXPECT_EQ(render.read(strategy).second, 2);
strategy.publish();
EXPECT_EQ(strategy.state_revision(), 1);
EXPECT_EQ(strategy.acquire_render_state(), 1);
EXPECT_EQ(render.read(strategy).first, 10);
EXPECT_EQ(render.read(strategy).second, 20);
}