More tests converted to fuc2.

This commit is contained in:
Zed A. Shaw 2026-06-16 13:58:10 -04:00
parent b8b42d5681
commit 903cf00661
10 changed files with 671 additions and 556 deletions

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "gui/event_router.hpp"
@ -7,18 +7,20 @@ using namespace fmt;
using namespace gui;
using enum gui::routing::Event;
using enum gui::routing::State;
using namespace fuc2;
using EventScript = std::vector<routing::Event>;
namespace event_router_tests {
using EventScript = std::vector<routing::Event>;
void run_script(routing::Router& router, routing::State expected, EventScript script) {
void run_script(routing::Router& router, routing::State expected, EventScript script) {
for(auto ev : script) {
router.event(ev);
}
REQUIRE(router.in_state(expected));
}
CHECK(router.in_state(expected));
}
TEST_CASE("basic router operations test", "[event_router]") {
void test_basic_router_operations_test() {
routing::Router router;
// start goes to idle
@ -54,4 +56,12 @@ TEST_CASE("basic router operations test", "[event_router]") {
KEY_PRESS,
MOUSE_UP,
});
}
fuc2::Set TESTS{
.name="event_router",
.tests={
TEST(test_basic_router_operations_test),
}
};
}

View file

@ -1,21 +1,23 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "algos/simplefsm.hpp"
using namespace fmt;
using std::string;
using namespace fuc2;
enum class MyState {
namespace fsm_tests {
enum class MyState {
START, RUNNING, END
};
};
enum class MyEvent {
enum class MyEvent {
STARTED, PUSH, QUIT
};
};
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> {
public:
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> {
public:
void event(MyEvent ev, string data="") {
switch($state) {
FSM_STATE(MyState, START, ev);
@ -43,25 +45,34 @@ public:
println("<<< STOP {}", (int)ev);
state(MyState::END);
}
};
};
TEST_CASE("confirm fsm works with optional data", "[utils]") {
void test_confirm_fsm_works_with_optional_data() {
MyFSM fsm;
REQUIRE(fsm.in_state(MyState::START));
CHECK(fsm.in_state(MyState::START));
fsm.event(MyEvent::STARTED);
REQUIRE(fsm.in_state(MyState::RUNNING));
CHECK(fsm.in_state(MyState::RUNNING));
fsm.event(MyEvent::PUSH);
REQUIRE(fsm.in_state(MyState::RUNNING));
CHECK(fsm.in_state(MyState::RUNNING));
fsm.event(MyEvent::PUSH);
REQUIRE(fsm.in_state(MyState::RUNNING));
CHECK(fsm.in_state(MyState::RUNNING));
fsm.event(MyEvent::PUSH);
REQUIRE(fsm.in_state(MyState::RUNNING));
CHECK(fsm.in_state(MyState::RUNNING));
fsm.event(MyEvent::QUIT, "DONE!");
REQUIRE(fsm.in_state(MyState::END));
CHECK(fsm.in_state(MyState::END));
}
fuc2::Set TESTS{
.name="fsm",
.tests={
TEST(test_confirm_fsm_works_with_optional_data),
}
};
}

View file

@ -1,52 +1,63 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "game/inventory.hpp"
using namespace fmt;
using namespace fuc2;
TEST_CASE("base test", "[inventory]") {
namespace inventory_tests {
void test_base_test() {
return;
inventory::Model inv;
DinkyECS::Entity test_ent = 1;
bool good = inv.add("hand_l", test_ent);
inv.invariant();
REQUIRE(good);
CHECK(good);
auto& slot = inv.get(test_ent);
REQUIRE(slot == "hand_l");
CHECK(slot == "hand_l");
// confirm that we get false when trying to do it again
// BUG: this dies
good = inv.add("hand_l", test_ent);
REQUIRE(!good);
CHECK(!good);
auto ent = inv.get(slot);
REQUIRE(ent == test_ent);
CHECK(ent == test_ent);
REQUIRE(inv.has(ent));
REQUIRE(inv.has(slot));
CHECK(inv.has(ent));
CHECK(inv.has(slot));
// test base remove
inv.remove(ent);
REQUIRE(!inv.has(slot));
REQUIRE(!inv.has(ent));
}
CHECK(!inv.has(slot));
CHECK(!inv.has(ent));
}
TEST_CASE("test swapping items", "[inventory]") {
void test_test_swapping_items() {
inventory::Model inv;
DinkyECS::Entity hand_l_ent = 10;
DinkyECS::Entity hand_r_ent = 20;
inv.add("hand_l", hand_l_ent);
inv.add("hand_r", hand_r_ent);
REQUIRE(inv.count() == 2);
CHECK(inv.count() == 2);
inv.swap(hand_l_ent, hand_r_ent);
REQUIRE(inv.get("hand_l") == hand_r_ent);
REQUIRE(inv.get("hand_r") == hand_l_ent);
CHECK(inv.get("hand_l") == hand_r_ent);
CHECK(inv.get("hand_r") == hand_l_ent);
REQUIRE(inv.count() == 2);
CHECK(inv.count() == 2);
}
fuc2::Set TESTS{
.name="inventory",
.tests={
TEST(test_base_test),
TEST(test_test_swapping_items),
}
};
}

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
#include <fstream>
@ -8,16 +8,19 @@
#include "algos/point.hpp"
using namespace lighting;
using namespace fuc2;
TEST_CASE("lighting a map works", "[lighting]") {
namespace lighting_tests {
void test_lighting_a_map_works() {
GameDB::init();
auto& level = GameDB::current_level();
auto& map = *level.map;
Point light1, light2;
REQUIRE(map.place_entity(0, light1));
REQUIRE(map.place_entity(0, light1));
CHECK(map.place_entity(0, light1));
CHECK(map.place_entity(0, light1));
LightSource source1{6, 1.0};
LightSource source2{4,3};
@ -39,4 +42,13 @@ TEST_CASE("lighting a map works", "[lighting]") {
Matrix &lighting = lr.lighting();
(void)lighting;
}
fuc2::Set TESTS{
.name="lighting",
.tests={
TEST(test_lighting_a_map_works),
}
};
}

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "game/components.hpp"
@ -6,8 +6,10 @@
using namespace fmt;
using namespace components;
using namespace fuc2;
TEST_CASE("test the loot ui", "[loot]") {
namespace loot_tests {
void test_test_the_loot_ui() {
auto items = settings::get("assets/items.json");
DinkyECS::World world;
auto torch = world.entity();
@ -17,5 +19,13 @@ TEST_CASE("test the loot ui", "[loot]") {
components::configure_entity(world, torch, data["components"]);
auto& torch_sprite = world.get<Sprite>(torch);
REQUIRE(torch_sprite.name == "torch_horizontal_floor");
CHECK(torch_sprite.name == "torch_horizontal_floor");
}
fuc2::Set TESTS{
.name="loot",
.tests={
TEST(test_test_the_loot_ui),
}
};
}

View file

@ -11,6 +11,13 @@ TEST_SET(component_tests);
TEST_SET(config_tests);
TEST_SET(dbc_tests);
TEST_SET(dinkyecs_tests);
TEST_SET(event_router_tests);
TEST_SET(inventory_tests);
TEST_SET(lighting_tests);
TEST_SET(loot_tests);
TEST_SET(map_tests);
TEST_SET(matrix_tests);
TEST_SET(mazes_tests);
int main(int argc, char* argv[]) {
run(ai_tests::TESTS);
@ -22,4 +29,11 @@ int main(int argc, char* argv[]) {
run(config_tests::TESTS);
run(dbc_tests::TESTS);
run(dinkyecs_tests::TESTS);
run(event_router_tests::TESTS);
run(inventory_tests::TESTS);
run(lighting_tests::TESTS);
run(loot_tests::TESTS);
run(map_tests::TESTS);
run(matrix_tests::TESTS);
run(mazes_tests::TESTS);
}

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
#include <fstream>
@ -12,13 +12,15 @@
using namespace fmt;
using namespace nlohmann;
using std::string;
using namespace fuc2;
json load_test_data(const string &fname) {
namespace map_tests {
json load_test_data(const string &fname) {
std::ifstream infile(fname);
return json::parse(infile);
}
}
TEST_CASE("camera control", "[map]") {
void test_camera_control() {
GameDB::init();
auto& level = GameDB::current_level();
@ -27,16 +29,16 @@ TEST_CASE("camera control", "[map]") {
Point center = map.center_camera({10,10}, 5, 5);
// map.dump(center.x, center.y);
REQUIRE(center.x == 8);
REQUIRE(center.y == 8);
CHECK(center.x == 8);
CHECK(center.y == 8);
Point translation = map.map_to_camera({10,10}, center);
REQUIRE(translation.x == 2);
REQUIRE(translation.y == 2);
}
CHECK(translation.x == 2);
CHECK(translation.y == 2);
}
TEST_CASE("map placement test", "[map-fail]") {
void test_map_placement_test() {
GameDB::init();
for(int i = 0; i < 10; i++) {
@ -45,15 +47,15 @@ TEST_CASE("map placement test", "[map-fail]") {
for(size_t rnum = 0; rnum < level.map->room_count(); rnum++) {
Point pos;
REQUIRE(level.map->place_entity(rnum, pos));
CHECK(level.map->place_entity(rnum, pos));
REQUIRE(!level.map->iswall(pos.x, pos.y));
REQUIRE(level.map->inmap(pos.x, pos.y));
CHECK(!level.map->iswall(pos.x, pos.y));
CHECK(level.map->inmap(pos.x, pos.y));
}
}
}
}
TEST_CASE("map image test", "[map]") {
void test_map_image_test() {
GameDB::init();
auto& level = GameDB::current_level();
@ -79,7 +81,17 @@ TEST_CASE("map image test", "[map]") {
// confirm we get two different maps
auto out_img = render->getTexture().copyToImage();
bool worked = out_img.saveToFile(fmt::format("tmp/map_render{}{}.png", it.x, it.y));
REQUIRE(worked);
CHECK(worked);
#endif
}
}
fuc2::Set TESTS{
.name="map",
.tests={
TEST(test_camera_control),
TEST(test_map_placement_test),
TEST(test_map_image_test),
}
};
}

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "game/config.hpp"
@ -13,25 +13,27 @@
using namespace nlohmann;
using namespace fmt;
using namespace fuc2;
using std::string, std::shared_ptr;
using matrix::Matrix;
std::shared_ptr<Map> make_map() {
namespace matrix_tests {
std::shared_ptr<Map> make_map() {
GameDB::init();
return GameDB::current_level().map;
}
}
// BUG: create a test that randomizes a map then does matrix ops on it
// BUG: create a test that randomizes a map then does matrix ops on it
inline void random_matrix(Matrix &out) {
inline void random_matrix(Matrix &out) {
for(size_t y = 0; y < out.size(); y++) {
for(size_t x = 0; x < out[0].size(); x++) {
out[y][x] = Random::uniform<int>(-10,10);
}
}
}
}
TEST_CASE("thrash matrix iterators", "[matrix]") {
void test_thrash_matrix_iterators() {
for(int count = 0; count < 5; count++) {
size_t width = Random::uniform<size_t>(1, 100);
size_t height = Random::uniform<size_t>(1, 100);
@ -46,12 +48,12 @@ TEST_CASE("thrash matrix iterators", "[matrix]") {
for(matrix::each_row it{test};
it.next(); cells.next())
{
REQUIRE(test[cells.y][cells.x] == test[it.y][it.x]);
CHECK(test[cells.y][cells.x] == test[it.y][it.x]);
}
}
}
}
TEST_CASE("thrash box distance iterators", "[matrix]") {
void test_thrash_box_distance_iterators() {
size_t width = Random::uniform<size_t>(10, 21);
size_t height = Random::uniform<size_t>(10, 25);
@ -70,9 +72,9 @@ TEST_CASE("thrash box distance iterators", "[matrix]") {
// matrix::width(result), matrix::height(result),
// target.x, target.y, box.right - box.left, box.bottom - box.top, size),
// result, target.x, target.y);
}
}
TEST_CASE("thrash box iterators", "[matrix]") {
void test_thrash_box_iterators() {
for(int count = 0; count < 5; count++) {
size_t width = Random::uniform<size_t>(1, 25);
size_t height = Random::uniform<size_t>(1, 33);
@ -96,14 +98,14 @@ TEST_CASE("thrash box iterators", "[matrix]") {
}
for(auto point : result) {
REQUIRE(test[point.y][point.x] == test_i);
CHECK(test[point.y][point.x] == test_i);
test[point.y][point.x] = 10; // kind of reset it for another try
}
}
}
}
}
TEST_CASE("thrash compass iterators", "[matrix]") {
void test_thrash_compass_iterators() {
for(int count = 0; count < 5; count++) {
size_t width = Random::uniform<size_t>(1, 25);
size_t height = Random::uniform<size_t>(1, 33);
@ -126,14 +128,14 @@ TEST_CASE("thrash compass iterators", "[matrix]") {
}
for(auto point : result) {
REQUIRE(test[point.y][point.x] == test_i);
CHECK(test[point.y][point.x] == test_i);
test[point.y][point.x] = 10; // kind of reset it for another try
}
}
}
}
}
TEST_CASE("prototype line algorithm", "[matrix]") {
void test_prototype_line_algorithm() {
size_t width = Random::uniform<size_t>(10, 12);
size_t height = Random::uniform<size_t>(10, 15);
Map map(width,height);
@ -149,7 +151,7 @@ TEST_CASE("prototype line algorithm", "[matrix]") {
for(matrix::line it{start, end}; it.next();)
{
REQUIRE(map.inmap(it.x, it.y));
CHECK(map.inmap(it.x, it.y));
result[it.y][it.x] = 15;
}
@ -165,11 +167,11 @@ TEST_CASE("prototype line algorithm", "[matrix]") {
}
}
REQUIRE(f_found);
CHECK(f_found);
}
}
}
TEST_CASE("prototype circle algorithm", "[matrix]") {
void test_prototype_circle_algorithm() {
for(int count = 0; count < 5; count++) {
size_t width = Random::uniform<size_t>(10, 13);
size_t height = Random::uniform<size_t>(10, 15);
@ -187,10 +189,10 @@ TEST_CASE("prototype circle algorithm", "[matrix]") {
for(int x = it.left; x < it.right; x++) {
// println("top={}, bottom={}, center.y={}, dy={}, left={}, right={}, x={}, y={}", it.top, it.bottom, it.center.y, it.dy, it.left, it.right, x, it.y);
// println("RESULT {},{}", matrix::width(result), matrix::height(result));
REQUIRE(it.y >= 0);
REQUIRE(x >= 0);
REQUIRE(it.y < int(matrix::height(result)));
REQUIRE(x < int(matrix::width(result)));
CHECK(it.y >= 0);
CHECK(x >= 0);
CHECK(it.y < int(matrix::height(result)));
CHECK(x < int(matrix::width(result)));
result[it.y][x] += 1;
}
}
@ -198,9 +200,9 @@ TEST_CASE("prototype circle algorithm", "[matrix]") {
// matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y);
}
}
}
}
TEST_CASE("viewport iterator", "[matrix]") {
void test_viewport_iterator() {
components::init();
textures::init();
GameDB::init();
@ -211,7 +213,7 @@ TEST_CASE("viewport iterator", "[matrix]") {
size_t view_width = width/2;
size_t view_height = height/2;
Point player;
REQUIRE(map->place_entity(1, player));
CHECK(map->place_entity(1, player));
Point start = map->center_camera(player, view_width, view_height);
size_t end_x = std::min(view_width, map->width() - start.x);
@ -224,9 +226,9 @@ TEST_CASE("viewport iterator", "[matrix]") {
// still working on this
}
}
}
}
TEST_CASE("random rectangle", "[matrix]") {
void test_random_rectangle() {
components::init();
for(int i = 0; i < 5; i++) {
shared_ptr<Map> map = make_map();
@ -239,19 +241,19 @@ TEST_CASE("random rectangle", "[matrix]") {
for(matrix::rando_rect it{map->walls(), room.x, room.y, room.width, room.height}; it.next();)
{
REQUIRE(size_t(it.x) >= room.x);
REQUIRE(size_t(it.y) >= room.y);
REQUIRE(size_t(it.x) <= room.x + room.width);
REQUIRE(size_t(it.y) <= room.y + room.height);
CHECK(size_t(it.x) >= room.x);
CHECK(size_t(it.y) >= room.y);
CHECK(size_t(it.x) <= room.x + room.width);
CHECK(size_t(it.y) <= room.y + room.height);
wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5;
}
}
// matrix::dump("WALLS FILLED", wall_copy);
}
}
}
TEST_CASE("standard rectangle", "[matrix]") {
void test_standard_rectangle() {
components::init();
for(int i = 0; i < 5; i++) {
shared_ptr<Map> map = make_map();
@ -263,10 +265,10 @@ TEST_CASE("standard rectangle", "[matrix]") {
for(matrix::rectangle it{map->walls(), room.x, room.y, room.width, room.height}; it.next();)
{
REQUIRE(size_t(it.x) >= room.x);
REQUIRE(size_t(it.y) >= room.y);
REQUIRE(size_t(it.x) <= room.x + room.width);
REQUIRE(size_t(it.y) <= room.y + room.height);
CHECK(size_t(it.x) >= room.x);
CHECK(size_t(it.y) >= room.y);
CHECK(size_t(it.x) <= room.x + room.width);
CHECK(size_t(it.y) <= room.y + room.height);
wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5;
}
@ -274,4 +276,20 @@ TEST_CASE("standard rectangle", "[matrix]") {
// matrix::dump("WALLS FILLED", wall_copy);
}
}
fuc2::Set TESTS{
.name="matrix",
.tests={
TEST(test_thrash_matrix_iterators),
TEST(test_thrash_box_distance_iterators),
TEST(test_thrash_box_iterators),
TEST(test_thrash_compass_iterators),
TEST(test_prototype_line_algorithm),
TEST(test_prototype_circle_algorithm),
TEST(test_viewport_iterator),
TEST(test_random_rectangle),
TEST(test_standard_rectangle),
}
};
}

View file

@ -1,4 +1,4 @@
#include <catch2/catch_test_macros.hpp>
#include <fuc2/testing.hpp>
#include <fmt/core.h>
#include <string>
#include "algos/matrix.hpp"
@ -11,28 +11,30 @@
using std::string;
using matrix::Matrix;
using namespace fuc2;
TEST_CASE("hunt-and-kill", "[mazes]") {
namespace mazes_tests {
void test_hunt_and_kill() {
Map map(21, 21);
maze::Builder maze(map);
maze.hunt_and_kill();
REQUIRE(maze.repair() == true);
CHECK(maze.repair() == true);
if(DUMP) maze.dump("BASIC MAZE");
maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill();
maze.place_doors();
REQUIRE(maze.repair() == true);
CHECK(maze.repair() == true);
if(DUMP) maze.dump("ROOM MAZE");
REQUIRE(map.$dead_ends.size() > 0);
REQUIRE(map.$rooms.size() > 0);
}
CHECK(map.$dead_ends.size() > 0);
CHECK(map.$rooms.size() > 0);
}
TEST_CASE("hunt-and-kill box", "[mazes]") {
void test_hunt_and_kill_box() {
for(int i = 25; i < 65; i += 2) {
Map map(i, i);
maze::Builder maze(map);
@ -51,46 +53,46 @@ TEST_CASE("hunt-and-kill box", "[mazes]") {
maze.dump(valid ? "INNER BOX" : "FAILED BOX");
}
}
}
}
TEST_CASE("hunt-and-kill ring", "[mazes]") {
void test_hunt_and_kill_ring() {
Map map(21, 21);
maze::Builder maze(map);
maze.inner_donut(5.5, 3.5);
maze.hunt_and_kill();
REQUIRE(maze.repair() == true);
CHECK(maze.repair() == true);
if(DUMP) maze.dump("INNER RING");
REQUIRE(maze.$rooms.size() == 0);
}
CHECK(maze.$rooms.size() == 0);
}
TEST_CASE("hunt-and-kill fissure", "[mazes]") {
void test_hunt_and_kill_fissure() {
Map map(21, 21);
maze::Builder maze(map);
maze.divide({3,3}, {19,18});
maze.hunt_and_kill();
REQUIRE(maze.repair() == true);
CHECK(maze.repair() == true);
if(DUMP) maze.dump("FISSURE MAZE");
REQUIRE(maze.$rooms.size() == 0);
}
CHECK(maze.$rooms.size() == 0);
}
TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") {
void test_hunt_and_kill_no_dead_ends() {
Map map(21, 21);
maze::Builder maze(map);
maze.hunt_and_kill();
maze.remove_dead_ends();
REQUIRE(maze.repair() == true);
CHECK(maze.repair() == true);
if(DUMP) maze.dump("NO DEAD ENDS");
}
}
TEST_CASE("hunt-and-kill too much", "[mazes]") {
void test_hunt_and_kill_too_much() {
for(int i = 25; i < 65; i += 2) {
Map map(i, i);
maze::Builder maze(map);
@ -108,9 +110,9 @@ TEST_CASE("hunt-and-kill too much", "[mazes]") {
maze.dump("COMBINED");
}
}
}
}
TEST_CASE("hunt-and-kill validator", "[mazes]") {
void test_hunt_and_kill_validator() {
bool valid = true;
Stats mofm;
@ -145,11 +147,11 @@ TEST_CASE("hunt-and-kill validator", "[mazes]") {
mofm.dump();
}
REQUIRE(mofm.mean() > 0.20);
}
CHECK(mofm.mean() > 0.20);
}
TEST_CASE("hunt-and-kill scripting", "[mazes]") {
void test_hunt_and_kill_scripting() {
using namespace nlohmann::literals;
// go up by 2 to keep odd
@ -173,10 +175,25 @@ TEST_CASE("hunt-and-kill scripting", "[mazes]") {
auto [maze, valid] = maze::script(map, script);
if(valid) {
REQUIRE(maze.validate() == true);
REQUIRE(map.INVARIANT() == true);
CHECK(maze.validate() == true);
CHECK(map.INVARIANT() == true);
}
if(DUMP) maze.dump(valid ? "SCRIPTED" : "SCRIPTED FAIL!");
}
}
fuc2::Set TESTS{
.name="mazes",
.tests={
TEST(test_hunt_and_kill_scripting),
TEST(test_hunt_and_kill_validator),
TEST(test_hunt_and_kill_too_much),
TEST(test_hunt_and_kill_no_dead_ends),
TEST(test_hunt_and_kill_fissure),
TEST(test_hunt_and_kill_ring),
TEST(test_hunt_and_kill_box),
TEST(test_hunt_and_kill),
}
};
}

View file

@ -1,12 +1,4 @@
tests = files(
'event_router.cpp',
'fsm.cpp',
'inventory.cpp',
'lighting.cpp',
'loot.cpp',
'map.cpp',
'matrix.cpp',
'mazes.cpp',
'palette.cpp',
'pathing.cpp',
'rituals.cpp',
@ -19,6 +11,14 @@ tests = files(
)
fuc2_tests = files(
'mazes.cpp',
'matrix.cpp',
'map.cpp',
'loot.cpp',
'lighting.cpp',
'inventory.cpp',
'fsm.cpp',
'event_router.cpp',
'dinkyecs.cpp',
'dbc.cpp',
'ai.cpp',