aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/jsonpath/ut/lax_ut.cpp
diff options
context:
space:
mode:
authorvvvv <vvvv@yandex-team.com>2024-11-06 23:54:28 +0300
committervvvv <vvvv@yandex-team.com>2024-11-07 00:04:25 +0300
commitcf2a23963ac10add28c50cc114fbf48953eca5aa (patch)
tree174b849b8ecfa96b0c8e4409ab3287721a9210c8 /yql/essentials/minikql/jsonpath/ut/lax_ut.cpp
parent3a3113a2bf5a7fab32bde414932082b264c559fc (diff)
downloadydb-cf2a23963ac10add28c50cc114fbf48953eca5aa.tar.gz
Prepare move yql/minikql YQL-19206
types,jsonpath,dom commit_hash:6b54be5968b6a30b6d97fe3a1611574bcefc749e
Diffstat (limited to 'yql/essentials/minikql/jsonpath/ut/lax_ut.cpp')
-rw-r--r--yql/essentials/minikql/jsonpath/ut/lax_ut.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/yql/essentials/minikql/jsonpath/ut/lax_ut.cpp b/yql/essentials/minikql/jsonpath/ut/lax_ut.cpp
new file mode 100644
index 0000000000..4d5dda83ac
--- /dev/null
+++ b/yql/essentials/minikql/jsonpath/ut/lax_ut.cpp
@@ -0,0 +1,283 @@
+#include "test_base.h"
+
+class TJsonPathLaxTest : public TJsonPathTestBase {
+public:
+ TJsonPathLaxTest()
+ : TJsonPathTestBase()
+ {
+ }
+
+ UNIT_TEST_SUITE(TJsonPathLaxTest);
+ UNIT_TEST(TestArrayUnwrap);
+ UNIT_TEST(TestArrayWrap);
+ UNIT_TEST(TestInvalidArrayIndices);
+ UNIT_TEST(TestStructuralErrorsHandling);
+ UNIT_TEST(TestCompareOperations);
+ UNIT_TEST(TestFilter);
+ UNIT_TEST(TestNumericMethods);
+ UNIT_TEST(TestDoubleMethod);
+ UNIT_TEST(TestKeyValueMethod);
+ UNIT_TEST(TestExistsPredicate);
+ UNIT_TEST(TestLikeRegexPredicate);
+ UNIT_TEST(TestStartsWithPredicate);
+ UNIT_TEST_SUITE_END();
+
+ void TestArrayUnwrap() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ {R"([
+ {"key": 1},
+ {"key": 2}
+ ])", "$.key", {"1", "2"}},
+ {R"([
+ {"key": 1},
+ {"key": 2}
+ ])", "$.*", {"1", "2"}},
+ {R"({
+ "first": {"key": 1},
+ "second": []
+ })", "$.*.key", {"1"}},
+ {R"({
+ "first": {"key": 1},
+ "second": []
+ })", "$.*.*", {"1"}},
+ {R"({"another_key": 123})", "$.key", {}},
+ {R"([
+ {"key": [{"nested": 28}]},
+ {"key": [{"nested": 29}]}
+ ])", "$.key.nested", {"28", "29"}},
+ {R"([
+ {"key": [{"nested": 28}]},
+ {"key": [{"nested": 29}]}
+ ])", "$.*.*", {"28", "29"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestArrayWrap() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ {R"([1, 2])", "$[*][0]", {"1", "2"}},
+ {R"([[1], 2, [3]])", "$[*][0]", {"1", "2", "3"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestInvalidArrayIndices() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ {R"({
+ "idx": -1,
+ "array": [1, 2, 3]
+ })", "$.array[$.idx]", {}},
+ {R"({
+ "from": -1,
+ "to": 3,
+ "array": [1, 2, 3]
+ })", "$.array[$.from to $.to]", {}},
+ {R"({
+ "from": 0,
+ "to": -1,
+ "array": [1, 2, 3]
+ })", "$.array[$.from to $.to]", {}},
+ {R"([1, 2, 3, 4, 5])", "$[3 to 0]", {}},
+ {R"({
+ "idx": -1,
+ "array": [1, 2, 3]
+ })", "$.array[$.idx, 1 to 2]", {"2", "3"}},
+ {R"({
+ "from": -1,
+ "to": 3,
+ "array": [1, 2, 3]
+ })", "$.array[0, $.from to $.to, 2 to 2]", {"1", "3"}},
+ {R"({
+ "from": 0,
+ "to": -1,
+ "array": [1, 2, 3]
+ })", "$.array[0, $.from to $.to, 1 to 1]", {"1", "2"}},
+ {R"([1, 2, 3, 4, 5])", "$[0, 3 to 0, 1]", {"1", "2"}},
+ {R"([[1, 2], [3, 4, 5], []])", "$[*][2]", {"5"}},
+ {"[]", "$[last]", {}},
+ {"[]", "$[last to 0]", {}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestStructuralErrorsHandling() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ {R"([[{"key": 1}]])", "$.key", {}},
+ {R"([[{"key": 1}]])", "$.*", {}},
+ {R"([
+ {"key": 1},
+ {"not_key": 2},
+ {"key": 3}
+ ])", "$[*].key", {"1", "3"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestCompareOperations() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ // Check unwrap
+ {R"({
+ "left": [1, 2, 3],
+ "right": [4, 5, 6]
+ })", "$.left < $.right", {"true"}},
+ // Check incomparable types
+ // NOTE: Even though values of types string and number are incomparable,
+ // pair 1 < 4 is true and was found first, so the overall result is true
+ {R"({
+ "left": [1, 2, "string"],
+ "right": [4, 5, 6]
+ })", "$.left < $.right", {"true"}},
+ // NOTE: In this example pair "string" < 4 results in error and was found first,
+ // so overall result is null
+ {R"({
+ "left": ["string", 2, 3],
+ "right": [4, 5, 6]
+ })", "$.left < $.right", {"null"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestFilter() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ // Check unwrap
+ {R"([
+ {"age": 18},
+ {"age": 25},
+ {"age": 50},
+ {"age": 5}
+ ])", "$ ? (@.age >= 18 && @.age <= 30) . age", {"18", "25"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestNumericMethods() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ // Check unwrap
+ {"[-1.23, 4.56, 3, 0]", "$.abs()", {"1.23", "4.56", "3", "0"}},
+ {"[-1.23, 4.56, 3, 0]", "$.floor()", {"-2", "4", "3", "0"}},
+ {"[-1.23, 4.56, 3, 0]", "$.ceiling()", {"-1", "5", "3", "0"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestDoubleMethod() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ // Check unwrap
+ {R"([
+ "123", "123.4", "0.567", "1234e-1", "567e-3", "123.4e-1",
+ "123e3", "123e+3", "1.23e+1", "1.23e1",
+ "12e0", "12.3e0", "0", "0.0", "0.0e0"
+ ])", "$.double()", {
+ "123", "123.4", "0.567", "123.4", "0.567", "12.34",
+ "123000", "123000", "12.3", "12.3",
+ "12", "12.3", "0", "0", "0",
+ }},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestKeyValueMethod() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ // Check unwrap
+ {R"([{
+ "one": 1,
+ "two": 2,
+ "three": 3
+ }])", "$.keyvalue().name", {"\"one\"", "\"three\"", "\"two\""}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestExistsPredicate() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ {R"({
+ "key": 123
+ })", "exists ($.another_key)", {"false"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestLikeRegexPredicate() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ // Check unwrapping
+ {R"(["string", "123", "456"])", R"($ like_regex "[0-9]+")", {"true"}},
+
+ // Check early stopping
+ {R"([123, "123", "456"])", R"($ like_regex "[0-9]+")", {"null"}},
+ {R"(["123", "456", 123])", R"($ like_regex "[0-9]+")", {"true"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+
+ void TestStartsWithPredicate() {
+ const TVector<TMultiOutputTestCase> testCases = {
+ {R"(["a", "b", "c"])", R"("abcd" starts with $[*])", {"true"}},
+ {R"(["a", 1.45, 50])", R"("abcd" starts with $[*])", {"true"}},
+ {R"([1.45, 50, "a"])", R"("abcd" starts with $[*])", {"null"}},
+ {R"(["b", "c"])", R"("abcd" starts with $[*])", {"false"}},
+ };
+
+ for (const auto& testCase : testCases) {
+ for (const auto mode : LAX_MODES) {
+ RunTestCase(testCase.Json, mode + testCase.JsonPath, testCase.Result);
+ }
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TJsonPathLaxTest); \ No newline at end of file