diff --git a/tests/event_router.cpp b/tests/event_router.cpp index 588ad35..4402c2d 100644 --- a/tests/event_router.cpp +++ b/tests/event_router.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "gui/event_router.hpp" @@ -7,51 +7,61 @@ using namespace fmt; using namespace gui; using enum gui::routing::Event; using enum gui::routing::State; +using namespace fuc2; -using EventScript = std::vector; +namespace event_router_tests { + using EventScript = std::vector; -void run_script(routing::Router& router, routing::State expected, EventScript script) { - for(auto ev : script) { - router.event(ev); + void run_script(routing::Router& router, routing::State expected, EventScript script) { + for(auto ev : script) { + router.event(ev); + } + + CHECK(router.in_state(expected)); } - REQUIRE(router.in_state(expected)); -} - -TEST_CASE("basic router operations test", "[event_router]") { - routing::Router router; - - // start goes to idle - run_script(router, IDLE, { - STARTED - }); - - // simulate drag and drop - run_script(router, IDLE, { - MOUSE_DOWN, - MOUSE_MOVE, - MOUSE_UP, - KEY_PRESS - }); - - // moving the mouse outside dnd - run_script(router, IDLE, { - MOUSE_MOVE, - KEY_PRESS, - MOUSE_MOVE - }); - - // regular mouse click - run_script(router, IDLE, { - MOUSE_DOWN, - MOUSE_UP - }); - - // possible bad key press in a move? - run_script(router, IDLE, { - MOUSE_DOWN, - MOUSE_MOVE, - KEY_PRESS, - MOUSE_UP, - }); + void test_basic_router_operations_test() { + routing::Router router; + + // start goes to idle + run_script(router, IDLE, { + STARTED + }); + + // simulate drag and drop + run_script(router, IDLE, { + MOUSE_DOWN, + MOUSE_MOVE, + MOUSE_UP, + KEY_PRESS + }); + + // moving the mouse outside dnd + run_script(router, IDLE, { + MOUSE_MOVE, + KEY_PRESS, + MOUSE_MOVE + }); + + // regular mouse click + run_script(router, IDLE, { + MOUSE_DOWN, + MOUSE_UP + }); + + // possible bad key press in a move? + run_script(router, IDLE, { + MOUSE_DOWN, + MOUSE_MOVE, + KEY_PRESS, + MOUSE_UP, + }); + } + + fuc2::Set TESTS{ + .name="event_router", + .tests={ + TEST(test_basic_router_operations_test), + } + }; } diff --git a/tests/fsm.cpp b/tests/fsm.cpp index e3a1798..d9b51c1 100644 --- a/tests/fsm.cpp +++ b/tests/fsm.cpp @@ -1,67 +1,78 @@ -#include +#include #include #include #include "algos/simplefsm.hpp" using namespace fmt; using std::string; +using namespace fuc2; -enum class MyState { - START, RUNNING, END -}; +namespace fsm_tests { + enum class MyState { + START, RUNNING, END + }; -enum class MyEvent { - STARTED, PUSH, QUIT -}; + enum class MyEvent { + STARTED, PUSH, QUIT + }; -class MyFSM : public DeadSimpleFSM { -public: - void event(MyEvent ev, string data="") { - switch($state) { - FSM_STATE(MyState, START, ev); - FSM_STATE(MyState, RUNNING, ev, data); - FSM_STATE(MyState, END, ev); - } + class MyFSM : public DeadSimpleFSM { + public: + void event(MyEvent ev, string data="") { + switch($state) { + FSM_STATE(MyState, START, ev); + FSM_STATE(MyState, RUNNING, ev, data); + FSM_STATE(MyState, END, ev); + } + } + + void START(MyEvent ev) { + println("<<< START {}", (int)ev); + state(MyState::RUNNING); + } + + void RUNNING(MyEvent ev, string &data) { + if(ev == MyEvent::QUIT) { + println("<<< QUITTING {}", data); + state(MyState::END); + } else { + println("<<< RUN: {}", data); + state(MyState::RUNNING); + } + } + + void END(MyEvent ev) { + println("<<< STOP {}", (int)ev); + state(MyState::END); + } + }; + + void test_confirm_fsm_works_with_optional_data() { + MyFSM fsm; + + CHECK(fsm.in_state(MyState::START)); + + fsm.event(MyEvent::STARTED); + CHECK(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::PUSH); + CHECK(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::PUSH); + CHECK(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::PUSH); + CHECK(fsm.in_state(MyState::RUNNING)); + + fsm.event(MyEvent::QUIT, "DONE!"); + CHECK(fsm.in_state(MyState::END)); } - void START(MyEvent ev) { - println("<<< START {}", (int)ev); - state(MyState::RUNNING); - } - void RUNNING(MyEvent ev, string &data) { - if(ev == MyEvent::QUIT) { - println("<<< QUITTING {}", data); - state(MyState::END); - } else { - println("<<< RUN: {}", data); - state(MyState::RUNNING); - } - } - - void END(MyEvent ev) { - println("<<< STOP {}", (int)ev); - state(MyState::END); - } -}; - -TEST_CASE("confirm fsm works with optional data", "[utils]") { - MyFSM fsm; - - REQUIRE(fsm.in_state(MyState::START)); - - fsm.event(MyEvent::STARTED); - REQUIRE(fsm.in_state(MyState::RUNNING)); - - fsm.event(MyEvent::PUSH); - REQUIRE(fsm.in_state(MyState::RUNNING)); - - fsm.event(MyEvent::PUSH); - REQUIRE(fsm.in_state(MyState::RUNNING)); - - fsm.event(MyEvent::PUSH); - REQUIRE(fsm.in_state(MyState::RUNNING)); - - fsm.event(MyEvent::QUIT, "DONE!"); - REQUIRE(fsm.in_state(MyState::END)); + fuc2::Set TESTS{ + .name="fsm", + .tests={ + TEST(test_confirm_fsm_works_with_optional_data), + } + }; } diff --git a/tests/inventory.cpp b/tests/inventory.cpp index ce93daa..270d0f1 100644 --- a/tests/inventory.cpp +++ b/tests/inventory.cpp @@ -1,52 +1,63 @@ -#include +#include #include #include #include "game/inventory.hpp" using namespace fmt; +using namespace fuc2; -TEST_CASE("base test", "[inventory]") { - return; - inventory::Model inv; - DinkyECS::Entity test_ent = 1; +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); + bool good = inv.add("hand_l", test_ent); + inv.invariant(); + CHECK(good); - auto& slot = inv.get(test_ent); - REQUIRE(slot == "hand_l"); + auto& slot = inv.get(test_ent); + 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); + // confirm that we get false when trying to do it again + // BUG: this dies + good = inv.add("hand_l", test_ent); + CHECK(!good); - auto ent = inv.get(slot); - REQUIRE(ent == test_ent); + auto ent = inv.get(slot); + 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)); -} - -TEST_CASE("test swapping items", "[inventory]") { - 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); - - inv.swap(hand_l_ent, hand_r_ent); - - REQUIRE(inv.get("hand_l") == hand_r_ent); - REQUIRE(inv.get("hand_r") == hand_l_ent); - - REQUIRE(inv.count() == 2); + // test base remove + inv.remove(ent); + CHECK(!inv.has(slot)); + CHECK(!inv.has(ent)); + } + + 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); + CHECK(inv.count() == 2); + + inv.swap(hand_l_ent, hand_r_ent); + + CHECK(inv.get("hand_l") == hand_r_ent); + CHECK(inv.get("hand_r") == hand_l_ent); + + CHECK(inv.count() == 2); + } + + fuc2::Set TESTS{ + .name="inventory", + .tests={ + TEST(test_base_test), + TEST(test_test_swapping_items), + } + }; } diff --git a/tests/lighting.cpp b/tests/lighting.cpp index b8cd308..1ac6ce8 100644 --- a/tests/lighting.cpp +++ b/tests/lighting.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,35 +8,47 @@ #include "algos/point.hpp" using namespace lighting; +using namespace fuc2; -TEST_CASE("lighting a map works", "[lighting]") { - GameDB::init(); - auto& level = GameDB::current_level(); - auto& map = *level.map; +namespace lighting_tests { - Point light1, light2; + void test_lighting_a_map_works() { + GameDB::init(); + auto& level = GameDB::current_level(); + auto& map = *level.map; - REQUIRE(map.place_entity(0, light1)); - REQUIRE(map.place_entity(0, light1)); + Point light1, light2; - LightSource source1{6, 1.0}; - LightSource source2{4,3}; + CHECK(map.place_entity(0, light1)); + CHECK(map.place_entity(0, light1)); - LightRender lr(map.walls()); + LightSource source1{6, 1.0}; + LightSource source2{4,3}; - lr.reset_light(); + LightRender lr(map.walls()); - lr.set_light_target(light1); - lr.set_light_target(light2); + lr.reset_light(); - lr.path_light(map.walls()); + lr.set_light_target(light1); + lr.set_light_target(light2); - lr.render_light(source1, light1); - lr.render_light(source2, light2); + lr.path_light(map.walls()); - lr.clear_light_target(light1); - lr.clear_light_target(light2); + lr.render_light(source1, light1); + lr.render_light(source2, light2); - Matrix &lighting = lr.lighting(); - (void)lighting; + lr.clear_light_target(light1); + lr.clear_light_target(light2); + + Matrix &lighting = lr.lighting(); + (void)lighting; + } + + + fuc2::Set TESTS{ + .name="lighting", + .tests={ + TEST(test_lighting_a_map_works), + } + }; } diff --git a/tests/loot.cpp b/tests/loot.cpp index 6f72bd2..bf09426 100644 --- a/tests/loot.cpp +++ b/tests/loot.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "game/components.hpp" @@ -6,16 +6,26 @@ using namespace fmt; using namespace components; +using namespace fuc2; -TEST_CASE("test the loot ui", "[loot]") { - auto items = settings::get("assets/items.json"); - DinkyECS::World world; - auto torch = world.entity(); - auto& data = items["TORCH_BAD"]; +namespace loot_tests { + void test_test_the_loot_ui() { + auto items = settings::get("assets/items.json"); + DinkyECS::World world; + auto torch = world.entity(); + auto& data = items["TORCH_BAD"]; - components::init(); - components::configure_entity(world, torch, data["components"]); + components::init(); + components::configure_entity(world, torch, data["components"]); - auto& torch_sprite = world.get(torch); - REQUIRE(torch_sprite.name == "torch_horizontal_floor"); + auto& torch_sprite = world.get(torch); + CHECK(torch_sprite.name == "torch_horizontal_floor"); + } + + fuc2::Set TESTS{ + .name="loot", + .tests={ + TEST(test_test_the_loot_ui), + } + }; } diff --git a/tests/main.cpp b/tests/main.cpp index d3f60f9..9c39b2f 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -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); } diff --git a/tests/map.cpp b/tests/map.cpp index cf9ef69..4d0530f 100644 --- a/tests/map.cpp +++ b/tests/map.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -12,74 +12,86 @@ using namespace fmt; using namespace nlohmann; using std::string; +using namespace fuc2; -json load_test_data(const string &fname) { - std::ifstream infile(fname); - return json::parse(infile); -} +namespace map_tests { + json load_test_data(const string &fname) { + std::ifstream infile(fname); + return json::parse(infile); + } -TEST_CASE("camera control", "[map]") { - GameDB::init(); + void test_camera_control() { + GameDB::init(); - auto& level = GameDB::current_level(); - auto& map = *level.map; + auto& level = GameDB::current_level(); + auto& map = *level.map; - Point center = map.center_camera({10,10}, 5, 5); + Point center = map.center_camera({10,10}, 5, 5); - // map.dump(center.x, center.y); - REQUIRE(center.x == 8); - REQUIRE(center.y == 8); + // map.dump(center.x, center.y); + CHECK(center.x == 8); + CHECK(center.y == 8); - Point translation = map.map_to_camera({10,10}, center); + 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]") { - GameDB::init(); + void test_map_placement_test() { + GameDB::init(); - for(int i = 0; i < 10; i++) { - auto& level = GameDB::create_level(); + for(int i = 0; i < 10; i++) { + auto& level = GameDB::create_level(); - for(size_t rnum = 0; rnum < level.map->room_count(); rnum++) { - Point pos; + 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]") { - GameDB::init(); + void test_map_image_test() { + GameDB::init(); - auto& level = GameDB::current_level(); - Matrix map_tiles = matrix::make(7,7); - EntityGrid entity_map; + auto& level = GameDB::current_level(); + Matrix map_tiles = matrix::make(7,7); + EntityGrid entity_map; - auto render = std::make_shared(); - sf::Sprite sprite{render->getTexture()}; - auto player = level.world->get_the(); - auto& player_pos = level.world->get(player.entity); - auto player_display = level.world->get(player.entity).display; + auto render = std::make_shared(); + sf::Sprite sprite{render->getTexture()}; + auto player = level.world->get_the(); + auto& player_pos = level.world->get(player.entity); + auto player_display = level.world->get(player.entity).display; - for(matrix::each_row it{level.map->walls()}; it.next();) { - player_pos.location.x = it.x; - player_pos.location.y = it.y; - System::draw_map(map_tiles, entity_map); - System::render_map(map_tiles, entity_map, *render, 2, player_display); + for(matrix::each_row it{level.map->walls()}; it.next();) { + player_pos.location.x = it.x; + player_pos.location.y = it.y; + System::draw_map(map_tiles, entity_map); + System::render_map(map_tiles, entity_map, *render, 2, player_display); - // randomly test about 80% of them - if(Random::uniform(0, 100) < 20) break; + // randomly test about 80% of them + if(Random::uniform(0, 100) < 20) break; #ifdef TEST_RENDER - // 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); + // 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)); + CHECK(worked); #endif + } } + + fuc2::Set TESTS{ + .name="map", + .tests={ + TEST(test_camera_control), + TEST(test_map_placement_test), + TEST(test_map_image_test), + } + }; } diff --git a/tests/matrix.cpp b/tests/matrix.cpp index 993f52b..e01a97e 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "game/config.hpp" @@ -13,265 +13,283 @@ using namespace nlohmann; using namespace fmt; +using namespace fuc2; using std::string, std::shared_ptr; using matrix::Matrix; -std::shared_ptr make_map() { - GameDB::init(); - return GameDB::current_level().map; -} - -// BUG: create a test that randomizes a map then does matrix ops on it - -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(-10,10); - } - } -} - -TEST_CASE("thrash matrix iterators", "[matrix]") { - for(int count = 0; count < 5; count++) { - size_t width = Random::uniform(1, 100); - size_t height = Random::uniform(1, 100); - - Matrix test(height, matrix::Row(width)); - random_matrix(test); - - // first make a randomized matrix - matrix::each_cell cells{test}; - cells.next(); // kick off the other iterator - - for(matrix::each_row it{test}; - it.next(); cells.next()) - { - REQUIRE(test[cells.y][cells.x] == test[it.y][it.x]); - } - } -} - -TEST_CASE("thrash box distance iterators", "[matrix]") { - size_t width = Random::uniform(10, 21); - size_t height = Random::uniform(10, 25); - - Matrix result(height, matrix::Row(width)); - matrix::assign(result, 0); - - size_t size = Random::uniform(4, 10); - - Point target{width/2, height/2}; - matrix::box box{result, target.x, target.y, size}; - while(box.next()) { - result[box.y][box.x] = box.distance(); +namespace matrix_tests { + std::shared_ptr make_map() { + GameDB::init(); + return GameDB::current_level().map; } - // matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}", - // matrix::width(result), matrix::height(result), - // target.x, target.y, box.right - box.left, box.bottom - box.top, size), - // result, target.x, target.y); -} + // BUG: create a test that randomizes a map then does matrix ops on it -TEST_CASE("thrash box iterators", "[matrix]") { - for(int count = 0; count < 5; count++) { - size_t width = Random::uniform(1, 25); - size_t height = Random::uniform(1, 33); - - Matrix test(height, matrix::Row(width)); - random_matrix(test); - - // this will be greater than the random_matrix cells - int test_i = Random::uniform(20,30); - - // go through every cell - for(matrix::each_cell target{test}; target.next();) { - PointList result; - // make a random size box - size_t size = Random::uniform(1, 33); - matrix::box box{test, target.x, target.y, size}; - - while(box.next()) { - test[box.y][box.x] = test_i; - result.push_back({box.x, box.y}); - } - - for(auto point : result) { - REQUIRE(test[point.y][point.x] == test_i); - test[point.y][point.x] = 10; // kind of reset it for another try + 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(-10,10); } } } -} -TEST_CASE("thrash compass iterators", "[matrix]") { - for(int count = 0; count < 5; count++) { - size_t width = Random::uniform(1, 25); - size_t height = Random::uniform(1, 33); + void test_thrash_matrix_iterators() { + for(int count = 0; count < 5; count++) { + size_t width = Random::uniform(1, 100); + size_t height = Random::uniform(1, 100); - Matrix test(height, matrix::Row(width)); - random_matrix(test); + Matrix test(height, matrix::Row(width)); + random_matrix(test); - // this will be greater than the random_matrix cells - int test_i = Random::uniform(20,30); + // first make a randomized matrix + matrix::each_cell cells{test}; + cells.next(); // kick off the other iterator - // go through every cell - for(matrix::each_cell target{test}; target.next();) { - PointList result; - // make a random size box - matrix::compass compass{test, target.x, target.y}; - - while(compass.next()) { - test[compass.y][compass.x] = test_i; - result.push_back({compass.x, compass.y}); - } - - for(auto point : result) { - REQUIRE(test[point.y][point.x] == test_i); - test[point.y][point.x] = 10; // kind of reset it for another try + for(matrix::each_row it{test}; + it.next(); cells.next()) + { + CHECK(test[cells.y][cells.x] == test[it.y][it.x]); } } } -} -TEST_CASE("prototype line algorithm", "[matrix]") { - size_t width = Random::uniform(10, 12); - size_t height = Random::uniform(10, 15); - Map map(width,height); - // create a target for the paths - Point start{.x=map.width() / 2, .y=map.height()/2}; + void test_thrash_box_distance_iterators() { + size_t width = Random::uniform(10, 21); + size_t height = Random::uniform(10, 25); - for(matrix::box box{map.walls(), start.x, start.y, 3}; - box.next();) - { - Matrix result = map.walls(); - result[start.y][start.x] = 1; - Point end{.x=box.x, .y=box.y}; + Matrix result(height, matrix::Row(width)); + matrix::assign(result, 0); - for(matrix::line it{start, end}; it.next();) - { - REQUIRE(map.inmap(it.x, it.y)); - result[it.y][it.x] = 15; + size_t size = Random::uniform(4, 10); + + Point target{width/2, height/2}; + matrix::box box{result, target.x, target.y, size}; + while(box.next()) { + result[box.y][box.x] = box.distance(); } - result[start.y][start.x] = 15; + // matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}", + // matrix::width(result), matrix::height(result), + // target.x, target.y, box.right - box.left, box.bottom - box.top, size), + // result, target.x, target.y); + } - // matrix::dump("RESULT AFTER LINE", result, end.x, end.y); + void test_thrash_box_iterators() { + for(int count = 0; count < 5; count++) { + size_t width = Random::uniform(1, 25); + size_t height = Random::uniform(1, 33); - bool f_found = false; - for(matrix::each_cell it{result}; it.next();) { - if(result[it.y][it.x] == 15) { - f_found = true; - break; + Matrix test(height, matrix::Row(width)); + random_matrix(test); + + // this will be greater than the random_matrix cells + int test_i = Random::uniform(20,30); + + // go through every cell + for(matrix::each_cell target{test}; target.next();) { + PointList result; + // make a random size box + size_t size = Random::uniform(1, 33); + matrix::box box{test, target.x, target.y, size}; + + while(box.next()) { + test[box.y][box.x] = test_i; + result.push_back({box.x, box.y}); + } + + for(auto point : result) { + CHECK(test[point.y][point.x] == test_i); + test[point.y][point.x] = 10; // kind of reset it for another try + } } } - - REQUIRE(f_found); } -} -TEST_CASE("prototype circle algorithm", "[matrix]") { - for(int count = 0; count < 5; count++) { - size_t width = Random::uniform(10, 13); + void test_thrash_compass_iterators() { + for(int count = 0; count < 5; count++) { + size_t width = Random::uniform(1, 25); + size_t height = Random::uniform(1, 33); + + Matrix test(height, matrix::Row(width)); + random_matrix(test); + + // this will be greater than the random_matrix cells + int test_i = Random::uniform(20,30); + + // go through every cell + for(matrix::each_cell target{test}; target.next();) { + PointList result; + // make a random size box + matrix::compass compass{test, target.x, target.y}; + + while(compass.next()) { + test[compass.y][compass.x] = test_i; + result.push_back({compass.x, compass.y}); + } + + for(auto point : result) { + CHECK(test[point.y][point.x] == test_i); + test[point.y][point.x] = 10; // kind of reset it for another try + } + } + } + } + + void test_prototype_line_algorithm() { + size_t width = Random::uniform(10, 12); size_t height = Random::uniform(10, 15); - int pos_mod = Random::uniform(-3,3); Map map(width,height); - // create a target for the paths - Point start{.x=map.width() / 2 + pos_mod, .y=map.height()/2 + pos_mod}; + Point start{.x=map.width() / 2, .y=map.height()/2}; - for(float radius = 1.0f; radius < 4.0f; radius += 0.1f) { - // use an empty map + for(matrix::box box{map.walls(), start.x, start.y, 3}; + box.next();) + { Matrix result = map.walls(); + result[start.y][start.x] = 1; + Point end{.x=box.x, .y=box.y}; - for(matrix::circle it{result, start, radius}; it.next();) { - 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))); - result[it.y][x] += 1; + for(matrix::line it{start, end}; it.next();) + { + CHECK(map.inmap(it.x, it.y)); + result[it.y][it.x] = 15; + } + + result[start.y][start.x] = 15; + + // matrix::dump("RESULT AFTER LINE", result, end.x, end.y); + + bool f_found = false; + for(matrix::each_cell it{result}; it.next();) { + if(result[it.y][it.x] == 15) { + f_found = true; + break; } } - // matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y); + CHECK(f_found); } } -} -TEST_CASE("viewport iterator", "[matrix]") { - components::init(); - textures::init(); - GameDB::init(); - size_t width = Random::uniform(20, 22); - size_t height = Random::uniform(21, 25); - shared_ptr map = make_map(); + void test_prototype_circle_algorithm() { + for(int count = 0; count < 5; count++) { + size_t width = Random::uniform(10, 13); + size_t height = Random::uniform(10, 15); + int pos_mod = Random::uniform(-3,3); + Map map(width,height); - size_t view_width = width/2; - size_t view_height = height/2; - Point player; - REQUIRE(map->place_entity(1, player)); - Point start = map->center_camera(player, view_width, view_height); + // create a target for the paths + Point start{.x=map.width() / 2 + pos_mod, .y=map.height()/2 + pos_mod}; - size_t end_x = std::min(view_width, map->width() - start.x); - size_t end_y = std::min(view_height, map->height() - start.y); + for(float radius = 1.0f; radius < 4.0f; radius += 0.1f) { + // use an empty map + Matrix result = map.walls(); - matrix::viewport it{map->walls(), start, int(view_width), int(view_height)}; + for(matrix::circle it{result, start, radius}; it.next();) { + 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)); + 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; + } + } - for(size_t y = 0; y < end_y; ++y) { - for(size_t x = 0; x < end_x && it.next(); ++x) { - // still working on this - } - } -} - -TEST_CASE("random rectangle", "[matrix]") { - components::init(); - for(int i = 0; i < 5; i++) { - shared_ptr map = make_map(); - map->invert_space(); - auto wall_copy = map->walls(); - - for(size_t rnum = 0; rnum < map->room_count(); rnum++) { - Room &room = map->room(rnum); - Point pos; - - 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); - - wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5; + // matrix::dump(format("RESULT AFTER CIRCLE radius {}", radius), result, start.x, start.y); } } - // matrix::dump("WALLS FILLED", wall_copy); } -} -TEST_CASE("standard rectangle", "[matrix]") { - components::init(); - for(int i = 0; i < 5; i++) { + void test_viewport_iterator() { + components::init(); + textures::init(); + GameDB::init(); + size_t width = Random::uniform(20, 22); + size_t height = Random::uniform(21, 25); shared_ptr map = make_map(); - auto wall_copy = map->walls(); - for(size_t rnum = 0; rnum < map->room_count(); rnum++) { - Room &room = map->room(rnum); - Point pos; + size_t view_width = width/2; + size_t view_height = height/2; + Point player; + CHECK(map->place_entity(1, player)); + Point start = map->center_camera(player, view_width, view_height); - 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); + size_t end_x = std::min(view_width, map->width() - start.x); + size_t end_y = std::min(view_height, map->height() - start.y); - wall_copy[it.y][it.x] = wall_copy[it.y][it.x] + 5; + matrix::viewport it{map->walls(), start, int(view_width), int(view_height)}; + + for(size_t y = 0; y < end_y; ++y) { + for(size_t x = 0; x < end_x && it.next(); ++x) { + // still working on this } } - - // matrix::dump("WALLS FILLED", wall_copy); } + + void test_random_rectangle() { + components::init(); + for(int i = 0; i < 5; i++) { + shared_ptr map = make_map(); + map->invert_space(); + auto wall_copy = map->walls(); + + for(size_t rnum = 0; rnum < map->room_count(); rnum++) { + Room &room = map->room(rnum); + Point pos; + + for(matrix::rando_rect it{map->walls(), room.x, room.y, room.width, room.height}; it.next();) + { + 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); + } + } + + void test_standard_rectangle() { + components::init(); + for(int i = 0; i < 5; i++) { + shared_ptr map = make_map(); + auto wall_copy = map->walls(); + + for(size_t rnum = 0; rnum < map->room_count(); rnum++) { + Room &room = map->room(rnum); + Point pos; + + for(matrix::rectangle it{map->walls(), room.x, room.y, room.width, room.height}; it.next();) + { + 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); + } + } + + 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), + } + }; } diff --git a/tests/mazes.cpp b/tests/mazes.cpp index d66a71b..2ddad45 100644 --- a/tests/mazes.cpp +++ b/tests/mazes.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "algos/matrix.hpp" @@ -11,150 +11,152 @@ using std::string; using matrix::Matrix; +using namespace fuc2; -TEST_CASE("hunt-and-kill", "[mazes]") { - Map map(21, 21); - maze::Builder maze(map); - - maze.hunt_and_kill(); - REQUIRE(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); - - if(DUMP) maze.dump("ROOM MAZE"); - - REQUIRE(map.$dead_ends.size() > 0); - REQUIRE(map.$rooms.size() > 0); -} - -TEST_CASE("hunt-and-kill box", "[mazes]") { - for(int i = 25; i < 65; i += 2) { - Map map(i, i); +namespace mazes_tests { + void test_hunt_and_kill() { + Map map(21, 21); maze::Builder maze(map); maze.hunt_and_kill(); - maze.clear(); - maze.inner_box(6, 4); + CHECK(maze.repair() == true); + + if(DUMP) maze.dump("BASIC MAZE"); + maze.randomize_rooms(ROOM_SIZE); - - maze.hunt_and_kill(); - maze.open_box(6); - maze.place_doors(); - auto valid = maze.repair(); - - if(i == 41 && DUMP) { - maze.dump(valid ? "INNER BOX" : "FAILED BOX"); - } - } -} - -TEST_CASE("hunt-and-kill ring", "[mazes]") { - Map map(21, 21); - maze::Builder maze(map); - - maze.inner_donut(5.5, 3.5); - maze.hunt_and_kill(); - REQUIRE(maze.repair() == true); - - if(DUMP) maze.dump("INNER RING"); - - REQUIRE(maze.$rooms.size() == 0); -} - -TEST_CASE("hunt-and-kill fissure", "[mazes]") { - Map map(21, 21); - maze::Builder maze(map); - - maze.divide({3,3}, {19,18}); - maze.hunt_and_kill(); - REQUIRE(maze.repair() == true); - - if(DUMP) maze.dump("FISSURE MAZE"); - - REQUIRE(maze.$rooms.size() == 0); -} - -TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") { - Map map(21, 21); - maze::Builder maze(map); - - maze.hunt_and_kill(); - maze.remove_dead_ends(); - REQUIRE(maze.repair() == true); - - if(DUMP) maze.dump("NO DEAD ENDS"); -} - -TEST_CASE("hunt-and-kill too much", "[mazes]") { - for(int i = 25; i < 65; i += 2) { - Map map(i, i); - maze::Builder maze(map); - - maze.hunt_and_kill(); - maze.randomize_rooms(ROOM_SIZE); - maze.clear(); - maze.inner_donut(9, 4); - maze.divide({3,3}, {15,16}); maze.hunt_and_kill(); maze.place_doors(); - auto valid = maze.repair(); + CHECK(maze.repair() == true); - if(i == 41 && DUMP && valid) { - maze.dump("COMBINED"); - } + if(DUMP) maze.dump("ROOM MAZE"); + + CHECK(map.$dead_ends.size() > 0); + CHECK(map.$rooms.size() > 0); } -} -TEST_CASE("hunt-and-kill validator", "[mazes]") { - bool valid = true; - Stats mofm; - - for(int i = 0; i < 10; i++) { - Stats door_prob; - - do { - Map map(33, 33); + void test_hunt_and_kill_box() { + for(int i = 25; i < 65; i += 2) { + Map map(i, i); maze::Builder maze(map); maze.hunt_and_kill(); maze.clear(); maze.inner_box(6, 4); maze.randomize_rooms(ROOM_SIZE); + maze.hunt_and_kill(); maze.open_box(6); maze.place_doors(); - valid = maze.repair(); + auto valid = maze.repair(); - if(i == 9 && DUMP) { - maze.dump(valid ? "VALIDATED" : "FAILED!"); + if(i == 41 && DUMP) { + maze.dump(valid ? "INNER BOX" : "FAILED BOX"); } - door_prob.sample(valid); - } while(!valid); - - if(DUMP) door_prob.dump(); - mofm.sample(door_prob.mean()); + } } - if(DUMP) { - fmt::println("FINAL m-of-m"); - mofm.dump(); + 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(); + CHECK(maze.repair() == true); + + if(DUMP) maze.dump("INNER RING"); + + CHECK(maze.$rooms.size() == 0); } - REQUIRE(mofm.mean() > 0.20); -} + void test_hunt_and_kill_fissure() { + Map map(21, 21); + maze::Builder maze(map); + + maze.divide({3,3}, {19,18}); + maze.hunt_and_kill(); + CHECK(maze.repair() == true); + + if(DUMP) maze.dump("FISSURE MAZE"); + + CHECK(maze.$rooms.size() == 0); + } + + void test_hunt_and_kill_no_dead_ends() { + Map map(21, 21); + maze::Builder maze(map); + + maze.hunt_and_kill(); + maze.remove_dead_ends(); + CHECK(maze.repair() == true); + + if(DUMP) maze.dump("NO DEAD ENDS"); + } + + void test_hunt_and_kill_too_much() { + for(int i = 25; i < 65; i += 2) { + Map map(i, i); + maze::Builder maze(map); + + maze.hunt_and_kill(); + maze.randomize_rooms(ROOM_SIZE); + maze.clear(); + maze.inner_donut(9, 4); + maze.divide({3,3}, {15,16}); + maze.hunt_and_kill(); + maze.place_doors(); + auto valid = maze.repair(); + + if(i == 41 && DUMP && valid) { + maze.dump("COMBINED"); + } + } + } + + void test_hunt_and_kill_validator() { + bool valid = true; + Stats mofm; + + for(int i = 0; i < 10; i++) { + Stats door_prob; + + do { + Map map(33, 33); + maze::Builder maze(map); + + maze.hunt_and_kill(); + maze.clear(); + maze.inner_box(6, 4); + maze.randomize_rooms(ROOM_SIZE); + maze.hunt_and_kill(); + maze.open_box(6); + maze.place_doors(); + valid = maze.repair(); + + if(i == 9 && DUMP) { + maze.dump(valid ? "VALIDATED" : "FAILED!"); + } + door_prob.sample(valid); + } while(!valid); + + if(DUMP) door_prob.dump(); + mofm.sample(door_prob.mean()); + } + + if(DUMP) { + fmt::println("FINAL m-of-m"); + mofm.dump(); + } + + CHECK(mofm.mean() > 0.20); + } -TEST_CASE("hunt-and-kill scripting", "[mazes]") { - using namespace nlohmann::literals; + void test_hunt_and_kill_scripting() { + using namespace nlohmann::literals; - // go up by 2 to keep odd - for(int i = 0; i < 20; i+=2) { - auto script = R"( + // go up by 2 to keep odd + for(int i = 0; i < 20; i+=2) { + auto script = R"( [ {"action": "hunt_and_kill"}, {"action": "clear"}, @@ -169,14 +171,29 @@ TEST_CASE("hunt-and-kill scripting", "[mazes]") { ] )"_json; - Map map(23+i, 23+i); - auto [maze, valid] = maze::script(map, script); + Map map(23+i, 23+i); + auto [maze, valid] = maze::script(map, script); - if(valid) { - REQUIRE(maze.validate() == true); - REQUIRE(map.INVARIANT() == true); + if(valid) { + CHECK(maze.validate() == true); + CHECK(map.INVARIANT() == true); + } + + if(DUMP) maze.dump(valid ? "SCRIPTED" : "SCRIPTED FAIL!"); } - - 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), + } + }; } diff --git a/tests/meson.build b/tests/meson.build index 07d4a87..72bb61c 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -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',