// Copyright 2023 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include namespace DB { namespace tests { class TestJsonBinary : public ::testing::Test { public: static void checkJsonPathKeyCacheDisable(std::shared_ptr path_expr) { for (const auto & leg_ptr : path_expr->getLegs()) { if (leg_ptr->type == JsonPathLeg::JsonPathLegKey) ASSERT_TRUE(leg_ptr->dot_key.status == JsonPathObjectKeyCacheDisabled); } } static void checkJsonPathKeyUncached(std::shared_ptr path_expr) { for (const auto & leg_ptr : path_expr->getLegs()) { if (leg_ptr->type == JsonPathLeg::JsonPathLegKey) ASSERT_TRUE(leg_ptr->dot_key.status == JsonPathObjectKeyUncached); } } }; TEST_F(TestJsonBinary, TestUnquoteLiteral) try { char json_literals[3] = { 0x0, /// null 0x1, /// true 0x2 /// false }; std::vector expected = {"null", "true", "false"}; for (size_t i = 0; i < 3; ++i) { JsonBinary json_binary(JsonBinary::TYPE_CODE_LITERAL, StringRef(json_literals + i, 1)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected[i]); } } CATCH TEST_F(TestJsonBinary, TestUnquoteInteger) try { UInt8 json_integers[3][8] = { {0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; std::vector expected = {"-3", "3", "18446744073709551615"}; { JsonBinary json_binary(JsonBinary::TYPE_CODE_INT64, StringRef(json_integers[0], 8)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected[0]); } { JsonBinary json_binary(JsonBinary::TYPE_CODE_INT64, StringRef(json_integers[1], 8)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected[1]); } { JsonBinary json_binary(JsonBinary::TYPE_CODE_UINT64, StringRef(json_integers[2], 8)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected[2]); } } CATCH TEST_F(TestJsonBinary, TestUnquoteFloat64) try { UInt8 json_floats[16][8] = { {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x40}, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x15, 0x1e, 0x9f, 0x79, 0x96, 0x1b, 0x4b, 0x44}, {0x63, 0x4a, 0x45, 0x1e, 0xa6, 0x14, 0x4b, 0x44}, {0x46, 0x44, 0xb9, 0xe6, 0x8f, 0xc4, 0xb0, 0x3e}, {0x76, 0x83, 0xd, 0xf4, 0xf5, 0x21, 0xb4, 0x3e}, {0xd9, 0x44, 0xb9, 0xbf, 0xb9, 0x89, 0x1a, 0x3f}, {0x0, 0x80, 0xe0, 0x37, 0x79, 0xc3, 0x41, 0x43}, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc0}, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, {0x15, 0x1e, 0x9f, 0x79, 0x96, 0x1b, 0x4b, 0xc4}, {0x63, 0x4a, 0x45, 0x1e, 0xa6, 0x14, 0x4b, 0xc4}, {0x46, 0x44, 0xb9, 0xe6, 0x8f, 0xc4, 0xb0, 0xbe}, {0x76, 0x83, 0xd, 0xf4, 0xf5, 0x21, 0xb4, 0xbe}, {0xd9, 0x44, 0xb9, 0xbf, 0xb9, 0x89, 0x1a, 0xbf}, {0x0, 0x80, 0xe0, 0x37, 0x79, 0xc3, 0x41, 0xc3}, }; std::vector expected = { "3", "0", "1.0001e+21", "999100000000000000000", "9.9944e-7", "1.2e-6", "0.0001012344", "10000000000000000", "-3", "-0", "-1.0001e+21", "-999100000000000000000", "-9.9944e-7", "-1.2e-6", "-0.0001012344", "-10000000000000000", }; for (size_t i = 0; i < expected.size(); ++i) { JsonBinary json_binary(JsonBinary::TYPE_CODE_FLOAT64, StringRef(json_floats[i], 8)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected[i]); } } CATCH TEST_F(TestJsonBinary, TestUnquoteObject) try { { UInt8 json_object[] = {0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0}; JsonBinary json_binary(JsonBinary::TYPE_CODE_OBJECT, StringRef(json_object, 8)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "{}"); } { UInt8 json_object[] = {0x1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0xc, 0x14, 0x0, 0x0, 0x0, 0x61, 0x1, 0x62}; JsonBinary json_binary( JsonBinary::TYPE_CODE_OBJECT, StringRef(json_object, sizeof(json_object) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "{\"a\": \"b\"}"); } { UInt8 json_object[] = {0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9, 0x14, 0x0, 0x0, 0x0, 0x61, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; JsonBinary json_binary( JsonBinary::TYPE_CODE_OBJECT, StringRef(json_object, sizeof(json_object) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "{\"a\": 3}"); } { UInt8 json_object[] = {0x1, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x61}; JsonBinary json_binary( JsonBinary::TYPE_CODE_OBJECT, StringRef(json_object, sizeof(json_object) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "{\"a\": null}"); } } CATCH TEST_F(TestJsonBinary, TestUnquoteArray) try { { UInt8 json_array[] = {0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0}; JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[]"); } { UInt8 json_array[] = {0x2, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xc, 0x12, 0x0, 0x0, 0x0, 0xc, 0x14, 0x0, 0x0, 0x0, 0x1, 0x61, 0x1, 0x62}; JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[\"a\", \"b\"]"); } { UInt8 json_array[] = {0x1, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x0, 0x0}; JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[true]"); } { UInt8 json_array[] = {0x1, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x9, 0xd, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[3]"); } } CATCH TEST_F(TestJsonBinary, TestUnquoteMixed) try { { // clang-format off UInt8 json_array[] = { 0x3, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0xc, 0x17, 0x0, 0x0, 0x0, 0xc, 0x19, 0x0, 0x0, 0x0, 0x1, 0x1b, 0x0, 0x0, 0x0, 0x1, 0x61, 0x1, 0x62, 0x1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0xc, 0x14, 0x0, 0x0, 0x0, 0x61, 0x1, 0x62 }; // clang-format on JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[\"a\", \"b\", {\"a\": \"b\"}]"); } { // clang-format off UInt8 json_array[] = { 0x4, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x9, 0x1c, 0x0, 0x0, 0x0, 0xb, 0x24, 0x0, 0x0, 0x0, 0xc, 0x2c, 0x0, 0x0, 0x0, 0x1, 0x2e, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x40, 0x1, 0x33, 0x1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0xc, 0x14, 0x0, 0x0, 0x0, 0x61, 0x1, 0x62 }; // clang-format on JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[3, 3, \"3\", {\"a\": \"b\"}]"); } { // clang-format off UInt8 json_array[] = { 0x2, 0x0, 0x0, 0x0, 0x63, 0x0, 0x0, 0x0, 0xc, 0x12, 0x0, 0x0, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x1, 0x61, 0x1, 0x0, 0x0, 0x0, 0x4f, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x14, 0x0, 0x0, 0x0, 0x61, 0x3, 0x0, 0x0, 0x0, 0x3b, 0x0, 0x0, 0x0, 0xb, 0x17, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x40, 0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0xb, 0x14, 0x0, 0x0, 0x0, 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x40 }; // clang-format on JsonBinary json_binary(JsonBinary::TYPE_CODE_ARRAY, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "[\"a\", {\"a\": [3, null, {\"b\": 4}]}]"); } { // clang-format off UInt8 json_array[] = { 0x1, 0x0, 0x0, 0x0, 0x4f, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x62, 0x1, 0x0, 0x0, 0x0, 0x3b, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x14, 0x0, 0x0, 0x0, 0x63, 0x3, 0x0, 0x0, 0x0, 0x27, 0x0, 0x0, 0x0, 0x9, 0x17, 0x0, 0x0, 0x0, 0xb, 0x1f, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc0 }; // clang-format on JsonBinary json_binary(JsonBinary::TYPE_CODE_OBJECT, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "{\"b\": {\"c\": [3, -3, true]}}"); } { // clang-format off UInt8 json_array[] = { 0x1, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x62, 0x1, 0x0, 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x14, 0x0, 0x0, 0x0, 0x63, 0x3, 0x0, 0x0, 0x0, 0x4c, 0x0, 0x0, 0x0, 0x9, 0x17, 0x0, 0x0, 0x0, 0xb, 0x1f, 0x0, 0x0, 0x0, 0xc, 0x27, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc0, 0x24, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x20, 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x22, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 }; // clang-format on JsonBinary json_binary(JsonBinary::TYPE_CODE_OBJECT, StringRef(json_array, sizeof(json_array) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == "{\"b\": {\"c\": [3, -3, \"hello, \\\"escaped 你好 quotes\\\" world\"]}}"); } } CATCH TEST_F(TestJsonBinary, TestUnquoteDateAndTime) try { { UInt8 json_date[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x98, 0x1f}; String expected = "2022-01-31"; JsonBinary json_binary(JsonBinary::TYPE_CODE_DATE, StringRef(json_date, 8)); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_date[] = {0x20, 0x4d, 0x0, 0x14, 0x35, 0x7e, 0x98, 0x1f}; String expected = "2022-01-31 03:20:20.001234"; JsonBinary json_binary(JsonBinary::TYPE_CODE_DATETIME, StringRef(json_date, sizeof(json_date) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_date[] = {0x20, 0x4d, 0x0, 0x14, 0x35, 0xfe, 0x98, 0x1f}; String expected = "2022-03-31 03:20:20.001234"; JsonBinary json_binary( JsonBinary::TYPE_CODE_TIMESTAMP, StringRef(json_date, sizeof(json_date) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } } CATCH TEST_F(TestJsonBinary, TestUnquoteDuration) try { { UInt8 json_duration[] = {0x50, 0x58, 0xe1, 0x78, 0xf7, 0xa, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0}; String expected = "03:20:58.001234"; JsonBinary json_binary( JsonBinary::TYPE_CODE_DURATION, StringRef(json_duration, sizeof(json_duration) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_duration[] = {0xb0, 0xa7, 0x1e, 0x87, 0x8, 0xf5, 0xff, 0xff, 0x6, 0x0, 0x0, 0x0}; String expected = "-03:20:58.001234"; JsonBinary json_binary( JsonBinary::TYPE_CODE_DURATION, StringRef(json_duration, sizeof(json_duration) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } } CATCH TEST_F(TestJsonBinary, TestUnquoteOpaque) try { { UInt8 json_opaque[] = {0xe9, 0x1, 0x39}; String expected = "base64:type233:OQ=="; JsonBinary json_binary( JsonBinary::TYPE_CODE_OPAQUE, StringRef(json_opaque, sizeof(json_opaque) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { // clang-format off UInt8 json_opaque[] = { 0xe9, 0x80, 0x1, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39 }; // clang-format on String expected = "base64:type233:" "OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5" "OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk="; JsonBinary json_binary( JsonBinary::TYPE_CODE_OPAQUE, StringRef(json_opaque, sizeof(json_opaque) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } } CATCH TEST_F(TestJsonBinary, TestUnquoteString) try { { UInt8 json_string[] = {0x0}; String expected; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_string[] = {0xa, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64}; String expected = "HelloWorld"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_string[] = {0x6, 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd}; String expected = "你好"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { // clang-format off UInt8 json_string[] = { 0x1d, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x22, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 }; // clang-format on String expected = "hello, \"escaped quotes\" world"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { // clang-format off UInt8 json_string[] = { 0x24, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x20, 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x22, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 }; // clang-format on String expected = "hello, \"escaped 你好 quotes\" world"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_string[] = {0x1, 0x27}; String expected = "'"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_string[] = {0x2, 0x27, 0x27}; String expected = "''"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } { UInt8 json_string[] = {0x4, 0x61, 0xa, 0x62, 0x5c}; String expected = "a\nb\\"; JsonBinary json_binary( JsonBinary::TYPE_CODE_STRING, StringRef(json_string, sizeof(json_string) / sizeof(UInt8))); auto str = JsonBinary::unquoteString(json_binary.toString()); ASSERT_TRUE(str == expected); } } CATCH TEST_F(TestJsonBinary, TestExtract) try { // clang-format off /// `{"\"hello\"": "world", "a": [1, "2", {"aa": "bb"}, 4.0, {"aa": "cc"}], "b": true, "c": ["d"]}` UInt8 bj1[] = { 0x4, 0x0, 0x0, 0x0, 0xb6, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x7, 0x0, 0x3b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x1, 0x0, 0xc, 0x3e, 0x0, 0x0, 0x0, 0x3, 0x44, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x0, 0x0, 0x3, 0xa7, 0x0, 0x0, 0x0, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x61, 0x62, 0x63, 0x5, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5, 0x0, 0x0, 0x0, 0x63, 0x0, 0x0, 0x0, 0x9, 0x21, 0x0, 0x0, 0x0, 0xc, 0x29, 0x0, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x0, 0x0, 0xb, 0x43, 0x0, 0x0, 0x0, 0x1, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x32, 0x1, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x15, 0x0, 0x0, 0x0, 0x61, 0x61, 0x2, 0x62, 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x40, 0x1, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x15, 0x0, 0x0, 0x0, 0x61, 0x61, 0x2, 0x63, 0x63, 0x1, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xc, 0xd, 0x0, 0x0, 0x0, 0x1, 0x64 }; JsonBinary json_binary_1(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj1, sizeof(bj1) / sizeof(UInt8))); /// `[{"a": 1, "b": true}, 3, 3.5, "hello, world", null, true]` UInt8 bj2[] = { 0x6, 0x0, 0x0, 0x0, 0x6b, 0x0, 0x0, 0x0, 0x1, 0x26, 0x0, 0x0, 0x0, 0x9, 0x4e, 0x0, 0x0, 0x0, 0xb, 0x56, 0x0, 0x0, 0x0, 0xc, 0x5e, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9, 0x20, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x0, 0x0, 0x61, 0x62, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xc, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 }; JsonBinary json_binary_2(JsonBinary::TYPE_CODE_ARRAY, StringRef(bj2, sizeof(bj2) / sizeof(UInt8))); /// `{"properties": {"$type": "TiDB"}}` UInt8 bj3[] = { 0x1, 0x0, 0x0, 0x0, 0x3a, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0xa, 0x0, 0x1, 0x1d, 0x0, 0x0, 0x0, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1, 0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x5, 0x0, 0xc, 0x18, 0x0, 0x0, 0x0, 0x24, 0x74, 0x79, 0x70, 0x65, 0x4, 0x54, 0x69, 0x44, 0x42 }; JsonBinary json_binary_3(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj3, sizeof(bj3) / sizeof(UInt8))); /// `{"properties": {"$type$type": {"$a$a" : "TiDB"}}}` UInt8 bj4[] = { 0x1, 0x0, 0x0, 0x0, 0x56, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0xa, 0x0, 0x1, 0x1d, 0x0, 0x0, 0x0, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0xa, 0x0, 0x1, 0x1d, 0x0, 0x0, 0x0, 0x24, 0x74, 0x79, 0x70, 0x65, 0x24, 0x74, 0x79, 0x70, 0x65, 0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x4, 0x0, 0xc, 0x17, 0x0, 0x0, 0x0, 0x24, 0x61, 0x24, 0x61, 0x4, 0x54, 0x69, 0x44, 0x42 }; JsonBinary json_binary_4(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj4, sizeof(bj4) / sizeof(UInt8))); /// `{"properties": {"$type": {"$a" : {"$b" : "TiDB"}}}}` UInt8 bj5[] = { 0x1, 0x0, 0x0, 0x0, 0x64, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0xa, 0x0, 0x1, 0x1d, 0x0, 0x0, 0x0, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1, 0x0, 0x0, 0x0, 0x47, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x5, 0x0, 0x1, 0x18, 0x0, 0x0, 0x0, 0x24, 0x74, 0x79, 0x70, 0x65, 0x1, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1, 0x15, 0x0, 0x0, 0x0, 0x24, 0x61, 0x1, 0x0, 0x0, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x15, 0x0, 0x0, 0x0, 0x24, 0x62, 0x4, 0x54, 0x69, 0x44, 0x42 }; JsonBinary json_binary_5(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj5, sizeof(bj5) / sizeof(UInt8))); /// `{"properties": {"$type": {"$a$a" : "TiDB"}},"hello": {"$b$b": "world","$c": "amazing"}}` UInt8 bj6[] = { 0x2, 0x0, 0x0, 0x0, 0x93, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x5, 0x0, 0x23, 0x0, 0x0, 0x0, 0xa, 0x0, 0x1, 0x2d, 0x0, 0x0, 0x0, 0x1, 0x5f, 0x0, 0x0, 0x0, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x4, 0x0, 0x22, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x24, 0x0, 0x0, 0x0, 0xc, 0x2a, 0x0, 0x0, 0x0, 0x24, 0x62, 0x24, 0x62, 0x24, 0x63, 0x5, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x7, 0x61, 0x6d, 0x61, 0x7a, 0x69, 0x6e, 0x67, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x5, 0x0, 0x1, 0x18, 0x0, 0x0, 0x0, 0x24, 0x74, 0x79, 0x70, 0x65, 0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x4, 0x0, 0xc, 0x17, 0x0, 0x0, 0x0, 0x24, 0x61, 0x24, 0x61, 0x4, 0x54, 0x69, 0x44, 0x42 }; JsonBinary json_binary_6(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj6, sizeof(bj6) / sizeof(UInt8))); /// `{ "a": { "x" : { "b": { "y": { "b": { "z": { "c": 100 } } } } } } }` UInt8 bj7[] = { 0x1, 0x0, 0x0, 0x0, 0x94, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x61, 0x1, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x78, 0x1, 0x0, 0x0, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x62, 0x1, 0x0, 0x0, 0x0, 0x58, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x79, 0x1, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x62, 0x1, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x7a, 0x1, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9, 0x14, 0x0, 0x0, 0x0, 0x63, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; JsonBinary json_binary_7(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj7, sizeof(bj7) / sizeof(UInt8))); /// `{ "a": { "b" : [ 1, 2, 3 ] } }` UInt8 bj8[] = { 0x1, 0x0, 0x0, 0x0, 0x57, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x61, 0x1, 0x0, 0x0, 0x0, 0x43, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x14, 0x0, 0x0, 0x0, 0x62, 0x3, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x9, 0x17, 0x0, 0x0, 0x0, 0x9, 0x1f, 0x0, 0x0, 0x0, 0x9, 0x27, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; JsonBinary json_binary_8(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj8, sizeof(bj8) / sizeof(UInt8))); /// `[[0,1],[2,3],[4,[5,6]]]` UInt8 bj9[] = { 0x3, 0x0, 0x0, 0x0, 0x97, 0x0, 0x0, 0x0, 0x3, 0x17, 0x0, 0x0, 0x0, 0x3, 0x39, 0x0, 0x0, 0x0, 0x3, 0x5b, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x9, 0x12, 0x0, 0x0, 0x0, 0x9, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x9, 0x12, 0x0, 0x0, 0x0, 0x9, 0x1a, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x9, 0x12, 0x0, 0x0, 0x0, 0x3, 0x1a, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x9, 0x12, 0x0, 0x0, 0x0, 0x9, 0x1a, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; JsonBinary json_binary_9(JsonBinary::TYPE_CODE_ARRAY, StringRef(bj9, sizeof(bj9) / sizeof(UInt8))); /// `[1]` UInt8 bj10[] = {0x1, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x9, 0xd, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; JsonBinary json_binary_10(JsonBinary::TYPE_CODE_ARRAY, StringRef(bj10, sizeof(bj10) / sizeof(UInt8))); /// `{"metadata": {"comment": "1234"}}` UInt8 bj11[] = { 0x1, 0x0, 0x0, 0x0, 0x3a, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x1b, 0x0, 0x0, 0x0, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x7, 0x0, 0xc, 0x1a, 0x0, 0x0, 0x0, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x4, 0x31, 0x32, 0x33, 0x34 }; JsonBinary json_binary_11(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj11, sizeof(bj11) / sizeof(UInt8))); /// `{"metadata": {"age": 19, "name": "Tom"}}` UInt8 bj12[] = { 0x1, 0x0, 0x0, 0x0, 0x4c, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x1b, 0x0, 0x0, 0x0, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x3, 0x0, 0x21, 0x0, 0x0, 0x0, 0x4, 0x0, 0x9, 0x25, 0x0, 0x0, 0x0, 0xc, 0x2d, 0x0, 0x0, 0x0, 0x61, 0x67, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x54, 0x6f, 0x6d }; JsonBinary json_binary_12(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj12, sizeof(bj12) / sizeof(UInt8))); UInt8 bj13[] = {0x1, 0x0, 0x0, 0x0, 0x4f, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x14, 0x0, 0x0, 0x0, 0x62, 0x1, 0x0, 0x0, 0x0, 0x3b, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x6, 0x0, 0x3, 0x19, 0x0, 0x0, 0x0, 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd, 0x2, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x9, 0x12, 0x0, 0x0, 0x0, 0xb, 0x1a, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc0}; JsonBinary json_binary_13(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj13, sizeof(bj13) / sizeof(UInt8))); // clang-format on struct TestData { JsonBinary bj; std::vector path_expr_vec; bool found; String expected_result; }; std::vector test_data_vec{ {json_binary_3, {"$"}, true, R"({"properties": {"$type": "TiDB"}})"}, {json_binary_1, {"$.a"}, true, R"([1, "2", {"aa": "bb"}, 4, {"aa": "cc"}])"}, {json_binary_2, {"$.a"}, false, ""}, {json_binary_1, {"$[0]"}, true, R"({"\"hello\"": "world", "a": [1, "2", {"aa": "bb"}, 4, {"aa": "cc"}], "b": true, "c": ["d"]})"}, {json_binary_2, {"$[0]"}, true, R"({"a": 1, "b": true})"}, {json_binary_1, {"$.a[2].aa"}, true, "bb"}, {json_binary_1, {"$.a[*].aa"}, true, R"(["bb", "cc"])"}, {json_binary_1, {"$.*[0]"}, true, R"(["world", 1, true, "d"])"}, {json_binary_1, {"$.a[*].\"aa\""}, true, R"(["bb", "cc"])"}, {json_binary_1, {R"($."\"hello\"")"}, true, "world"}, {json_binary_1, {"$**[1]"}, true, "[\"2\"]"}, {json_binary_3, {"$.properties.$type"}, true, "TiDB"}, {json_binary_4, {"$.properties.$type$type"}, true, R"({"$a$a": "TiDB"})"}, {json_binary_4, {"$.properties.$type$type.$a$a"}, true, "TiDB"}, {json_binary_5, {"$.properties.$type.$a.$b"}, true, "TiDB"}, {json_binary_5, {"$.properties.$type.$a.*[0]"}, true, "[\"TiDB\"]"}, {json_binary_11, {"$.metadata.comment"}, true, "1234"}, {json_binary_13, {"$.b.你好"}, true, "[3, -3]"}, {json_binary_9, {"$[0]"}, true, "[0, 1]"}, {json_binary_9, {"$[last][last]"}, true, "[5, 6]"}, {json_binary_9, {"$[last-1][last]"}, true, "3"}, {json_binary_9, {"$[last-1][last-1]"}, true, "2"}, {json_binary_9, {"$[1 to 2]"}, true, "[[2, 3], [4, [5, 6]]]"}, {json_binary_1, {"$.a", "$[5]"}, true, R"([[1, "2", {"aa": "bb"}, 4, {"aa": "cc"}]])"}, {json_binary_2, {"$.a", "$[0]"}, true, R"([{"a": 1, "b": true}])"}, {json_binary_6, {"$.properties", "$[1]"}, true, R"([{"$type": {"$a$a": "TiDB"}}])"}, {json_binary_6, {"$.hello", "$[2]"}, true, R"([{"$b$b": "world", "$c": "amazing"}])"}, {json_binary_7, {"$.a**.b**.c"}, true, "[100]"}, {json_binary_8, {"$**[0]"}, true, R"([{"a": {"b": [1, 2, 3]}}, {"b": [1, 2, 3]}, 1, 2, 3])"}, {json_binary_9, {"$**[0]"}, true, "[[0, 1], 0, 1, 2, 3, 4, 5, 6]"}, {json_binary_10, {"$**[0]"}, true, "[1]"}, {json_binary_12, {"$.metadata.age", "$.metadata.name"}, true, "[19, \"Tom\"]"}, }; for (auto & i : test_data_vec) { std::vector path_expr_container_vec; for (auto & j : i.path_expr_vec) { auto path_expr = JsonPathExpr::parseJsonPathExpr(j); ASSERT_TRUE(path_expr); path_expr_container_vec.push_back(std::make_unique(path_expr)); } /// Test twice to validate cache functionality for (size_t j = 0; j < 2; ++j) { auto col_to = ColumnString::create(); ColumnString::Chars_t & data_to = col_to->getChars(); ColumnString::Offsets & offsets_to = col_to->getOffsets(); JsonBinary::JsonBinaryWriteBuffer write_buffer(data_to); bool found = i.bj.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE(found == i.found); if (found) { writeChar(0, write_buffer); offsets_to.push_back(write_buffer.count()); data_to.resize(write_buffer.count()); JsonBinary result(data_to[0], StringRef(col_to->getDataAt(0).data + 1, col_to->getDataAt(0).size - 1)); ASSERT_TRUE(i.expected_result == JsonBinary::unquoteString(result.toString())); } } } } CATCH TEST_F(TestJsonBinary, TestExtractKeyCache) try { // clang-format off /// `{"\"hello\"": "world", "a": [1, "2", {"aa": "bb"}, 4.0, {"aa": "cc"}], "b": true, "c": ["d"]}` UInt8 bj1[] = { 0x4, 0x0, 0x0, 0x0, 0xb6, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x7, 0x0, 0x3b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x1, 0x0, 0xc, 0x3e, 0x0, 0x0, 0x0, 0x3, 0x44, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x0, 0x0, 0x3, 0xa7, 0x0, 0x0, 0x0, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x61, 0x62, 0x63, 0x5, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5, 0x0, 0x0, 0x0, 0x63, 0x0, 0x0, 0x0, 0x9, 0x21, 0x0, 0x0, 0x0, 0xc, 0x29, 0x0, 0x0, 0x0, 0x1, 0x2b, 0x0, 0x0, 0x0, 0xb, 0x43, 0x0, 0x0, 0x0, 0x1, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x32, 0x1, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x15, 0x0, 0x0, 0x0, 0x61, 0x61, 0x2, 0x62, 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x40, 0x1, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x15, 0x0, 0x0, 0x0, 0x61, 0x61, 0x2, 0x63, 0x63, 0x1, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xc, 0xd, 0x0, 0x0, 0x0, 0x1, 0x64 }; // clang-format on JsonBinary json_binary_1(JsonBinary::TYPE_CODE_OBJECT, StringRef(bj1, sizeof(bj1) / sizeof(UInt8))); auto col_to = ColumnString::create(); ColumnString::Chars_t & data_to = col_to->getChars(); JsonBinary::JsonBinaryWriteBuffer write_buffer(data_to); { /// Simple cache success check std::vector path_expr_container_vec; auto path_expr = JsonPathExpr::parseJsonPathExpr("$.a"); ASSERT_TRUE(path_expr); path_expr_container_vec.push_back(std::make_unique(path_expr)); checkJsonPathKeyUncached(path_expr); bool found = json_binary_1.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE( found && path_expr->getLegs()[0]->dot_key.status == JsonPathObjectKeyCached && path_expr->getLegs()[0]->dot_key.cached_index == 1); } { /// Simple cache success check 2 std::vector path_expr_container_vec; auto path_expr = JsonPathExpr::parseJsonPathExpr("$.a[2].aa"); ASSERT_TRUE(path_expr); path_expr_container_vec.push_back(std::make_unique(path_expr)); checkJsonPathKeyUncached(path_expr); bool found = json_binary_1.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE(found); ASSERT_TRUE( path_expr->getLegs()[0]->dot_key.status == JsonPathObjectKeyCached && path_expr->getLegs()[0]->dot_key.cached_index == 1); ASSERT_TRUE( path_expr->getLegs()[2]->dot_key.status == JsonPathObjectKeyCached && path_expr->getLegs()[2]->dot_key.cached_index == 0); /// Extract once more found = json_binary_1.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE(found); ASSERT_TRUE( path_expr->getLegs()[0]->dot_key.status == JsonPathObjectKeyCached && path_expr->getLegs()[0]->dot_key.cached_index == 1); ASSERT_TRUE( path_expr->getLegs()[2]->dot_key.status == JsonPathObjectKeyCached && path_expr->getLegs()[2]->dot_key.cached_index == 0); } { /// Un-cacheable case 1: Asterisk-star for key std::vector path_expr_container_vec; auto path_expr = JsonPathExpr::parseJsonPathExpr("$.*[0]"); ASSERT_TRUE(path_expr); path_expr_container_vec.push_back(std::make_unique(path_expr)); checkJsonPathKeyCacheDisable(path_expr); bool found = json_binary_1.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE(found); checkJsonPathKeyCacheDisable(path_expr); } { /// Un-cacheable case 2: Asterisk-star for array index std::vector path_expr_container_vec; auto path_expr = JsonPathExpr::parseJsonPathExpr("$.a[*].aa"); ASSERT_TRUE(path_expr); path_expr_container_vec.push_back(std::make_unique(path_expr)); checkJsonPathKeyCacheDisable(path_expr); bool found = json_binary_1.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE(found); checkJsonPathKeyCacheDisable(path_expr); } { /// Un-cacheable case 3: Double Asterisk-star std::vector path_expr_container_vec; auto path_expr = JsonPathExpr::parseJsonPathExpr("$**[2].aa"); ASSERT_TRUE(path_expr); path_expr_container_vec.push_back(std::make_unique(path_expr)); checkJsonPathKeyCacheDisable(path_expr); bool found = json_binary_1.extract(path_expr_container_vec, write_buffer); ASSERT_TRUE(found); checkJsonPathKeyCacheDisable(path_expr); } } CATCH TEST_F(TestJsonBinary, TestConstant) try { for (size_t i = 0; i < 32; ++i) { ASSERT_TRUE(!JsonSafeAscii[i]); } for (size_t i = 32; i < 128; ++i) { if (i == '"' || i == '\\') ASSERT_TRUE(!JsonSafeAscii[i]); else ASSERT_TRUE(JsonSafeAscii[i]); } } CATCH } // namespace tests } // namespace DB