Files
EVEngine/test/action_game_event.cpp

89 lines
3.7 KiB
C++

#include "action/ActionGameplayEventBlock.h"
#include "action/ActionNotifyRegistry.h"
#include "action/game_event/ActionGameEventSink.h"
#include "game_event/GameEvent.h"
#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include <chrono>
#include <cstdint>
#include <span>
namespace {
eve::SubjectRef subject(const char* text) {
auto parsed = eve::PersistentId::parse(text);
REQUIRE(parsed.has_value());
return eve::SubjectRef::fromPersistentId(*parsed);
}
eve::LogicalId id(const char* text) {
auto parsed = eve::LogicalId::parse(text);
REQUIRE(parsed.has_value());
return *parsed;
}
} // namespace
TEST_CASE("actionGameEvent.validatesAndAppendsToPersistentLog") {
eve::Value::Object invalidPayload{{"tag", eve::Value("not canonical")}};
CHECK(!eve::action::ActionGameplayEventBinding::fromPayload(invalidPayload).ok());
auto registry = eve::action::ActionNotifyRegistry::withBuiltins();
REQUIRE(registry.ok());
eve::action::ActionTimelineEvent event;
event.kind = eve::action::ActionTimelineEventKind::Notify;
event.trackId = id("action-track:gameplay");
event.itemId = id("action-item:event");
event.type = id("gameplay:event");
event.payload = {{"tag", eve::Value("Combat.Action.Hit")},
{"targetIndex", eve::Value(std::int64_t{0})},
{"data", eve::Value(eve::Value::Object{{"power", eve::Value(std::int64_t{7})}})}};
eve::action::ActionNotifyContext context;
context.executionId = eve::action::ActionExecutionId(71);
ecs::EntityHandle sourceHandle{nullptr, typeid(void), 3, 1};
ecs::EntityHandle targetHandle{nullptr, typeid(void), 5, 2};
context.source = sourceHandle;
context.targets.push_back(targetHandle);
context.tick = eve::SimulationTick(42);
auto absent = registry.value().dispatch(event, context);
CHECK(!absent.ok());
CHECK_EQ(absent.status().code(), eve::StatusCode::NotFound);
const auto timestamp = std::chrono::system_clock::time_point(std::chrono::milliseconds(1710000000123));
eve::game_event::GameEventLog log(
[](std::span<std::uint8_t> bytes) {
for (std::size_t index = 0; index < bytes.size(); ++index)
bytes[index] = static_cast<std::uint8_t>(index + 1);
return true;
},
[timestamp] { return timestamp; });
const auto sourceSubject = subject("018f0f4e-6b3c-7ab1-8def-0123456789ab");
const auto targetSubject = subject("018f0f4e-6b3c-7ab2-8def-0123456789ab");
eve::action::game_event_adapter::ActionGameEventSink sink(
log, [=](ecs::EntityHandle handle) -> eve::Result<eve::SubjectRef> {
if (handle.id == sourceHandle.id) return eve::Result<eve::SubjectRef>::success(sourceSubject);
if (handle.id == targetHandle.id) return eve::Result<eve::SubjectRef>::success(targetSubject);
return eve::Result<eve::SubjectRef>::failure(
eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "entity is stale", "entity"));
});
sink.setEnabled(true);
REQUIRE(registry.value().dispatch(event, context).ok());
REQUIRE(sink.lastSequence().has_value());
const auto* stored = log.find(*sink.lastSequence());
REQUIRE(stored != nullptr);
CHECK_EQ(stored->type, std::string("Combat.Action.Hit"));
CHECK_EQ(stored->source, sourceSubject.format());
CHECK_EQ(stored->subject, targetSubject.format());
CHECK_EQ(stored->schemaId, id("action:gameplay-event-v1"));
CHECK_EQ(stored->schemaVersion.value(), 1U);
CHECK_EQ(stored->tick, eve::SimulationTick(42));
CHECK_EQ(stored->payload, std::string("{\"power\":7}"));
sink.setEnabled(false);
CHECK(!registry.value().dispatch(event, context).ok());
CHECK_EQ(log.size(), 1);
}