fix bug where selecting the same layout for a shipyard discarded the current progress and buffers
This commit is contained in:
@@ -262,6 +262,123 @@ TEST_CASE("Shipyard: setShipLayout cancels in-progress production",
|
||||
CHECK_FALSE(b2->production.has_value());
|
||||
}
|
||||
|
||||
// Applying a configuration a building already has is a no-op (REQ-MAT-INPUT-BUFFER).
|
||||
// setRecipe has always worked this way; setShipLayout did not, and wiped the shipyard
|
||||
// on every re-apply. That matters now that a blueprint configuration transfer
|
||||
// (REQ-UI-BLUEPRINT-TRANSFER) can be clicked repeatedly onto matching shipyards.
|
||||
|
||||
TEST_CASE("Shipyard: re-applying the same layout keeps production and buffers",
|
||||
"[modules][shipyard]")
|
||||
{
|
||||
Simulation sim(loadTestConfig(), 42);
|
||||
const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
|
||||
REQUIRE(def != nullptr);
|
||||
const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
|
||||
REQUIRE(yardDef != nullptr);
|
||||
|
||||
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||
SimulationTestAccess::buildings(sim).setRecipe(SimulationTestAccess::state(sim), yardId, "interceptor");
|
||||
|
||||
ShipLayoutConfig layout;
|
||||
PlacedModule pm;
|
||||
pm.moduleId = "armor_plate";
|
||||
pm.position = QPoint(0, 0);
|
||||
pm.rotation = Rotation::East;
|
||||
layout.placedModules.push_back(pm);
|
||||
|
||||
SimulationTestAccess::buildings(sim).setShipLayout(SimulationTestAccess::state(sim), yardId, layout);
|
||||
fillMaterials(sim, yardId, *def, layout);
|
||||
sim.tick();
|
||||
|
||||
const Building* before = findBuilding(sim.getFactoryState(), yardId);
|
||||
REQUIRE(before != nullptr);
|
||||
REQUIRE(before->production.has_value());
|
||||
const Tick completesAt = before->production->completesAt;
|
||||
|
||||
// A separately built but equal layout: equality is by value, not by identity.
|
||||
ShipLayoutConfig sameLayout;
|
||||
sameLayout.placedModules.push_back(pm);
|
||||
SimulationTestAccess::buildings(sim).setShipLayout(SimulationTestAccess::state(sim), yardId, sameLayout);
|
||||
|
||||
const Building* after = findBuilding(sim.getFactoryState(), yardId);
|
||||
REQUIRE(after != nullptr);
|
||||
REQUIRE(after->production.has_value());
|
||||
CHECK(after->production->completesAt == completesAt);
|
||||
CHECK(after->inputBuffer.caps.at(ItemType{"iron_ingot"}) == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Shipyard: an empty layout on an unconfigured shipyard changes nothing",
|
||||
"[modules][shipyard]")
|
||||
{
|
||||
// An unset layout and an empty one are the same state everywhere that matters, so
|
||||
// clearing an already-unconfigured shipyard must not cancel its cycle. This is the
|
||||
// case a transfer from a layout-less source shipyard produces.
|
||||
Simulation sim(loadTestConfig(), 42);
|
||||
const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
|
||||
REQUIRE(def != nullptr);
|
||||
const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
|
||||
REQUIRE(yardDef != nullptr);
|
||||
|
||||
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||
SimulationTestAccess::buildings(sim).setRecipe(SimulationTestAccess::state(sim), yardId, "interceptor");
|
||||
|
||||
ShipLayoutConfig emptyLayout;
|
||||
fillMaterials(sim, yardId, *def, emptyLayout);
|
||||
sim.tick();
|
||||
|
||||
const Building* before = findBuilding(sim.getFactoryState(), yardId);
|
||||
REQUIRE(before != nullptr);
|
||||
REQUIRE(before->production.has_value());
|
||||
REQUIRE_FALSE(before->shipLayout.has_value());
|
||||
|
||||
SimulationTestAccess::buildings(sim).setShipLayout(SimulationTestAccess::state(sim), yardId, emptyLayout);
|
||||
|
||||
const Building* after = findBuilding(sim.getFactoryState(), yardId);
|
||||
REQUIRE(after != nullptr);
|
||||
CHECK(after->production.has_value());
|
||||
CHECK_FALSE(after->shipLayout.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("Shipyard: the same modules in a different order count as a change",
|
||||
"[modules][shipyard]")
|
||||
{
|
||||
// Layout equality is deliberately order-sensitive (see ShipLayout.h): the safe
|
||||
// answer when in doubt is "changed", which costs a buffer reset rather than
|
||||
// leaving a shipyard building the wrong ship.
|
||||
Simulation sim(loadTestConfig(), 42);
|
||||
const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
|
||||
REQUIRE(def != nullptr);
|
||||
const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
|
||||
REQUIRE(yardDef != nullptr);
|
||||
|
||||
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||
SimulationTestAccess::buildings(sim).setRecipe(SimulationTestAccess::state(sim), yardId, "interceptor");
|
||||
|
||||
PlacedModule armor;
|
||||
armor.moduleId = "armor_plate";
|
||||
armor.position = QPoint(0, 0);
|
||||
armor.rotation = Rotation::East;
|
||||
PlacedModule sensor;
|
||||
sensor.moduleId = "sensor_booster";
|
||||
sensor.position = QPoint(1, 0);
|
||||
sensor.rotation = Rotation::East;
|
||||
|
||||
ShipLayoutConfig layout;
|
||||
layout.placedModules.push_back(armor);
|
||||
layout.placedModules.push_back(sensor);
|
||||
SimulationTestAccess::buildings(sim).setShipLayout(SimulationTestAccess::state(sim), yardId, layout);
|
||||
fillMaterials(sim, yardId, *def, layout);
|
||||
sim.tick();
|
||||
REQUIRE(findBuilding(sim.getFactoryState(), yardId)->production.has_value());
|
||||
|
||||
ShipLayoutConfig reordered;
|
||||
reordered.placedModules.push_back(sensor);
|
||||
reordered.placedModules.push_back(armor);
|
||||
SimulationTestAccess::buildings(sim).setShipLayout(SimulationTestAccess::state(sim), yardId, reordered);
|
||||
|
||||
CHECK_FALSE(findBuilding(sim.getFactoryState(), yardId)->production.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("Shipyard: builds a bare hull when no layout is configured",
|
||||
"[modules][shipyard]")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user