Add catch2
This commit is contained in:
parent
5665b1de6e
commit
6b07f40c1f
4 changed files with 269 additions and 4 deletions
|
@ -5,10 +5,23 @@ set(PROJECT_NAME dinkyecs_sandbox)
|
||||||
project(${PROJECT_NAME})
|
project(${PROJECT_NAME})
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
file(GLOB PROJECT_SRC *.cpp *.hpp *.h)
|
|
||||||
|
|
||||||
find_package(nlohmann_json)
|
find_package(nlohmann_json)
|
||||||
find_package(fmt)
|
find_package(fmt)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${PROJECT_SRC})
|
add_library(dinkyecs STATIC dbc.hpp dbc.cpp dinkyecs.hpp)
|
||||||
target_link_libraries(${PROJECT_NAME} nlohmann_json::nlohmann_json fmt::fmt)
|
target_link_libraries(dinkyecs ${PROJECT_DEPS} nlohmann_json::nlohmann_json fmt::fmt)
|
||||||
|
|
||||||
|
set(PROJECT_DEPS dinkyecs)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME} main.cpp)
|
||||||
|
target_link_libraries(${PROJECT_NAME} ${PROJECT_DEPS})
|
||||||
|
|
||||||
|
#######################################################
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
file(GLOB TEST_SRC ./tests/*.cpp ./tests/*.hpp ./tests/*.h)
|
||||||
|
add_executable(tests ${TEST_SRC})
|
||||||
|
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain ${PROJECT_DEPS})
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
catch_discover_tests(tests)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[requires]
|
[requires]
|
||||||
nlohmann_json/3.11.3
|
nlohmann_json/3.11.3
|
||||||
|
catch2/3.8.0
|
||||||
fmt/11.1.3
|
fmt/11.1.3
|
||||||
|
|
||||||
[generators]
|
[generators]
|
||||||
|
|
4
main.cpp
4
main.cpp
|
@ -90,9 +90,13 @@ int main()
|
||||||
configure(world, test);
|
configure(world, test);
|
||||||
|
|
||||||
Position &pos = world.get<Position>(test);
|
Position &pos = world.get<Position>(test);
|
||||||
|
Position &pos2 = world.get<Position>(test);
|
||||||
REQUIRE(pos.location.x == 10);
|
REQUIRE(pos.location.x == 10);
|
||||||
REQUIRE(pos.location.y == 20);
|
REQUIRE(pos.location.y == 20);
|
||||||
|
|
||||||
|
REQUIRE(pos2.location.x == 10);
|
||||||
|
REQUIRE(pos2.location.y == 20);
|
||||||
|
|
||||||
Velocity &vel = world.get<Velocity>(test);
|
Velocity &vel = world.get<Velocity>(test);
|
||||||
REQUIRE(vel.x == 1);
|
REQUIRE(vel.x == 1);
|
||||||
REQUIRE(vel.y == 2);
|
REQUIRE(vel.y == 2);
|
||||||
|
|
247
tests/dinkyecs.cpp
Normal file
247
tests/dinkyecs.cpp
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch2/catch_all.hpp>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include "../dinkyecs.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
using namespace fmt;
|
||||||
|
using DinkyECS::Entity;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
size_t x;
|
||||||
|
size_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Player {
|
||||||
|
string name;
|
||||||
|
Entity eid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Position {
|
||||||
|
Point location;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Motion {
|
||||||
|
int dx;
|
||||||
|
int dy;
|
||||||
|
bool random=false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Velocity {
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Gravity {
|
||||||
|
double level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DaGUI {
|
||||||
|
int event;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using a function catches instances where I'm not copying
|
||||||
|
* the data into the world.
|
||||||
|
*/
|
||||||
|
void configure(DinkyECS::World &world, Entity &test) {
|
||||||
|
println("---Configuring the base system.");
|
||||||
|
Entity test2 = world.entity();
|
||||||
|
|
||||||
|
world.set<Position>(test, {10,20});
|
||||||
|
world.set<Velocity>(test, {1,2});
|
||||||
|
|
||||||
|
world.set<Position>(test2, {1,1});
|
||||||
|
world.set<Velocity>(test2, {9,19});
|
||||||
|
|
||||||
|
println("---- Setting up the player as a fact in the system.");
|
||||||
|
|
||||||
|
auto player_eid = world.entity();
|
||||||
|
Player player_info{"Zed", player_eid};
|
||||||
|
// just set some player info as a fact with the entity id
|
||||||
|
world.set_the<Player>(player_info);
|
||||||
|
|
||||||
|
world.set<Velocity>(player_eid, {0,0});
|
||||||
|
world.set<Position>(player_eid, {0,0});
|
||||||
|
|
||||||
|
auto enemy = world.entity();
|
||||||
|
world.set<Velocity>(enemy, {0,0});
|
||||||
|
world.set<Position>(enemy, {0,0});
|
||||||
|
|
||||||
|
println("--- Creating facts (singletons)");
|
||||||
|
world.set_the<Gravity>({0.9});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("confirm ECS system works", "[ecs]") {
|
||||||
|
DinkyECS::World world;
|
||||||
|
Entity test = world.entity();
|
||||||
|
|
||||||
|
configure(world, test);
|
||||||
|
|
||||||
|
Position &pos = world.get<Position>(test);
|
||||||
|
REQUIRE(pos.location.x == 10);
|
||||||
|
REQUIRE(pos.location.y == 20);
|
||||||
|
|
||||||
|
Velocity &vel = world.get<Velocity>(test);
|
||||||
|
REQUIRE(vel.x == 1);
|
||||||
|
REQUIRE(vel.y == 2);
|
||||||
|
|
||||||
|
world.query<Position>([](const auto &ent, auto &pos) {
|
||||||
|
REQUIRE(ent > 0);
|
||||||
|
REQUIRE(pos.location.x >= 0);
|
||||||
|
REQUIRE(pos.location.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
world.query<Velocity>([](const auto &ent, auto &vel) {
|
||||||
|
REQUIRE(ent > 0);
|
||||||
|
REQUIRE(vel.x >= 0);
|
||||||
|
REQUIRE(vel.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
println("--- Manually get the velocity in position system:");
|
||||||
|
world.query<Position>([&](const auto &ent, auto &pos) {
|
||||||
|
Velocity &vel = world.get<Velocity>(ent);
|
||||||
|
|
||||||
|
REQUIRE(ent > 0);
|
||||||
|
REQUIRE(pos.location.x >= 0);
|
||||||
|
REQUIRE(pos.location.y >= 0);
|
||||||
|
REQUIRE(ent > 0);
|
||||||
|
REQUIRE(vel.x >= 0);
|
||||||
|
REQUIRE(vel.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
println("--- Query only entities with Position and Velocity:");
|
||||||
|
world.query<Position, Velocity>([&](const auto &ent, auto &pos, auto &vel) {
|
||||||
|
Gravity &grav = world.get_the<Gravity>();
|
||||||
|
REQUIRE(grav.level <= 1.0f);
|
||||||
|
REQUIRE(grav.level > 0.5f);
|
||||||
|
REQUIRE(ent > 0);
|
||||||
|
REQUIRE(pos.location.x >= 0);
|
||||||
|
REQUIRE(pos.location.y >= 0);
|
||||||
|
REQUIRE(ent > 0);
|
||||||
|
REQUIRE(vel.x >= 0);
|
||||||
|
REQUIRE(vel.y >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// now remove Velocity
|
||||||
|
REQUIRE(world.has<Velocity>(test));
|
||||||
|
world.remove<Velocity>(test);
|
||||||
|
REQUIRE_THROWS(world.get<Velocity>(test));
|
||||||
|
REQUIRE(!world.has<Velocity>(test));
|
||||||
|
|
||||||
|
println("--- After remove test, should only result in test2:");
|
||||||
|
world.query<Position, Velocity>([&](const auto &ent, auto &pos, auto &vel) {
|
||||||
|
auto &in_position = world.get<Position>(ent);
|
||||||
|
auto &in_velocity = world.get<Velocity>(ent);
|
||||||
|
REQUIRE(pos.location.x >= 0);
|
||||||
|
REQUIRE(pos.location.y >= 0);
|
||||||
|
REQUIRE(in_position.location.x == pos.location.x);
|
||||||
|
REQUIRE(in_position.location.y == pos.location.y);
|
||||||
|
REQUIRE(in_velocity.x == vel.x);
|
||||||
|
REQUIRE(in_velocity.y == vel.y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GUIEvent {
|
||||||
|
HIT, MISS
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("confirm that the event system works", "[ecs]") {
|
||||||
|
DinkyECS::World world;
|
||||||
|
DinkyECS::Entity player = world.entity();
|
||||||
|
|
||||||
|
world.send<GUIEvent>(GUIEvent::HIT, player, string{"hello"});
|
||||||
|
|
||||||
|
bool ready = world.has_event<GUIEvent>();
|
||||||
|
REQUIRE(ready == true);
|
||||||
|
|
||||||
|
auto [event, entity, data] = world.recv<GUIEvent>();
|
||||||
|
REQUIRE(event == GUIEvent::HIT);
|
||||||
|
REQUIRE(entity == player);
|
||||||
|
auto &str_data = std::any_cast<string&>(data);
|
||||||
|
REQUIRE(string{"hello"} == str_data);
|
||||||
|
|
||||||
|
ready = world.has_event<GUIEvent>();
|
||||||
|
REQUIRE(ready == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("confirm copying and constants", "[ecs-constants]") {
|
||||||
|
DinkyECS::World world1;
|
||||||
|
|
||||||
|
Player player_info{"Zed", world1.entity()};
|
||||||
|
world1.set_the<Player>(player_info);
|
||||||
|
|
||||||
|
world1.set<Position>(player_info.eid, {10,10});
|
||||||
|
world1.make_constant(player_info.eid);
|
||||||
|
|
||||||
|
DinkyECS::World world2;
|
||||||
|
world1.clone_into(world2);
|
||||||
|
|
||||||
|
auto &test1 = world1.get<Position>(player_info.eid);
|
||||||
|
auto &test2 = world2.get<Position>(player_info.eid);
|
||||||
|
|
||||||
|
REQUIRE(test2.location.x == test1.location.x);
|
||||||
|
REQUIRE(test2.location.y == test1.location.y);
|
||||||
|
|
||||||
|
// check for accidental reference
|
||||||
|
test1.location.x = 100;
|
||||||
|
REQUIRE(test2.location.x != test1.location.x);
|
||||||
|
|
||||||
|
// test the facts copy over
|
||||||
|
auto &player2 = world2.get_the<Player>();
|
||||||
|
REQUIRE(player2.eid == player_info.eid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("test serialization with nlohmann::json", "[ecs-serialize]") {
|
||||||
|
/*
|
||||||
|
DinkyECS::ComponentMap component_map;
|
||||||
|
DinkyECS::Component<Position>(component_map);
|
||||||
|
DinkyECS::Component<Velocity>(component_map);
|
||||||
|
DinkyECS::Component<Motion>(component_map);
|
||||||
|
DinkyECS::Component<Gravity>(component_map);
|
||||||
|
DinkyECS::Component<DaGUI>(component_map);
|
||||||
|
|
||||||
|
auto data = R"(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"_type": "Position",
|
||||||
|
"location": {
|
||||||
|
"x": 10,
|
||||||
|
"y": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_type": "Motion",
|
||||||
|
"dx": 0,
|
||||||
|
"dy": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_type": "Velocity",
|
||||||
|
"x": 0.1,
|
||||||
|
"y": 10.2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)"_json;
|
||||||
|
|
||||||
|
DinkyECS::World world;
|
||||||
|
DinkyECS::Entity ent1 = world.entity();
|
||||||
|
DinkyECS::Entity ent2 = world.entity();
|
||||||
|
|
||||||
|
DinkyECS::configure(component_map, world, ent1, data);
|
||||||
|
DinkyECS::configure(component_map, world, ent2, data);
|
||||||
|
|
||||||
|
world.query<Position, Motion>([&](const auto ent, auto &pos, auto &motion) {
|
||||||
|
fmt::println("entity: {}; position={},{} and motion={},{} motion.random={}",
|
||||||
|
ent, pos.location.x, pos.location.y,
|
||||||
|
motion.dx, motion.dy, motion.random);
|
||||||
|
REQUIRE(pos.location.x == 10);
|
||||||
|
REQUIRE(pos.location.y == 5);
|
||||||
|
REQUIRE(motion.dx == 0);
|
||||||
|
REQUIRE(motion.dy == 1);
|
||||||
|
REQUIRE(motion.random == false);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
Loading…
Reference in a new issue