Use std::optional instead of sentinel values for absent data
This commit is contained in:
@@ -119,7 +119,7 @@ TEST_CASE("BuildingSystem: place miner occupies expected body tiles", "[building
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
REQUIRE(id != kInvalidBuildingId);
|
||||
|
||||
// Miner mask ["AA","A>"] with East rotation → body at (0,0),(1,0),(0,1).
|
||||
@@ -138,8 +138,8 @@ TEST_CASE("BuildingSystem: place rejects a building above the world (y < 0)", "[
|
||||
|
||||
// Miner mask ["AA","A>"] East → body at (0,0),(1,0),(0,1); at y=-1 the top
|
||||
// row sits above the world.
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner, QPoint(0, -1), Rotation::East, 0);
|
||||
REQUIRE(id == kInvalidBuildingId);
|
||||
const std::optional<BuildingId> id = f.bs.place(BuildingType::Miner, QPoint(0, -1), Rotation::East, 0);
|
||||
REQUIRE_FALSE(id.has_value());
|
||||
REQUIRE(f.bs.getAllSites().empty());
|
||||
REQUIRE_FALSE(f.bs.isTileOccupied(QPoint(0, 0)));
|
||||
}
|
||||
@@ -151,9 +151,9 @@ TEST_CASE("BuildingSystem: place rejects a building below the world (y >= height
|
||||
|
||||
// Anchored on the last in-bounds row, the miner's lower body row reaches
|
||||
// y == heightTiles, which is outside the world.
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner,
|
||||
const std::optional<BuildingId> id = f.bs.place(BuildingType::Miner,
|
||||
QPoint(0, heightTiles - 1), Rotation::East, 0);
|
||||
REQUIRE(id == kInvalidBuildingId);
|
||||
REQUIRE_FALSE(id.has_value());
|
||||
REQUIRE(f.bs.getAllSites().empty());
|
||||
}
|
||||
|
||||
@@ -162,9 +162,9 @@ TEST_CASE("BuildingSystem: place rejects a building left of the asteroid edge",
|
||||
PlacementFixture f;
|
||||
const int leftEdgeX = -f.cfg.world.regions.asteroidWidth_tiles;
|
||||
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner,
|
||||
const std::optional<BuildingId> id = f.bs.place(BuildingType::Miner,
|
||||
QPoint(leftEdgeX - 1, 0), Rotation::East, 0);
|
||||
REQUIRE(id == kInvalidBuildingId);
|
||||
REQUIRE_FALSE(id.has_value());
|
||||
REQUIRE(f.bs.getAllSites().empty());
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ TEST_CASE("BuildingSystem: place accepts a building flush against the world's le
|
||||
|
||||
// Miner body min relative x is 0, so its leftmost cell sits exactly on the edge.
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner,
|
||||
QPoint(leftEdgeX, 0), Rotation::East, 0);
|
||||
QPoint(leftEdgeX, 0), Rotation::East, 0).value();
|
||||
REQUIRE(id != kInvalidBuildingId);
|
||||
REQUIRE(f.bs.isTileOccupied(QPoint(leftEdgeX, 0)));
|
||||
}
|
||||
@@ -187,7 +187,7 @@ TEST_CASE("BuildingSystem: place imposes no right-side bound (space extends righ
|
||||
PlacementFixture f;
|
||||
|
||||
const BuildingId id = f.bs.place(BuildingType::Miner,
|
||||
QPoint(1000, 0), Rotation::East, 0);
|
||||
QPoint(1000, 0), Rotation::East, 0).value();
|
||||
REQUIRE(id != kInvalidBuildingId);
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ TEST_CASE("BuildingSystem: placed building enters construction queue", "[buildin
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
REQUIRE(bs.getAllSites().size() == 1);
|
||||
REQUIRE(bs.getAllBuildings().empty());
|
||||
@@ -277,7 +277,7 @@ TEST_CASE("BuildingSystem: demolish frees tiles and returns refund", "[building]
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
// Miner construction_time_seconds = 10. completesAt = secondsToTicks(10) = 300.
|
||||
// We need to process tick 300 itself, so run 301 ticks (ticks 0..300).
|
||||
@@ -351,7 +351,7 @@ TEST_CASE("BuildingSystem: construction completes after configured duration", "[
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
// Miner construction_time_seconds = 10. completesAt = secondsToTicks(10) = 300.
|
||||
// We need to process tick 300 itself, so run 301 ticks (ticks 0..300).
|
||||
@@ -377,7 +377,7 @@ TEST_CASE("BuildingSystem: second building starts after first completes", "[buil
|
||||
rng);
|
||||
|
||||
bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id2 = bs.place(BuildingType::Miner, QPoint(5, 5), Rotation::East, 0);
|
||||
const BuildingId id2 = bs.place(BuildingType::Miner, QPoint(5, 5), Rotation::East, 0).value();
|
||||
|
||||
// Process through tick 300 to complete first miner's construction.
|
||||
Tick tick = 0;
|
||||
@@ -406,7 +406,7 @@ TEST_CASE("BuildingSystem: miner produces iron_ore after recipe duration", "[bui
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(id, "mine_iron_ore");
|
||||
|
||||
Tick tick = 0;
|
||||
@@ -439,7 +439,7 @@ TEST_CASE("BuildingSystem: miner output buffer stalls when full", "[building]")
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(id, "mine_iron_ore");
|
||||
|
||||
Tick tick = 0;
|
||||
@@ -479,8 +479,8 @@ TEST_CASE("BuildingSystem: productionBuildingCount excludes construction sites",
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId minerId = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId smelterId = bs.place(BuildingType::Smelter, QPoint(10, 0), Rotation::East, 0);
|
||||
const BuildingId minerId = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
const BuildingId smelterId = bs.place(BuildingType::Smelter, QPoint(10, 0), Rotation::East, 0).value();
|
||||
(void)smelterId;
|
||||
|
||||
Tick tick = 0;
|
||||
@@ -519,7 +519,7 @@ TEST_CASE("BuildingSystem: activeProductionBuildingCount tracks production cycle
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(id, "mine_iron_ore");
|
||||
|
||||
Tick tick = 0;
|
||||
@@ -563,7 +563,7 @@ TEST_CASE("BuildingSystem: smelter input buffer fills from adjacent west-flowing
|
||||
|
||||
// Smelter mask ["AA ","AA>"] → body (0,0),(1,0),(0,1),(1,1).
|
||||
// Output port (2,1) East. Input port example: (2,0) West.
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0).value();
|
||||
// Smelters have no recipe selection (REQ-BLD-SMELTER); they auto-accept any
|
||||
// ore/scrap that is an input to a smelter recipe.
|
||||
|
||||
@@ -603,7 +603,7 @@ TEST_CASE("BuildingSystem: accepted input travels inward before entering the buf
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0).value();
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(15.0)) + 1, tick);
|
||||
|
||||
@@ -645,7 +645,7 @@ TEST_CASE("BuildingSystem: input reservation caps buffered plus in-transit at th
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::ReprocessingPlant,
|
||||
QPoint(0, 0), Rotation::East, 0);
|
||||
QPoint(0, 0), Rotation::East, 0).value();
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(25.0)) + 1, tick);
|
||||
|
||||
@@ -686,7 +686,7 @@ TEST_CASE("BuildingSystem: smelter auto-smelts ore without a recipe selection",
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(15.0)) + 1, tick);
|
||||
@@ -732,7 +732,7 @@ TEST_CASE("BuildingSystem: smelter runs a satisfiable recipe while an incomplete
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(15.0)) + 1, tick);
|
||||
@@ -786,7 +786,7 @@ TEST_CASE("BuildingSystem: miner output buffer drains onto adjacent belt", "[bui
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(id, "mine_iron_ore");
|
||||
|
||||
// Belt at the miner's output port tile (1,1) flowing East.
|
||||
@@ -826,12 +826,12 @@ TEST_CASE("BuildingSystem: output port couples directly into an adjacent input p
|
||||
rng);
|
||||
|
||||
// Miner at (0,0): body (0,0),(1,0),(0,1); output port tile (1,1) flowing East.
|
||||
const BuildingId minerId = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId minerId = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(minerId, "mine_iron_ore");
|
||||
// Smelter anchored at (1,1): body (1,1),(2,1),(1,2),(2,2). Its body cell (1,1) is
|
||||
// the miner's output-port tile, and its west input edge there faces East, so the
|
||||
// two ports meet — no belt placed anywhere.
|
||||
const BuildingId smelterId = bs.place(BuildingType::Smelter, QPoint(1, 1), Rotation::East, 0);
|
||||
const BuildingId smelterId = bs.place(BuildingType::Smelter, QPoint(1, 1), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
// Smelter build (15s) + margin for coupling and a smelt cycle.
|
||||
@@ -866,11 +866,11 @@ TEST_CASE("BuildingSystem: direct coupling to a non-consumer leaves the item stu
|
||||
rng);
|
||||
|
||||
// Producing miner at (0,0), output port (1,1) East.
|
||||
const BuildingId minerId = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId minerId = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(minerId, "mine_iron_ore");
|
||||
// A second, idle miner anchored at (1,1) occupies the output-port tile but takes
|
||||
// no inputs, so it cannot accept the iron_ore.
|
||||
const BuildingId sinkId = bs.place(BuildingType::Miner, QPoint(1, 1), Rotation::East, 0);
|
||||
const BuildingId sinkId = bs.place(BuildingType::Miner, QPoint(1, 1), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
// Both miners build sequentially (10s each), then the producer runs and jams.
|
||||
@@ -904,7 +904,7 @@ TEST_CASE("BuildingSystem: setRecipe clears output buffer and active production"
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||
bs.setRecipe(id, "mine_iron_ore");
|
||||
|
||||
Tick tick = 0;
|
||||
@@ -948,7 +948,7 @@ TEST_CASE("BuildingSystem: reprocessing plant output buffer capacity equals max
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::ReprocessingPlant,
|
||||
QPoint(0, 0), Rotation::East, 0);
|
||||
QPoint(0, 0), Rotation::East, 0).value();
|
||||
// Reprocessing plants have no recipe selection (REQ-BLD-REPROCESSING); the
|
||||
// single reprocessing recipe is applied automatically on completion.
|
||||
|
||||
@@ -980,7 +980,7 @@ TEST_CASE("BuildingSystem: reprocessing plant produces one cycle output then sta
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::ReprocessingPlant,
|
||||
QPoint(0, 0), Rotation::East, 0);
|
||||
QPoint(0, 0), Rotation::East, 0).value();
|
||||
// Reprocessing plants have no recipe selection (REQ-BLD-REPROCESSING); the
|
||||
// single reprocessing recipe is applied automatically on completion.
|
||||
|
||||
@@ -1056,7 +1056,7 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the site id for a que
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
const std::optional<BuildingId> result =
|
||||
bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::North);
|
||||
@@ -1079,7 +1079,7 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the building id for a
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
||||
@@ -1154,7 +1154,7 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget works for a symmetric multi-t
|
||||
|
||||
// Smelter is a fully filled 2×2 footprint — rotating the ghost produces the
|
||||
// same four body tiles, so findRotateInPlaceTarget must still return the id.
|
||||
const BuildingId id = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
const std::optional<BuildingId> result =
|
||||
bs.findRotateInPlaceTarget(BuildingType::Smelter, QPoint(0, 0), Rotation::North);
|
||||
@@ -1181,7 +1181,7 @@ TEST_CASE("BuildingSystem: rotateInPlace updates the rotation field of a constru
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0).value();
|
||||
REQUIRE(bs.findSite(id)->rotation == Rotation::East);
|
||||
|
||||
bs.rotateInPlace(id, Rotation::North);
|
||||
@@ -1204,7 +1204,7 @@ TEST_CASE("BuildingSystem: rotateInPlace preserves the construction progress of
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0).value();
|
||||
const Tick completesAt = bs.findSite(id)->completesAt;
|
||||
REQUIRE(completesAt > 0);
|
||||
|
||||
@@ -1228,7 +1228,7 @@ TEST_CASE("BuildingSystem: rotateInPlace updates rotation and output port direct
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
||||
@@ -1259,7 +1259,7 @@ TEST_CASE("BuildingSystem: rotateInPlace re-registers a belt tile with BeltSyste
|
||||
[](const std::string&) -> bool { return true; },
|
||||
rng);
|
||||
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0).value();
|
||||
|
||||
Tick tick = 0;
|
||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
||||
@@ -1276,7 +1276,7 @@ TEST_CASE("BuildingSystem: splitter filters configured on a construction site ca
|
||||
PlacementFixture f;
|
||||
|
||||
const QPoint tile(5, 5);
|
||||
const BuildingId id = f.bs.place(BuildingType::Splitter, tile, Rotation::East, 0);
|
||||
const BuildingId id = f.bs.place(BuildingType::Splitter, tile, Rotation::East, 0).value();
|
||||
REQUIRE(id != kInvalidBuildingId);
|
||||
REQUIRE(f.bs.findSite(id) != nullptr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user