lax_ut.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #include "test_base.h"
  2. class TJsonPathLaxTest : public TJsonPathTestBase {
  3. public:
  4. TJsonPathLaxTest()
  5. : TJsonPathTestBase()
  6. {
  7. }
  8. UNIT_TEST_SUITE(TJsonPathLaxTest);
  9. UNIT_TEST(TestArrayUnwrap);
  10. UNIT_TEST(TestArrayWrap);
  11. UNIT_TEST(TestInvalidArrayIndices);
  12. UNIT_TEST(TestStructuralErrorsHandling);
  13. UNIT_TEST(TestCompareOperations);
  14. UNIT_TEST(TestFilter);
  15. UNIT_TEST(TestNumericMethods);
  16. UNIT_TEST(TestDoubleMethod);
  17. UNIT_TEST(TestKeyValueMethod);
  18. UNIT_TEST(TestExistsPredicate);
  19. UNIT_TEST(TestLikeRegexPredicate);
  20. UNIT_TEST(TestStartsWithPredicate);
  21. UNIT_TEST_SUITE_END();
  22. void TestArrayUnwrap() {
  23. const TVector<TMultiOutputTestCase> testCases = {
  24. {R"([
  25. {"key": 1},
  26. {"key": 2}
  27. ])", "$.key", {"1", "2"}},
  28. {R"([
  29. {"key": 1},
  30. {"key": 2}
  31. ])", "$.*", {"1", "2"}},
  32. {R"({
  33. "first": {"key": 1},
  34. "second": []
  35. })", "$.*.key", {"1"}},
  36. {R"({
  37. "first": {"key": 1},
  38. "second": []
  39. })", "$.*.*", {"1"}},
  40. {R"({"another_key": 123})", "$.key", {}},
  41. {R"([
  42. {"key": [{"nested": 28}]},
  43. {"key": [{"nested": 29}]}
  44. ])", "$.key.nested", {"28", "29"}},
  45. {R"([
  46. {"key": [{"nested": 28}]},
  47. {"key": [{"nested": 29}]}
  48. ])", "$.*.*", {"28", "29"}},
  49. };
  50. for (const auto& testCase : testCases) {
  51. for (const auto mode : LAX_MODES) {
  52. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  53. }
  54. }
  55. }
  56. void TestArrayWrap() {
  57. const TVector<TMultiOutputTestCase> testCases = {
  58. {R"([1, 2])", "$[*][0]", {"1", "2"}},
  59. {R"([[1], 2, [3]])", "$[*][0]", {"1", "2", "3"}},
  60. };
  61. for (const auto& testCase : testCases) {
  62. for (const auto mode : LAX_MODES) {
  63. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  64. }
  65. }
  66. }
  67. void TestInvalidArrayIndices() {
  68. const TVector<TMultiOutputTestCase> testCases = {
  69. {R"({
  70. "idx": -1,
  71. "array": [1, 2, 3]
  72. })", "$.array[$.idx]", {}},
  73. {R"({
  74. "from": -1,
  75. "to": 3,
  76. "array": [1, 2, 3]
  77. })", "$.array[$.from to $.to]", {}},
  78. {R"({
  79. "from": 0,
  80. "to": -1,
  81. "array": [1, 2, 3]
  82. })", "$.array[$.from to $.to]", {}},
  83. {R"([1, 2, 3, 4, 5])", "$[3 to 0]", {}},
  84. {R"({
  85. "idx": -1,
  86. "array": [1, 2, 3]
  87. })", "$.array[$.idx, 1 to 2]", {"2", "3"}},
  88. {R"({
  89. "from": -1,
  90. "to": 3,
  91. "array": [1, 2, 3]
  92. })", "$.array[0, $.from to $.to, 2 to 2]", {"1", "3"}},
  93. {R"({
  94. "from": 0,
  95. "to": -1,
  96. "array": [1, 2, 3]
  97. })", "$.array[0, $.from to $.to, 1 to 1]", {"1", "2"}},
  98. {R"([1, 2, 3, 4, 5])", "$[0, 3 to 0, 1]", {"1", "2"}},
  99. {R"([[1, 2], [3, 4, 5], []])", "$[*][2]", {"5"}},
  100. {"[]", "$[last]", {}},
  101. {"[]", "$[last to 0]", {}},
  102. };
  103. for (const auto& testCase : testCases) {
  104. for (const auto mode : LAX_MODES) {
  105. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  106. }
  107. }
  108. }
  109. void TestStructuralErrorsHandling() {
  110. const TVector<TMultiOutputTestCase> testCases = {
  111. {R"([[{"key": 1}]])", "$.key", {}},
  112. {R"([[{"key": 1}]])", "$.*", {}},
  113. {R"([
  114. {"key": 1},
  115. {"not_key": 2},
  116. {"key": 3}
  117. ])", "$[*].key", {"1", "3"}},
  118. };
  119. for (const auto& testCase : testCases) {
  120. for (const auto mode : LAX_MODES) {
  121. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  122. }
  123. }
  124. }
  125. void TestCompareOperations() {
  126. const TVector<TMultiOutputTestCase> testCases = {
  127. // Check unwrap
  128. {R"({
  129. "left": [1, 2, 3],
  130. "right": [4, 5, 6]
  131. })", "$.left < $.right", {"true"}},
  132. // Check incomparable types
  133. // NOTE: Even though values of types string and number are incomparable,
  134. // pair 1 < 4 is true and was found first, so the overall result is true
  135. {R"({
  136. "left": [1, 2, "string"],
  137. "right": [4, 5, 6]
  138. })", "$.left < $.right", {"true"}},
  139. // NOTE: In this example pair "string" < 4 results in error and was found first,
  140. // so overall result is null
  141. {R"({
  142. "left": ["string", 2, 3],
  143. "right": [4, 5, 6]
  144. })", "$.left < $.right", {"null"}},
  145. };
  146. for (const auto& testCase : testCases) {
  147. for (const auto mode : LAX_MODES) {
  148. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  149. }
  150. }
  151. }
  152. void TestFilter() {
  153. const TVector<TMultiOutputTestCase> testCases = {
  154. // Check unwrap
  155. {R"([
  156. {"age": 18},
  157. {"age": 25},
  158. {"age": 50},
  159. {"age": 5}
  160. ])", "$ ? (@.age >= 18 && @.age <= 30) . age", {"18", "25"}},
  161. };
  162. for (const auto& testCase : testCases) {
  163. for (const auto mode : LAX_MODES) {
  164. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  165. }
  166. }
  167. }
  168. void TestNumericMethods() {
  169. const TVector<TMultiOutputTestCase> testCases = {
  170. // Check unwrap
  171. {"[-1.23, 4.56, 3, 0]", "$.abs()", {"1.23", "4.56", "3", "0"}},
  172. {"[-1.23, 4.56, 3, 0]", "$.floor()", {"-2", "4", "3", "0"}},
  173. {"[-1.23, 4.56, 3, 0]", "$.ceiling()", {"-1", "5", "3", "0"}},
  174. };
  175. for (const auto& testCase : testCases) {
  176. for (const auto mode : LAX_MODES) {
  177. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  178. }
  179. }
  180. }
  181. void TestDoubleMethod() {
  182. const TVector<TMultiOutputTestCase> testCases = {
  183. // Check unwrap
  184. {R"([
  185. "123", "123.4", "0.567", "1234e-1", "567e-3", "123.4e-1",
  186. "123e3", "123e+3", "1.23e+1", "1.23e1",
  187. "12e0", "12.3e0", "0", "0.0", "0.0e0"
  188. ])", "$.double()", {
  189. "123", "123.4", "0.567", "123.4", "0.567", "12.34",
  190. "123000", "123000", "12.3", "12.3",
  191. "12", "12.3", "0", "0", "0",
  192. }},
  193. };
  194. for (const auto& testCase : testCases) {
  195. for (const auto mode : LAX_MODES) {
  196. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  197. }
  198. }
  199. }
  200. void TestKeyValueMethod() {
  201. const TVector<TMultiOutputTestCase> testCases = {
  202. // Check unwrap
  203. {R"([{
  204. "one": 1,
  205. "two": 2,
  206. "three": 3
  207. }])", "$.keyvalue().name", {"\"one\"", "\"three\"", "\"two\""}},
  208. };
  209. for (const auto& testCase : testCases) {
  210. for (const auto mode : LAX_MODES) {
  211. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  212. }
  213. }
  214. }
  215. void TestExistsPredicate() {
  216. const TVector<TMultiOutputTestCase> testCases = {
  217. {R"({
  218. "key": 123
  219. })", "exists ($.another_key)", {"false"}},
  220. };
  221. for (const auto& testCase : testCases) {
  222. for (const auto mode : LAX_MODES) {
  223. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  224. }
  225. }
  226. }
  227. void TestLikeRegexPredicate() {
  228. const TVector<TMultiOutputTestCase> testCases = {
  229. // Check unwrapping
  230. {R"(["string", "123", "456"])", R"($ like_regex "[0-9]+")", {"true"}},
  231. // Check early stopping
  232. {R"([123, "123", "456"])", R"($ like_regex "[0-9]+")", {"null"}},
  233. {R"(["123", "456", 123])", R"($ like_regex "[0-9]+")", {"true"}},
  234. };
  235. for (const auto& testCase : testCases) {
  236. for (const auto mode : LAX_MODES) {
  237. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  238. }
  239. }
  240. }
  241. void TestStartsWithPredicate() {
  242. const TVector<TMultiOutputTestCase> testCases = {
  243. {R"(["a", "b", "c"])", R"("abcd" starts with $[*])", {"true"}},
  244. {R"(["a", 1.45, 50])", R"("abcd" starts with $[*])", {"true"}},
  245. {R"([1.45, 50, "a"])", R"("abcd" starts with $[*])", {"null"}},
  246. {R"(["b", "c"])", R"("abcd" starts with $[*])", {"false"}},
  247. };
  248. for (const auto& testCase : testCases) {
  249. for (const auto mode : LAX_MODES) {
  250. RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
  251. }
  252. }
  253. }
  254. };
  255. UNIT_TEST_SUITE_REGISTRATION(TJsonPathLaxTest);