#include "json_test.h" #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" #include "monster_test_bfbs_generated.h" #include "monster_test_generated.h" #include "optional_scalars_generated.h" #include "test_assert.h" namespace flatbuffers { namespace tests { using namespace MyGame::Example; // Check stringify of an default enum value to json void JsonDefaultTest(const std::string &tests_data_path) { // load FlatBuffer schema (.fbs) from disk std::string schemafile; TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(), false, &schemafile), true); // parse schema first, so we can use it to parse the data after flatbuffers::Parser parser; auto include_test_path = flatbuffers::ConCatPathFileName(tests_data_path, "include_test"); const char *include_directories[] = { tests_data_path.c_str(), include_test_path.c_str(), nullptr }; TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true); // create incomplete monster and store to json parser.opts.output_default_scalars_in_json = true; parser.opts.output_enum_identifiers = true; flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("default_enum"); MonsterBuilder color_monster(builder); color_monster.add_name(name); FinishMonsterBuffer(builder, color_monster.Finish()); std::string jsongen; auto result = GenText(parser, builder.GetBufferPointer(), &jsongen); TEST_NULL(result); // default value of the "color" field is Blue TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true); // default value of the "testf" field is 3.14159 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true); } void JsonEnumsTest(const std::string &tests_data_path) { // load FlatBuffer schema (.fbs) from disk std::string schemafile; TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(), false, &schemafile), true); // parse schema first, so we can use it to parse the data after flatbuffers::Parser parser; auto include_test_path = flatbuffers::ConCatPathFileName(tests_data_path, "include_test"); const char *include_directories[] = { tests_data_path.c_str(), include_test_path.c_str(), nullptr }; parser.opts.output_enum_identifiers = true; TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true); flatbuffers::FlatBufferBuilder builder; auto name = builder.CreateString("bitflag_enum"); MonsterBuilder color_monster(builder); color_monster.add_name(name); color_monster.add_color(Color(Color_Blue | Color_Red)); FinishMonsterBuffer(builder, color_monster.Finish()); std::string jsongen; auto result = GenText(parser, builder.GetBufferPointer(), &jsongen); TEST_NULL(result); TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true); // Test forward compatibility with 'output_enum_identifiers = true'. // Current Color doesn't have '(1u << 2)' field, let's add it. builder.Clear(); std::string future_json; auto future_name = builder.CreateString("future bitflag_enum"); MonsterBuilder future_color(builder); future_color.add_name(future_name); future_color.add_color( static_cast((1u << 2) | Color_Blue | Color_Red)); FinishMonsterBuffer(builder, future_color.Finish()); result = GenText(parser, builder.GetBufferPointer(), &future_json); TEST_NULL(result); TEST_EQ(std::string::npos != future_json.find("color: 13"), true); } void JsonOptionalTest(const std::string &tests_data_path, bool default_scalars) { // load FlatBuffer schema (.fbs) and JSON from disk std::string schemafile; std::string jsonfile; TEST_EQ( flatbuffers::LoadFile((tests_data_path + "optional_scalars.fbs").c_str(), false, &schemafile), true); TEST_EQ(flatbuffers::LoadFile((tests_data_path + "optional_scalars" + (default_scalars ? "_defaults" : "") + ".json") .c_str(), false, &jsonfile), true); auto include_test_path = flatbuffers::ConCatPathFileName(tests_data_path, "include_test"); const char *include_directories[] = { tests_data_path.c_str(), include_test_path.c_str(), nullptr }; // parse schema first, so we can use it to parse the data after flatbuffers::Parser parser; parser.opts.output_default_scalars_in_json = default_scalars; TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true); TEST_EQ(parser.ParseJson(jsonfile.c_str()), true); // here, parser.builder_ contains a binary buffer that is the parsed data. // First, verify it, just in case: flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(), parser.builder_.GetSize()); TEST_EQ(optional_scalars::VerifyScalarStuffBuffer(verifier), true); // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; auto result = GenText(parser, parser.builder_.GetBufferPointer(), &jsongen); TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str()); } void ParseIncorrectMonsterJsonTest(const std::string &tests_data_path) { std::string schemafile; TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.bfbs").c_str(), true, &schemafile), true); flatbuffers::Parser parser; flatbuffers::Verifier verifier( reinterpret_cast(schemafile.c_str()), schemafile.size()); TEST_EQ(reflection::VerifySchemaBuffer(verifier), true); TEST_EQ( parser.Deserialize(reinterpret_cast(schemafile.c_str()), schemafile.size()), true); TEST_EQ(parser.ParseJson("{name:\"monster\"}"), true); TEST_EQ(parser.ParseJson(""), false); TEST_EQ(parser.ParseJson("{name: 1}"), false); TEST_EQ(parser.ParseJson("{name:+1}"), false); TEST_EQ(parser.ParseJson("{name:-1}"), false); TEST_EQ(parser.ParseJson("{name:-f}"), false); TEST_EQ(parser.ParseJson("{name:+f}"), false); } void JsonUnsortedArrayTest() { flatbuffers::Parser parser; TEST_EQ(parser.Deserialize(MyGame::Example::MonsterBinarySchema::data(), MyGame::Example::MonsterBinarySchema::size()), true); auto jsonStr = R"( { "name": "lookupTest", "testarrayoftables": [ { "name": "aaa" }, { "name": "ccc" }, { "name": "bbb" } ] } )"; TEST_EQ(parser.ParseJson(jsonStr), true); auto monster = flatbuffers::GetRoot( parser.builder_.GetBufferPointer()); TEST_NOTNULL(monster->testarrayoftables()->LookupByKey("aaa")); TEST_NOTNULL(monster->testarrayoftables()->LookupByKey("bbb")); TEST_NOTNULL(monster->testarrayoftables()->LookupByKey("ccc")); } void JsonUnionStructTest() { // schema to parse data auto schema = R"( struct MyStruct { field: int; } union UnionWithStruct { MyStruct } table JsonUnionStructTest { union_with_struct: UnionWithStruct; } root_type JsonUnionStructTest; )"; // source text to parse and expected result of generation text back auto json_source = R"({ union_with_struct_type: "MyStruct", union_with_struct: { field: 12345 } } )"; flatbuffers::Parser parser; // set output language to JSON, so we assure that is supported parser.opts.lang_to_generate = IDLOptions::kJson; // parse schema first, so we assure that output language is supported // and can use it to parse the data after TEST_EQ(true, parser.Parse(schema)); TEST_EQ(true, parser.ParseJson(json_source)); // now generate text back from the binary, and compare the two: std::string json_generated; auto generate_result = GenText(parser, parser.builder_.GetBufferPointer(), &json_generated); TEST_NULL(generate_result); TEST_EQ_STR(json_source, json_generated.c_str()); } } // namespace tests } // namespace flatbuffers