xref: /aosp_15_r20/external/libtextclassifier/native/utils/flatbuffers/mutable_test.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
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