• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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