DataModel.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "../../../Source/Core/DataModel.cpp"
  29. #include "RmlUi/Core/Core.h"
  30. #include "RmlUi/Core/SystemInterface.h"
  31. #include <RmlUi/Core/DataModelHandle.h>
  32. #include <RmlUi/Core/Types.h>
  33. #include <doctest.h>
  34. using namespace Rml;
  35. TEST_CASE("Data variables")
  36. {
  37. using IntVector = Vector<int>;
  38. struct FunData {
  39. int i = 99;
  40. String x = "hello";
  41. IntVector magic = { 3, 5, 7, 11, 13 };
  42. };
  43. using FunArray = Array<FunData, 3>;
  44. struct SmartData {
  45. bool valid = true;
  46. FunData fun;
  47. FunArray more_fun;
  48. };
  49. DataModel model;
  50. DataTypeRegister types;
  51. DataModelConstructor handle(&model, &types);
  52. // Setup data type register
  53. {
  54. handle.RegisterArray<IntVector>();
  55. if (auto fun_handle = handle.RegisterStruct<FunData>())
  56. {
  57. fun_handle.RegisterMember("i", &FunData::i);
  58. fun_handle.RegisterMember("x", &FunData::x);
  59. fun_handle.RegisterMember("magic", &FunData::magic);
  60. }
  61. handle.RegisterArray<FunArray>();
  62. if (auto smart_handle = handle.RegisterStruct<SmartData>())
  63. {
  64. smart_handle.RegisterMember("valid", &SmartData::valid);
  65. smart_handle.RegisterMember("fun", &SmartData::fun);
  66. smart_handle.RegisterMember("more_fun", &SmartData::more_fun);
  67. }
  68. }
  69. SmartData data;
  70. data.fun.x = "Hello, we're in SmartData!";
  71. handle.Bind("data", &data);
  72. // Test data addresses, setters, and assignments
  73. {
  74. Vector<String> test_addresses = { "data.more_fun[1].magic[3]", "data.more_fun[1].magic.size", "data.fun.x", "data.valid" };
  75. Vector<String> expected_results = { ToString(data.more_fun[1].magic[3]), ToString(int(data.more_fun[1].magic.size())), ToString(data.fun.x), ToString(data.valid) };
  76. Vector<String> results;
  77. for (auto& str_address : test_addresses)
  78. {
  79. DataAddress address = ParseAddress(str_address);
  80. Variant result;
  81. if (model.GetVariableInto(address, result))
  82. results.push_back(result.Get<String>());
  83. }
  84. CHECK(results == expected_results);
  85. REQUIRE(model.GetVariable(ParseAddress("data.more_fun[1].magic[1]")).Set(Variant(String("199"))));
  86. CHECK(data.more_fun[1].magic[1] == 199);
  87. data.fun.magic = { 99, 190, 55, 2000, 50, 60, 70, 80, 90 };
  88. Variant get_result;
  89. const int magic_size = int(data.fun.magic.size());
  90. REQUIRE(model.GetVariable(ParseAddress("data.fun.magic.size")).Get(get_result));
  91. CHECK(get_result.Get<String>() == ToString(magic_size));
  92. CHECK(model.GetVariable(ParseAddress("data.fun.magic")).Size() == magic_size);
  93. REQUIRE(model.GetVariable(ParseAddress("data.fun.magic[8]")).Get(get_result));
  94. CHECK(get_result.Get<String>() == "90");
  95. }
  96. }
  97. struct YesStr {
  98. int scalar;
  99. int* scalarptr;
  100. const int* scalarptr2;
  101. Vector<int> yesvector;
  102. };
  103. struct FooStr {
  104. String scalar_string = "yes";
  105. int scalar;
  106. int* scalarptr;
  107. YesStr* yesptr;
  108. SharedPtr<YesStr> yesshr;
  109. const int* scalarptr2;
  110. Vector<int> foovector;
  111. Vector<int>* foovectorptr;
  112. };
  113. struct BarStr {
  114. int scalar;
  115. int* scalarptr;
  116. const int* scalarptr2;
  117. FooStr foo;
  118. FooStr* fooptr;
  119. SharedPtr<FooStr> fooshr;
  120. Vector<int> barvector;
  121. Vector<int>* barvectorptr;
  122. };
  123. void registerStructs(DataModelConstructor& handle)
  124. {
  125. handle.RegisterArray<Vector<int>>();
  126. if (auto fun_handle = handle.RegisterStruct<YesStr>())
  127. {
  128. fun_handle.RegisterMember("scalar", &YesStr::scalar);
  129. fun_handle.RegisterMember("scalarptr", &YesStr::scalarptr);
  130. // requires constness support - fun_handle.RegisterMember("scalarptr2", &YesStr::scalarptr2);
  131. fun_handle.RegisterMember("yesvector", &YesStr::yesvector);
  132. }
  133. if (auto fun_handle = handle.RegisterStruct<FooStr>())
  134. {
  135. fun_handle.RegisterMember("scalar", &FooStr::scalar);
  136. fun_handle.RegisterMember("scalarptr", &FooStr::scalarptr);
  137. // requires constness support - fun_handle.RegisterMember("scalarptr2", &FooStr::scalarptr2);
  138. fun_handle.RegisterMember("string", &FooStr::scalar_string);
  139. fun_handle.RegisterMember("yesptr", &FooStr::yesptr);
  140. fun_handle.RegisterMember("yesshr", &FooStr::yesshr);
  141. fun_handle.RegisterMember("foovector", &FooStr::foovector);
  142. fun_handle.RegisterMember("foovectorptr", &FooStr::foovectorptr);
  143. }
  144. if (auto smart_handle = handle.RegisterStruct<BarStr>())
  145. {
  146. smart_handle.RegisterMember("scalar", &BarStr::scalar);
  147. smart_handle.RegisterMember("scalarptr", &BarStr::scalarptr);
  148. // requires constness support - smart_handle.RegisterMember("scalarptr2", &BarStr::scalarptr2);
  149. smart_handle.RegisterMember("foo", &BarStr::foo);
  150. smart_handle.RegisterMember("fooptr", &BarStr::fooptr);
  151. smart_handle.RegisterMember("fooshr", &BarStr::fooshr);
  152. smart_handle.RegisterMember("barvector", &BarStr::barvector);
  153. smart_handle.RegisterMember("barvectorptr", &BarStr::barvectorptr);
  154. }
  155. }
  156. TEST_CASE("Data variables pointers")
  157. {
  158. DataModel model;
  159. DataTypeRegister types;
  160. DataModelConstructor handle(&model, &types);
  161. // Setup data type register
  162. registerStructs(handle);
  163. BarStr example;
  164. handle.Bind("example", &example);
  165. {
  166. int for_scalars_ptrsa = 13;
  167. int for_scalars_ptrsb = 69;
  168. example.scalar = 666;
  169. example.scalarptr = &for_scalars_ptrsa;
  170. example.scalarptr2 = &for_scalars_ptrsa;
  171. example.foo.scalar = 1337;
  172. example.foo.scalarptr = &for_scalars_ptrsb;
  173. example.foo.scalarptr2 = &for_scalars_ptrsb;
  174. example.fooptr = new FooStr();
  175. example.fooptr->scalar = 1337;
  176. example.fooptr->scalarptr = &for_scalars_ptrsb;
  177. example.fooptr->scalarptr2 = &for_scalars_ptrsb;
  178. example.fooshr = std::make_shared<FooStr>();
  179. *example.fooshr = example.foo;
  180. Vector<String> test_addresses = {"example.scalar", "example.scalarptr", /*"example.scalarptr2", */
  181. "example.foo.scalar", "example.foo.scalarptr", /*const "example.foo.scalarptr2", */ "example.foo.string", "example.fooptr.scalar",
  182. "example.fooptr.scalarptr", /*const "example.fooptr.scalarptr2" ,*/ "example.fooptr.string", "example.fooshr.scalar",
  183. "example.fooshr.scalarptr", /*const "example.fooshr.scalarptr2", */ "example.fooshr.string"};
  184. Vector<String> expected_results = {ToString(example.scalar), ToString(*example.scalarptr), /*const ToString(*example.scalarptr2), */
  185. ToString(example.foo.scalar), ToString(*example.foo.scalarptr),
  186. /*const ToString(*example.foo.scalarptr2) ,*/ ToString(example.foo.scalar_string), ToString(example.fooptr->scalar),
  187. ToString(*example.fooptr->scalarptr), /*const ToString(*example.fooptr->scalarptr2),*/ ToString(example.fooptr->scalar_string),
  188. ToString(example.fooshr->scalar), ToString(*example.fooshr->scalarptr),
  189. /*const ToString(*example.fooshr->scalarptr2) ,*/ ToString(example.fooshr->scalar_string)};
  190. Vector<String> results;
  191. for (auto& str_address : test_addresses)
  192. {
  193. DataAddress address = ParseAddress(str_address);
  194. Variant result;
  195. if (model.GetVariableInto(address, result))
  196. results.push_back(result.Get<String>());
  197. }
  198. CHECK(results == expected_results);
  199. }
  200. {
  201. delete example.fooptr;
  202. int new_int_value = 88;
  203. example.fooptr = new FooStr();
  204. example.fooptr->scalar = 2137;
  205. example.fooptr->scalarptr = &new_int_value;
  206. example.fooptr->scalarptr2 = &new_int_value;
  207. example.fooshr = std::make_shared<FooStr>();
  208. *example.fooshr = example.foo;
  209. Vector<String> test_addresses = {"example.fooptr.scalar", "example.fooptr.scalarptr",
  210. /*const "example.fooptr.scalarptr2" , */ "example.fooptr.string", "example.fooshr.scalar", "example.fooshr.scalarptr",
  211. /*const "example.fooshr.scalarptr2" , */ "example.fooshr.string"};
  212. Vector<String> expected_results = {ToString(example.fooptr->scalar), ToString(*example.fooptr->scalarptr),
  213. /*const ToString(*example.fooptr->scalarptr2),*/ ToString(example.fooptr->scalar_string), ToString(example.fooshr->scalar),
  214. ToString(*example.fooshr->scalarptr), /*const ToString(*example.fooshr->scalarptr2),*/ ToString(example.fooshr->scalar_string)};
  215. Vector<String> results;
  216. for (auto& str_address : test_addresses)
  217. {
  218. DataAddress address = ParseAddress(str_address);
  219. Variant result;
  220. if (model.GetVariableInto(address, result))
  221. results.push_back(result.Get<String>());
  222. }
  223. CHECK(results == expected_results);
  224. }
  225. }
  226. TEST_CASE("Data variables pointers - nulls")
  227. {
  228. class SystemInterfaceImpl : public SystemInterface {
  229. public:
  230. double GetElapsedTime() override { return 0; }
  231. };
  232. SystemInterface* obj = new SystemInterfaceImpl();
  233. SetSystemInterface(obj);
  234. // Setup data type register
  235. DataModel model;
  236. DataTypeRegister types;
  237. DataModelConstructor handle(&model, &types);
  238. // Setup data type register
  239. registerStructs(handle);
  240. BarStr example;
  241. BarStr* exampleptr;
  242. UniquePtr<BarStr> exampleunq;
  243. UniquePtr<BarStr> exampleunq2;
  244. handle.Bind("example", &example);
  245. handle.Bind("exampleptr", &exampleptr);
  246. handle.Bind("exampleunq", &exampleunq);
  247. handle.Bind("exampleunq2", &exampleunq2);
  248. {
  249. example.fooptr = nullptr;
  250. example.fooshr = std::shared_ptr<FooStr>();
  251. example.barvectorptr = nullptr;
  252. exampleptr = nullptr;
  253. exampleunq = MakeUnique<BarStr>();
  254. exampleunq->fooptr = nullptr;
  255. exampleunq2 = MakeUnique<BarStr>();
  256. exampleunq2->fooptr = new FooStr();
  257. exampleunq2->fooptr->scalarptr = nullptr;
  258. exampleunq2->fooptr->yesptr = nullptr;
  259. Vector<String> test_addresses = {
  260. "example.fooptr.scalarptr",
  261. "example.fooptr",
  262. "example.fooshr",
  263. "example.fooshr.scalarptr",
  264. "example.fooptr.yesptr",
  265. "example.fooptr.yesptr.scalar",
  266. "example.fooptr.yesshr",
  267. "example.fooptr.yesshr.scalar",
  268. "example.barvectorptr",
  269. "example.barvectorptr[0]",
  270. "example.fooptr.foovectorptr",
  271. "example.fooptr.foovectorptr[0]",
  272. "exampleptr",
  273. "exampleptr.barvectorptr",
  274. "exampleptr.barvectorptr[0]",
  275. "exampleptr.fooptr",
  276. "exampleptr.fooptr.foovectorptr",
  277. "exampleptr.fooptr.foovectorptr[0]",
  278. /*"exampleunq", - this is not null*/ "exampleunq.fooptr",
  279. "exampleunq.fooptr.yesptr",
  280. /*"exampleunq2", - this is not null*/ /*"exampleunq2.fooptr", - this is not null*/ "exampleunq2.fooptr.scalarptr",
  281. "exampleunq2.fooptr.yesptr",
  282. };
  283. Vector<void*> expected_results = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  284. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
  285. Vector<void*> results;
  286. for (auto& str_address : test_addresses)
  287. {
  288. DataAddress address = ParseAddress(str_address);
  289. Variant result;
  290. model.GetVariableInto(address, result);
  291. results.push_back(result.Get<void*>());
  292. }
  293. CHECK(results == expected_results);
  294. }
  295. }