Now fully off catch2. YAY!

This commit is contained in:
Zed A. Shaw 2026-06-17 00:32:31 -04:00
parent 903cf00661
commit 21e7700deb
16 changed files with 610 additions and 498 deletions

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "algos/spatialmap.hpp"
@ -9,244 +9,268 @@
using DinkyECS::Entity;
using namespace fmt;
using namespace fuc2;
namespace spatialmap_tests {
void test_SpatialMap_insert() {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto item = world.entity();
auto potion = world.entity();
auto enemy = world.entity();
Point at{10,10};
Point enemy_at{11,11};
map.insert(at, item, false);
map.insert(at, potion, false);
CHECK(!map.occupied(at));
map.insert(at, player, true);
CHECK(map.occupied_by(at) == player);
BLOWS_UP([&]() {
map.insert(at, enemy, true);
});
map.insert(enemy_at, enemy, true);
CHECK(map.occupied_by(enemy_at) == enemy);
CHECK(map.occupied(enemy_at));
}
void test_SpatialMap_remove() {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto item = world.entity();
Point at{120, 120};
// confirm that things can be in any order
map.insert(at, player, true);
map.insert(at, item, false);
CHECK(map.occupied(at));
CHECK(map.occupied_by(at) == player);
auto data = map.remove(at, player);
CHECK(!map.occupied(at));
CHECK(data.entity == player);
CHECK(data.collision == true);
BLOWS_UP([&]() {
map.remove(at, player);
});
}
TEST_CASE("SpatialMap::insert", "[spatialmap]") {
DinkyECS::World world;
SpatialMap map;
void test_SpatialMap_move() {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto item = world.entity();
auto potion = world.entity();
auto enemy = world.entity();
Point at{10,10};
Point enemy_at{11,11};
auto player = world.entity();
auto item = world.entity();
Point at{10, 320};
map.insert(at, player, true);
map.insert(at, item, false);
CHECK(map.occupied(at));
map.insert(at, item, false);
map.insert(at, potion, false);
REQUIRE(!map.occupied(at));
auto enemy = world.entity();
auto potion = world.entity();
Point enemy_at{11, 320};
map.insert(enemy_at, enemy, true);
map.insert(enemy_at, potion, false);
CHECK(map.occupied(enemy_at));
CHECK(map.occupied_by(enemy_at) == enemy);
map.insert(at, player, true);
REQUIRE(map.occupied_by(at) == player);
Point target{at.x + 1, at.y};
REQUIRE_THROWS(map.insert(at, enemy, true));
// try bad move with a slot that's empty
BLOWS_UP([&]() {
map.move({0,0}, target, player);
});
map.insert(enemy_at, enemy, true);
REQUIRE(map.occupied_by(enemy_at) == enemy);
REQUIRE(map.occupied(enemy_at));
}
// try move into an occupied spot also fails
BLOWS_UP([&]() {
map.move(at, target, player);
});
TEST_CASE("SpatialMap::remove", "[spatialmap]") {
DinkyECS::World world;
SpatialMap map;
// now move to a new spot, need to add them back
map.insert(at, player, true);
target.x++; // just move farther
map.move(at, target, player);
auto player = world.entity();
auto item = world.entity();
Point at{120, 120};
// confirm that things can be in any order
map.insert(at, player, true);
map.insert(at, item, false);
REQUIRE(map.occupied(at));
REQUIRE(map.occupied_by(at) == player);
auto data = map.remove(at, player);
REQUIRE(!map.occupied(at));
REQUIRE(data.entity == player);
REQUIRE(data.collision == true);
REQUIRE_THROWS(map.remove(at, player));
}
CHECK(map.occupied(target));
CHECK(map.occupied_by(target) == player);
auto data = map.remove(target, player);
CHECK(data.entity == player);
CHECK(data.collision == true);
}
TEST_CASE("SpatialMap::move", "[spatialmap]") {
DinkyECS::World world;
SpatialMap map;
void test_SpatialMap_occupied() {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto item = world.entity();
Point at{10, 320};
map.insert(at, player, true);
map.insert(at, item, false);
REQUIRE(map.occupied(at));
auto player = world.entity();
auto item = world.entity();
auto enemy = world.entity();
auto potion = world.entity();
Point enemy_at{11, 320};
map.insert(enemy_at, enemy, true);
map.insert(enemy_at, potion, false);
REQUIRE(map.occupied(enemy_at));
REQUIRE(map.occupied_by(enemy_at) == enemy);
Point at{1000, 20};
// first test empty locations
CHECK(!map.something_there(at));
CHECK(!map.occupied(at));
Point target{at.x + 1, at.y};
// then when there's something without collision
map.insert(at, item, false);
CHECK(map.something_there(at));
CHECK(!map.occupied(at));
// try bad move with a slot that's empty
REQUIRE_THROWS(map.move({0,0}, target, player));
// finally with collision and an item there
map.insert(at, player, true);
CHECK(map.something_there(at));
CHECK(map.occupied(at));
CHECK(map.occupied_by(at) == player);
// try move into an occupied spot also fails
REQUIRE_THROWS(map.move(at, target, player));
// then remove the item and still have collision
// now move to a new spot, need to add them back
map.insert(at, player, true);
target.x++; // just move farther
map.move(at, target, player);
map.remove(at, item);
CHECK(map.something_there(at));
CHECK(map.occupied(at));
CHECK(map.occupied_by(at) == player);
REQUIRE(map.occupied(target));
REQUIRE(map.occupied_by(target) == player);
auto data = map.remove(target, player);
REQUIRE(data.entity == player);
REQUIRE(data.collision == true);
}
// remove player and back to no collision
map.remove(at, player);
CHECK(!map.something_there(at));
CHECK(!map.occupied(at));
// last thing, put just the player in at a new spot
Point target{at.x+1, at.y+10};
map.insert(target, player, true);
CHECK(map.something_there(target));
CHECK(map.occupied(target));
CHECK(map.occupied_by(target) == player);
}
TEST_CASE("SpatialMap::occupied/something_there", "[spatialmap]") {
DinkyECS::World world;
SpatialMap map;
void test_SpatialMap_get() {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto item = world.entity();
auto player = world.entity();
auto item = world.entity();
Point at{101, 31};
Point at{1000, 20};
// first test empty locations
REQUIRE(!map.something_there(at));
REQUIRE(!map.occupied(at));
// finally with collision and an item there
map.insert(at, player, true);
CHECK(map.occupied(at));
CHECK(map.occupied_by(at) == player);
// then when there's something without collision
map.insert(at, item, false);
REQUIRE(map.something_there(at));
REQUIRE(!map.occupied(at));
auto entity = map.get(at);
CHECK(player == entity);
// finally with collision and an item there
map.insert(at, player, true);
REQUIRE(map.something_there(at));
REQUIRE(map.occupied(at));
REQUIRE(map.occupied_by(at) == player);
// This probably doesn't work so need to
// rethink how get works.
map.insert(at, item, false);
entity = map.get(at);
CHECK(entity == item);
}
// then remove the item and still have collision
void test_SpatialMap_find() {
DinkyECS::World world;
SpatialMap map;
Point at{101, 31};
DinkyECS::Entity should_collide = DinkyECS::NONE;
map.remove(at, item);
REQUIRE(map.something_there(at));
REQUIRE(map.occupied(at));
REQUIRE(map.occupied_by(at) == player);
for(int i = 0; i < 10; i++) {
auto ent = world.entity();
map.insert(at, ent, i == 8);
// remove player and back to no collision
map.remove(at, player);
REQUIRE(!map.something_there(at));
REQUIRE(!map.occupied(at));
if(i == 8) {
should_collide = ent;
}
}
// last thing, put just the player in at a new spot
Point target{at.x+1, at.y+10};
map.insert(target, player, true);
REQUIRE(map.something_there(target));
REQUIRE(map.occupied(target));
REQUIRE(map.occupied_by(target) == player);
}
auto collision = map.find(at, [&](auto data) -> bool {
return data.collision;
});
CHECK(collision == should_collide);
TEST_CASE("SpatialMap::get", "[spatialmap]") {
DinkyECS::World world;
SpatialMap map;
auto no_collide = map.find(at, [&](auto data) -> bool {
return !data.collision;
});
auto player = world.entity();
auto item = world.entity();
Point at{101, 31};
CHECK(no_collide != should_collide);
}
// finally with collision and an item there
map.insert(at, player, true);
REQUIRE(map.occupied(at));
REQUIRE(map.occupied_by(at) == player);
void test_SpatialMap_neighbors() {
DinkyECS::World world;
SpatialMap map;
auto entity = map.get(at);
REQUIRE(player == entity);
auto player = world.entity();
auto enemy1 = world.entity();
auto enemy2 = world.entity();
//auto item1 = world.entity();
//auto item2 = world.entity();
Point at{101, 31};
// This probably doesn't work so need to
// rethink how get works.
map.insert(at, item, false);
entity = map.get(at);
REQUIRE(entity == item);
}
map.insert(at, player, true);
map.insert({at.x+1, at.y}, enemy1, true);
map.insert({at.x-1, at.y+1}, enemy2, true);
TEST_CASE("SpatialMap::find", "[spatialmap-find]") {
DinkyECS::World world;
SpatialMap map;
Point at{101, 31};
DinkyECS::Entity should_collide = DinkyECS::NONE;
auto result = map.neighbors(at, true);
CHECK(result.found);
CHECK(result.nearby.size() == 2);
for(int i = 0; i < 10; i++) {
auto ent = world.entity();
map.insert(at, ent, i == 8);
bool maybe = result.nearby[0] == enemy1 || result.nearby[1] == enemy1;
CHECK(maybe);
if(i == 8) {
should_collide = ent;
maybe = result.nearby[0] == enemy2 || result.nearby[1] == enemy2;
CHECK(maybe);
result = map.neighbors(at, false);
CHECK(result.found);
CHECK(result.nearby.size() == 1);
CHECK(result.nearby[0] == enemy1);
}
void test_SpatialMap_distance_sorted() {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto enemy1 = world.entity();
auto item = world.entity();
map.insert({1,1}, player, true);
map.insert({4,4}, enemy1, true);
map.insert({3, 3}, item, false);
SortedEntities result;
map.distance_sorted(result, {1, 1}, 100);
CHECK(result.size() == 3);
CHECK(result[0].entity == enemy1);
CHECK(result[1].entity == item);
CHECK(result[2].entity == player);
int prev_dist = std::numeric_limits<int>::max();
for(auto rec : result) {
CHECK(rec.dist_square < prev_dist);
prev_dist = rec.dist_square;
}
}
auto collision = map.find(at, [&](auto data) -> bool {
return data.collision;
});
REQUIRE(collision == should_collide);
auto no_collide = map.find(at, [&](auto data) -> bool {
return !data.collision;
});
REQUIRE(no_collide != should_collide);
}
TEST_CASE("SpatialMap::neighbors", "[spatialmap-neighbors]") {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto enemy1 = world.entity();
auto enemy2 = world.entity();
//auto item1 = world.entity();
//auto item2 = world.entity();
Point at{101, 31};
map.insert(at, player, true);
map.insert({at.x+1, at.y}, enemy1, true);
map.insert({at.x-1, at.y+1}, enemy2, true);
auto result = map.neighbors(at, true);
REQUIRE(result.found);
REQUIRE(result.nearby.size() == 2);
bool maybe = result.nearby[0] == enemy1 || result.nearby[1] == enemy1;
REQUIRE(maybe);
maybe = result.nearby[0] == enemy2 || result.nearby[1] == enemy2;
REQUIRE(maybe);
result = map.neighbors(at, false);
REQUIRE(result.found);
REQUIRE(result.nearby.size() == 1);
REQUIRE(result.nearby[0] == enemy1);
}
TEST_CASE("SpatialMap::distance_sorted", "[spatialmap]") {
DinkyECS::World world;
SpatialMap map;
auto player = world.entity();
auto enemy1 = world.entity();
auto item = world.entity();
map.insert({1,1}, player, true);
map.insert({4,4}, enemy1, true);
map.insert({3, 3}, item, false);
SortedEntities result;
map.distance_sorted(result, {1, 1}, 100);
REQUIRE(result.size() == 3);
REQUIRE(result[0].entity == enemy1);
REQUIRE(result[1].entity == item);
REQUIRE(result[2].entity == player);
int prev_dist = std::numeric_limits<int>::max();
for(auto rec : result) {
REQUIRE(rec.dist_square < prev_dist);
prev_dist = rec.dist_square;
}
fuc2::Set TESTS{
.name="spatialmap",
.tests={
TEST(test_SpatialMap_distance_sorted),
TEST(test_SpatialMap_neighbors),
TEST(test_SpatialMap_find),
TEST(test_SpatialMap_get),
TEST(test_SpatialMap_occupied),
TEST(test_SpatialMap_move),
TEST(test_SpatialMap_remove),
TEST(test_SpatialMap_insert),
}
};
}