meta_data.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. #include <gtest/gtest.h>
  2. #include <entt/core/hashed_string.hpp>
  3. #include <entt/meta/factory.hpp>
  4. #include <entt/meta/meta.hpp>
  5. #include <entt/meta/resolve.hpp>
  6. struct base_t {
  7. virtual ~base_t() = default;
  8. static void destroy(base_t &) {
  9. ++counter;
  10. }
  11. inline static int counter = 0;
  12. int value{3};
  13. };
  14. struct derived_t: base_t {
  15. derived_t() {}
  16. };
  17. struct clazz_t {
  18. clazz_t()
  19. : i{0},
  20. j{1},
  21. base{}
  22. {}
  23. int i{0};
  24. const int j{1};
  25. base_t base{};
  26. inline static int h{2};
  27. inline static const int k{3};
  28. };
  29. struct setter_getter_t {
  30. setter_getter_t(): value{0} {}
  31. int setter(int val) {
  32. return value = val;
  33. }
  34. int getter() {
  35. return value;
  36. }
  37. int setter_with_ref(const int &val) {
  38. return value = val;
  39. }
  40. const int & getter_with_ref() {
  41. return value;
  42. }
  43. static int static_setter(setter_getter_t &type, int value) {
  44. return type.value = value;
  45. }
  46. static int static_getter(const setter_getter_t &type) {
  47. return type.value;
  48. }
  49. int value;
  50. };
  51. enum class property_t {
  52. random,
  53. value
  54. };
  55. struct MetaData: ::testing::Test {
  56. void SetUp() override {
  57. using namespace entt::literals;
  58. entt::meta<double>()
  59. .type("double"_hs)
  60. .conv<int>();
  61. entt::meta<base_t>()
  62. .type("base"_hs)
  63. .dtor<base_t::destroy>()
  64. .data<&base_t::value>("value"_hs);
  65. entt::meta<derived_t>()
  66. .type("derived"_hs)
  67. .base<base_t>()
  68. .dtor<derived_t::destroy>();
  69. entt::meta<clazz_t>()
  70. .type("clazz"_hs)
  71. .data<&clazz_t::i, entt::as_ref_t>("i"_hs).prop(3, 0)
  72. .data<&clazz_t::i, entt::as_cref_t>("ci"_hs)
  73. .data<&clazz_t::j>("j"_hs).prop(true, 1)
  74. .data<&clazz_t::h>("h"_hs).prop(property_t::random, 2)
  75. .data<&clazz_t::k>("k"_hs).prop(property_t::value, 3)
  76. .data<&clazz_t::base>("base"_hs)
  77. .data<&clazz_t::i, entt::as_void_t>("void"_hs);
  78. entt::meta<setter_getter_t>()
  79. .type("setter_getter"_hs)
  80. .data<&setter_getter_t::static_setter, &setter_getter_t::static_getter>("x"_hs)
  81. .data<&setter_getter_t::setter, &setter_getter_t::getter>("y"_hs)
  82. .data<&setter_getter_t::static_setter, &setter_getter_t::getter>("z"_hs)
  83. .data<&setter_getter_t::setter_with_ref, &setter_getter_t::getter_with_ref>("w"_hs)
  84. .data<nullptr, &setter_getter_t::getter>("z_ro"_hs)
  85. .data<nullptr, &setter_getter_t::value>("value"_hs);
  86. base_t::counter = 0;
  87. }
  88. void TearDown() override {
  89. entt::meta_reset();
  90. }
  91. };
  92. TEST_F(MetaData, Functionalities) {
  93. using namespace entt::literals;
  94. auto data = entt::resolve<clazz_t>().data("i"_hs);
  95. clazz_t instance{};
  96. ASSERT_TRUE(data);
  97. ASSERT_EQ(data.type(), entt::resolve<int>());
  98. ASSERT_EQ(data.id(), "i"_hs);
  99. ASSERT_FALSE(data.is_const());
  100. ASSERT_FALSE(data.is_static());
  101. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  102. ASSERT_TRUE(data.set(instance, 42));
  103. ASSERT_EQ(data.get(instance).cast<int>(), 42);
  104. for(auto curr: data.prop()) {
  105. ASSERT_EQ(curr.key(), 3);
  106. ASSERT_EQ(curr.value(), 0);
  107. }
  108. ASSERT_FALSE(data.prop(2));
  109. ASSERT_FALSE(data.prop('c'));
  110. auto prop = data.prop(3);
  111. ASSERT_TRUE(prop);
  112. ASSERT_EQ(prop.key(), 3);
  113. ASSERT_EQ(prop.value(), 0);
  114. }
  115. TEST_F(MetaData, Const) {
  116. using namespace entt::literals;
  117. auto data = entt::resolve<clazz_t>().data("j"_hs);
  118. clazz_t instance{};
  119. ASSERT_TRUE(data);
  120. ASSERT_EQ(data.type(), entt::resolve<int>());
  121. ASSERT_EQ(data.id(), "j"_hs);
  122. ASSERT_TRUE(data.is_const());
  123. ASSERT_FALSE(data.is_static());
  124. ASSERT_EQ(data.get(instance).cast<int>(), 1);
  125. ASSERT_FALSE(data.set(instance, 42));
  126. ASSERT_EQ(data.get(instance).cast<int>(), 1);
  127. for(auto curr: data.prop()) {
  128. ASSERT_EQ(curr.key(), true);
  129. ASSERT_EQ(curr.value(), 1);
  130. }
  131. ASSERT_FALSE(data.prop(false));
  132. ASSERT_FALSE(data.prop('c'));
  133. auto prop = data.prop(true);
  134. ASSERT_TRUE(prop);
  135. ASSERT_EQ(prop.key(), true);
  136. ASSERT_EQ(prop.value(), 1);
  137. }
  138. TEST_F(MetaData, Static) {
  139. using namespace entt::literals;
  140. auto data = entt::resolve<clazz_t>().data("h"_hs);
  141. ASSERT_TRUE(data);
  142. ASSERT_EQ(data.type(), entt::resolve<int>());
  143. ASSERT_EQ(data.id(), "h"_hs);
  144. ASSERT_FALSE(data.is_const());
  145. ASSERT_TRUE(data.is_static());
  146. ASSERT_EQ(data.get({}).cast<int>(), 2);
  147. ASSERT_TRUE(data.set({}, 42));
  148. ASSERT_EQ(data.get({}).cast<int>(), 42);
  149. for(auto curr: data.prop()) {
  150. ASSERT_EQ(curr.key(), property_t::random);
  151. ASSERT_EQ(curr.value(), 2);
  152. }
  153. ASSERT_FALSE(data.prop(property_t::value));
  154. ASSERT_FALSE(data.prop('c'));
  155. auto prop = data.prop(property_t::random);
  156. ASSERT_TRUE(prop);
  157. ASSERT_EQ(prop.key(), property_t::random);
  158. ASSERT_EQ(prop.value(), 2);
  159. }
  160. TEST_F(MetaData, ConstStatic) {
  161. using namespace entt::literals;
  162. auto data = entt::resolve<clazz_t>().data("k"_hs);
  163. ASSERT_TRUE(data);
  164. ASSERT_EQ(data.type(), entt::resolve<int>());
  165. ASSERT_EQ(data.id(), "k"_hs);
  166. ASSERT_TRUE(data.is_const());
  167. ASSERT_TRUE(data.is_static());
  168. ASSERT_EQ(data.get({}).cast<int>(), 3);
  169. ASSERT_FALSE(data.set({}, 42));
  170. ASSERT_EQ(data.get({}).cast<int>(), 3);
  171. for(auto curr: data.prop()) {
  172. ASSERT_EQ(curr.key(), property_t::value);
  173. ASSERT_EQ(curr.value(), 3);
  174. }
  175. ASSERT_FALSE(data.prop(property_t::random));
  176. ASSERT_FALSE(data.prop('c'));
  177. auto prop = data.prop(property_t::value);
  178. ASSERT_TRUE(prop);
  179. ASSERT_EQ(prop.key(), property_t::value);
  180. ASSERT_EQ(prop.value(), 3);
  181. }
  182. TEST_F(MetaData, GetMetaAnyArg) {
  183. using namespace entt::literals;
  184. entt::meta_any any{clazz_t{}};
  185. any.cast<clazz_t &>().i = 99;
  186. const auto value = entt::resolve<clazz_t>().data("i"_hs).get(any);
  187. ASSERT_TRUE(value);
  188. ASSERT_TRUE(static_cast<bool>(value.cast<int>()));
  189. ASSERT_EQ(value.cast<int>(), 99);
  190. }
  191. TEST_F(MetaData, GetInvalidArg) {
  192. using namespace entt::literals;
  193. auto instance = 0;
  194. ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).get(instance));
  195. }
  196. TEST_F(MetaData, SetMetaAnyArg) {
  197. using namespace entt::literals;
  198. entt::meta_any any{clazz_t{}};
  199. entt::meta_any value{42};
  200. ASSERT_EQ(any.cast<clazz_t>().i, 0);
  201. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, value));
  202. ASSERT_EQ(any.cast<clazz_t>().i, 42);
  203. }
  204. TEST_F(MetaData, SetInvalidArg) {
  205. using namespace entt::literals;
  206. ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).set({}, 'c'));
  207. }
  208. TEST_F(MetaData, SetCast) {
  209. using namespace entt::literals;
  210. clazz_t instance{};
  211. ASSERT_EQ(base_t::counter, 0);
  212. ASSERT_TRUE(entt::resolve<clazz_t>().data("base"_hs).set(instance, derived_t{}));
  213. ASSERT_EQ(base_t::counter, 1);
  214. }
  215. TEST_F(MetaData, SetConvert) {
  216. using namespace entt::literals;
  217. clazz_t instance{};
  218. ASSERT_EQ(instance.i, 0);
  219. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(instance, 3.));
  220. ASSERT_EQ(instance.i, 3);
  221. }
  222. TEST_F(MetaData, SetByRef) {
  223. using namespace entt::literals;
  224. entt::meta_any any{clazz_t{}};
  225. int value{42};
  226. ASSERT_EQ(any.cast<clazz_t>().i, 0);
  227. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, entt::make_meta<int &>(value)));
  228. ASSERT_EQ(any.cast<clazz_t>().i, 42);
  229. value = 3;
  230. auto wrapper = entt::make_meta<int &>(value);
  231. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, wrapper.as_ref()));
  232. ASSERT_EQ(any.cast<clazz_t>().i, 3);
  233. }
  234. TEST_F(MetaData, SetByConstRef) {
  235. using namespace entt::literals;
  236. entt::meta_any any{clazz_t{}};
  237. int value{42};
  238. ASSERT_EQ(any.cast<clazz_t>().i, 0);
  239. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, entt::make_meta<const int &>(value)));
  240. ASSERT_EQ(any.cast<clazz_t>().i, 42);
  241. value = 3;
  242. auto wrapper = entt::make_meta<const int &>(value);
  243. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, wrapper.as_ref()));
  244. ASSERT_EQ(any.cast<clazz_t>().i, 3);
  245. }
  246. TEST_F(MetaData, SetterGetterAsFreeFunctions) {
  247. using namespace entt::literals;
  248. auto data = entt::resolve<setter_getter_t>().data("x"_hs);
  249. setter_getter_t instance{};
  250. ASSERT_TRUE(data);
  251. ASSERT_EQ(data.type(), entt::resolve<int>());
  252. ASSERT_EQ(data.id(), "x"_hs);
  253. ASSERT_FALSE(data.is_const());
  254. ASSERT_FALSE(data.is_static());
  255. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  256. ASSERT_TRUE(data.set(instance, 42));
  257. ASSERT_EQ(data.get(instance).cast<int>(), 42);
  258. }
  259. TEST_F(MetaData, SetterGetterAsMemberFunctions) {
  260. using namespace entt::literals;
  261. auto data = entt::resolve<setter_getter_t>().data("y"_hs);
  262. setter_getter_t instance{};
  263. ASSERT_TRUE(data);
  264. ASSERT_EQ(data.type(), entt::resolve<int>());
  265. ASSERT_EQ(data.id(), "y"_hs);
  266. ASSERT_FALSE(data.is_const());
  267. ASSERT_FALSE(data.is_static());
  268. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  269. ASSERT_TRUE(data.set(instance, 42));
  270. ASSERT_EQ(data.get(instance).cast<int>(), 42);
  271. }
  272. TEST_F(MetaData, SetterGetterWithRefAsMemberFunctions) {
  273. using namespace entt::literals;
  274. auto data = entt::resolve<setter_getter_t>().data("w"_hs);
  275. setter_getter_t instance{};
  276. ASSERT_TRUE(data);
  277. ASSERT_EQ(data.type(), entt::resolve<int>());
  278. ASSERT_EQ(data.id(), "w"_hs);
  279. ASSERT_FALSE(data.is_const());
  280. ASSERT_FALSE(data.is_static());
  281. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  282. ASSERT_TRUE(data.set(instance, 42));
  283. ASSERT_EQ(data.get(instance).cast<int>(), 42);
  284. }
  285. TEST_F(MetaData, SetterGetterMixed) {
  286. using namespace entt::literals;
  287. auto data = entt::resolve<setter_getter_t>().data("z"_hs);
  288. setter_getter_t instance{};
  289. ASSERT_TRUE(data);
  290. ASSERT_EQ(data.type(), entt::resolve<int>());
  291. ASSERT_EQ(data.id(), "z"_hs);
  292. ASSERT_FALSE(data.is_const());
  293. ASSERT_FALSE(data.is_static());
  294. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  295. ASSERT_TRUE(data.set(instance, 42));
  296. ASSERT_EQ(data.get(instance).cast<int>(), 42);
  297. }
  298. TEST_F(MetaData, SetterGetterReadOnly) {
  299. using namespace entt::literals;
  300. auto data = entt::resolve<setter_getter_t>().data("z_ro"_hs);
  301. setter_getter_t instance{};
  302. ASSERT_TRUE(data);
  303. ASSERT_EQ(data.type(), entt::resolve<int>());
  304. ASSERT_EQ(data.id(), "z_ro"_hs);
  305. ASSERT_TRUE(data.is_const());
  306. ASSERT_FALSE(data.is_static());
  307. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  308. ASSERT_FALSE(data.set(instance, 42));
  309. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  310. }
  311. TEST_F(MetaData, SetterGetterReadOnlyDataMember) {
  312. using namespace entt::literals;
  313. auto data = entt::resolve<setter_getter_t>().data("value"_hs);
  314. setter_getter_t instance{};
  315. ASSERT_TRUE(data);
  316. ASSERT_EQ(data.type(), entt::resolve<int>());
  317. ASSERT_EQ(data.id(), "value"_hs);
  318. ASSERT_TRUE(data.is_const());
  319. ASSERT_FALSE(data.is_static());
  320. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  321. ASSERT_FALSE(data.set(instance, 42));
  322. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  323. }
  324. TEST_F(MetaData, ConstInstance) {
  325. using namespace entt::literals;
  326. clazz_t instance{};
  327. ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(instance).try_cast<int>(), nullptr);
  328. ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(instance).try_cast<const int>(), nullptr);
  329. ASSERT_EQ(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)).try_cast<int>(), nullptr);
  330. // as_ref_t adapts to the constness of the passed object and returns const references in case
  331. ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)).try_cast<const int>(), nullptr);
  332. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).get(instance));
  333. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(instance, 3));
  334. ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)));
  335. ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).set(std::as_const(instance), 3));
  336. ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).get(instance));
  337. ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).set(instance, 3));
  338. ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).get(std::as_const(instance)));
  339. ASSERT_FALSE(entt::resolve<clazz_t>().data("ci"_hs).set(std::as_const(instance), 3));
  340. ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).get(instance));
  341. ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).set(instance, 3));
  342. ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).get(std::as_const(instance)));
  343. ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).set(std::as_const(instance), 3));
  344. }
  345. TEST_F(MetaData, AsVoid) {
  346. using namespace entt::literals;
  347. auto data = entt::resolve<clazz_t>().data("void"_hs);
  348. clazz_t instance{};
  349. ASSERT_TRUE(data.set(instance, 42));
  350. ASSERT_EQ(instance.i, 42);
  351. ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
  352. }
  353. TEST_F(MetaData, AsRef) {
  354. using namespace entt::literals;
  355. clazz_t instance{};
  356. auto data = entt::resolve<clazz_t>().data("i"_hs);
  357. ASSERT_EQ(instance.i, 0);
  358. ASSERT_EQ(data.type(), entt::resolve<int>());
  359. data.get(instance).cast<int &>() = 3;
  360. ASSERT_EQ(instance.i, 3);
  361. }
  362. TEST_F(MetaData, AsConstRef) {
  363. using namespace entt::literals;
  364. clazz_t instance{};
  365. auto data = entt::resolve<clazz_t>().data("ci"_hs);
  366. ASSERT_EQ(instance.i, 0);
  367. ASSERT_EQ(data.type(), entt::resolve<int>());
  368. ASSERT_DEATH(data.get(instance).cast<int &>() = 3, "");
  369. ASSERT_EQ(data.get(instance).cast<const int &>(), 0);
  370. ASSERT_EQ(data.get(instance).cast<int>(), 0);
  371. ASSERT_EQ(instance.i, 0);
  372. }
  373. TEST_F(MetaData, FromBase) {
  374. using namespace entt::literals;
  375. auto type = entt::resolve<derived_t>();
  376. derived_t instance{};
  377. ASSERT_TRUE(type.data("value"_hs));
  378. ASSERT_EQ(instance.value, 3);
  379. ASSERT_TRUE(type.data("value"_hs).set(instance, 42));
  380. ASSERT_EQ(instance.value, 42);
  381. }
  382. TEST_F(MetaData, ReRegistration) {
  383. using namespace entt::literals;
  384. SetUp();
  385. auto *node = entt::internal::meta_info<base_t>::resolve();
  386. auto type = entt::resolve<base_t>();
  387. ASSERT_NE(node->data, nullptr);
  388. ASSERT_EQ(node->data->next, nullptr);
  389. ASSERT_TRUE(type.data("value"_hs));
  390. entt::meta<base_t>().data<&base_t::value>("field"_hs);
  391. ASSERT_NE(node->data, nullptr);
  392. ASSERT_EQ(node->data->next, nullptr);
  393. ASSERT_FALSE(type.data("value"_hs));
  394. ASSERT_TRUE(type.data("field"_hs));
  395. }
  396. TEST_F(MetaData, NameCollision) {
  397. using namespace entt::literals;
  398. ASSERT_NO_FATAL_FAILURE(entt::meta<clazz_t>().data<&clazz_t::j>("j"_hs));
  399. ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs));
  400. ASSERT_NO_FATAL_FAILURE(entt::meta<clazz_t>().data<&clazz_t::j>("cj"_hs));
  401. ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs));
  402. ASSERT_TRUE(entt::resolve<clazz_t>().data("cj"_hs));
  403. ASSERT_DEATH(entt::meta<clazz_t>().data<&clazz_t::j>("i"_hs), "");
  404. }