Files
EVEngine/test/production_time.cpp
T

100 lines
3.8 KiB
C++

#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include "common/Time.h"
#include "production/Production.h"
using eve::production::WorkQueue;
namespace {
class ManualTimeSource final : public eve::ITimeSource {
public:
eve::MonotonicTimestamp monotonicNow() const override { return now; }
eve::WallClockTimestamp wallClockNow() const override { return eve::WallClockTimestamp(1234); }
eve::MonotonicTimestamp now;
};
} // namespace
TEST_CASE("production.injectedStepsPauseAndRestoreTick") {
WorkQueue queue;
auto idResult = queue.enqueue("factory", "vehicle", "tank", eve::Value(eve::Value::Object{}), 1.0);
REQUIRE(idResult.ok());
const auto id = std::move(idResult).takeValue();
auto first = queue.advance({eve::SimulationTick(1), eve::Duration::fromNanoseconds(400000000)});
REQUIRE(first.ok());
auto firstTask = queue.find(id);
REQUIRE(firstTask);
CHECK_EQ(firstTask->get().progress.seconds(), 0.4);
CHECK_EQ(queue.currentTick().value(), std::uint64_t(1));
auto duplicate = queue.advance({eve::SimulationTick(1), eve::Duration::fromNanoseconds(400000000)});
CHECK(!duplicate.ok());
firstTask = queue.find(id);
REQUIRE(firstTask);
CHECK_EQ(firstTask->get().progress.seconds(), 0.4);
auto second = queue.advance({eve::SimulationTick(2), eve::Duration::fromNanoseconds(600000000)});
REQUIRE(second.ok());
firstTask = queue.find(id);
REQUIRE(firstTask);
CHECK_EQ(firstTask->get().progress.seconds(), 1.0);
CHECK(firstTask->get().state == eve::production::TaskState::Completed);
auto savedResult = queue.snapshot();
REQUIRE(savedResult.ok());
const auto saved = std::move(savedResult).takeValue();
CHECK(saved.find("\"tick\":\"2\"") != std::string::npos);
CHECK(saved.find("wallClock") == std::string::npos);
WorkQueue restored;
auto restoredResult = restored.restore(saved);
REQUIRE(restoredResult.ok());
CHECK_EQ(restored.currentTick().value(), std::uint64_t(2));
auto afterRestore = restored.advance({eve::SimulationTick(3), eve::Duration::fromNanoseconds(1)});
REQUIRE(afterRestore.ok());
CHECK_EQ(restored.currentTick().value(), std::uint64_t(3));
}
TEST_CASE("production.advanceFacadeAdvancesDeterministicTick") {
WorkQueue queue;
auto idResult = queue.enqueue("factory", "vehicle", "tank", eve::Value(eve::Value::Object{}), 1.0);
REQUIRE(idResult.ok());
const auto id = std::move(idResult).takeValue();
auto step = queue.advance({eve::SimulationTick(1), eve::Duration::fromNanoseconds(125000000)});
REQUIRE(step.ok());
CHECK_EQ(queue.currentTick().value(), std::uint64_t(1));
auto task = queue.find(id);
REQUIRE(task);
CHECK_EQ(task->get().progress.seconds(), 0.125);
auto saved = queue.snapshot();
REQUIRE(saved.ok());
CHECK(std::move(saved).takeValue().find("wallClock") == std::string::npos);
}
TEST_CASE("production.clockStepsAreTheOnlySimulationInput") {
ManualTimeSource source;
eve::SimulationClock clock(source, eve::Duration::fromNanoseconds(250000000));
WorkQueue queue;
auto idResult = queue.enqueue("factory", "vehicle", "tank", eve::Value(eve::Value::Object{}), 0.5);
REQUIRE(idResult.ok());
const auto id = std::move(idResult).takeValue();
REQUIRE(clock.setRate(0.5).ok());
REQUIRE(clock.sample().ok());
source.now = eve::MonotonicTimestamp(1000000000);
auto steps = clock.sample();
REQUIRE(steps.ok());
CHECK_EQ(steps.value().size(), std::size_t(2));
for (const auto& step : steps.value()) {
auto applied = queue.advance(step);
REQUIRE(applied.ok());
}
auto task = queue.find(id);
REQUIRE(task);
CHECK(task->get().state == eve::production::TaskState::Completed);
CHECK_EQ(queue.currentTick(), clock.currentTick());
}