DynamicTest.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. /*
  2. * Copyright 2011-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/dynamic.h>
  17. #include <folly/Range.h>
  18. #include <folly/json.h>
  19. #include <folly/portability/GTest.h>
  20. #include <iterator>
  21. using folly::dynamic;
  22. using folly::StringPiece;
  23. TEST(Dynamic, Default) {
  24. dynamic obj;
  25. EXPECT_TRUE(obj.isNull());
  26. }
  27. TEST(Dynamic, ObjectBasics) {
  28. dynamic obj = dynamic::object("a", false);
  29. EXPECT_EQ(obj.at("a"), false);
  30. EXPECT_EQ(obj.size(), 1);
  31. obj.insert("a", true);
  32. dynamic key{"a"};
  33. folly::StringPiece sp{"a"};
  34. std::string s{"a"};
  35. EXPECT_EQ(obj.size(), 1);
  36. EXPECT_EQ(obj.at("a"), true);
  37. EXPECT_EQ(obj.at(sp), true);
  38. EXPECT_EQ(obj.at(key), true);
  39. obj.at(sp) = nullptr;
  40. EXPECT_EQ(obj.size(), 1);
  41. EXPECT_TRUE(obj.at(s) == nullptr);
  42. obj["a"] = 12;
  43. EXPECT_EQ(obj[sp], 12);
  44. obj[key] = "foo";
  45. EXPECT_EQ(obj["a"], "foo");
  46. (void)obj["b"];
  47. EXPECT_EQ(obj.size(), 2);
  48. obj.erase("a");
  49. EXPECT_TRUE(obj.find(sp) == obj.items().end());
  50. obj.erase("b");
  51. EXPECT_EQ(obj.size(), 0);
  52. dynamic newObject = dynamic::object;
  53. newObject["z"] = 12;
  54. EXPECT_EQ(newObject.size(), 1);
  55. newObject["a"] = true;
  56. EXPECT_EQ(newObject.size(), 2);
  57. EXPECT_EQ(*newObject.keys().begin(), newObject.items().begin()->first);
  58. EXPECT_EQ(*newObject.values().begin(), newObject.items().begin()->second);
  59. std::vector<std::pair<std::string, dynamic>> found;
  60. found.emplace_back(
  61. newObject.keys().begin()->asString(), *newObject.values().begin());
  62. EXPECT_EQ(
  63. *std::next(newObject.keys().begin()),
  64. std::next(newObject.items().begin())->first);
  65. EXPECT_EQ(
  66. *std::next(newObject.values().begin()),
  67. std::next(newObject.items().begin())->second);
  68. found.emplace_back(
  69. std::next(newObject.keys().begin())->asString(),
  70. *std::next(newObject.values().begin()));
  71. std::sort(found.begin(), found.end());
  72. EXPECT_EQ("a", found[0].first);
  73. EXPECT_TRUE(found[0].second.asBool());
  74. EXPECT_EQ("z", found[1].first);
  75. EXPECT_EQ(12, found[1].second.asInt());
  76. dynamic obj2 = dynamic::object;
  77. EXPECT_TRUE(obj2.isObject());
  78. dynamic d3 = nullptr;
  79. EXPECT_TRUE(d3 == nullptr);
  80. d3 = dynamic::object;
  81. EXPECT_TRUE(d3.isObject());
  82. d3["foo"] = dynamic::array(1, 2, 3);
  83. EXPECT_EQ(d3.count("foo"), 1);
  84. d3[123] = 321;
  85. EXPECT_EQ(d3.at(123), 321);
  86. d3["123"] = 42;
  87. EXPECT_EQ(d3.at("123"), 42);
  88. EXPECT_EQ(d3.at(123), 321);
  89. dynamic objInsert = folly::dynamic::object();
  90. dynamic objA = folly::dynamic::object("1", "2");
  91. dynamic objB = folly::dynamic::object("1", "2");
  92. objInsert.insert("1", std::move(objA));
  93. objInsert.insert("1", std::move(objB));
  94. EXPECT_EQ(objInsert.find("1")->second.size(), 1);
  95. // Looking up objects as keys
  96. // clang-format off
  97. dynamic objDefinedInOneOrder = folly::dynamic::object
  98. ("bar", "987")
  99. ("baz", folly::dynamic::array(1, 2, 3))
  100. ("foo2", folly::dynamic::object("1", "2"));
  101. dynamic sameObjInDifferentOrder = folly::dynamic::object
  102. ("bar", "987")
  103. ("foo2", folly::dynamic::object("1", "2"))
  104. ("baz", folly::dynamic::array(1, 2, 3));
  105. // clang-format on
  106. newObject[objDefinedInOneOrder] = 12;
  107. EXPECT_EQ(newObject.at(objDefinedInOneOrder).getInt(), 12);
  108. EXPECT_EQ(newObject.at(sameObjInDifferentOrder).getInt(), 12);
  109. // Merge two objects
  110. dynamic origMergeObj1 = folly::dynamic::object();
  111. // clang-format off
  112. dynamic mergeObj1 = origMergeObj1 = folly::dynamic::object
  113. ("key1", "value1")
  114. ("key2", "value2");
  115. dynamic mergeObj2 = folly::dynamic::object
  116. ("key2", "value3")
  117. ("key3", "value4");
  118. // clang-format on
  119. // Merged object where we prefer the values in mergeObj2
  120. // clang-format off
  121. dynamic combinedPreferObj2 = folly::dynamic::object
  122. ("key1", "value1")
  123. ("key2", "value3")
  124. ("key3", "value4");
  125. // clang-format on
  126. // Merged object where we prefer the values in mergeObj1
  127. // clang-format off
  128. dynamic combinedPreferObj1 = folly::dynamic::object
  129. ("key1", "value1")
  130. ("key2", "value2")
  131. ("key3", "value4");
  132. // clang-format on
  133. auto newMergeObj = dynamic::merge(mergeObj1, mergeObj2);
  134. EXPECT_EQ(newMergeObj, combinedPreferObj2);
  135. EXPECT_EQ(mergeObj1, origMergeObj1); // mergeObj1 should be unchanged
  136. mergeObj1.update(mergeObj2);
  137. EXPECT_EQ(mergeObj1, combinedPreferObj2);
  138. dynamic arr = dynamic::array(1, 2, 3, 4, 5, 6);
  139. EXPECT_THROW(mergeObj1.update(arr), std::exception);
  140. mergeObj1 = origMergeObj1; // reset it
  141. mergeObj1.update_missing(mergeObj2);
  142. EXPECT_EQ(mergeObj1, combinedPreferObj1);
  143. }
  144. namespace {
  145. struct StaticStrings {
  146. static constexpr auto kA = "a";
  147. static constexpr const char* kB = "b";
  148. static const folly::StringPiece kFoo;
  149. static const std::string kBar;
  150. };
  151. /* static */ const folly::StringPiece StaticStrings::kFoo{"foo"};
  152. /* static */ const std::string StaticStrings::kBar{"bar"};
  153. } // namespace
  154. TEST(Dynamic, ObjectHeterogeneousAccess) {
  155. dynamic empty;
  156. dynamic foo{"foo"};
  157. const char* a = "a";
  158. StringPiece sp{"a"};
  159. std::string str{"a"};
  160. dynamic bar{"bar"};
  161. const char* b = "b";
  162. dynamic obj = dynamic::object("a", 123)(empty, 456)(foo, 789);
  163. // at()
  164. EXPECT_EQ(obj.at(empty), 456);
  165. EXPECT_EQ(obj.at(nullptr), 456);
  166. EXPECT_EQ(obj.at(foo), 789);
  167. EXPECT_EQ(obj.at(a), 123);
  168. EXPECT_EQ(obj.at(StaticStrings::kA), 123);
  169. EXPECT_EQ(obj.at("a"), 123);
  170. EXPECT_EQ(obj.at(sp), 123);
  171. EXPECT_EQ(obj.at(StringPiece{"a"}), 123);
  172. EXPECT_EQ(obj.at(StaticStrings::kFoo), 789);
  173. EXPECT_EQ(obj.at(std::string{"a"}), 123);
  174. EXPECT_EQ(obj.at(str), 123);
  175. EXPECT_THROW(obj.at(b), std::out_of_range);
  176. EXPECT_THROW(obj.at(StringPiece{b}), std::out_of_range);
  177. EXPECT_THROW(obj.at(StaticStrings::kBar), std::out_of_range);
  178. // get_ptr()
  179. EXPECT_NE(obj.get_ptr(empty), nullptr);
  180. EXPECT_EQ(*obj.get_ptr(empty), 456);
  181. EXPECT_NE(obj.get_ptr(nullptr), nullptr);
  182. EXPECT_EQ(*obj.get_ptr(nullptr), 456);
  183. EXPECT_NE(obj.get_ptr(foo), nullptr);
  184. EXPECT_EQ(*obj.get_ptr(foo), 789);
  185. EXPECT_NE(obj.get_ptr(a), nullptr);
  186. EXPECT_EQ(*obj.get_ptr(a), 123);
  187. EXPECT_NE(obj.get_ptr(StaticStrings::kA), nullptr);
  188. EXPECT_EQ(*obj.get_ptr(StaticStrings::kA), 123);
  189. EXPECT_NE(obj.get_ptr("a"), nullptr);
  190. EXPECT_EQ(*obj.get_ptr("a"), 123);
  191. EXPECT_NE(obj.get_ptr(sp), nullptr);
  192. EXPECT_EQ(*obj.get_ptr(sp), 123);
  193. EXPECT_NE(obj.get_ptr(StringPiece{"a"}), nullptr);
  194. EXPECT_EQ(*obj.get_ptr(StringPiece{"a"}), 123);
  195. EXPECT_NE(obj.get_ptr(StaticStrings::kFoo), nullptr);
  196. EXPECT_EQ(*obj.get_ptr(StaticStrings::kFoo), 789);
  197. EXPECT_NE(obj.get_ptr(std::string{"a"}), nullptr);
  198. EXPECT_EQ(*obj.get_ptr(std::string{"a"}), 123);
  199. EXPECT_NE(obj.get_ptr(str), nullptr);
  200. EXPECT_EQ(*obj.get_ptr(str), 123);
  201. EXPECT_EQ(obj.get_ptr(b), nullptr);
  202. EXPECT_EQ(obj.get_ptr(StringPiece{b}), nullptr);
  203. EXPECT_EQ(obj.get_ptr(StaticStrings::kBar), nullptr);
  204. // find()
  205. EXPECT_EQ(obj.find(empty)->second, 456);
  206. EXPECT_EQ(obj.find(nullptr)->second, 456);
  207. EXPECT_EQ(obj.find(foo)->second, 789);
  208. EXPECT_EQ(obj.find(a)->second, 123);
  209. EXPECT_EQ(obj.find(StaticStrings::kA)->second, 123);
  210. EXPECT_EQ(obj.find("a")->second, 123);
  211. EXPECT_EQ(obj.find(sp)->second, 123);
  212. EXPECT_EQ(obj.find(StringPiece{"a"})->second, 123);
  213. EXPECT_EQ(obj.find(StaticStrings::kFoo)->second, 789);
  214. EXPECT_EQ(obj.find(std::string{"a"})->second, 123);
  215. EXPECT_EQ(obj.find(str)->second, 123);
  216. EXPECT_TRUE(obj.find(b) == obj.items().end());
  217. EXPECT_TRUE(obj.find(StringPiece{b}) == obj.items().end());
  218. EXPECT_TRUE(obj.find(StaticStrings::kBar) == obj.items().end());
  219. // count()
  220. EXPECT_EQ(obj.count(empty), 1);
  221. EXPECT_EQ(obj.count(nullptr), 1);
  222. EXPECT_EQ(obj.count(foo), 1);
  223. EXPECT_EQ(obj.count(a), 1);
  224. EXPECT_EQ(obj.count(StaticStrings::kA), 1);
  225. EXPECT_EQ(obj.count("a"), 1);
  226. EXPECT_EQ(obj.count(sp), 1);
  227. EXPECT_EQ(obj.count(StringPiece{"a"}), 1);
  228. EXPECT_EQ(obj.count(StaticStrings::kFoo), 1);
  229. EXPECT_EQ(obj.count(std::string{"a"}), 1);
  230. EXPECT_EQ(obj.count(str), 1);
  231. EXPECT_EQ(obj.count(b), 0);
  232. EXPECT_EQ(obj.count(StringPiece{b}), 0);
  233. EXPECT_EQ(obj.count(StaticStrings::kBar), 0);
  234. // operator[]
  235. EXPECT_EQ(obj[empty], 456);
  236. EXPECT_EQ(obj[nullptr], 456);
  237. EXPECT_EQ(obj[foo], 789);
  238. EXPECT_EQ(obj[a], 123);
  239. EXPECT_EQ(obj[StaticStrings::kA], 123);
  240. EXPECT_EQ(obj["a"], 123);
  241. EXPECT_EQ(obj[sp], 123);
  242. EXPECT_EQ(obj[StringPiece{"a"}], 123);
  243. EXPECT_EQ(obj[StaticStrings::kFoo], 789);
  244. EXPECT_EQ(obj[std::string{"a"}], 123);
  245. EXPECT_EQ(obj[str], 123);
  246. EXPECT_EQ(obj[b], nullptr);
  247. obj[b] = 42;
  248. EXPECT_EQ(obj[StringPiece{b}], 42);
  249. obj[StaticStrings::kBar] = 43;
  250. EXPECT_EQ(obj["bar"], 43);
  251. // erase() + dynamic&&
  252. EXPECT_EQ(obj.erase(StaticStrings::kB), /* num elements erased */ 1);
  253. dynamic obj2 = obj;
  254. dynamic obj3 = obj;
  255. dynamic obj4 = obj;
  256. EXPECT_EQ(std::move(obj).find(StaticStrings::kFoo)->second, 789);
  257. EXPECT_EQ(std::move(obj2).at(StaticStrings::kA), 123);
  258. EXPECT_EQ(std::move(obj3)[nullptr], 456);
  259. EXPECT_EQ(std::move(obj4).erase(StaticStrings::kBar), 1);
  260. }
  261. TEST(Dynamic, CastFromVectorOfBooleans) {
  262. std::vector<bool> b;
  263. b.push_back(true);
  264. b.push_back(false);
  265. dynamic obj = dynamic::object("a", b[0])("b", b[1]);
  266. EXPECT_EQ(obj.at("a"), true);
  267. EXPECT_EQ(obj.at("b"), false);
  268. }
  269. TEST(Dynamic, CastFromConstVectorOfBooleans) {
  270. const std::vector<bool> b = {true, false};
  271. dynamic obj = dynamic::object("a", b[0])("b", b[1]);
  272. EXPECT_EQ(obj.at("a"), true);
  273. EXPECT_EQ(obj.at("b"), false);
  274. }
  275. TEST(Dynamic, ObjectErase) {
  276. dynamic obj = dynamic::object("key1", "val")("key2", "val2");
  277. EXPECT_EQ(obj.count("key1"), 1);
  278. EXPECT_EQ(obj.count("key2"), 1);
  279. EXPECT_EQ(obj.erase("key1"), 1);
  280. EXPECT_EQ(obj.count("key1"), 0);
  281. EXPECT_EQ(obj.count("key2"), 1);
  282. EXPECT_EQ(obj.erase("key1"), 0);
  283. obj["key1"] = 12;
  284. EXPECT_EQ(obj.count("key1"), 1);
  285. EXPECT_EQ(obj.count("key2"), 1);
  286. auto it = obj.find("key2");
  287. obj.erase(it);
  288. EXPECT_EQ(obj.count("key1"), 1);
  289. EXPECT_EQ(obj.count("key2"), 0);
  290. obj["asd"] = 42.0;
  291. obj["foo"] = 42.0;
  292. EXPECT_EQ(obj.size(), 3);
  293. auto ret = obj.erase(std::next(obj.items().begin()), obj.items().end());
  294. EXPECT_TRUE(ret == obj.items().end());
  295. EXPECT_EQ(obj.size(), 1);
  296. obj.erase(obj.items().begin());
  297. EXPECT_TRUE(obj.empty());
  298. }
  299. TEST(Dynamic, ArrayErase) {
  300. dynamic arr = dynamic::array(1, 2, 3, 4, 5, 6);
  301. EXPECT_THROW(arr.erase(1), std::exception);
  302. EXPECT_EQ(arr.size(), 6);
  303. EXPECT_EQ(arr[0], 1);
  304. arr.erase(arr.begin());
  305. EXPECT_EQ(arr.size(), 5);
  306. arr.erase(std::next(arr.begin()), std::prev(arr.end()));
  307. EXPECT_EQ(arr.size(), 2);
  308. EXPECT_EQ(arr[0], 2);
  309. EXPECT_EQ(arr[1], 6);
  310. }
  311. TEST(Dynamic, StringBasics) {
  312. dynamic str = "hello world";
  313. EXPECT_EQ(11, str.size());
  314. EXPECT_FALSE(str.empty());
  315. str = "";
  316. EXPECT_TRUE(str.empty());
  317. }
  318. TEST(Dynamic, ArrayBasics) {
  319. dynamic array = dynamic::array(1, 2, 3);
  320. EXPECT_EQ(array.size(), 3);
  321. EXPECT_EQ(array.at(0), 1);
  322. EXPECT_EQ(array.at(1), 2);
  323. EXPECT_EQ(array.at(2), 3);
  324. EXPECT_ANY_THROW(array.at(-1));
  325. EXPECT_ANY_THROW(array.at(3));
  326. array.push_back("foo");
  327. EXPECT_EQ(array.size(), 4);
  328. array.resize(12, "something");
  329. EXPECT_EQ(array.size(), 12);
  330. EXPECT_EQ(array[11], "something");
  331. }
  332. TEST(Dynamic, DeepCopy) {
  333. dynamic val = dynamic::array("foo", "bar", dynamic::array("foo1", "bar1"));
  334. EXPECT_EQ(val.at(2).at(0), "foo1");
  335. EXPECT_EQ(val.at(2).at(1), "bar1");
  336. dynamic val2 = val;
  337. EXPECT_EQ(val2.at(2).at(0), "foo1");
  338. EXPECT_EQ(val2.at(2).at(1), "bar1");
  339. EXPECT_EQ(val.at(2).at(0), "foo1");
  340. EXPECT_EQ(val.at(2).at(1), "bar1");
  341. val2.at(2).at(0) = "foo3";
  342. val2.at(2).at(1) = "bar3";
  343. EXPECT_EQ(val.at(2).at(0), "foo1");
  344. EXPECT_EQ(val.at(2).at(1), "bar1");
  345. EXPECT_EQ(val2.at(2).at(0), "foo3");
  346. EXPECT_EQ(val2.at(2).at(1), "bar3");
  347. dynamic obj = dynamic::object("a", "b")("c", dynamic::array("d", "e", "f"));
  348. EXPECT_EQ(obj.at("a"), "b");
  349. dynamic obj2 = obj;
  350. obj2.at("a") = dynamic::array(1, 2, 3);
  351. EXPECT_EQ(obj.at("a"), "b");
  352. dynamic expected = dynamic::array(1, 2, 3);
  353. EXPECT_EQ(obj2.at("a"), expected);
  354. }
  355. TEST(Dynamic, ArrayReassignment) {
  356. dynamic o = 1;
  357. dynamic d1 = dynamic::array(o);
  358. EXPECT_EQ(dynamic::ARRAY, d1.type());
  359. d1 = dynamic::array(o);
  360. EXPECT_EQ(dynamic::ARRAY, d1.type());
  361. }
  362. TEST(Dynamic, Operator) {
  363. bool caught = false;
  364. try {
  365. dynamic d1 = dynamic::object;
  366. dynamic d2 = dynamic::object;
  367. auto foo = d1 < d2;
  368. LOG(ERROR) << "operator < returned " << static_cast<int>(foo)
  369. << " instead of throwing";
  370. } catch (std::exception const&) {
  371. caught = true;
  372. }
  373. EXPECT_TRUE(caught);
  374. dynamic foo = "asd";
  375. dynamic bar = "bar";
  376. dynamic sum = foo + bar;
  377. EXPECT_EQ(sum, "asdbar");
  378. dynamic some = 12;
  379. dynamic nums = 4;
  380. dynamic math = some / nums;
  381. EXPECT_EQ(math, 3);
  382. }
  383. TEST(Dynamic, Conversions) {
  384. dynamic str = "12.0";
  385. EXPECT_EQ(str.asDouble(), 12.0);
  386. EXPECT_ANY_THROW(str.asInt());
  387. EXPECT_ANY_THROW(str.asBool());
  388. str = "12";
  389. EXPECT_EQ(str.asInt(), 12);
  390. EXPECT_EQ(str.asDouble(), 12.0);
  391. str = "0";
  392. EXPECT_EQ(str.asBool(), false);
  393. EXPECT_EQ(str.asInt(), 0);
  394. EXPECT_EQ(str.asDouble(), 0);
  395. EXPECT_EQ(str.asString(), "0");
  396. dynamic num = 12;
  397. EXPECT_EQ("12", num.asString());
  398. EXPECT_EQ(12.0, num.asDouble());
  399. }
  400. TEST(Dynamic, GetSetDefaultTest) {
  401. dynamic d1 = dynamic::object("foo", "bar");
  402. EXPECT_EQ(d1.getDefault("foo", "baz"), "bar");
  403. EXPECT_EQ(d1.getDefault("quux", "baz"), "baz");
  404. dynamic d2 = dynamic::object("foo", "bar");
  405. EXPECT_EQ(d2.setDefault("foo", "quux"), "bar");
  406. d2.setDefault("bar", dynamic::array).push_back(42);
  407. EXPECT_EQ(d2["bar"][0], 42);
  408. dynamic d3 = dynamic::object, empty = dynamic::object;
  409. EXPECT_EQ(d3.getDefault("foo"), empty);
  410. d3.setDefault("foo")["bar"] = "baz";
  411. EXPECT_EQ(d3["foo"]["bar"], "baz");
  412. // we do not allow getDefault/setDefault on arrays
  413. dynamic d4 = dynamic::array;
  414. EXPECT_ANY_THROW(d4.getDefault("foo", "bar"));
  415. EXPECT_ANY_THROW(d4.setDefault("foo", "bar"));
  416. // Using dynamic keys
  417. dynamic k10{10}, k20{20}, kTrue{true};
  418. dynamic d5 = dynamic::object(k10, "foo");
  419. EXPECT_EQ(d5.setDefault(k10, "bar"), "foo");
  420. EXPECT_EQ(d5.setDefault(k20, "bar"), "bar");
  421. EXPECT_EQ(d5.setDefault(kTrue, "baz"), "baz");
  422. EXPECT_EQ(d5.setDefault(StaticStrings::kA, "foo"), "foo");
  423. EXPECT_EQ(d5.setDefault(StaticStrings::kB, "foo"), "foo");
  424. EXPECT_EQ(d5.setDefault(StaticStrings::kFoo, "bar"), "bar");
  425. EXPECT_EQ(d5.setDefault(StaticStrings::kBar, "foo"), "foo");
  426. }
  427. TEST(Dynamic, ObjectForwarding) {
  428. // Make sure dynamic::object can be constructed the same way as any
  429. // dynamic.
  430. dynamic d = dynamic::object("asd", dynamic::array("foo", "bar"));
  431. // clang-format off
  432. dynamic d2 = dynamic::object("key2", dynamic::array("value", "words"))
  433. ("key", "value1");
  434. // clang-format on
  435. }
  436. TEST(Dynamic, GetPtr) {
  437. dynamic array = dynamic::array(1, 2, "three");
  438. EXPECT_TRUE(array.get_ptr(0));
  439. EXPECT_FALSE(array.get_ptr(-1));
  440. EXPECT_FALSE(array.get_ptr(3));
  441. EXPECT_EQ(dynamic("three"), *array.get_ptr(2));
  442. const dynamic& carray = array;
  443. EXPECT_EQ(dynamic("three"), *carray.get_ptr(2));
  444. dynamic object = dynamic::object("one", 1)("two", 2);
  445. EXPECT_TRUE(object.get_ptr("one"));
  446. EXPECT_FALSE(object.get_ptr("three"));
  447. EXPECT_EQ(dynamic(2), *object.get_ptr("two"));
  448. *object.get_ptr("one") = 11;
  449. EXPECT_EQ(dynamic(11), *object.get_ptr("one"));
  450. const dynamic& cobject = object;
  451. EXPECT_EQ(dynamic(2), *cobject.get_ptr("two"));
  452. }
  453. TEST(Dynamic, Assignment) {
  454. const dynamic ds[] = {
  455. dynamic::array(1, 2, 3),
  456. dynamic::object("a", true),
  457. 24,
  458. 26.5,
  459. true,
  460. "hello",
  461. };
  462. const dynamic dd[] = {
  463. dynamic::array(5, 6),
  464. dynamic::object("t", "T")(1, 7),
  465. 9000,
  466. 3.14159,
  467. false,
  468. "world",
  469. };
  470. for (const auto& source : ds) {
  471. for (const auto& dest : dd) {
  472. dynamic tmp(dest);
  473. EXPECT_EQ(tmp, dest);
  474. tmp = source;
  475. EXPECT_EQ(tmp, source);
  476. }
  477. }
  478. }
  479. std::string make_long_string() {
  480. return std::string(100, 'a');
  481. }
  482. TEST(Dynamic, GetDefault) {
  483. const auto s = make_long_string();
  484. dynamic kDynamicKey{10};
  485. dynamic ds(s);
  486. dynamic tmp(s);
  487. dynamic d1 = dynamic::object("key1", s);
  488. dynamic d2 = dynamic::object("key2", s);
  489. dynamic d3 = dynamic::object("key3", s);
  490. dynamic d4 = dynamic::object("key4", s);
  491. // lvalue - lvalue
  492. dynamic ayy("ayy");
  493. EXPECT_EQ(ds, d1.getDefault("key1", ayy));
  494. EXPECT_EQ(ds, d1.getDefault("key1", ayy));
  495. EXPECT_EQ(ds, d1.getDefault("not-a-key", tmp));
  496. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kA, tmp));
  497. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kB, tmp));
  498. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kFoo, tmp));
  499. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kBar, tmp));
  500. EXPECT_EQ(ds, d1.getDefault(kDynamicKey, tmp));
  501. EXPECT_EQ(ds, tmp);
  502. // lvalue - rvalue
  503. EXPECT_EQ(ds, d1.getDefault("key1", "ayy"));
  504. EXPECT_EQ(ds, d1.getDefault("key1", "ayy"));
  505. EXPECT_EQ(ds, d1.getDefault("not-a-key", std::move(tmp)));
  506. EXPECT_NE(ds, tmp);
  507. tmp = s;
  508. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kA, std::move(tmp)));
  509. EXPECT_NE(ds, tmp);
  510. tmp = s;
  511. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kB, std::move(tmp)));
  512. EXPECT_NE(ds, tmp);
  513. tmp = s;
  514. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kFoo, std::move(tmp)));
  515. EXPECT_NE(ds, tmp);
  516. tmp = s;
  517. EXPECT_EQ(ds, d1.getDefault(StaticStrings::kBar, std::move(tmp)));
  518. EXPECT_NE(ds, tmp);
  519. tmp = s;
  520. EXPECT_EQ(ds, d1.getDefault(kDynamicKey, std::move(tmp)));
  521. EXPECT_NE(ds, tmp);
  522. // rvalue - lvalue
  523. tmp = s;
  524. EXPECT_EQ(ds, std::move(d1).getDefault("key1", ayy));
  525. EXPECT_NE(ds, d1["key1"]);
  526. EXPECT_EQ(ds, std::move(d2).getDefault("not-a-key", tmp));
  527. EXPECT_EQ(dynamic(dynamic::object("key2", s)), d2);
  528. EXPECT_EQ(ds, tmp);
  529. EXPECT_EQ(ds, std::move(d2).getDefault(StaticStrings::kA, tmp));
  530. EXPECT_EQ(dynamic(dynamic::object("key2", s)), d2);
  531. EXPECT_EQ(ds, tmp);
  532. EXPECT_EQ(ds, std::move(d2).getDefault(StaticStrings::kB, tmp));
  533. EXPECT_EQ(dynamic(dynamic::object("key2", s)), d2);
  534. EXPECT_EQ(ds, tmp);
  535. EXPECT_EQ(ds, std::move(d2).getDefault(StaticStrings::kFoo, tmp));
  536. EXPECT_EQ(dynamic(dynamic::object("key2", s)), d2);
  537. EXPECT_EQ(ds, tmp);
  538. EXPECT_EQ(ds, std::move(d2).getDefault(StaticStrings::kBar, tmp));
  539. EXPECT_EQ(dynamic(dynamic::object("key2", s)), d2);
  540. EXPECT_EQ(ds, tmp);
  541. EXPECT_EQ(ds, std::move(d2).getDefault(kDynamicKey, tmp));
  542. EXPECT_EQ(dynamic(dynamic::object("key2", s)), d2);
  543. EXPECT_EQ(ds, tmp);
  544. // rvalue - rvalue
  545. EXPECT_EQ(ds, std::move(d3).getDefault("key3", std::move(tmp)));
  546. EXPECT_NE(ds, d3["key3"]);
  547. EXPECT_EQ(ds, tmp);
  548. EXPECT_EQ(ds, std::move(d4).getDefault("not-a-key", std::move(tmp)));
  549. EXPECT_EQ(dynamic(dynamic::object("key4", s)), d4);
  550. EXPECT_NE(ds, tmp);
  551. tmp = s;
  552. EXPECT_EQ(ds, std::move(d4).getDefault(StaticStrings::kA, std::move(tmp)));
  553. EXPECT_EQ(dynamic(dynamic::object("key4", s)), d4);
  554. EXPECT_NE(ds, tmp);
  555. tmp = s;
  556. EXPECT_EQ(ds, std::move(d4).getDefault(StaticStrings::kB, std::move(tmp)));
  557. EXPECT_EQ(dynamic(dynamic::object("key4", s)), d4);
  558. EXPECT_NE(ds, tmp);
  559. tmp = s;
  560. EXPECT_EQ(ds, std::move(d4).getDefault(StaticStrings::kFoo, std::move(tmp)));
  561. EXPECT_EQ(dynamic(dynamic::object("key4", s)), d4);
  562. EXPECT_NE(ds, tmp);
  563. tmp = s;
  564. EXPECT_EQ(ds, std::move(d4).getDefault(StaticStrings::kBar, std::move(tmp)));
  565. EXPECT_EQ(dynamic(dynamic::object("key4", s)), d4);
  566. EXPECT_NE(ds, tmp);
  567. tmp = s;
  568. EXPECT_EQ(ds, std::move(d4).getDefault(kDynamicKey, std::move(tmp)));
  569. EXPECT_EQ(dynamic(dynamic::object("key4", s)), d4);
  570. EXPECT_NE(ds, tmp);
  571. }
  572. TEST(Dynamic, GetString) {
  573. const dynamic c(make_long_string());
  574. dynamic d(make_long_string());
  575. dynamic m(make_long_string());
  576. auto s = make_long_string();
  577. EXPECT_EQ(s, c.getString());
  578. EXPECT_EQ(s, c.getString());
  579. d.getString() += " hello";
  580. EXPECT_EQ(s + " hello", d.getString());
  581. EXPECT_EQ(s + " hello", d.getString());
  582. EXPECT_EQ(s, std::move(m).getString());
  583. EXPECT_EQ(s, m.getString());
  584. auto moved = std::move(m).getString();
  585. EXPECT_EQ(s, moved);
  586. EXPECT_NE(dynamic(s), m);
  587. }
  588. TEST(Dynamic, GetSmallThings) {
  589. const dynamic cint(5);
  590. const dynamic cdouble(5.0);
  591. const dynamic cbool(true);
  592. dynamic dint(5);
  593. dynamic ddouble(5.0);
  594. dynamic dbool(true);
  595. dynamic mint(5);
  596. dynamic mdouble(5.0);
  597. dynamic mbool(true);
  598. EXPECT_EQ(5, cint.getInt());
  599. dint.getInt() = 6;
  600. EXPECT_EQ(6, dint.getInt());
  601. EXPECT_EQ(5, std::move(mint).getInt());
  602. EXPECT_EQ(5.0, cdouble.getDouble());
  603. ddouble.getDouble() = 6.0;
  604. EXPECT_EQ(6.0, ddouble.getDouble());
  605. EXPECT_EQ(5.0, std::move(mdouble).getDouble());
  606. EXPECT_TRUE(cbool.getBool());
  607. dbool.getBool() = false;
  608. EXPECT_FALSE(dbool.getBool());
  609. EXPECT_TRUE(std::move(mbool).getBool());
  610. }
  611. TEST(Dynamic, At) {
  612. const dynamic cd = dynamic::object("key1", make_long_string());
  613. dynamic dd = dynamic::object("key1", make_long_string());
  614. dynamic md = dynamic::object("key1", make_long_string());
  615. dynamic ds(make_long_string());
  616. EXPECT_EQ(ds, cd.at("key1"));
  617. EXPECT_EQ(ds, cd.at("key1"));
  618. dd.at("key1").getString() += " hello";
  619. EXPECT_EQ(dynamic(make_long_string() + " hello"), dd.at("key1"));
  620. EXPECT_EQ(dynamic(make_long_string() + " hello"), dd.at("key1"));
  621. EXPECT_EQ(ds, std::move(md).at("key1")); // move available, but not performed
  622. EXPECT_EQ(ds, md.at("key1"));
  623. dynamic moved = std::move(md).at("key1"); // move performed
  624. EXPECT_EQ(ds, moved);
  625. EXPECT_NE(ds, md.at("key1"));
  626. }
  627. TEST(Dynamic, Brackets) {
  628. const dynamic cd = dynamic::object("key1", make_long_string());
  629. dynamic dd = dynamic::object("key1", make_long_string());
  630. dynamic md = dynamic::object("key1", make_long_string());
  631. dynamic ds(make_long_string());
  632. EXPECT_EQ(ds, cd["key1"]);
  633. EXPECT_EQ(ds, cd["key1"]);
  634. dd["key1"].getString() += " hello";
  635. EXPECT_EQ(dynamic(make_long_string() + " hello"), dd["key1"]);
  636. EXPECT_EQ(dynamic(make_long_string() + " hello"), dd["key1"]);
  637. EXPECT_EQ(ds, std::move(md)["key1"]); // move available, but not performed
  638. EXPECT_EQ(ds, md["key1"]);
  639. dynamic moved = std::move(md)["key1"]; // move performed
  640. EXPECT_EQ(ds, moved);
  641. EXPECT_NE(ds, md["key1"]);
  642. }
  643. TEST(Dynamic, PrintNull) {
  644. std::stringstream ss;
  645. ss << folly::dynamic(nullptr);
  646. EXPECT_EQ("null", ss.str());
  647. }
  648. TEST(Dynamic, WriteThroughArrayIterators) {
  649. dynamic const cint(0);
  650. dynamic d = dynamic::array(cint, cint, cint);
  651. size_t size = d.size();
  652. for (auto& val : d) {
  653. EXPECT_EQ(val, cint);
  654. }
  655. EXPECT_EQ(d.size(), size);
  656. dynamic ds(make_long_string());
  657. for (auto& val : d) {
  658. val = ds; // assign through reference
  659. }
  660. ds = "short string";
  661. dynamic ds2(make_long_string());
  662. for (auto& val : d) {
  663. EXPECT_EQ(val, ds2);
  664. }
  665. EXPECT_EQ(d.size(), size);
  666. }
  667. TEST(Dynamic, MoveOutOfArrayIterators) {
  668. dynamic ds(make_long_string());
  669. dynamic d = dynamic::array(ds, ds, ds);
  670. size_t size = d.size();
  671. for (auto& val : d) {
  672. EXPECT_EQ(val, ds);
  673. }
  674. EXPECT_EQ(d.size(), size);
  675. for (auto& val : d) {
  676. dynamic waste = std::move(val); // force moving out
  677. EXPECT_EQ(waste, ds);
  678. }
  679. for (auto& val : d) {
  680. EXPECT_NE(val, ds);
  681. }
  682. EXPECT_EQ(d.size(), size);
  683. }
  684. TEST(Dynamic, WriteThroughObjectIterators) {
  685. dynamic const cint(0);
  686. dynamic d = dynamic::object("key1", cint)("key2", cint);
  687. size_t size = d.size();
  688. for (auto& val : d.items()) {
  689. EXPECT_EQ(val.second, cint);
  690. }
  691. EXPECT_EQ(d.size(), size);
  692. dynamic ds(make_long_string());
  693. for (auto& val : d.items()) {
  694. val.second = ds; // assign through reference
  695. }
  696. ds = "short string";
  697. dynamic ds2(make_long_string());
  698. for (auto& val : d.items()) {
  699. EXPECT_EQ(val.second, ds2);
  700. }
  701. EXPECT_EQ(d.size(), size);
  702. }
  703. TEST(Dynamic, MoveOutOfObjectIterators) {
  704. dynamic ds(make_long_string());
  705. dynamic d = dynamic::object("key1", ds)("key2", ds);
  706. size_t size = d.size();
  707. for (auto& val : d.items()) {
  708. EXPECT_EQ(val.second, ds);
  709. }
  710. EXPECT_EQ(d.size(), size);
  711. for (auto& val : d.items()) {
  712. dynamic waste = std::move(val.second); // force moving out
  713. EXPECT_EQ(waste, ds);
  714. }
  715. for (auto& val : d.items()) {
  716. EXPECT_NE(val.second, ds);
  717. }
  718. EXPECT_EQ(d.size(), size);
  719. }
  720. TEST(Dynamic, ArrayIteratorInterop) {
  721. dynamic d = dynamic::array(0, 1, 2);
  722. dynamic const& cdref = d;
  723. auto it = d.begin();
  724. auto cit = cdref.begin();
  725. EXPECT_EQ(it, cit);
  726. EXPECT_EQ(cit, d.begin());
  727. EXPECT_EQ(it, cdref.begin());
  728. // Erase using non-const iterator
  729. it = d.erase(it);
  730. cit = cdref.begin();
  731. EXPECT_EQ(*it, 1);
  732. EXPECT_EQ(cit, it);
  733. // Assign from non-const to const, preserve equality
  734. decltype(cit) cit2 = it;
  735. EXPECT_EQ(cit, cit2);
  736. }
  737. TEST(Dynamic, ObjectIteratorInterop) {
  738. dynamic ds = make_long_string();
  739. dynamic d = dynamic::object(0, ds)(1, ds)(2, ds);
  740. dynamic const& cdref = d;
  741. auto it = d.find(0);
  742. auto cit = cdref.find(0);
  743. EXPECT_NE(it, cdref.items().end());
  744. EXPECT_NE(cit, cdref.items().end());
  745. EXPECT_EQ(it, cit);
  746. ++cit;
  747. // Erase using non-const iterator
  748. auto it2 = d.erase(it);
  749. EXPECT_EQ(cit, it2);
  750. // Assign from non-const to const, preserve equality
  751. decltype(cit) cit2 = it2;
  752. EXPECT_EQ(cit, cit2);
  753. }
  754. TEST(Dynamic, MergePatchWithNonObject) {
  755. dynamic target = dynamic::object("a", "b")("c", "d");
  756. dynamic patch = dynamic::array(1, 2, 3);
  757. target.merge_patch(patch);
  758. EXPECT_TRUE(target.isArray());
  759. }
  760. TEST(Dynamic, MergePatchReplaceInFlatObject) {
  761. dynamic target = dynamic::object("a", "b")("c", "d");
  762. dynamic patch = dynamic::object("a", "z");
  763. target.merge_patch(patch);
  764. EXPECT_EQ("z", target["a"].getString());
  765. EXPECT_EQ("d", target["c"].getString());
  766. }
  767. TEST(Dynamic, MergePatchAddInFlatObject) {
  768. dynamic target = dynamic::object("a", "b")("c", "d");
  769. dynamic patch = dynamic::object("e", "f");
  770. target.merge_patch(patch);
  771. EXPECT_EQ("b", target["a"].getString());
  772. EXPECT_EQ("d", target["c"].getString());
  773. EXPECT_EQ("f", target["e"].getString());
  774. }
  775. TEST(Dynamic, MergePatchReplaceInNestedObject) {
  776. dynamic target = dynamic::object("a", dynamic::object("d", 10))("b", "c");
  777. dynamic patch = dynamic::object("a", dynamic::object("d", 100));
  778. target.merge_patch(patch);
  779. EXPECT_EQ(100, target["a"]["d"].getInt());
  780. EXPECT_EQ("c", target["b"].getString());
  781. }
  782. TEST(Dynamic, MergePatchAddInNestedObject) {
  783. dynamic target = dynamic::object("a", dynamic::object("d", 10))("b", "c");
  784. dynamic patch = dynamic::object("a", dynamic::object("e", "f"));
  785. target.merge_patch(patch);
  786. EXPECT_EQ(10, target["a"]["d"].getInt());
  787. EXPECT_EQ("f", target["a"]["e"].getString());
  788. EXPECT_EQ("c", target["b"].getString());
  789. }
  790. TEST(Dynamic, MergeNestePatch) {
  791. dynamic target = dynamic::object("a", dynamic::object("d", 10))("b", "c");
  792. dynamic patch = dynamic::object(
  793. "a", dynamic::object("d", dynamic::array(1, 2, 3)))("b", 100);
  794. target.merge_patch(patch);
  795. EXPECT_EQ(100, target["b"].getInt());
  796. {
  797. auto ary = patch["a"]["d"];
  798. ASSERT_TRUE(ary.isArray());
  799. EXPECT_EQ(1, ary[0].getInt());
  800. EXPECT_EQ(2, ary[1].getInt());
  801. EXPECT_EQ(3, ary[2].getInt());
  802. }
  803. }
  804. TEST(Dynamic, MergePatchRemoveInFlatObject) {
  805. dynamic target = dynamic::object("a", "b")("c", "d");
  806. dynamic patch = dynamic::object("c", nullptr);
  807. target.merge_patch(patch);
  808. EXPECT_EQ("b", target["a"].getString());
  809. EXPECT_EQ(0, target.count("c"));
  810. }
  811. TEST(Dynamic, MergePatchRemoveInNestedObject) {
  812. dynamic target =
  813. dynamic::object("a", dynamic::object("d", 10)("e", "f"))("b", "c");
  814. dynamic patch = dynamic::object("a", dynamic::object("e", nullptr));
  815. target.merge_patch(patch);
  816. EXPECT_EQ(10, target["a"]["d"].getInt());
  817. EXPECT_EQ(0, target["a"].count("e"));
  818. EXPECT_EQ("c", target["b"].getString());
  819. }
  820. TEST(Dynamic, MergePatchRemoveNonExistent) {
  821. dynamic target = dynamic::object("a", "b")("c", "d");
  822. dynamic patch = dynamic::object("e", nullptr);
  823. target.merge_patch(patch);
  824. EXPECT_EQ("b", target["a"].getString());
  825. EXPECT_EQ("d", target["c"].getString());
  826. EXPECT_EQ(2, target.size());
  827. }
  828. TEST(Dynamic, MergeDiffFlatObjects) {
  829. dynamic source = dynamic::object("a", 0)("b", 1)("c", 2);
  830. dynamic target = dynamic::object("a", 1)("b", 2);
  831. auto patch = dynamic::merge_diff(source, target);
  832. EXPECT_EQ(3, patch.size());
  833. EXPECT_EQ(1, patch["a"].getInt());
  834. EXPECT_EQ(2, patch["b"].getInt());
  835. EXPECT_TRUE(patch["c"].isNull());
  836. source.merge_patch(patch);
  837. EXPECT_EQ(source, target);
  838. }
  839. TEST(Dynamic, MergeDiffNestedObjects) {
  840. dynamic source = dynamic::object("a", dynamic::object("b", 1)("c", 2))(
  841. "d", dynamic::array(1, 2, 3));
  842. dynamic target = dynamic::object("a", dynamic::object("b", 2))(
  843. "d", dynamic::array(2, 3, 4));
  844. auto patch = dynamic::merge_diff(source, target);
  845. EXPECT_EQ(2, patch.size());
  846. EXPECT_EQ(2, patch["a"].size());
  847. EXPECT_EQ(2, patch["a"]["b"].getInt());
  848. EXPECT_TRUE(patch["a"]["c"].isNull());
  849. EXPECT_TRUE(patch["d"].isArray());
  850. EXPECT_EQ(3, patch["d"].size());
  851. EXPECT_EQ(2, patch["d"][0].getInt());
  852. EXPECT_EQ(3, patch["d"][1].getInt());
  853. EXPECT_EQ(4, patch["d"][2].getInt());
  854. source.merge_patch(patch);
  855. EXPECT_EQ(source, target);
  856. }
  857. using folly::json_pointer;
  858. TEST(Dynamic, JSONPointer) {
  859. dynamic target = dynamic::object;
  860. dynamic ary = dynamic::array("bar", "baz", dynamic::array("bletch", "xyzzy"));
  861. target["foo"] = ary;
  862. target[""] = 0;
  863. target["a/b"] = 1;
  864. target["c%d"] = 2;
  865. target["e^f"] = 3;
  866. target["g|h"] = 4;
  867. target["i\\j"] = 5;
  868. target["k\"l"] = 6;
  869. target[" "] = 7;
  870. target["m~n"] = 8;
  871. target["xyz"] = dynamic::object;
  872. target["xyz"][""] = dynamic::object("nested", "abc");
  873. target["xyz"]["def"] = dynamic::array(1, 2, 3);
  874. target["long_array"] = dynamic::array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
  875. target["-"] = dynamic::object("x", "y");
  876. EXPECT_EQ(target, *target.get_ptr(json_pointer::parse("")));
  877. EXPECT_EQ(ary, *(target.get_ptr(json_pointer::parse("/foo"))));
  878. EXPECT_EQ("bar", target.get_ptr(json_pointer::parse("/foo/0"))->getString());
  879. EXPECT_EQ(0, target.get_ptr(json_pointer::parse("/"))->getInt());
  880. EXPECT_EQ(1, target.get_ptr(json_pointer::parse("/a~1b"))->getInt());
  881. EXPECT_EQ(2, target.get_ptr(json_pointer::parse("/c%d"))->getInt());
  882. EXPECT_EQ(3, target.get_ptr(json_pointer::parse("/e^f"))->getInt());
  883. EXPECT_EQ(4, target.get_ptr(json_pointer::parse("/g|h"))->getInt());
  884. EXPECT_EQ(5, target.get_ptr(json_pointer::parse("/i\\j"))->getInt());
  885. EXPECT_EQ(6, target.get_ptr(json_pointer::parse("/k\"l"))->getInt());
  886. EXPECT_EQ(7, target.get_ptr(json_pointer::parse("/ "))->getInt());
  887. EXPECT_EQ(8, target.get_ptr(json_pointer::parse("/m~0n"))->getInt());
  888. // empty key in path
  889. EXPECT_EQ(
  890. "abc", target.get_ptr(json_pointer::parse("/xyz//nested"))->getString());
  891. EXPECT_EQ(3, target.get_ptr(json_pointer::parse("/xyz/def/2"))->getInt());
  892. EXPECT_EQ("baz", ary.get_ptr(json_pointer::parse("/1"))->getString());
  893. EXPECT_EQ("bletch", ary.get_ptr(json_pointer::parse("/2/0"))->getString());
  894. // double-digit index
  895. EXPECT_EQ(
  896. 12, target.get_ptr(json_pointer::parse("/long_array/11"))->getInt());
  897. // allow '-' to index in objects
  898. EXPECT_EQ("y", target.get_ptr(json_pointer::parse("/-/x"))->getString());
  899. // invalid JSON pointers formatting when accessing array
  900. EXPECT_THROW(
  901. target.get_ptr(json_pointer::parse("/foo/01")), std::invalid_argument);
  902. // non-existent keys/indexes
  903. EXPECT_EQ(nullptr, ary.get_ptr(json_pointer::parse("/3")));
  904. EXPECT_EQ(nullptr, target.get_ptr(json_pointer::parse("/unknown_key")));
  905. // intermediate key not found
  906. EXPECT_EQ(nullptr, target.get_ptr(json_pointer::parse("/foox/test")));
  907. // Intermediate key is '-'
  908. EXPECT_EQ(nullptr, target.get_ptr(json_pointer::parse("/foo/-/key")));
  909. // invalid path in object (key in array)
  910. EXPECT_THROW(
  911. target.get_ptr(json_pointer::parse("/foo/1/bar")), folly::TypeError);
  912. // Allow "-" index in the array
  913. EXPECT_EQ(nullptr, target.get_ptr(json_pointer::parse("/foo/-")));
  914. }