This commit is contained in:
Connor
2026-02-16 16:55:17 +09:00
parent 7ae69ea1ff
commit cf20ed827e
5 changed files with 316 additions and 41 deletions

View File

@@ -0,0 +1,162 @@
#include <doctest/doctest.h>
#include "Components/Configs/WorldConfig.hpp"
#include "Core/WorldInstance.h"
#include "Components/Chute.hpp"
TEST_SUITE("Chute") {
TEST_CASE("chute transports item from source to destination") {
WorldConfig config{};
uint16_t stoneID = config.RegisterItem("Stone");
WorldInstance world{ config };
// source inventory with items, destination empty
auto source = world.GetEcsWorld().entity();
Inventory_Helper(source, config, 100);
source.ensure<Inventory>().AddItems(stoneID, 3);
auto dest = world.GetEcsWorld().entity();
Inventory_Helper(dest, config, 100);
// vertical drop: (0,10) -> (0,0), should be fast
std::vector<Vector2> path = { {0, 10}, {0, 0} };
auto chuteEntity = world.GetEcsWorld().entity();
Chute_Helper(chuteEntity, path,
source.get<Inventory>(),
dest.get<Inventory>());
// get the transit time
auto chute = chuteEntity.get<Chute>();
uint16_t transitTicks = chute.Data.GetMetaData()->TicksToReachEnd;
CHECK(transitTicks > 0);
// tick once to pull items from source into chute
world.ProcessFrame();
auto srcInv = source.get<Inventory>();
CHECK(srcInv.GetItemsAmount(stoneID) == 0);
// tick until items arrive
for (uint16_t i = 1; i < transitTicks; ++i)
world.ProcessFrame();
auto destInv = dest.get<Inventory>();
CHECK(destInv.GetItemsAmount(stoneID) == 0);
world.ProcessFrame();
destInv = dest.get<Inventory>();
CHECK(destInv.GetItemsAmount(stoneID) == 3);
}
TEST_CASE("chute respects transit time for longer paths") {
WorldConfig config{};
uint16_t ironID = config.RegisterItem("Iron");
WorldInstance world{ config };
auto source = world.GetEcsWorld().entity();
Inventory_Helper(source, config, 100);
source.ensure<Inventory>().AddItems(ironID, 1);
auto dest = world.GetEcsWorld().entity();
Inventory_Helper(dest, config, 100);
// multi-link path with gradual descent
std::vector<Vector2> path = { {0, 10}, {1, 9}, {2, 8}, {3, 7}, {4, 6}, {5, 5} };
auto chuteEntity = world.GetEcsWorld().entity();
Chute_Helper(chuteEntity, path,
source.get<Inventory>(),
dest.get<Inventory>());
auto chute = chuteEntity.get<Chute>();
uint16_t transitTicks = chute.Data.GetMetaData()->TicksToReachEnd;
CHECK(transitTicks > 1);
// pull items into chute
world.ProcessFrame();
// tick one less than transit time — item should not have arrived
for (uint16_t i = 1; i < transitTicks; ++i)
world.ProcessFrame();
auto destInv = dest.get<Inventory>();
CHECK(destInv.GetItemsAmount(ironID) == 0);
// one more tick — item arrives
world.ProcessFrame();
destInv = dest.get<Inventory>();
CHECK(destInv.GetItemsAmount(ironID) == 1);
}
TEST_CASE("chute overflows to world inventory when destination is full") {
WorldConfig config{};
uint16_t stoneID = config.RegisterItem("Stone");
WorldInstance world{ config };
auto source = world.GetEcsWorld().entity();
Inventory_Helper(source, config, 100);
source.ensure<Inventory>().AddItems(stoneID, 3);
// destination can only hold 1
auto dest = world.GetEcsWorld().entity();
Inventory_Helper(dest, config, 1);
std::vector<Vector2> path = { {0, 10}, {0, 0} };
auto chuteEntity = world.GetEcsWorld().entity();
Chute_Helper(chuteEntity, path,
source.get<Inventory>(),
dest.get<Inventory>());
auto chute = chuteEntity.get<Chute>();
uint16_t transitTicks = chute.Data.GetMetaData()->TicksToReachEnd;
// tick enough for all items to arrive
for (uint16_t i = 0; i <= transitTicks; ++i)
world.ProcessFrame();
auto destInv = dest.get<Inventory>();
CHECK(destInv.GetItemsAmount(stoneID) == 1);
auto& worldInv = world.GetEcsWorld().ensure<WorldInventory>();
CHECK(worldInv.GetItemsAmount(stoneID) == 2);
}
TEST_CASE("horizontal chute uses minimum speed") {
WorldConfig config{};
uint16_t woodID = config.RegisterItem("Wood");
WorldInstance world{ config };
auto source = world.GetEcsWorld().entity();
Inventory_Helper(source, config, 100);
source.ensure<Inventory>().AddItems(woodID, 1);
auto dest = world.GetEcsWorld().entity();
Inventory_Helper(dest, config, 100);
// flat path: dy=0 throughout, should use MinSpeed
ChuteConfig chuteConfig{ .Gravity = 1.0f, .MinSpeed = 0.5f };
std::vector<Vector2> path = { {0, 0}, {5, 0} };
auto chuteEntity = world.GetEcsWorld().entity();
Chute_Helper(chuteEntity, path,
source.get<Inventory>(),
dest.get<Inventory>(),
chuteConfig);
auto chute = chuteEntity.get<Chute>();
uint16_t transitTicks = chute.Data.GetMetaData()->TicksToReachEnd;
// distance=5, speed=0.5 -> 10 ticks
CHECK(transitTicks == 10);
// tick enough for item to arrive
for (uint16_t i = 0; i <= transitTicks; ++i)
world.ProcessFrame();
auto destInv = dest.get<Inventory>();
CHECK(destInv.GetItemsAmount(woodID) == 1);
}
}