163 lines
7.5 KiB
C++
163 lines
7.5 KiB
C++
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
|
|
#include "common/Module.h"
|
|
#include "effects/Effects.h"
|
|
|
|
#include <simplesquirrel/simplesquirrel.hpp>
|
|
|
|
#include <string>
|
|
|
|
using namespace eve::effects;
|
|
|
|
TEST_CASE("effects.apply.stableFactsAndDeterministicQueries") {
|
|
EffectContainer effects;
|
|
auto firstResult = effects.apply("unit:7", "weather.wet", "zone:2", 3, 10.0, "surface", StackPolicy::Stack);
|
|
auto secondResult = effects.apply("unit:7", "policy.tax", "state:1", 9, 0.0, "policy", StackPolicy::Stack);
|
|
REQUIRE(firstResult.ok());
|
|
REQUIRE(secondResult.ok());
|
|
const auto first = std::move(firstResult).takeValue();
|
|
const auto second = std::move(secondResult).takeValue();
|
|
|
|
CHECK_EQ(first, std::string("effect-0000000000000001"));
|
|
CHECK_EQ(second, std::string("effect-0000000000000002"));
|
|
REQUIRE(effects.subjectCount("unit:7") == 2);
|
|
CHECK_EQ(effects.subjectAt("unit:7", 0)->id, first);
|
|
CHECK_EQ(effects.subjectAt("unit:7", 1)->id, second);
|
|
CHECK_EQ(effects.find(first)->type, std::string("weather.wet"));
|
|
CHECK_EQ(effects.find(first)->source, std::string("zone:2"));
|
|
CHECK_EQ(effects.find(second)->remaining, -1.0);
|
|
}
|
|
|
|
TEST_CASE("effects.stackPolicy.replaceStackRefresh") {
|
|
EffectContainer effects;
|
|
auto oldResult = effects.apply("base:1", "policy.a", "leader:1", 1, 5.0, "administration", StackPolicy::Stack);
|
|
auto stackedResult = effects.apply("base:1", "policy.b", "leader:2", 2, 7.0, "administration", StackPolicy::Stack);
|
|
REQUIRE(oldResult.ok());
|
|
REQUIRE(stackedResult.ok());
|
|
const auto old = std::move(oldResult).takeValue();
|
|
const auto stacked = std::move(stackedResult).takeValue();
|
|
CHECK_EQ(effects.effectCount(), 2);
|
|
|
|
auto refreshedResult =
|
|
effects.apply("base:1", "ignored.new.type", "ignored:new", 8, 12.0, "administration", StackPolicy::Refresh);
|
|
REQUIRE(refreshedResult.ok());
|
|
const auto refreshed = std::move(refreshedResult).takeValue();
|
|
CHECK_EQ(refreshed, old);
|
|
CHECK_EQ(effects.find(old)->type, std::string("policy.a"));
|
|
CHECK_EQ(effects.find(old)->source, std::string("leader:1"));
|
|
CHECK_EQ(effects.find(old)->priority, 8);
|
|
CHECK_EQ(effects.find(old)->remaining, 12.0);
|
|
CHECK_EQ(effects.effectCount(), 2);
|
|
|
|
auto replacementResult =
|
|
effects.apply("base:1", "policy.c", "leader:3", 4, 3.0, "administration", StackPolicy::Replace);
|
|
REQUIRE(replacementResult.ok());
|
|
const auto replacement = std::move(replacementResult).takeValue();
|
|
CHECK(effects.find(old) == nullptr);
|
|
CHECK(effects.find(stacked) == nullptr);
|
|
REQUIRE(effects.effectCount() == 1);
|
|
CHECK_EQ(effects.effectAt(0)->id, replacement);
|
|
CHECK_EQ(effects.eventAt(2)->kind == EffectEventKind::Refreshed, true);
|
|
CHECK_EQ(effects.eventAt(3)->reason, std::string("replaced"));
|
|
CHECK_EQ(effects.eventAt(4)->reason, std::string("replaced"));
|
|
CHECK_EQ(effects.eventAt(5)->kind == EffectEventKind::Applied, true);
|
|
}
|
|
|
|
TEST_CASE("effects.update.expiresFiniteFactsInCreationOrder") {
|
|
EffectContainer effects;
|
|
auto firstResult = effects.apply("army:1", "one", "", 0, 0.5, "", StackPolicy::Stack);
|
|
auto permanentResult = effects.apply("army:1", "permanent", "", 0, 0.0, "", StackPolicy::Stack);
|
|
auto secondResult = effects.apply("army:1", "two", "", 0, 0.5, "", StackPolicy::Stack);
|
|
REQUIRE(firstResult.ok());
|
|
REQUIRE(permanentResult.ok());
|
|
REQUIRE(secondResult.ok());
|
|
const auto first = std::move(firstResult).takeValue();
|
|
const auto permanent = std::move(permanentResult).takeValue();
|
|
const auto second = std::move(secondResult).takeValue();
|
|
effects.clearEvents();
|
|
|
|
REQUIRE(effects.update(0.25).ok());
|
|
CHECK_EQ(effects.find(first)->remaining, 0.25);
|
|
REQUIRE(effects.update(0.25).ok());
|
|
CHECK(effects.find(first) == nullptr);
|
|
CHECK(effects.find(second) == nullptr);
|
|
CHECK(effects.find(permanent) != nullptr);
|
|
REQUIRE(effects.eventCount() == 2);
|
|
CHECK_EQ(effects.eventAt(0)->effectId, first);
|
|
CHECK_EQ(effects.eventAt(1)->effectId, second);
|
|
CHECK_EQ(effects.eventAt(0)->sequence, uint64_t{4});
|
|
CHECK_EQ(effects.eventAt(0)->kind == EffectEventKind::Expired, true);
|
|
}
|
|
|
|
TEST_CASE("effects.tagsAndPayload.areDeterministic") {
|
|
EffectContainer effects;
|
|
auto idResult = effects.apply("unit:2", "condition", "system", 0, 0.0, "", StackPolicy::Stack);
|
|
REQUIRE(idResult.ok());
|
|
const auto id = std::move(idResult).takeValue();
|
|
auto* effect = effects.find(id);
|
|
REQUIRE(effect != nullptr);
|
|
CHECK(effect->addTag("visible").ok());
|
|
CHECK(effect->addTag("administrative").ok());
|
|
CHECK(effect->addTag("visible").status().code() == eve::StatusCode::NoOp);
|
|
CHECK_EQ(effect->tagAt(0), std::string("administrative"));
|
|
CHECK_EQ(effect->tagAt(1), std::string("visible"));
|
|
CHECK_EQ(effects.taggedAt("unit:2", "visible", 0)->id, id);
|
|
|
|
effect->payload.setString("name", "A\nB");
|
|
effect->payload.setNumber("weight", 2.5);
|
|
CHECK(effect->payload.setJson("data", "[1,2]").ok());
|
|
CHECK(!effect->payload.setJson("bad", "oops").ok());
|
|
CHECK_EQ(effect->payload.toJson(), std::string("{\"data\":[1,2],\"name\":\"A\\nB\",\"weight\":2.5}"));
|
|
}
|
|
|
|
TEST_CASE("effects.remove.emitsStableEvent") {
|
|
EffectContainer effects;
|
|
auto idResult = effects.apply("subject", "type", "source", 0, 0.0, "", StackPolicy::Stack);
|
|
REQUIRE(idResult.ok());
|
|
const auto id = std::move(idResult).takeValue();
|
|
CHECK(effects.remove(id, "subject_deleted").ok());
|
|
CHECK(!effects.remove(id).ok());
|
|
REQUIRE(effects.eventCount() == 2);
|
|
CHECK_EQ(effects.eventAt(1)->kind == EffectEventKind::Removed, true);
|
|
CHECK_EQ(effects.eventAt(1)->reason, std::string("subject_deleted"));
|
|
}
|
|
|
|
TEST_CASE("effects.script.containerLifecycle") {
|
|
ssq::VM vm(1024, ssq::Libs::ALL);
|
|
eve::ModuleManager::expose(vm);
|
|
vm.run(vm.compileSource(R"(
|
|
result <- "fail";
|
|
local module = eve.Effects();
|
|
local effectsResult = module.newContainer();
|
|
local effects = effectsResult.ok ? effectsResult.value : null;
|
|
local idResult = { ok = false, value = "" };
|
|
if (effects != null) {
|
|
idResult = effects.apply("base:4", "policy.production", "leader:8", 5, 1.0,
|
|
"production-policy", "refresh");
|
|
}
|
|
local id = idResult.ok ? idResult.value : "";
|
|
local effect = effects != null && idResult.ok ? effects.find(id) : null;
|
|
local tagResult = { ok = false };
|
|
local payloadResult = { ok = false };
|
|
if (effect != null) {
|
|
tagResult = effect.addTag("economic");
|
|
payloadResult = effect.getPayload().setJson("rate", "1.25");
|
|
}
|
|
local sameResult = { ok = false, value = "" };
|
|
if (effects != null) {
|
|
sameResult = effects.apply("base:4", "ignored", "ignored", 7, 2.0,
|
|
"production-policy", "refresh");
|
|
}
|
|
local same = sameResult.ok ? sameResult.value : "";
|
|
if (effectsResult.ok && idResult.ok && tagResult.ok && payloadResult.ok && sameResult.ok && same == id &&
|
|
effect != null && effect.getType() == "policy.production" &&
|
|
effect.getSource() == "leader:8" && effect.hasTag("economic") &&
|
|
effect.getPayload().getJson("rate") == "1.25" &&
|
|
effects.eventAt(1).getKind() == "refreshed") {
|
|
result = "ok";
|
|
}
|
|
)"));
|
|
CHECK_EQ(vm.find("result").toString(), std::string("ok"));
|
|
}
|