/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include "json_binary.h" #include "json_dom.h" #include "sql_time.h" #include #include "test_utils.h" #include #include namespace json_binary_unittest { using namespace json_binary; class JsonBinaryTest : public ::testing::Test { protected: virtual void SetUp() { initializer.SetUp(); } virtual void TearDown() { initializer.TearDown(); } my_testing::Server_initializer initializer; }; /** Get a copy of the string value represented by val. */ std::string get_string(const Value &val) { return std::string(val.get_data(), val.get_data_length()); } TEST_F(JsonBinaryTest, BasicTest) { const char *doc= "false"; const char *msg; size_t msg_offset; std::auto_ptr dom(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); String buf; EXPECT_FALSE(serialize(dom.get(), &buf)); Value val1= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val1.is_valid()); EXPECT_EQ(Value::LITERAL_FALSE, val1.type()); doc= "-123"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val2= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val2.is_valid()); EXPECT_EQ(Value::INT, val2.type()); EXPECT_EQ(-123LL, val2.get_int64()); doc= "3.14"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val3= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val3.is_valid()); EXPECT_EQ(Value::DOUBLE, val3.type()); EXPECT_EQ(3.14, val3.get_double()); doc= "18446744073709551615"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val4= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val4.is_valid()); EXPECT_EQ(Value::UINT, val4.type()); EXPECT_EQ(18446744073709551615ULL, val4.get_uint64()); doc= "\"abc\""; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val5= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val5.is_valid()); EXPECT_EQ(Value::STRING, val5.type()); EXPECT_EQ("abc", get_string(val5)); doc= "[ 1, 2, 3 ]"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val6= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val6.is_valid()); EXPECT_EQ(Value::ARRAY, val6.type()); EXPECT_EQ(3U, val6.element_count()); for (int i= 0; i < 3; i++) { Value v= val6.element(i); EXPECT_EQ(Value::INT, v.type()); EXPECT_EQ(i + 1, v.get_int64()); } EXPECT_EQ(Value::ERROR, val6.element(3).type()); doc= "[ 1, [ \"a\", [ 3.14 ] ] ]"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); // Top-level doc is an array of size 2. Value val7= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val7.is_valid()); EXPECT_EQ(Value::ARRAY, val7.type()); EXPECT_EQ(2U, val7.element_count()); // First element is the integer 1. Value v7_1= val7.element(0); EXPECT_TRUE(v7_1.is_valid()); EXPECT_EQ(Value::INT, v7_1.type()); EXPECT_EQ(1, v7_1.get_int64()); // The second element is a nested array of size 2. Value v7_2= val7.element(1); EXPECT_TRUE(v7_2.is_valid()); EXPECT_EQ(Value::ARRAY, v7_2.type()); EXPECT_EQ(2U, v7_2.element_count()); // The first element of the nested array is the string "a". Value v7_3= v7_2.element(0); EXPECT_TRUE(v7_3.is_valid()); EXPECT_EQ(Value::STRING, v7_3.type()); EXPECT_EQ("a", get_string(v7_3)); // The second element of the nested array is yet another array. Value v7_4= v7_2.element(1); EXPECT_TRUE(v7_4.is_valid()); EXPECT_EQ(Value::ARRAY, v7_4.type()); // The second nested array has one element, the double 3.14. EXPECT_EQ(1U, v7_4.element_count()); Value v7_5= v7_4.element(0); EXPECT_TRUE(v7_5.is_valid()); EXPECT_EQ(Value::DOUBLE, v7_5.type()); EXPECT_EQ(3.14, v7_5.get_double()); doc= "{\"key\" : \"val\"}"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val8= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val8.is_valid()); EXPECT_EQ(Value::OBJECT, val8.type()); EXPECT_EQ(1U, val8.element_count()); Value val8_k= val8.key(0); EXPECT_TRUE(val8_k.is_valid()); EXPECT_EQ(Value::STRING, val8_k.type()); EXPECT_EQ("key", get_string(val8_k)); Value val8_v= val8.element(0); EXPECT_TRUE(val8_v.is_valid()); EXPECT_EQ(Value::STRING, val8_v.type()); EXPECT_EQ("val", get_string(val8_v)); EXPECT_EQ(Value::ERROR, val8.key(1).type()); EXPECT_EQ(Value::ERROR, val8.element(1).type()); Value v8_v1= val8.lookup("key", 3); EXPECT_EQ(Value::STRING, v8_v1.type()); EXPECT_TRUE(v8_v1.is_valid()); EXPECT_EQ("val", get_string(v8_v1)); doc= "{ \"a\" : \"b\", \"c\" : [ \"d\" ] }"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val9= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val9.is_valid()); EXPECT_EQ(Value::OBJECT, val9.type()); EXPECT_EQ(2U, val9.element_count()); Value v9_k1= val9.key(0); EXPECT_EQ(Value::STRING, v9_k1.type()); EXPECT_EQ("a", get_string(v9_k1)); Value v9_v1= val9.element(0); EXPECT_EQ(Value::STRING, v9_v1.type()); EXPECT_EQ("b", get_string(v9_v1)); Value v9_k2= val9.key(1); EXPECT_EQ(Value::STRING, v9_k2.type()); EXPECT_EQ("c", get_string(v9_k2)); Value v9_v2= val9.element(1); EXPECT_EQ(Value::ARRAY, v9_v2.type()); EXPECT_EQ(1U, v9_v2.element_count()); Value v9_v2_1= v9_v2.element(0); EXPECT_EQ(Value::STRING, v9_v2_1.type()); EXPECT_EQ("d", get_string(v9_v2_1)); EXPECT_EQ("b", get_string(val9.lookup("a", 1))); Value v9_c= val9.lookup("c", 1); EXPECT_EQ(Value::ARRAY, v9_c.type()); EXPECT_EQ(1U, v9_c.element_count()); Value v9_c1= v9_c.element(0); EXPECT_EQ(Value::STRING, v9_c1.type()); EXPECT_EQ("d", get_string(v9_c1)); char blob[4]; int4store(blob, 0xCAFEBABEU); Json_opaque opaque(MYSQL_TYPE_TINY_BLOB, blob, 4); EXPECT_FALSE(serialize(&opaque, &buf)); Value val10= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val10.is_valid()); EXPECT_EQ(Value::OPAQUE, val10.type()); EXPECT_EQ(MYSQL_TYPE_TINY_BLOB, val10.field_type()); EXPECT_EQ(4U, val10.get_data_length()); EXPECT_EQ(0xCAFEBABEU, uint4korr(val10.get_data())); doc= "[true,false,null,0,\"0\",\"\",{},[]]"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val11= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val11.is_valid()); EXPECT_EQ(Value::ARRAY, val11.type()); EXPECT_EQ(8U, val11.element_count()); EXPECT_EQ(Value::LITERAL_TRUE, val11.element(0).type()); EXPECT_EQ(Value::LITERAL_FALSE, val11.element(1).type()); EXPECT_EQ(Value::LITERAL_NULL, val11.element(2).type()); EXPECT_EQ(Value::INT, val11.element(3).type()); EXPECT_EQ(Value::STRING, val11.element(4).type()); EXPECT_EQ(Value::STRING, val11.element(5).type()); EXPECT_EQ(Value::OBJECT, val11.element(6).type()); EXPECT_EQ(Value::ARRAY, val11.element(7).type()); EXPECT_EQ(0, val11.element(3).get_int64()); EXPECT_EQ("0", get_string(val11.element(4))); EXPECT_EQ("", get_string(val11.element(5))); EXPECT_EQ(0U, val11.element(6).element_count()); EXPECT_EQ(0U, val11.element(7).element_count()); doc= "{}"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val12= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val12.is_valid()); EXPECT_EQ(Value::OBJECT, val12.type()); EXPECT_EQ(0U, val12.element_count()); EXPECT_EQ(Value::ERROR, val12.lookup("", 0).type()); EXPECT_EQ(Value::ERROR, val12.lookup("key", 3).type()); EXPECT_FALSE(val12.lookup("no such key", 11).is_valid()); doc= "[]"; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val13= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val13.is_valid()); EXPECT_EQ(Value::ARRAY, val13.type()); EXPECT_EQ(0U, val13.element_count()); doc= "{\"key1\":1, \"key2\":2, \"key1\":3, \"key1\\u0000x\":4, " "\"key1\\u0000y\":5, \"a\":6, \"ab\":7, \"b\":8, \"\":9, \"\":10}"; const std::string expected_keys[]= { "", "a", "b", "ab", "key1", "key2", std::string("key1\0x", 6), std::string("key1\0y", 6) }; const int64 expected_values[]= { 9, 6, 8, 7, 1, 2, 4, 5 }; dom.reset(Json_dom::parse(doc, strlen(doc), &msg, &msg_offset)); EXPECT_FALSE(serialize(dom.get(), &buf)); Value val14= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val14.is_valid()); EXPECT_EQ(Value::OBJECT, val14.type()); EXPECT_EQ(8U, val14.element_count()); for (size_t i= 0; i < val14.element_count(); i++) { EXPECT_EQ(expected_keys[i], get_string(val14.key(i))); Value val= val14.element(i); EXPECT_EQ(Value::INT, val.type()); EXPECT_EQ(expected_values[i], val.get_int64()); Value val_lookup= val14.lookup(expected_keys[i].data(), expected_keys[i].length()); EXPECT_EQ(Value::INT, val_lookup.type()); EXPECT_EQ(expected_values[i], val_lookup.get_int64()); } // Store a decimal. my_decimal md; EXPECT_EQ(E_DEC_OK, double2my_decimal(E_DEC_FATAL_ERROR, 123.45, &md)); EXPECT_EQ(5U, md.precision()); EXPECT_EQ(2, md.frac); Json_decimal jd(md); EXPECT_FALSE(serialize(&jd, &buf)); Value val15= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val15.is_valid()); EXPECT_EQ(Value::OPAQUE, val15.type()); EXPECT_EQ(MYSQL_TYPE_NEWDECIMAL, val15.field_type()); my_decimal md_out; EXPECT_FALSE(Json_decimal::convert_from_binary(val15.get_data(), val15.get_data_length(), &md_out)); EXPECT_EQ(5U, md_out.precision()); EXPECT_EQ(2, md_out.frac); double d_out; EXPECT_EQ(E_DEC_OK, my_decimal2double(E_DEC_FATAL_ERROR, &md_out, &d_out)); EXPECT_EQ(123.45, d_out); } /* Test storing of TIME, DATE and DATETIME. */ TEST_F(JsonBinaryTest, DateAndTimeTest) { const char *tstr= "13:14:15.654321"; const char *dstr= "20140517"; const char *dtstr= "2015-01-15 15:16:17.123456"; MYSQL_TIME t; MYSQL_TIME d; MYSQL_TIME dt; MYSQL_TIME_STATUS status; EXPECT_FALSE(str_to_time(&my_charset_utf8mb4_bin, tstr, strlen(tstr), &t, 0, &status)); EXPECT_FALSE(str_to_datetime(&my_charset_utf8mb4_bin, dstr, strlen(dstr), &d, 0, &status)); EXPECT_FALSE(str_to_datetime(&my_charset_utf8mb4_bin, dtstr, strlen(dtstr), &dt, 0, &status)); // Create an array that contains a TIME, a DATE and a DATETIME. Json_array array; Json_datetime tt(t, MYSQL_TYPE_TIME); Json_datetime td(d, MYSQL_TYPE_DATE); Json_datetime tdt(dt, MYSQL_TYPE_DATETIME); array.append_clone(&tt); array.append_clone(&td); array.append_clone(&tdt); // Store the array ... String buf; EXPECT_FALSE(serialize(&array, &buf)); // ... and read it back. Value val= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val.is_valid()); EXPECT_EQ(Value::ARRAY, val.type()); EXPECT_EQ(3U, val.element_count()); // The first element should be the TIME "13:14:15.654321". Value t_val= val.element(0); EXPECT_EQ(Value::OPAQUE, t_val.type()); EXPECT_EQ(MYSQL_TYPE_TIME, t_val.field_type()); const size_t json_datetime_packed_size= Json_datetime::PACKED_SIZE; EXPECT_EQ(json_datetime_packed_size, t_val.get_data_length()); MYSQL_TIME t_out; Json_datetime::from_packed(t_val.get_data(), t_val.field_type(), &t_out); EXPECT_EQ(13U, t_out.hour); EXPECT_EQ(14U, t_out.minute); EXPECT_EQ(15U, t_out.second); EXPECT_EQ(654321U, t_out.second_part); EXPECT_FALSE(t_out.neg); EXPECT_EQ(MYSQL_TIMESTAMP_TIME, t_out.time_type); // The second element should be the DATE "2014-05-17". Value d_val= val.element(1); EXPECT_EQ(Value::OPAQUE, d_val.type()); EXPECT_EQ(MYSQL_TYPE_DATE, d_val.field_type()); EXPECT_EQ(json_datetime_packed_size, d_val.get_data_length()); MYSQL_TIME d_out; Json_datetime::from_packed(d_val.get_data(), d_val.field_type(), &d_out); EXPECT_EQ(2014U, d_out.year); EXPECT_EQ(5U, d_out.month); EXPECT_EQ(17U, d_out.day); EXPECT_FALSE(d_out.neg); EXPECT_EQ(MYSQL_TIMESTAMP_DATE, d_out.time_type); // The third element should be the DATETIME "2015-01-15 15:16:17.123456". Value dt_val= val.element(2); EXPECT_EQ(Value::OPAQUE, dt_val.type()); EXPECT_EQ(MYSQL_TYPE_DATETIME, dt_val.field_type()); EXPECT_EQ(json_datetime_packed_size, dt_val.get_data_length()); MYSQL_TIME dt_out; Json_datetime::from_packed(dt_val.get_data(), dt_val.field_type(), &dt_out); EXPECT_EQ(2015U, dt_out.year); EXPECT_EQ(1U, dt_out.month); EXPECT_EQ(15U, dt_out.day); EXPECT_EQ(15U, dt_out.hour); EXPECT_EQ(16U, dt_out.minute); EXPECT_EQ(17U, dt_out.second); EXPECT_EQ(123456U, dt_out.second_part); EXPECT_FALSE(dt_out.neg); EXPECT_EQ(MYSQL_TIMESTAMP_DATETIME, dt_out.time_type); } /* Validate that the contents of an array are as expected. The array should contain values that alternate between literal true, literal false, literal null and the string "a". */ void validate_array_contents(const Value &array, size_t expected_size) { EXPECT_EQ(Value::ARRAY, array.type()); EXPECT_TRUE(array.is_valid()); EXPECT_EQ(expected_size, array.element_count()); for (size_t i= 0; i < array.element_count(); i++) { Value val= array.element(i); EXPECT_TRUE(val.is_valid()); Value::enum_type t= val.type(); if (i % 4 == 0) EXPECT_EQ(Value::LITERAL_TRUE, t); else if (i % 4 == 1) EXPECT_EQ(Value::LITERAL_FALSE, t); else if (i % 4 == 2) EXPECT_EQ(Value::LITERAL_NULL, t); else { EXPECT_EQ(Value::STRING, t); EXPECT_EQ("a", get_string(val)); } } } /* Test some arrays and objects that exceed 64KB. Arrays and objects are stored in a different format if more than two bytes are required for the internal offsets. */ TEST_F(JsonBinaryTest, LargeDocumentTest) { Json_array array; Json_boolean literal_true(true); Json_boolean literal_false(false); Json_null literal_null; Json_string string("a"); for (int i= 0; i < 20000; i++) { array.append_clone(&literal_true); array.append_clone(&literal_false); array.append_clone(&literal_null); array.append_clone(&string); } EXPECT_EQ(80000U, array.size()); String buf; EXPECT_FALSE(serialize(&array, &buf)); Value val= parse_binary(buf.ptr(), buf.length()); { SCOPED_TRACE(""); validate_array_contents(val, array.size()); } /* Extract the raw binary representation of the large array, and verify that it is valid. */ String raw; EXPECT_FALSE(val.raw_binary(&raw)); { SCOPED_TRACE(""); validate_array_contents(parse_binary(raw.ptr(), raw.length()), array.size()); } Json_array array2; array2.append_clone(&array); array2.append_clone(&array); EXPECT_FALSE(serialize(&array2, &buf)); Value val2= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val2.is_valid()); EXPECT_EQ(Value::ARRAY, val2.type()); EXPECT_EQ(2U, val2.element_count()); { SCOPED_TRACE(""); validate_array_contents(val2.element(0), array.size()); } { SCOPED_TRACE(""); validate_array_contents(val2.element(1), array.size()); } Json_object object; object.add_clone("a", &array); Json_string s_c("c"); object.add_clone("b", &s_c); EXPECT_FALSE(serialize(&object, &buf)); Value val3= parse_binary(buf.ptr(), buf.length()); EXPECT_TRUE(val3.is_valid()); EXPECT_EQ(Value::OBJECT, val3.type()); EXPECT_EQ(2U, val3.element_count()); EXPECT_EQ("a", get_string(val3.key(0))); { SCOPED_TRACE(""); validate_array_contents(val3.element(0), array.size()); } EXPECT_EQ("b", get_string(val3.key(1))); EXPECT_EQ(Value::STRING, val3.element(1).type()); EXPECT_EQ("c", get_string(val3.element(1))); { SCOPED_TRACE(""); validate_array_contents(val3.lookup("a", 1), array.size()); } EXPECT_EQ("c", get_string(val3.lookup("b", 1))); /* Extract the raw binary representation of the large object, and verify that it is valid. */ EXPECT_FALSE(val3.raw_binary(&raw)); { SCOPED_TRACE(""); Value val_a= parse_binary(raw.ptr(), raw.length()).lookup("a", 1); validate_array_contents(val_a, array.size()); } /* Bug#23031146: INSERTING 64K SIZE RECORDS TAKE TOO MUCH TIME If a big (>64KB) sub-document was located at a deep nesting level, serialization used to be very slow. */ { SCOPED_TRACE(""); // Wrap "array" in 50 more levels of arrays. const size_t depth= 50; Json_array deeply_nested_array; Json_array *current_array= &deeply_nested_array; for (size_t i= 1; i < depth; i++) { Json_array *a= new (std::nothrow) Json_array(); ASSERT_FALSE(current_array->append_alias(a)); current_array= a; } current_array->append_clone(&array); // Serialize it. This used to take "forever". ASSERT_FALSE(serialize(&deeply_nested_array, &buf)); // Parse the serialized DOM and verify its contents. Value val= parse_binary(buf.ptr(), buf.length()); for (size_t i= 0; i < depth; i++) { ASSERT_EQ(Value::ARRAY, val.type()); ASSERT_EQ(1U, val.element_count()); val= val.element(0); } validate_array_contents(val, array.size()); // Now test the same with object. Json_object deeply_nested_object; Json_object *current_object= &deeply_nested_object; for (size_t i= 1; i < depth; i++) { Json_object *o= new (std::nothrow) Json_object(); ASSERT_FALSE(current_object->add_alias("key", o)); current_object= o; } current_object->add_clone("key", &array); ASSERT_FALSE(serialize(&deeply_nested_object, &buf)); val= parse_binary(buf.ptr(), buf.length()); for (size_t i= 0; i < depth; i++) { ASSERT_EQ(Value::OBJECT, val.type()); ASSERT_EQ(1U, val.element_count()); ASSERT_EQ("key", get_string(val.key(0))); val= val.element(0); } validate_array_contents(val, array.size()); } } /* Various tests for the Value::raw_binary() function. */ TEST_F(JsonBinaryTest, RawBinaryTest) { Json_array array; Json_string as("a string"); array.append_clone(&as); Json_int ji(-123); array.append_clone(&ji); Json_uint jui(42); array.append_clone(&jui); Json_double jd(1.5); array.append_clone(&jd); Json_null jn; array.append_clone(&jn); Json_boolean jbt(true); array.append_clone(&jbt); Json_boolean jbf(false); array.append_clone(&jbf); Json_opaque jo(MYSQL_TYPE_BLOB, "abcd", 4); array.append_clone(&jo); Json_object object; object.add_clone("key", &jbt); array.append_clone(&object); Json_array array2; array2.append_clone(&jbf); array.append_clone(&array2); String buf; EXPECT_FALSE(json_binary::serialize(&array, &buf)); Value v1= parse_binary(buf.ptr(), buf.length()); String raw; EXPECT_FALSE(v1.raw_binary(&raw)); Value v1_copy= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::ARRAY, v1_copy.type()); EXPECT_EQ(array.size(), v1_copy.element_count()); EXPECT_FALSE(v1.element(0).raw_binary(&raw)); Value v1_0= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::STRING, v1_0.type()); EXPECT_EQ("a string", std::string(v1_0.get_data(), v1_0.get_data_length())); EXPECT_FALSE(v1.element(1).raw_binary(&raw)); Value v1_1= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::INT, v1_1.type()); EXPECT_EQ(-123, v1_1.get_int64()); EXPECT_FALSE(v1.element(2).raw_binary(&raw)); Value v1_2= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::UINT, v1_2.type()); EXPECT_EQ(42U, v1_2.get_uint64()); EXPECT_FALSE(v1.element(3).raw_binary(&raw)); Value v1_3= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::DOUBLE, v1_3.type()); EXPECT_EQ(1.5, v1_3.get_double()); EXPECT_FALSE(v1.element(4).raw_binary(&raw)); Value v1_4= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::LITERAL_NULL, v1_4.type()); EXPECT_FALSE(v1.element(5).raw_binary(&raw)); Value v1_5= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::LITERAL_TRUE, v1_5.type()); EXPECT_FALSE(v1.element(6).raw_binary(&raw)); Value v1_6= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::LITERAL_FALSE, v1_6.type()); EXPECT_FALSE(v1.element(7).raw_binary(&raw)); Value v1_7= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::OPAQUE, v1_7.type()); EXPECT_EQ(MYSQL_TYPE_BLOB, v1_7.field_type()); EXPECT_EQ("abcd", std::string(v1_7.get_data(), v1_7.get_data_length())); EXPECT_FALSE(v1.element(8).raw_binary(&raw)); Value v1_8= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::OBJECT, v1_8.type()); EXPECT_EQ(object.cardinality(), v1_8.element_count()); EXPECT_EQ(Value::LITERAL_TRUE, v1_8.lookup("key", 3).type()); EXPECT_FALSE(v1.element(8).key(0).raw_binary(&raw)); Value v1_8_key= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::STRING, v1_8_key.type()); EXPECT_EQ("key", std::string(v1_8_key.get_data(), v1_8_key.get_data_length())); EXPECT_FALSE(v1.element(8).element(0).raw_binary(&raw)); Value v1_8_val= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::LITERAL_TRUE, v1_8_val.type()); EXPECT_FALSE(v1.element(9).raw_binary(&raw)); Value v1_9= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::ARRAY, v1_9.type()); EXPECT_EQ(array2.size(), v1_9.element_count()); EXPECT_EQ(Value::LITERAL_FALSE, v1_9.element(0).type()); EXPECT_FALSE(v1.element(9).element(0).raw_binary(&raw)); Value v1_9_0= parse_binary(raw.ptr(), raw.length()); EXPECT_EQ(Value::LITERAL_FALSE, v1_9_0.type()); } /* Create a JSON string of the given size, serialize it as a JSON binary, and then deserialize it and verify that we get the same string back. */ void serialize_deserialize_string(size_t size) { SCOPED_TRACE(testing::Message() << "size = " << size); char *str= new char[size]; memset(str, 'a', size); Json_string jstr(std::string(str, size)); String buf; EXPECT_FALSE(json_binary::serialize(&jstr, &buf)); Value v= parse_binary(buf.ptr(), buf.length()); EXPECT_EQ(Value::STRING, v.type()); EXPECT_EQ(size, v.get_data_length()); EXPECT_EQ(0, memcmp(str, v.get_data(), size)); delete[] str; } /* Test strings of variable length. Test especially around the boundaries where the representation of the string length changes: - Strings of length 0-127 use 1 byte length fields. - Strings of length 128-16383 use 2 byte length fields. - Strings of length 16384-2097151 use 3 byte length fields. - Strings of length 2097152-268435455 use 4 byte length fields. - Strings of length 268435456-... use 5 byte length fields. We probably don't have enough memory to test the last category here... */ TEST_F(JsonBinaryTest, StringLengthTest) { serialize_deserialize_string(0); serialize_deserialize_string(1); serialize_deserialize_string(127); serialize_deserialize_string(128); serialize_deserialize_string(16383); serialize_deserialize_string(16384); serialize_deserialize_string(2097151); serialize_deserialize_string(2097152); serialize_deserialize_string(3000000); } }