1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fstream>
18 #include <map>
19 #include <memory>
20 #include <string>
21
22 #include "utils/flatbuffers.h"
23 #include "utils/flatbuffers_generated.h"
24 #include "utils/flatbuffers_test_generated.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "flatbuffers/flatbuffers.h"
28 #include "flatbuffers/reflection.h"
29 #include "flatbuffers/reflection_generated.h"
30
31 namespace libtextclassifier3 {
32 namespace {
33
GetTestMetadataPath()34 std::string GetTestMetadataPath() {
35 return "flatbuffers_test.bfbs";
36 }
37
LoadTestMetadata()38 std::string LoadTestMetadata() {
39 std::ifstream test_config_stream(GetTestMetadataPath());
40 return std::string((std::istreambuf_iterator<char>(test_config_stream)),
41 (std::istreambuf_iterator<char>()));
42 }
43
TEST(FlatbuffersTest,PrimitiveFieldsAreCorrectlySet)44 TEST(FlatbuffersTest, PrimitiveFieldsAreCorrectlySet) {
45 std::string metadata_buffer = LoadTestMetadata();
46 ReflectiveFlatbufferBuilder reflective_builder(
47 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data()));
48
49 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
50 EXPECT_TRUE(buffer != nullptr);
51 EXPECT_TRUE(buffer->Set("an_int_field", 42));
52 EXPECT_TRUE(buffer->Set("a_long_field", 84ll));
53 EXPECT_TRUE(buffer->Set("a_bool_field", true));
54 EXPECT_TRUE(buffer->Set("a_float_field", 1.f));
55 EXPECT_TRUE(buffer->Set("a_double_field", 1.0));
56
57 // Try to parse with the generated code.
58 std::string serialized_entity_data = buffer->Serialize();
59 std::unique_ptr<test::EntityDataT> entity_data =
60 LoadAndVerifyMutableFlatbuffer<test::EntityData>(
61 serialized_entity_data.data(), serialized_entity_data.size());
62 EXPECT_TRUE(entity_data != nullptr);
63 EXPECT_EQ(entity_data->an_int_field, 42);
64 EXPECT_EQ(entity_data->a_long_field, 84);
65 EXPECT_EQ(entity_data->a_bool_field, true);
66 EXPECT_NEAR(entity_data->a_float_field, 1.f, 1e-4);
67 EXPECT_NEAR(entity_data->a_double_field, 1.f, 1e-4);
68 }
69
TEST(FlatbuffersTest,HandlesUnknownFields)70 TEST(FlatbuffersTest, HandlesUnknownFields) {
71 std::string metadata_buffer = LoadTestMetadata();
72 const reflection::Schema* schema =
73 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data());
74 ReflectiveFlatbufferBuilder reflective_builder(schema);
75
76 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
77 EXPECT_TRUE(buffer != nullptr);
78
79 // Add a field that is not known to the (statically generated) code.
80 EXPECT_TRUE(buffer->Set("mystic", "this is an unknown field."));
81
82 flatbuffers::FlatBufferBuilder builder;
83 builder.Finish(flatbuffers::Offset<void>(buffer->Serialize(&builder)));
84
85 // Try to read the field again.
86 const flatbuffers::Table* extra =
87 flatbuffers::GetAnyRoot(builder.GetBufferPointer());
88 EXPECT_EQ(extra
89 ->GetPointer<const flatbuffers::String*>(
90 buffer->GetFieldOrNull("mystic")->offset())
91 ->str(),
92 "this is an unknown field.");
93 }
94
TEST(FlatbuffersTest,HandlesNestedFields)95 TEST(FlatbuffersTest, HandlesNestedFields) {
96 std::string metadata_buffer = LoadTestMetadata();
97 const reflection::Schema* schema =
98 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data());
99 ReflectiveFlatbufferBuilder reflective_builder(schema);
100
101 FlatbufferFieldPathT path;
102 path.field.emplace_back(new FlatbufferFieldT);
103 path.field.back()->field_name = "flight_number";
104 path.field.emplace_back(new FlatbufferFieldT);
105 path.field.back()->field_name = "carrier_code";
106 flatbuffers::FlatBufferBuilder path_builder;
107 path_builder.Finish(FlatbufferFieldPath::Pack(path_builder, &path));
108
109 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
110
111 ReflectiveFlatbuffer* parent = nullptr;
112 reflection::Field const* field = nullptr;
113 EXPECT_TRUE(
114 buffer->GetFieldWithParent(flatbuffers::GetRoot<FlatbufferFieldPath>(
115 path_builder.GetBufferPointer()),
116 &parent, &field));
117 EXPECT_EQ(parent, buffer->Mutable("flight_number"));
118 EXPECT_EQ(field,
119 buffer->Mutable("flight_number")->GetFieldOrNull("carrier_code"));
120 }
121
TEST(FlatbuffersTest,HandlesMultipleNestedFields)122 TEST(FlatbuffersTest, HandlesMultipleNestedFields) {
123 std::string metadata_buffer = LoadTestMetadata();
124 ReflectiveFlatbufferBuilder reflective_builder(
125 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data()));
126
127 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
128 ReflectiveFlatbuffer* flight_info = buffer->Mutable("flight_number");
129 flight_info->Set("carrier_code", "LX");
130 flight_info->Set("flight_code", 38);
131
132 ReflectiveFlatbuffer* contact_info = buffer->Mutable("contact_info");
133 EXPECT_TRUE(contact_info->Set("first_name", "Barack"));
134 EXPECT_TRUE(contact_info->Set("last_name", "Obama"));
135 EXPECT_TRUE(contact_info->Set("phone_number", "1-800-TEST"));
136 EXPECT_TRUE(contact_info->Set("score", 1.f));
137
138 // Try to parse with the generated code.
139 std::string serialized_entity_data = buffer->Serialize();
140 std::unique_ptr<test::EntityDataT> entity_data =
141 LoadAndVerifyMutableFlatbuffer<test::EntityData>(
142 serialized_entity_data.data(), serialized_entity_data.size());
143 EXPECT_TRUE(entity_data != nullptr);
144 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
145 EXPECT_EQ(entity_data->flight_number->flight_code, 38);
146 EXPECT_EQ(entity_data->contact_info->first_name, "Barack");
147 EXPECT_EQ(entity_data->contact_info->last_name, "Obama");
148 EXPECT_EQ(entity_data->contact_info->phone_number, "1-800-TEST");
149 EXPECT_NEAR(entity_data->contact_info->score, 1.f, 1e-4);
150 }
151
TEST(FlatbuffersTest,HandlesFieldsSetWithNamePath)152 TEST(FlatbuffersTest, HandlesFieldsSetWithNamePath) {
153 std::string metadata_buffer = LoadTestMetadata();
154 ReflectiveFlatbufferBuilder reflective_builder(
155 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data()));
156
157 FlatbufferFieldPathT path;
158 path.field.emplace_back(new FlatbufferFieldT);
159 path.field.back()->field_name = "flight_number";
160 path.field.emplace_back(new FlatbufferFieldT);
161 path.field.back()->field_name = "carrier_code";
162 flatbuffers::FlatBufferBuilder path_builder;
163 path_builder.Finish(FlatbufferFieldPath::Pack(path_builder, &path));
164
165 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
166 // Test setting value using Set function.
167 buffer->Mutable("flight_number")->Set("flight_code", 38);
168 // Test setting value using FlatbufferFieldPath.
169 buffer->Set(flatbuffers::GetRoot<FlatbufferFieldPath>(
170 path_builder.GetBufferPointer()),
171 "LX");
172
173 // Try to parse with the generated code.
174 std::string serialized_entity_data = buffer->Serialize();
175 std::unique_ptr<test::EntityDataT> entity_data =
176 LoadAndVerifyMutableFlatbuffer<test::EntityData>(
177 serialized_entity_data.data(), serialized_entity_data.size());
178 EXPECT_TRUE(entity_data != nullptr);
179 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
180 EXPECT_EQ(entity_data->flight_number->flight_code, 38);
181 }
182
TEST(FlatbuffersTest,HandlesFieldsSetWithOffsetPath)183 TEST(FlatbuffersTest, HandlesFieldsSetWithOffsetPath) {
184 std::string metadata_buffer = LoadTestMetadata();
185 ReflectiveFlatbufferBuilder reflective_builder(
186 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data()));
187
188 FlatbufferFieldPathT path;
189 path.field.emplace_back(new FlatbufferFieldT);
190 path.field.back()->field_offset = 14;
191 path.field.emplace_back(new FlatbufferFieldT);
192 path.field.back()->field_offset = 4;
193 flatbuffers::FlatBufferBuilder path_builder;
194 path_builder.Finish(FlatbufferFieldPath::Pack(path_builder, &path));
195
196 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
197 // Test setting value using Set function.
198 buffer->Mutable("flight_number")->Set("flight_code", 38);
199 // Test setting value using FlatbufferFieldPath.
200 buffer->Set(flatbuffers::GetRoot<FlatbufferFieldPath>(
201 path_builder.GetBufferPointer()),
202 "LX");
203
204 // Try to parse with the generated code.
205 std::string serialized_entity_data = buffer->Serialize();
206 std::unique_ptr<test::EntityDataT> entity_data =
207 LoadAndVerifyMutableFlatbuffer<test::EntityData>(
208 serialized_entity_data.data(), serialized_entity_data.size());
209 EXPECT_TRUE(entity_data != nullptr);
210 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
211 EXPECT_EQ(entity_data->flight_number->flight_code, 38);
212 }
213
TEST(FlatbuffersTest,PartialBuffersAreCorrectlyMerged)214 TEST(FlatbuffersTest, PartialBuffersAreCorrectlyMerged) {
215 std::string metadata_buffer = LoadTestMetadata();
216 ReflectiveFlatbufferBuilder reflective_builder(
217 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data()));
218 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
219 buffer->Set("an_int_field", 42);
220 buffer->Set("a_long_field", 84ll);
221 ReflectiveFlatbuffer* flight_info = buffer->Mutable("flight_number");
222 flight_info->Set("carrier_code", "LX");
223 flight_info->Set("flight_code", 38);
224
225 // Create message to merge.
226 test::EntityDataT additional_entity_data;
227 additional_entity_data.an_int_field = 43;
228 additional_entity_data.flight_number.reset(new test::FlightNumberInfoT);
229 additional_entity_data.flight_number->flight_code = 39;
230 additional_entity_data.contact_info.reset(new test::ContactInfoT);
231 additional_entity_data.contact_info->first_name = "Barack";
232 flatbuffers::FlatBufferBuilder to_merge_builder;
233 to_merge_builder.Finish(
234 test::EntityData::Pack(to_merge_builder, &additional_entity_data));
235
236 // Merge it.
237 EXPECT_TRUE(buffer->MergeFrom(
238 flatbuffers::GetAnyRoot(to_merge_builder.GetBufferPointer())));
239
240 // Try to parse it with the generated code.
241 std::string serialized_entity_data = buffer->Serialize();
242 std::unique_ptr<test::EntityDataT> entity_data =
243 LoadAndVerifyMutableFlatbuffer<test::EntityData>(
244 serialized_entity_data.data(), serialized_entity_data.size());
245 EXPECT_TRUE(entity_data != nullptr);
246 EXPECT_EQ(entity_data->an_int_field, 43);
247 EXPECT_EQ(entity_data->a_long_field, 84);
248 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
249 EXPECT_EQ(entity_data->flight_number->flight_code, 39);
250 EXPECT_EQ(entity_data->contact_info->first_name, "Barack");
251 }
252
TEST(FlatbuffersTest,PrimitiveAndNestedFieldsAreCorrectlyFlattened)253 TEST(FlatbuffersTest, PrimitiveAndNestedFieldsAreCorrectlyFlattened) {
254 std::string metadata_buffer = LoadTestMetadata();
255 ReflectiveFlatbufferBuilder reflective_builder(
256 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data()));
257 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
258 buffer->Set("an_int_field", 42);
259 buffer->Set("a_long_field", 84ll);
260 ReflectiveFlatbuffer* flight_info = buffer->Mutable("flight_number");
261 flight_info->Set("carrier_code", "LX");
262 flight_info->Set("flight_code", 38);
263
264 std::map<std::string, Variant> entity_data_map = buffer->AsFlatMap();
265 EXPECT_EQ(4, entity_data_map.size());
266 EXPECT_EQ(42, entity_data_map["an_int_field"].IntValue());
267 EXPECT_EQ(84, entity_data_map["a_long_field"].Int64Value());
268 EXPECT_EQ("LX", entity_data_map["flight_number.carrier_code"].StringValue());
269 EXPECT_EQ(38, entity_data_map["flight_number.flight_code"].IntValue());
270 }
271
TEST(FlatbuffersTest,RepeatedFieldSetThroughReflectionCanBeRead)272 TEST(FlatbuffersTest, RepeatedFieldSetThroughReflectionCanBeRead) {
273 std::string metadata_buffer = LoadTestMetadata();
274 const reflection::Schema* schema =
275 flatbuffers::GetRoot<reflection::Schema>(metadata_buffer.data());
276 ReflectiveFlatbufferBuilder reflective_builder(schema);
277 std::unique_ptr<ReflectiveFlatbuffer> buffer = reflective_builder.NewRoot();
278
279 auto reminders = buffer->Repeated<ReflectiveFlatbuffer>("reminders");
280 {
281 auto reminder = reminders->Add();
282 reminder->Set("title", "test reminder");
283 auto notes = reminder->Repeated<std::string>("notes");
284 notes->Add("note A");
285 notes->Add("note B");
286 }
287 {
288 auto reminder = reminders->Add();
289 reminder->Set("title", "test reminder 2");
290 auto notes = reminder->Repeated<std::string>("notes");
291 notes->Add("note i");
292 notes->Add("note ii");
293 notes->Add("note iii");
294 }
295 const std::string serialized_entity_data = buffer->Serialize();
296
297 std::unique_ptr<test::EntityDataT> entity_data =
298 LoadAndVerifyMutableFlatbuffer<test::EntityData>(
299 serialized_entity_data.data(), serialized_entity_data.size());
300 EXPECT_TRUE(entity_data != nullptr);
301 EXPECT_EQ(2, entity_data->reminders.size());
302 EXPECT_EQ("test reminder", entity_data->reminders[0]->title);
303 EXPECT_THAT(entity_data->reminders[0]->notes,
304 testing::ElementsAreArray({"note A", "note B"}));
305 EXPECT_EQ("test reminder 2", entity_data->reminders[1]->title);
306 EXPECT_THAT(entity_data->reminders[1]->notes,
307 testing::ElementsAreArray({"note i", "note ii", "note iii"}));
308 }
309
310 } // namespace
311 } // namespace libtextclassifier3
312