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 "utils/flatbuffers/mutable.h"
18
19 #include <map>
20 #include <memory>
21 #include <string>
22
23 #include "utils/flatbuffers/flatbuffers.h"
24 #include "utils/flatbuffers/flatbuffers_generated.h"
25 #include "utils/flatbuffers/flatbuffers_test_generated.h"
26 #include "utils/flatbuffers/test-utils.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "flatbuffers/flatbuffers.h"
30 #include "flatbuffers/reflection.h"
31 #include "flatbuffers/reflection_generated.h"
32
33 namespace libtextclassifier3 {
34 namespace {
35
36 using ::testing::ElementsAre;
37 using ::testing::SizeIs;
38
39 class MutableFlatbufferTest : public testing::Test {
40 public:
MutableFlatbufferTest()41 explicit MutableFlatbufferTest()
42 : schema_(LoadTestMetadata()), builder_(schema_.get()) {}
43
44 protected:
45 OwnedFlatbuffer<reflection::Schema, std::string> schema_;
46 MutableFlatbufferBuilder builder_;
47 };
48
TEST_F(MutableFlatbufferTest,PrimitiveFieldsAreCorrectlySet)49 TEST_F(MutableFlatbufferTest, PrimitiveFieldsAreCorrectlySet) {
50 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
51 EXPECT_TRUE(buffer != nullptr);
52 EXPECT_TRUE(buffer->Set("an_int_field", 42));
53 EXPECT_TRUE(buffer->Set("a_long_field", int64{84}));
54 EXPECT_TRUE(buffer->Set("a_bool_field", true));
55 EXPECT_TRUE(buffer->Set("a_float_field", 1.f));
56 EXPECT_TRUE(buffer->Set("a_double_field", 1.0));
57
58 // Try to parse with the generated code.
59 std::unique_ptr<test::EntityDataT> entity_data =
60 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
61 ASSERT_NE(entity_data, nullptr);
62 EXPECT_EQ(entity_data->an_int_field, 42);
63 EXPECT_EQ(entity_data->a_long_field, 84);
64 EXPECT_EQ(entity_data->a_bool_field, true);
65 EXPECT_NEAR(entity_data->a_float_field, 1.f, 1e-4);
66 EXPECT_NEAR(entity_data->a_double_field, 1.f, 1e-4);
67 }
68
TEST_F(MutableFlatbufferTest,EnumValuesCanBeSpecifiedByName)69 TEST_F(MutableFlatbufferTest, EnumValuesCanBeSpecifiedByName) {
70 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
71 EXPECT_TRUE(buffer != nullptr);
72
73 EXPECT_TRUE(IsEnum(buffer->GetFieldOrNull("enum_value")->type()));
74
75 EXPECT_TRUE(buffer->SetFromEnumValueName("enum_value", "VALUE_1"));
76
77 std::unique_ptr<test::EntityDataT> entity_data =
78 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
79 EXPECT_EQ(entity_data->enum_value,
80 libtextclassifier3::test::EnumValue_VALUE_1);
81 }
82
TEST_F(MutableFlatbufferTest,HandlesUnknownFields)83 TEST_F(MutableFlatbufferTest, HandlesUnknownFields) {
84 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
85 EXPECT_TRUE(buffer != nullptr);
86
87 // Add a field that is not known to the (statically generated) code.
88 EXPECT_TRUE(buffer->Set("mystic", "this is an unknown field."));
89
90 OwnedFlatbuffer<flatbuffers::Table, std::string> extra(buffer->Serialize());
91 EXPECT_EQ(extra
92 ->GetPointer<const flatbuffers::String*>(
93 buffer->GetFieldOrNull("mystic")->offset())
94 ->str(),
95 "this is an unknown field.");
96 }
97
TEST_F(MutableFlatbufferTest,HandlesNestedFields)98 TEST_F(MutableFlatbufferTest, HandlesNestedFields) {
99 OwnedFlatbuffer<FlatbufferFieldPath, std::string> path =
100 CreateFieldPath({"flight_number", "carrier_code"});
101 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
102
103 MutableFlatbuffer* parent = nullptr;
104 reflection::Field const* field = nullptr;
105 EXPECT_TRUE(buffer->GetFieldWithParent(path.get(), &parent, &field));
106 EXPECT_EQ(parent, buffer->Mutable("flight_number"));
107 EXPECT_EQ(field,
108 buffer->Mutable("flight_number")->GetFieldOrNull("carrier_code"));
109 }
110
TEST_F(MutableFlatbufferTest,HandlesMultipleNestedFields)111 TEST_F(MutableFlatbufferTest, HandlesMultipleNestedFields) {
112 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
113 MutableFlatbuffer* flight_info = buffer->Mutable("flight_number");
114 flight_info->Set("carrier_code", "LX");
115 flight_info->Set("flight_code", 38);
116
117 MutableFlatbuffer* contact_info = buffer->Mutable("contact_info");
118 EXPECT_TRUE(contact_info->Set("first_name", "Barack"));
119 EXPECT_TRUE(contact_info->Set("last_name", "Obama"));
120 EXPECT_TRUE(contact_info->Set("phone_number", "1-800-TEST"));
121 EXPECT_TRUE(contact_info->Set("score", 1.f));
122
123 // Try to parse with the generated code.
124 std::unique_ptr<test::EntityDataT> entity_data =
125 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
126 ASSERT_NE(entity_data, nullptr);
127 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
128 EXPECT_EQ(entity_data->flight_number->flight_code, 38);
129 EXPECT_EQ(entity_data->contact_info->first_name, "Barack");
130 EXPECT_EQ(entity_data->contact_info->last_name, "Obama");
131 EXPECT_EQ(entity_data->contact_info->phone_number, "1-800-TEST");
132 EXPECT_NEAR(entity_data->contact_info->score, 1.f, 1e-4);
133 }
134
TEST_F(MutableFlatbufferTest,HandlesFieldsSetWithNamePath)135 TEST_F(MutableFlatbufferTest, HandlesFieldsSetWithNamePath) {
136 FlatbufferFieldPathT path;
137 path.field.emplace_back(new FlatbufferFieldT);
138 path.field.back()->field_name = "flight_number";
139 path.field.emplace_back(new FlatbufferFieldT);
140 path.field.back()->field_name = "carrier_code";
141 flatbuffers::FlatBufferBuilder path_builder;
142 path_builder.Finish(FlatbufferFieldPath::Pack(path_builder, &path));
143
144 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
145 // Test setting value using Set function.
146 buffer->Mutable("flight_number")->Set("flight_code", 38);
147 // Test setting value using FlatbufferFieldPath.
148 buffer->Set(flatbuffers::GetRoot<FlatbufferFieldPath>(
149 path_builder.GetBufferPointer()),
150 "LX");
151
152 // Try to parse with the generated code.
153 std::unique_ptr<test::EntityDataT> entity_data =
154 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
155 ASSERT_NE(entity_data, nullptr);
156 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
157 EXPECT_EQ(entity_data->flight_number->flight_code, 38);
158 }
159
TEST_F(MutableFlatbufferTest,HandlesFieldsSetWithOffsetPath)160 TEST_F(MutableFlatbufferTest, HandlesFieldsSetWithOffsetPath) {
161 FlatbufferFieldPathT path;
162 path.field.emplace_back(new FlatbufferFieldT);
163 path.field.back()->field_offset = 14;
164 path.field.emplace_back(new FlatbufferFieldT);
165 path.field.back()->field_offset = 4;
166 flatbuffers::FlatBufferBuilder path_builder;
167 path_builder.Finish(FlatbufferFieldPath::Pack(path_builder, &path));
168
169 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
170 // Test setting value using Set function.
171 buffer->Mutable("flight_number")->Set("flight_code", 38);
172 // Test setting value using FlatbufferFieldPath.
173 buffer->Set(flatbuffers::GetRoot<FlatbufferFieldPath>(
174 path_builder.GetBufferPointer()),
175 "LX");
176
177 // Try to parse with the generated code.
178 std::unique_ptr<test::EntityDataT> entity_data =
179 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
180 ASSERT_NE(entity_data, nullptr);
181 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
182 EXPECT_EQ(entity_data->flight_number->flight_code, 38);
183 }
184
TEST_F(MutableFlatbufferTest,PartialBuffersAreCorrectlyMerged)185 TEST_F(MutableFlatbufferTest, PartialBuffersAreCorrectlyMerged) {
186 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
187 buffer->Set("an_int_field", 42);
188 buffer->Set("a_long_field", int64{84});
189 MutableFlatbuffer* flight_info = buffer->Mutable("flight_number");
190 flight_info->Set("carrier_code", "LX");
191 flight_info->Set("flight_code", 38);
192 auto* reminders = buffer->Repeated("reminders");
193 MutableFlatbuffer* reminder1 = reminders->Add();
194 reminder1->Set("title", "reminder1");
195 auto* reminder1_notes = reminder1->Repeated("notes");
196 reminder1_notes->Add("note1");
197 reminder1_notes->Add("note2");
198
199 // Create message to merge.
200 test::EntityDataT additional_entity_data;
201 additional_entity_data.an_int_field = 43;
202 additional_entity_data.flight_number.reset(new test::FlightNumberInfoT);
203 additional_entity_data.flight_number->flight_code = 39;
204 additional_entity_data.contact_info.reset(new test::ContactInfoT);
205 additional_entity_data.contact_info->first_name = "Barack";
206 additional_entity_data.reminders.push_back(
207 std::unique_ptr<test::ReminderT>(new test::ReminderT));
208 additional_entity_data.reminders[0]->notes.push_back("additional note1");
209 additional_entity_data.reminders[0]->notes.push_back("additional note2");
210 additional_entity_data.numbers.push_back(9);
211 additional_entity_data.numbers.push_back(10);
212 additional_entity_data.strings.push_back("str1");
213 additional_entity_data.strings.push_back("str2");
214
215 // Merge it.
216 EXPECT_TRUE(buffer->MergeFromSerializedFlatbuffer(
217 PackFlatbuffer<test::EntityData>(&additional_entity_data)));
218
219 // Try to parse it with the generated code.
220 std::unique_ptr<test::EntityDataT> entity_data =
221 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
222 ASSERT_NE(entity_data, nullptr);
223 EXPECT_EQ(entity_data->an_int_field, 43);
224 EXPECT_EQ(entity_data->a_long_field, 84);
225 EXPECT_EQ(entity_data->flight_number->carrier_code, "LX");
226 EXPECT_EQ(entity_data->flight_number->flight_code, 39);
227 EXPECT_EQ(entity_data->contact_info->first_name, "Barack");
228 ASSERT_THAT(entity_data->reminders, SizeIs(2));
229 EXPECT_THAT(entity_data->reminders[1]->notes,
230 ElementsAre("additional note1", "additional note2"));
231 EXPECT_THAT(entity_data->numbers, ElementsAre(9, 10));
232 EXPECT_THAT(entity_data->strings, ElementsAre("str1", "str2"));
233 }
234
TEST_F(MutableFlatbufferTest,MergesNestedFields)235 TEST_F(MutableFlatbufferTest, MergesNestedFields) {
236 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
237
238 // Set a multiply nested field.
239 OwnedFlatbuffer<FlatbufferFieldPath, std::string> field_path =
240 CreateFieldPath({"nested", "nestedb", "nesteda", "nestedb", "nesteda"});
241 buffer->Mutable(field_path.get())->Set("value", "le value");
242
243 std::unique_ptr<test::EntityDataT> entity_data =
244 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
245 ASSERT_NE(entity_data, nullptr);
246 EXPECT_EQ(entity_data->nested->nestedb->nesteda->nestedb->nesteda->value,
247 "le value");
248 }
249
TEST_F(MutableFlatbufferTest,PrimitiveAndNestedFieldsAreCorrectlyFlattened)250 TEST_F(MutableFlatbufferTest, PrimitiveAndNestedFieldsAreCorrectlyFlattened) {
251 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
252 buffer->Set("an_int_field", 42);
253 buffer->Set("a_long_field", int64{84});
254 MutableFlatbuffer* flight_info = buffer->Mutable("flight_number");
255 flight_info->Set("carrier_code", "LX");
256 flight_info->Set("flight_code", 38);
257
258 std::map<std::string, Variant> entity_data_map = buffer->AsFlatMap();
259 EXPECT_EQ(4, entity_data_map.size());
260 EXPECT_EQ(42, entity_data_map["an_int_field"].Value<int>());
261 EXPECT_EQ(84, entity_data_map["a_long_field"].Value<int64>());
262 EXPECT_EQ("LX", entity_data_map["flight_number.carrier_code"]
263 .ConstRefValue<std::string>());
264 EXPECT_EQ(38, entity_data_map["flight_number.flight_code"].Value<int>());
265 }
266
TEST_F(MutableFlatbufferTest,ToTextProtoWorks)267 TEST_F(MutableFlatbufferTest, ToTextProtoWorks) {
268 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
269 buffer->Set("an_int_field", 42);
270 buffer->Set("a_long_field", int64{84});
271 MutableFlatbuffer* flight_info = buffer->Mutable("flight_number");
272 flight_info->Set("carrier_code", "LX");
273 flight_info->Set("flight_code", 38);
274
275 // Add non primitive type.
276 auto reminders = buffer->Repeated("reminders");
277 auto foo_reminder = reminders->Add();
278 foo_reminder->Set("title", "foo reminder");
279 auto bar_reminder = reminders->Add();
280 bar_reminder->Set("title", "bar reminder");
281
282 // Add primitive type.
283 EXPECT_TRUE(buffer->Repeated("numbers")->Add(static_cast<int>(111)));
284 EXPECT_TRUE(buffer->Repeated("numbers")->Add(static_cast<int>(222)));
285 EXPECT_TRUE(buffer->Repeated("numbers")->Add(static_cast<int>(333)));
286
287 EXPECT_EQ(buffer->ToTextProto(),
288 "a_long_field: 84, an_int_field: 42, numbers: [111, 222, 333] , "
289 "reminders: [{title: 'foo reminder'}, {title: 'bar reminder'}] , "
290 "flight_number {flight_code: 38, carrier_code: 'LX'}");
291 }
292
TEST_F(MutableFlatbufferTest,RepeatedFieldSetThroughReflectionCanBeRead)293 TEST_F(MutableFlatbufferTest, RepeatedFieldSetThroughReflectionCanBeRead) {
294 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
295
296 auto reminders = buffer->Repeated("reminders");
297 {
298 auto reminder = reminders->Add();
299 reminder->Set("title", "test reminder");
300 auto notes = reminder->Repeated("notes");
301 notes->Add("note A");
302 notes->Add("note B");
303 }
304 {
305 auto reminder = reminders->Add();
306 reminder->Set("title", "test reminder 2");
307 reminder->Add("notes", "note i");
308 reminder->Add("notes", "note ii");
309 reminder->Add("notes", "note iii");
310 }
311
312 std::unique_ptr<test::EntityDataT> entity_data =
313 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
314 ASSERT_NE(entity_data, nullptr);
315 EXPECT_THAT(entity_data->reminders, SizeIs(2));
316 EXPECT_EQ(entity_data->reminders[0]->title, "test reminder");
317 EXPECT_THAT(entity_data->reminders[0]->notes,
318 ElementsAre("note A", "note B"));
319 EXPECT_EQ(entity_data->reminders[1]->title, "test reminder 2");
320 EXPECT_THAT(entity_data->reminders[1]->notes,
321 ElementsAre("note i", "note ii", "note iii"));
322 }
323
TEST_F(MutableFlatbufferTest,RepeatedFieldAddMethodWithIncompatibleValues)324 TEST_F(MutableFlatbufferTest, RepeatedFieldAddMethodWithIncompatibleValues) {
325 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
326 EXPECT_FALSE(buffer->Repeated("numbers")->Add(static_cast<int64>(123)));
327 EXPECT_FALSE(buffer->Repeated("numbers")->Add(static_cast<int8>(9)));
328 EXPECT_TRUE(buffer->Repeated("numbers")->Add(static_cast<int>(999)));
329
330 // Try to parse it with the generated code.
331 std::unique_ptr<test::EntityDataT> entity_data =
332 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
333 ASSERT_NE(entity_data, nullptr);
334 ASSERT_NE(entity_data, nullptr);
335 ASSERT_EQ(entity_data->numbers.size(), 1);
336 EXPECT_EQ(entity_data->numbers[0], 999);
337 }
338
TEST_F(MutableFlatbufferTest,RepeatedFieldGetAndSizeMethods)339 TEST_F(MutableFlatbufferTest, RepeatedFieldGetAndSizeMethods) {
340 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
341 EXPECT_TRUE(buffer->Repeated("numbers")->Add(1));
342 EXPECT_TRUE(buffer->Repeated("numbers")->Add(2));
343 EXPECT_TRUE(buffer->Repeated("numbers")->Add(3));
344
345 EXPECT_EQ(buffer->Repeated("numbers")->Size(), 3);
346 EXPECT_EQ(buffer->Repeated("numbers")->Get<int>(0), 1);
347 EXPECT_EQ(buffer->Repeated("numbers")->Get<int>(1), 2);
348 EXPECT_EQ(buffer->Repeated("numbers")->Get<int>(2), 3);
349 }
350
TEST_F(MutableFlatbufferTest,GetsRepeatedFieldFromPath)351 TEST_F(MutableFlatbufferTest, GetsRepeatedFieldFromPath) {
352 std::unique_ptr<MutableFlatbuffer> buffer = builder_.NewRoot();
353 OwnedFlatbuffer<FlatbufferFieldPath, std::string> notes =
354 CreateFieldPath({"nested", "repeated_str"});
355
356 EXPECT_TRUE(buffer->Repeated(notes.get())->Add("a"));
357 EXPECT_TRUE(buffer->Repeated(notes.get())->Add("test"));
358
359 std::unique_ptr<test::EntityDataT> entity_data =
360 LoadAndVerifyMutableFlatbuffer<test::EntityData>(buffer->Serialize());
361 ASSERT_NE(entity_data, nullptr);
362 EXPECT_THAT(entity_data->nested->repeated_str, SizeIs(2));
363 EXPECT_THAT(entity_data->nested->repeated_str, ElementsAre("a", "test"));
364 }
365
366 } // namespace
367 } // namespace libtextclassifier3
368