From fb585045692c482b6946fff63f0cd8425c8c70b5 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 2 Feb 2015 13:38:05 -0800 Subject: Support maps in JSON parsing and serialization. This is a sync of our internal developing of JSON parsing and serialization. It implements native understanding of MapEntry submessages, so that map fields with (key, value) pairs are serialized as JSON maps (objects) natively rather than as arrays of objects with 'key' and 'value' fields. The parser also now understands how to emit handler calls corresponding to MapEntry objects when processing a map field. This sync also picks up a bugfix in `table.c` to handle an alloc-failed case. --- tests/json/test_json.cc | 98 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) (limited to 'tests/json') diff --git a/tests/json/test_json.cc b/tests/json/test_json.cc index f1e2304..4465c76 100644 --- a/tests/json/test_json.cc +++ b/tests/json/test_json.cc @@ -85,6 +85,33 @@ static TestCase kTestRoundtripMessages[] = { TEST("{\"optional_string\":\"\\uFFFF\"}"), EXPECT("{\"optional_string\":\"\xEF\xBF\xBF\"}") }, + // map-field tests + { + TEST("{\"map_string_string\":{\"a\":\"value1\",\"b\":\"value2\"," + "\"c\":\"value3\"}}"), + EXPECT_SAME + }, + { + TEST("{\"map_int32_string\":{\"1\":\"value1\",\"-1\":\"value2\"," + "\"1234\":\"value3\"}}"), + EXPECT_SAME + }, + { + TEST("{\"map_bool_string\":{\"false\":\"value1\",\"true\":\"value2\"}}"), + EXPECT_SAME + }, + { + TEST("{\"map_string_int32\":{\"asdf\":1234,\"jkl;\":-1}}"), + EXPECT_SAME + }, + { + TEST("{\"map_string_bool\":{\"asdf\":true,\"jkl;\":false}}"), + EXPECT_SAME + }, + { + TEST("{\"map_string_msg\":{\"asdf\":{\"foo\":42},\"jkl;\":{\"foo\":84}}}"), + EXPECT_SAME + }, TEST_SENTINEL }; @@ -115,6 +142,53 @@ static const upb::MessageDef* BuildTestMessage( submsg->set_full_name("SubMessage", &st); AddField(submsg.get(), 1, "foo", UPB_TYPE_INT32, false); + // Create MapEntryStringString. + upb::reffed_ptr mapentry_string_string( + upb::MessageDef::New()); + mapentry_string_string->set_full_name("MapEntry_String_String", &st); + mapentry_string_string->setmapentry(true); + AddField(mapentry_string_string.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_string.get(), 2, "value", UPB_TYPE_STRING, false); + + // Create MapEntryInt32String. + upb::reffed_ptr mapentry_int32_string( + upb::MessageDef::New()); + mapentry_int32_string->set_full_name("MapEntry_Int32_String", &st); + mapentry_int32_string->setmapentry(true); + AddField(mapentry_int32_string.get(), 1, "key", UPB_TYPE_INT32, false); + AddField(mapentry_int32_string.get(), 2, "value", UPB_TYPE_STRING, false); + + // Create MapEntryBoolString. + upb::reffed_ptr mapentry_bool_string( + upb::MessageDef::New()); + mapentry_bool_string->set_full_name("MapEntry_Bool_String", &st); + mapentry_bool_string->setmapentry(true); + AddField(mapentry_bool_string.get(), 1, "key", UPB_TYPE_BOOL, false); + AddField(mapentry_bool_string.get(), 2, "value", UPB_TYPE_STRING, false); + + // Create MapEntryStringInt32. + upb::reffed_ptr mapentry_string_int32( + upb::MessageDef::New()); + mapentry_string_int32->set_full_name("MapEntry_String_Int32", &st); + mapentry_string_int32->setmapentry(true); + AddField(mapentry_string_int32.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_int32.get(), 2, "value", UPB_TYPE_INT32, false); + + // Create MapEntryStringBool. + upb::reffed_ptr mapentry_string_bool(upb::MessageDef::New()); + mapentry_string_bool->set_full_name("MapEntry_String_Bool", &st); + mapentry_string_bool->setmapentry(true); + AddField(mapentry_string_bool.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_bool.get(), 2, "value", UPB_TYPE_BOOL, false); + + // Create MapEntryStringMessage. + upb::reffed_ptr mapentry_string_msg(upb::MessageDef::New()); + mapentry_string_msg->set_full_name("MapEntry_String_Message", &st); + mapentry_string_msg->setmapentry(true); + AddField(mapentry_string_msg.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_msg.get(), 2, "value", UPB_TYPE_MESSAGE, false, + upb::upcast(submsg.get())); + // Create MyEnum. upb::reffed_ptr myenum(upb::EnumDef::New()); myenum->set_full_name("MyEnum", &st); @@ -150,13 +224,33 @@ static const upb::MessageDef* BuildTestMessage( AddField(md.get(), 19, "optional_enum", UPB_TYPE_ENUM, true, upb::upcast(myenum.get())); + AddField(md.get(), 20, "map_string_string", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_string.get())); + AddField(md.get(), 21, "map_int32_string", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_int32_string.get())); + AddField(md.get(), 22, "map_bool_string", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_bool_string.get())); + AddField(md.get(), 23, "map_string_int32", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_int32.get())); + AddField(md.get(), 24, "map_string_bool", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_bool.get())); + AddField(md.get(), 25, "map_string_msg", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_msg.get())); + // Add both to our symtab. - upb::Def* defs[3] = { + upb::Def* defs[9] = { upb::upcast(submsg.ReleaseTo(&defs)), upb::upcast(myenum.ReleaseTo(&defs)), upb::upcast(md.ReleaseTo(&defs)), + upb::upcast(mapentry_string_string.ReleaseTo(&defs)), + upb::upcast(mapentry_int32_string.ReleaseTo(&defs)), + upb::upcast(mapentry_bool_string.ReleaseTo(&defs)), + upb::upcast(mapentry_string_int32.ReleaseTo(&defs)), + upb::upcast(mapentry_string_bool.ReleaseTo(&defs)), + upb::upcast(mapentry_string_msg.ReleaseTo(&defs)), }; - symtab->Add(defs, 3, &defs, &st); + symtab->Add(defs, 9, &defs, &st); + ASSERT(st.ok()); // Return TestMessage. return symtab->LookupMessage("TestMessage"); -- cgit v1.2.3