1#include "json_test.h"
2
3#include "flatbuffers/flatbuffers.h"
4#include "flatbuffers/idl.h"
5#include "monster_test_bfbs_generated.h"
6#include "monster_test_generated.h"
7#include "optional_scalars_generated.h"
8#include "test_assert.h"
9
10namespace flatbuffers {
11namespace tests {
12
13using namespace MyGame::Example;
14
15// Check stringify of an default enum value to json
16void JsonDefaultTest(const std::string &tests_data_path) {
17 // load FlatBuffer schema (.fbs) from disk
18 std::string schemafile;
19 TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
20 false, &schemafile),
21 true);
22 // parse schema first, so we can use it to parse the data after
23 flatbuffers::Parser parser;
24 auto include_test_path =
25 flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
26 const char *include_directories[] = { tests_data_path.c_str(),
27 include_test_path.c_str(), nullptr };
28
29 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
30 // create incomplete monster and store to json
31 parser.opts.output_default_scalars_in_json = true;
32 parser.opts.output_enum_identifiers = true;
33 flatbuffers::FlatBufferBuilder builder;
34 auto name = builder.CreateString("default_enum");
35 MonsterBuilder color_monster(builder);
36 color_monster.add_name(name);
37 FinishMonsterBuffer(builder, color_monster.Finish());
38 std::string jsongen;
39 auto result = GenText(parser, builder.GetBufferPointer(), &jsongen);
40 TEST_NULL(result);
41 // default value of the "color" field is Blue
42 TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
43 // default value of the "testf" field is 3.14159
44 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
45}
46
47void JsonEnumsTest(const std::string &tests_data_path) {
48 // load FlatBuffer schema (.fbs) from disk
49 std::string schemafile;
50 TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
51 false, &schemafile),
52 true);
53 // parse schema first, so we can use it to parse the data after
54 flatbuffers::Parser parser;
55 auto include_test_path =
56 flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
57 const char *include_directories[] = { tests_data_path.c_str(),
58 include_test_path.c_str(), nullptr };
59 parser.opts.output_enum_identifiers = true;
60 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
61 flatbuffers::FlatBufferBuilder builder;
62 auto name = builder.CreateString("bitflag_enum");
63 MonsterBuilder color_monster(builder);
64 color_monster.add_name(name);
65 color_monster.add_color(Color(Color_Blue | Color_Red));
66 FinishMonsterBuffer(builder, color_monster.Finish());
67 std::string jsongen;
68 auto result = GenText(parser, builder.GetBufferPointer(), &jsongen);
69 TEST_NULL(result);
70 TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
71 // Test forward compatibility with 'output_enum_identifiers = true'.
72 // Current Color doesn't have '(1u << 2)' field, let's add it.
73 builder.Clear();
74 std::string future_json;
75 auto future_name = builder.CreateString("future bitflag_enum");
76 MonsterBuilder future_color(builder);
77 future_color.add_name(future_name);
78 future_color.add_color(
79 static_cast<Color>((1u << 2) | Color_Blue | Color_Red));
80 FinishMonsterBuffer(builder, future_color.Finish());
81 result = GenText(parser, builder.GetBufferPointer(), &future_json);
82 TEST_NULL(result);
83 TEST_EQ(std::string::npos != future_json.find("color: 13"), true);
84}
85
86void JsonOptionalTest(const std::string &tests_data_path,
87 bool default_scalars) {
88 // load FlatBuffer schema (.fbs) and JSON from disk
89 std::string schemafile;
90 std::string jsonfile;
91 TEST_EQ(
92 flatbuffers::LoadFile((tests_data_path + "optional_scalars.fbs").c_str(),
93 false, &schemafile),
94 true);
95 TEST_EQ(flatbuffers::LoadFile((tests_data_path + "optional_scalars" +
96 (default_scalars ? "_defaults" : "") + ".json")
97 .c_str(),
98 false, &jsonfile),
99 true);
100
101 auto include_test_path =
102 flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
103 const char *include_directories[] = { tests_data_path.c_str(),
104 include_test_path.c_str(), nullptr };
105
106 // parse schema first, so we can use it to parse the data after
107 flatbuffers::Parser parser;
108 parser.opts.output_default_scalars_in_json = default_scalars;
109 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
110 TEST_EQ(parser.ParseJson(jsonfile.c_str()), true);
111
112 // here, parser.builder_ contains a binary buffer that is the parsed data.
113
114 // First, verify it, just in case:
115 flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
116 parser.builder_.GetSize());
117 TEST_EQ(optional_scalars::VerifyScalarStuffBuffer(verifier), true);
118
119 // to ensure it is correct, we now generate text back from the binary,
120 // and compare the two:
121 std::string jsongen;
122 auto result = GenText(parser, parser.builder_.GetBufferPointer(), &jsongen);
123 TEST_NULL(result);
124 TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
125}
126
127void ParseIncorrectMonsterJsonTest(const std::string &tests_data_path) {
128 std::string schemafile;
129 TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.bfbs").c_str(),
130 true, &schemafile),
131 true);
132 flatbuffers::Parser parser;
133 flatbuffers::Verifier verifier(
134 reinterpret_cast<const uint8_t *>(schemafile.c_str()), schemafile.size());
135 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
136 TEST_EQ(
137 parser.Deserialize(reinterpret_cast<const uint8_t *>(schemafile.c_str()),
138 schemafile.size()),
139 true);
140 TEST_EQ(parser.ParseJson("{name:\"monster\"}"), true);
141 TEST_EQ(parser.ParseJson(""), false);
142 TEST_EQ(parser.ParseJson("{name: 1}"), false);
143 TEST_EQ(parser.ParseJson("{name:+1}"), false);
144 TEST_EQ(parser.ParseJson("{name:-1}"), false);
145 TEST_EQ(parser.ParseJson("{name:-f}"), false);
146 TEST_EQ(parser.ParseJson("{name:+f}"), false);
147}
148
149void JsonUnsortedArrayTest() {
150 flatbuffers::Parser parser;
151 TEST_EQ(parser.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
152 MyGame::Example::MonsterBinarySchema::size()),
153 true);
154 auto jsonStr = R"(
155 {
156 "name": "lookupTest",
157 "testarrayoftables": [
158 { "name": "aaa" },
159 { "name": "ccc" },
160 { "name": "bbb" }
161 ]
162 }
163 )";
164 TEST_EQ(parser.ParseJson(jsonStr), true);
165 auto monster = flatbuffers::GetRoot<MyGame::Example::Monster>(
166 parser.builder_.GetBufferPointer());
167
168 TEST_NOTNULL(monster->testarrayoftables()->LookupByKey("aaa"));
169 TEST_NOTNULL(monster->testarrayoftables()->LookupByKey("bbb"));
170 TEST_NOTNULL(monster->testarrayoftables()->LookupByKey("ccc"));
171}
172
173void JsonUnionStructTest() {
174 // schema to parse data
175 auto schema = R"(
176struct MyStruct { field: int; }
177union UnionWithStruct { MyStruct }
178table JsonUnionStructTest { union_with_struct: UnionWithStruct; }
179root_type JsonUnionStructTest;
180)";
181 // source text to parse and expected result of generation text back
182 auto json_source = R"({
183 union_with_struct_type: "MyStruct",
184 union_with_struct: {
185 field: 12345
186 }
187}
188)";
189
190 flatbuffers::Parser parser;
191 // set output language to JSON, so we assure that is supported
192 parser.opts.lang_to_generate = IDLOptions::kJson;
193 // parse schema first, so we assure that output language is supported
194 // and can use it to parse the data after
195 TEST_EQ(true, parser.Parse(schema));
196 TEST_EQ(true, parser.ParseJson(json_source));
197
198 // now generate text back from the binary, and compare the two:
199 std::string json_generated;
200 auto generate_result =
201 GenText(parser, parser.builder_.GetBufferPointer(), &json_generated);
202 TEST_NULL(generate_result);
203 TEST_EQ_STR(json_source, json_generated.c_str());
204}
205
206} // namespace tests
207} // namespace flatbuffers
View as plain text