Files
dota_factory/src/test/CommandTest.cpp

107 lines
3.5 KiB
C++

#include "catch.hpp"
#include <memory>
#include "BuildingSystem.h"
#include "Command.h"
#include "CommandManager.h"
#include "ConfigLoader.h"
#include "GameConfig.h"
#include "Rotation.h"
#include "Simulation.h"
#include "SimulationTestAccess.h"
namespace
{
GameConfig loadConfig()
{
return ConfigLoader::loadFromDirectory(CONFIG_DIR);
}
} // namespace
// The command chokepoint (Simulation::apply) must produce exactly the same state
// as driving the underlying mutators directly — that equivalence is what lets a
// recorded command stream reproduce a live run (see docs/replay_design.md).
TEST_CASE("apply(PlaceBuildingCommand) matches direct placement", "[command]")
{
Simulation viaCommand(loadConfig(), 99);
Simulation viaDirect(loadConfig(), 99);
PlaceBuildingCommand command;
command.type = BuildingType::Miner;
command.anchor = QPoint(-3, 0);
command.rotation = Rotation::East;
viaCommand.apply(command);
SimulationTestAccess::place(viaDirect, BuildingType::Miner, QPoint(-3, 0), Rotation::East);
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
}
TEST_CASE("apply(PlaceBuildingCommand) with recipe matches place-then-setRecipe", "[command]")
{
Simulation viaCommand(loadConfig(), 99);
Simulation viaDirect(loadConfig(), 99);
PlaceBuildingCommand command;
command.type = BuildingType::Miner;
command.anchor = QPoint(-2, 0);
command.rotation = Rotation::East;
command.recipeId = "mine_iron_ore";
viaCommand.apply(command);
const BuildingId id =
SimulationTestAccess::place(viaDirect, BuildingType::Miner, QPoint(-2, 0), Rotation::East).value();
SimulationTestAccess::buildings(viaDirect).setRecipe(id, "mine_iron_ore");
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
}
TEST_CASE("apply(DemolishCommand) matches direct demolish", "[command]")
{
Simulation viaCommand(loadConfig(), 99);
Simulation viaDirect(loadConfig(), 99);
const BuildingId idA =
SimulationTestAccess::place(viaCommand, BuildingType::Miner, QPoint(-3, 0), Rotation::East).value();
const BuildingId idB =
SimulationTestAccess::place(viaDirect, BuildingType::Miner, QPoint(-3, 0), Rotation::East).value();
REQUIRE(idA == idB);
DemolishCommand command;
command.id = idA;
viaCommand.apply(command);
SimulationTestAccess::demolish(viaDirect, idB);
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
}
TEST_CASE("CommandManager drains queued commands in FIFO order through apply", "[command]")
{
Simulation viaManager(loadConfig(), 99);
Simulation viaDirect(loadConfig(), 99);
CommandManager manager(viaManager);
std::shared_ptr<PlaceBuildingCommand> first = std::make_shared<PlaceBuildingCommand>();
first->type = BuildingType::Miner;
first->anchor = QPoint(-3, 0);
std::shared_ptr<PlaceBuildingCommand> second = std::make_shared<PlaceBuildingCommand>();
second->type = BuildingType::Belt;
second->anchor = QPoint(-2, 0);
manager.enqueue(first);
manager.enqueue(second);
REQUIRE(manager.hasPending());
manager.drain();
REQUIRE_FALSE(manager.hasPending());
SimulationTestAccess::place(viaDirect, BuildingType::Miner, QPoint(-3, 0), Rotation::East);
SimulationTestAccess::place(viaDirect, BuildingType::Belt, QPoint(-2, 0), Rotation::East);
REQUIRE(viaManager.computeStateChecksum() == viaDirect.computeStateChecksum());
}