flow.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include <cstddef>
  2. #include <memory>
  3. #include <utility>
  4. #include <gtest/gtest.h>
  5. #include <entt/core/hashed_string.hpp>
  6. #include <entt/graph/flow.hpp>
  7. #include "../common/config.h"
  8. #include "../common/throwing_allocator.hpp"
  9. TEST(Flow, Constructors) {
  10. entt::flow flow{};
  11. ASSERT_EQ(flow.size(), 0u);
  12. flow = entt::flow{std::allocator<entt::id_type>{}};
  13. ASSERT_EQ(flow.size(), 0u);
  14. flow.bind(0);
  15. flow.bind(3);
  16. flow.bind(99);
  17. ASSERT_EQ(flow.size(), 3u);
  18. const entt::flow temp{flow, flow.get_allocator()};
  19. const entt::flow other{std::move(flow), flow.get_allocator()};
  20. ASSERT_EQ(flow.size(), 0u); // NOLINT
  21. ASSERT_EQ(other.size(), 3u);
  22. ASSERT_EQ(other[0u], 0u);
  23. ASSERT_EQ(other[1u], 3u);
  24. ASSERT_EQ(other[2u], 99u);
  25. }
  26. TEST(Flow, Copy) {
  27. entt::flow flow{};
  28. flow.bind(0);
  29. flow.bind(3);
  30. flow.bind(99);
  31. entt::flow other{flow};
  32. ASSERT_EQ(flow.size(), 3u);
  33. ASSERT_EQ(other.size(), 3u);
  34. ASSERT_EQ(other[0u], 0u);
  35. ASSERT_EQ(other[1u], 3u);
  36. ASSERT_EQ(other[2u], 99u);
  37. flow.bind(1);
  38. other.bind(2);
  39. other = flow;
  40. ASSERT_EQ(other.size(), 4u);
  41. ASSERT_EQ(flow.size(), 4u);
  42. ASSERT_EQ(other[0u], 0u);
  43. ASSERT_EQ(other[1u], 3u);
  44. ASSERT_EQ(other[2u], 99u);
  45. ASSERT_EQ(other[3u], 1u);
  46. }
  47. TEST(Flow, Move) {
  48. entt::flow flow{};
  49. flow.bind(0);
  50. flow.bind(3);
  51. flow.bind(99);
  52. entt::flow other{std::move(flow)};
  53. ASSERT_EQ(flow.size(), 0u); // NOLINT
  54. ASSERT_EQ(other.size(), 3u);
  55. ASSERT_EQ(other[0u], 0u);
  56. ASSERT_EQ(other[1u], 3u);
  57. ASSERT_EQ(other[2u], 99u);
  58. flow = {};
  59. flow.bind(1);
  60. other.bind(2);
  61. other = std::move(flow);
  62. ASSERT_EQ(other.size(), 1u);
  63. ASSERT_EQ(flow.size(), 0u); // NOLINT
  64. ASSERT_EQ(other[0u], 1u);
  65. }
  66. TEST(Flow, Swap) {
  67. entt::flow flow{};
  68. entt::flow other{};
  69. flow.bind(7);
  70. ASSERT_EQ(other.size(), 0u);
  71. ASSERT_EQ(flow.size(), 1u);
  72. ASSERT_EQ(flow[0u], 7u);
  73. flow.swap(other);
  74. ASSERT_EQ(other.size(), 1u);
  75. ASSERT_EQ(flow.size(), 0u);
  76. ASSERT_EQ(other[0u], 7u);
  77. }
  78. TEST(Flow, Clear) {
  79. entt::flow flow{};
  80. flow.bind(0);
  81. flow.bind(99);
  82. ASSERT_EQ(flow.size(), 2u);
  83. ASSERT_EQ(flow[0u], 0u);
  84. ASSERT_EQ(flow[1u], 99u);
  85. flow.clear();
  86. ASSERT_EQ(flow.size(), 0u);
  87. }
  88. TEST(Flow, Set) {
  89. entt::flow flow{};
  90. flow.bind(0).set(10, true).bind(1).set(10, true).set(11, false);
  91. auto graph = flow.graph();
  92. ASSERT_EQ(flow.size(), 2u);
  93. ASSERT_EQ(flow.size(), graph.size());
  94. ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
  95. ASSERT_TRUE(graph.contains(0u, 1u));
  96. ASSERT_FALSE(graph.contains(1u, 0u));
  97. }
  98. TEST(Flow, RO) {
  99. entt::flow flow{};
  100. flow.bind(0).ro(10).bind(1).ro(10).ro(11);
  101. auto graph = flow.graph();
  102. ASSERT_EQ(flow.size(), 2u);
  103. ASSERT_EQ(flow.size(), graph.size());
  104. ASSERT_EQ(graph.edges().cbegin(), graph.edges().cend());
  105. }
  106. TEST(Flow, RangeRO) {
  107. entt::flow flow{};
  108. const entt::id_type res[2u]{10, 11};
  109. flow.bind(0).ro(res, res + 1).bind(1).ro(res, res + 2);
  110. auto graph = flow.graph();
  111. ASSERT_EQ(flow.size(), 2u);
  112. ASSERT_EQ(flow.size(), graph.size());
  113. ASSERT_EQ(graph.edges().cbegin(), graph.edges().cend());
  114. }
  115. TEST(Flow, RW) {
  116. entt::flow flow{};
  117. flow.bind(0).rw(10).bind(1).rw(10).rw(11);
  118. auto graph = flow.graph();
  119. ASSERT_EQ(flow.size(), 2u);
  120. ASSERT_EQ(flow.size(), graph.size());
  121. ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
  122. ASSERT_TRUE(graph.contains(0u, 1u));
  123. ASSERT_FALSE(graph.contains(1u, 0u));
  124. }
  125. TEST(Flow, RangeRW) {
  126. entt::flow flow{};
  127. const entt::id_type res[2u]{10, 11};
  128. flow.bind(0).rw(res, res + 1).bind(1).rw(res, res + 2);
  129. auto graph = flow.graph();
  130. ASSERT_EQ(flow.size(), 2u);
  131. ASSERT_EQ(flow.size(), graph.size());
  132. ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
  133. ASSERT_TRUE(graph.contains(0u, 1u));
  134. ASSERT_FALSE(graph.contains(1u, 0u));
  135. }
  136. TEST(Flow, Graph) {
  137. using namespace entt::literals;
  138. entt::flow flow{};
  139. flow.bind("task_0"_hs)
  140. .ro("resource_0"_hs)
  141. .rw("resource_1"_hs);
  142. flow.bind("task_1"_hs)
  143. .ro("resource_0"_hs)
  144. .rw("resource_2"_hs);
  145. flow.bind("task_2"_hs)
  146. .ro("resource_1"_hs)
  147. .rw("resource_3"_hs);
  148. flow.bind("task_3"_hs)
  149. .rw("resource_1"_hs)
  150. .ro("resource_2"_hs);
  151. flow.bind("task_4"_hs)
  152. .rw("resource_0"_hs);
  153. auto graph = flow.graph();
  154. ASSERT_EQ(flow.size(), 5u);
  155. ASSERT_EQ(flow.size(), graph.size());
  156. ASSERT_EQ(flow[0u], "task_0"_hs);
  157. ASSERT_EQ(flow[1u], "task_1"_hs);
  158. ASSERT_EQ(flow[2u], "task_2"_hs);
  159. ASSERT_EQ(flow[3u], "task_3"_hs);
  160. ASSERT_EQ(flow[4u], "task_4"_hs);
  161. auto it = graph.edges().cbegin();
  162. const auto last = graph.edges().cend();
  163. ASSERT_NE(it, last);
  164. ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{2u}));
  165. ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{4u}));
  166. ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{3u}));
  167. ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{4u}));
  168. ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{3u}));
  169. ASSERT_EQ(it, last);
  170. }
  171. TEST(Flow, Sync) {
  172. using namespace entt::literals;
  173. entt::flow flow{};
  174. flow.bind("task_0"_hs)
  175. .ro("resource_0"_hs);
  176. flow.bind("task_1"_hs)
  177. .rw("resource_1"_hs);
  178. flow.bind("task_2"_hs)
  179. .sync();
  180. flow.bind("task_3"_hs)
  181. .ro("resource_0"_hs)
  182. .rw("resource_2"_hs);
  183. flow.bind("task_4"_hs)
  184. .ro("resource_2"_hs);
  185. auto graph = flow.graph();
  186. ASSERT_EQ(flow.size(), 5u);
  187. ASSERT_EQ(flow.size(), graph.size());
  188. ASSERT_EQ(flow[0u], "task_0"_hs);
  189. ASSERT_EQ(flow[1u], "task_1"_hs);
  190. ASSERT_EQ(flow[2u], "task_2"_hs);
  191. ASSERT_EQ(flow[3u], "task_3"_hs);
  192. ASSERT_EQ(flow[4u], "task_4"_hs);
  193. auto it = graph.edges().cbegin();
  194. const auto last = graph.edges().cend();
  195. ASSERT_NE(it, last);
  196. ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{2u}));
  197. ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{2u}));
  198. ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{3u}));
  199. ASSERT_EQ(*it++, std::make_pair(std::size_t{3u}, std::size_t{4u}));
  200. ASSERT_EQ(it, last);
  201. }
  202. ENTT_DEBUG_TEST(FlowDeathTest, NoBind) {
  203. entt::flow flow{};
  204. ASSERT_DEATH(flow.ro(42), "");
  205. ASSERT_DEATH(flow.rw(42), "");
  206. flow.bind(0);
  207. ASSERT_NO_THROW(flow.ro(1));
  208. ASSERT_NO_THROW(flow.rw(2));
  209. }
  210. TEST(Flow, DirectRebind) {
  211. entt::flow flow{};
  212. flow.bind(0).ro(10).rw(10).bind(1).ro(10);
  213. auto graph = flow.graph();
  214. ASSERT_EQ(flow.size(), 2u);
  215. ASSERT_EQ(flow.size(), graph.size());
  216. ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
  217. ASSERT_TRUE(graph.contains(0u, 1u));
  218. ASSERT_FALSE(graph.contains(1u, 0u));
  219. }
  220. TEST(Flow, DeferredRebind) {
  221. entt::flow flow{};
  222. flow.bind(0).ro(10).bind(1).ro(10).bind(0).rw(10);
  223. auto graph = flow.graph();
  224. ASSERT_EQ(flow.size(), 2u);
  225. ASSERT_EQ(flow.size(), graph.size());
  226. ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
  227. ASSERT_FALSE(graph.contains(0u, 1u));
  228. ASSERT_TRUE(graph.contains(1u, 0u));
  229. }
  230. TEST(Flow, Loop) {
  231. entt::flow flow{};
  232. flow.bind(0).rw(10).bind(1).ro(10).bind(0).rw(10);
  233. auto graph = flow.graph();
  234. ASSERT_EQ(flow.size(), 2u);
  235. ASSERT_EQ(flow.size(), graph.size());
  236. ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
  237. ASSERT_TRUE(graph.contains(0u, 1u));
  238. ASSERT_TRUE(graph.contains(1u, 0u));
  239. }
  240. TEST(Flow, ThrowingAllocator) {
  241. entt::basic_flow<test::throwing_allocator<entt::id_type>> flow{};
  242. flow.get_allocator().throw_counter<std::pair<std::size_t, entt::id_type>>(0u);
  243. ASSERT_EQ(flow.size(), 0u);
  244. ASSERT_THROW(flow.bind(1), test::throwing_allocator_exception);
  245. ASSERT_EQ(flow.size(), 0u);
  246. flow.bind(1);
  247. ASSERT_EQ(flow.size(), 1u);
  248. }