This commit is contained in:
2026-08-09 22:47:13 +08:00
parent 1354aa54ba
commit 11407faf86
11 changed files with 85 additions and 143 deletions
+4 -87
View File
@@ -1,13 +1,7 @@
#include <structive/property/property.hpp>
#include <atomic>
#include <barrier>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include "test.hpp"
#include <memory>
#include <semaphore>
#include <string>
#include <thread>
#include <type_traits>
using namespace structive;
struct Test_Tag_Category {};
@@ -30,7 +24,6 @@ struct Test_Multi_Attribute {
};
template <int Value>
inline constexpr Test_Multi_Attribute<Value> test_multi{};
#define REQUIRE(expression) do { if (!(expression)) { std::fprintf(stderr, "REQUIRE failed: %s:%d: %s\n", __FILE__, __LINE__, #expression); std::abort(); } } while (false)
struct Device : Property_Object<Device> {
Device() = default;
explicit Device(Property_Synchronization synchronization) : Property_Object(std::move(synchronization)) {}
@@ -253,6 +246,9 @@ int main() {
auto validation = validate_property_value<&Device::temperature>(device.schema(), 500);
REQUIRE(validation.has_value());
REQUIRE(validation->code == "max_value");
device.write<&Device::temperature>(500);
REQUIRE(device.read<&Device::temperature>() == 500);
device.write<&Device::temperature>(23);
REQUIRE(!update_speed_range(device, 200, 100));
REQUIRE(device.read<&Device::min_speed>() == 10);
REQUIRE(device.read<&Device::max_speed>() == 100);
@@ -288,21 +284,6 @@ int main() {
non_copyable_visited = true;
});
REQUIRE(non_copyable_visited);
Property_Object_Base& erased = device;
REQUIRE(erased.runtime_object_type() == typeid(Device));
REQUIRE(erased.runtime_property_count() == 5);
int runtime_value = 0;
REQUIRE(erased.runtime_read("temperature", &runtime_value, &runtime_read_int) == Runtime_Access_Result::ok);
REQUIRE(runtime_value == 23);
REQUIRE(erased.runtime_read("immutable_id", &runtime_value, &runtime_read_int) == Runtime_Access_Result::ok);
REQUIRE(runtime_value == 7);
int runtime_write_value = 35;
REQUIRE(erased.runtime_write("temperature", typeid(int), &runtime_write_value) == Runtime_Access_Result::ok);
REQUIRE(device.temperature == 35);
REQUIRE(erased.runtime_write("immutable_id", typeid(int), &runtime_write_value) == Runtime_Access_Result::not_writable);
double wrong_type = 1.0;
REQUIRE(erased.runtime_write("temperature", typeid(double), &wrong_type) == Runtime_Access_Result::type_mismatch);
REQUIRE(erased.runtime_write("missing", typeid(int), &runtime_write_value) == Runtime_Access_Result::unknown_property);
Read_Only_Device read_only_device;
REQUIRE(read_only_device.resolved_synchronization().lock_count == 1);
REQUIRE(read_only_device.lock_slot<&Read_Only_Device::id>() == Resolved_Synchronization_View::unsynchronized_slot);
@@ -314,70 +295,6 @@ int main() {
REQUIRE(pure_read_only.lock_slot<&Pure_Read_Only_Device::version>() == Resolved_Synchronization_View::unsynchronized_slot);
REQUIRE(pure_read_only.read<&Pure_Read_Only_Device::id>() == 21);
REQUIRE(pure_read_only.read<&Pure_Read_Only_Device::version>() == 4);
Property_Object_Base& read_only_erased = read_only_device;
std::binary_semaphore read_only_done{0};
std::jthread read_only_reader;
{
auto guard = read_only_device.lock_unique<&Read_Only_Device::value>();
read_only_reader = std::jthread([&] {
int value = 0;
REQUIRE(read_only_erased.runtime_read("id", &value, &runtime_read_int) == Runtime_Access_Result::ok);
REQUIRE(value == 11);
read_only_done.release();
});
REQUIRE(read_only_done.try_acquire_for(std::chrono::milliseconds(100)));
}
read_only_reader.join();
std::binary_semaphore runtime_blocked_done{0};
std::jthread runtime_writer;
{
auto guard = device.lock_unique<&Device::temperature>();
runtime_writer = std::jthread([&] {
int value = 36;
REQUIRE(erased.runtime_write("temperature", typeid(int), &value) == Runtime_Access_Result::ok);
runtime_blocked_done.release();
});
REQUIRE(!runtime_blocked_done.try_acquire_for(std::chrono::milliseconds(20)));
}
REQUIRE(runtime_blocked_done.try_acquire_for(std::chrono::seconds(2)));
runtime_writer.join();
REQUIRE(device.read<&Device::temperature>() == 36);
std::binary_semaphore independent_done{0};
{
auto guard = device.lock_unique({"temperature"});
std::jthread writer([&] {
device.write<&Device::pressure>(200);
independent_done.release();
});
REQUIRE(independent_done.try_acquire_for(std::chrono::seconds(2)));
}
bool dynamic_read_only_unique_rejected = false;
try {
auto guard = device.lock_unique({"immutable_id"});
(void) guard;
} catch (const std::invalid_argument&) {
dynamic_read_only_unique_rejected = true;
}
REQUIRE(dynamic_read_only_unique_rejected);
std::barrier gate(2);
std::atomic<int> completed{0};
std::jthread first([&] {
gate.arrive_and_wait();
auto guard = device.lock_unique({"temperature", "pressure"});
guard.set<&Device::temperature>(40);
guard.set<&Device::pressure>(140);
completed.fetch_add(1, std::memory_order_release);
});
std::jthread second([&] {
gate.arrive_and_wait();
auto guard = device.lock_unique({"pressure", "temperature"});
guard.set<&Device::pressure>(141);
guard.set<&Device::temperature>(41);
completed.fetch_add(1, std::memory_order_release);
});
first.join();
second.join();
REQUIRE(completed.load(std::memory_order_acquire) == 2);
Device copied = device;
REQUIRE(copied.temperature == device.temperature);
copied.write<&Device::temperature>(99);