#include #include #include #include "../common/config.h" #include "../common/throwing_allocator.hpp" TEST(Flow, Constructors) { entt::flow flow{}; ASSERT_EQ(flow.size(), 0u); flow = entt::flow{std::allocator{}}; ASSERT_EQ(flow.size(), 0u); flow.bind(0); flow.bind(3); flow.bind(99); ASSERT_EQ(flow.size(), 3u); entt::flow temp{flow, flow.get_allocator()}; entt::flow other{std::move(flow), flow.get_allocator()}; ASSERT_EQ(flow.size(), 0u); ASSERT_EQ(other.size(), 3u); ASSERT_EQ(other[0u], 0u); ASSERT_EQ(other[1u], 3u); ASSERT_EQ(other[2u], 99u); } TEST(Flow, Copy) { entt::flow flow{}; flow.bind(0); flow.bind(3); flow.bind(99); entt::flow other{flow}; ASSERT_EQ(flow.size(), 3u); ASSERT_EQ(other.size(), 3u); ASSERT_EQ(other[0u], 0u); ASSERT_EQ(other[1u], 3u); ASSERT_EQ(other[2u], 99u); flow.bind(1); other.bind(2); other = flow; ASSERT_EQ(other.size(), 4u); ASSERT_EQ(flow.size(), 4u); ASSERT_EQ(other[0u], 0u); ASSERT_EQ(other[1u], 3u); ASSERT_EQ(other[2u], 99u); ASSERT_EQ(other[3u], 1u); } TEST(Flow, Move) { entt::flow flow{}; flow.bind(0); flow.bind(3); flow.bind(99); entt::flow other{std::move(flow)}; ASSERT_EQ(flow.size(), 0u); ASSERT_EQ(other.size(), 3u); ASSERT_EQ(other[0u], 0u); ASSERT_EQ(other[1u], 3u); ASSERT_EQ(other[2u], 99u); flow = {}; flow.bind(1); other.bind(2); other = std::move(flow); ASSERT_EQ(other.size(), 1u); ASSERT_EQ(flow.size(), 0u); ASSERT_EQ(other[0u], 1u); } TEST(Flow, Swap) { entt::flow flow{}; entt::flow other{}; flow.bind(7); ASSERT_EQ(other.size(), 0u); ASSERT_EQ(flow.size(), 1u); ASSERT_EQ(flow[0u], 7u); flow.swap(other); ASSERT_EQ(other.size(), 1u); ASSERT_EQ(flow.size(), 0u); ASSERT_EQ(other[0u], 7u); } TEST(Flow, Clear) { entt::flow flow{}; flow.bind(0); flow.bind(99); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow[0u], 0u); ASSERT_EQ(flow[1u], 99u); flow.clear(); ASSERT_EQ(flow.size(), 0u); } TEST(Flow, Set) { entt::flow flow{}; flow.bind(0).set(10, true).bind(1).set(10, true).set(11, false); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_NE(graph.edges().cbegin(), graph.edges().cend()); ASSERT_TRUE(graph.contains(0u, 1u)); ASSERT_FALSE(graph.contains(1u, 0u)); } TEST(Flow, RO) { entt::flow flow{}; flow.bind(0).ro(10).bind(1).ro(10).ro(11); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_EQ(graph.edges().cbegin(), graph.edges().cend()); } TEST(Flow, RangeRO) { entt::flow flow{}; const entt::id_type res[2u]{10, 11}; flow.bind(0).ro(res, res + 1).bind(1).ro(res, res + 2); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_EQ(graph.edges().cbegin(), graph.edges().cend()); } TEST(Flow, RW) { entt::flow flow{}; flow.bind(0).rw(10).bind(1).rw(10).rw(11); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_NE(graph.edges().cbegin(), graph.edges().cend()); ASSERT_TRUE(graph.contains(0u, 1u)); ASSERT_FALSE(graph.contains(1u, 0u)); } TEST(Flow, RangeRW) { entt::flow flow{}; const entt::id_type res[2u]{10, 11}; flow.bind(0).rw(res, res + 1).bind(1).rw(res, res + 2); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_NE(graph.edges().cbegin(), graph.edges().cend()); ASSERT_TRUE(graph.contains(0u, 1u)); ASSERT_FALSE(graph.contains(1u, 0u)); } TEST(Flow, Graph) { using namespace entt::literals; entt::flow flow{}; flow.bind("task_0"_hs) .ro("resource_0"_hs) .rw("resource_1"_hs); flow.bind("task_1"_hs) .ro("resource_0"_hs) .rw("resource_2"_hs); flow.bind("task_2"_hs) .ro("resource_1"_hs) .rw("resource_3"_hs); flow.bind("task_3"_hs) .rw("resource_1"_hs) .ro("resource_2"_hs); flow.bind("task_4"_hs) .rw("resource_0"_hs); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 5u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_EQ(flow[0u], "task_0"_hs); ASSERT_EQ(flow[1u], "task_1"_hs); ASSERT_EQ(flow[2u], "task_2"_hs); ASSERT_EQ(flow[3u], "task_3"_hs); ASSERT_EQ(flow[4u], "task_4"_hs); auto it = graph.edges().cbegin(); const auto last = graph.edges().cend(); ASSERT_NE(it, last); ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{2u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{4u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{3u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{4u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{3u})); ASSERT_EQ(it, last); } TEST(Flow, Sync) { using namespace entt::literals; entt::flow flow{}; flow.bind("task_0"_hs) .ro("resource_0"_hs); flow.bind("task_1"_hs) .rw("resource_1"_hs); flow.bind("task_2"_hs) .sync(); flow.bind("task_3"_hs) .ro("resource_0"_hs) .rw("resource_2"_hs); flow.bind("task_4"_hs) .ro("resource_2"_hs); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 5u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_EQ(flow[0u], "task_0"_hs); ASSERT_EQ(flow[1u], "task_1"_hs); ASSERT_EQ(flow[2u], "task_2"_hs); ASSERT_EQ(flow[3u], "task_3"_hs); ASSERT_EQ(flow[4u], "task_4"_hs); auto it = graph.edges().cbegin(); const auto last = graph.edges().cend(); ASSERT_NE(it, last); ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{2u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{2u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{3u})); ASSERT_EQ(*it++, std::make_pair(std::size_t{3u}, std::size_t{4u})); ASSERT_EQ(it, last); } ENTT_DEBUG_TEST(FlowDeathTest, NoBind) { entt::flow flow{}; ASSERT_DEATH(flow.ro(42), ""); ASSERT_DEATH(flow.rw(42), ""); flow.bind(0); ASSERT_NO_FATAL_FAILURE(flow.ro(1)); ASSERT_NO_FATAL_FAILURE(flow.rw(2)); } TEST(Flow, DirectRebind) { entt::flow flow{}; flow.bind(0).ro(10).rw(10).bind(1).ro(10); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_NE(graph.edges().cbegin(), graph.edges().cend()); ASSERT_TRUE(graph.contains(0u, 1u)); ASSERT_FALSE(graph.contains(1u, 0u)); } TEST(Flow, DeferredRebind) { entt::flow flow{}; flow.bind(0).ro(10).bind(1).ro(10).bind(0).rw(10); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_NE(graph.edges().cbegin(), graph.edges().cend()); ASSERT_FALSE(graph.contains(0u, 1u)); ASSERT_TRUE(graph.contains(1u, 0u)); } TEST(Flow, Loop) { entt::flow flow{}; flow.bind(0).rw(10).bind(1).ro(10).bind(0).rw(10); auto graph = flow.graph(); ASSERT_EQ(flow.size(), 2u); ASSERT_EQ(flow.size(), graph.size()); ASSERT_NE(graph.edges().cbegin(), graph.edges().cend()); ASSERT_TRUE(graph.contains(0u, 1u)); ASSERT_TRUE(graph.contains(1u, 0u)); } TEST(Flow, ThrowingAllocator) { using allocator = test::throwing_allocator; using task_allocator = test::throwing_allocator>; using task_exception = typename task_allocator::exception_type; entt::basic_flow flow{}; task_allocator::trigger_on_allocate = true; ASSERT_EQ(flow.size(), 0u); ASSERT_THROW(flow.bind(1), task_exception); ASSERT_EQ(flow.size(), 0u); flow.bind(1); ASSERT_EQ(flow.size(), 1u); }