xref: /aosp_15_r20/external/flatbuffers/tests/cpp17/test_cpp17.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker  *
4*890232f2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker  *
8*890232f2SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker  *
10*890232f2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker  * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker  */
16*890232f2SAndroid Build Coastguard Worker 
17*890232f2SAndroid Build Coastguard Worker // This is a sandbox for modeling C++17 code generator.
18*890232f2SAndroid Build Coastguard Worker // C++17 code generator: "flatc --cpp-std c++17".
19*890232f2SAndroid Build Coastguard Worker // Warning:
20*890232f2SAndroid Build Coastguard Worker // This is an experimental feature and could change at any time.
21*890232f2SAndroid Build Coastguard Worker 
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
23*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flex_flat_util.h"
24*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flexbuffers.h"
25*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
26*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/minireflect.h"
27*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/registry.h"
28*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
29*890232f2SAndroid Build Coastguard Worker #include "stringify_util.h"
30*890232f2SAndroid Build Coastguard Worker #include "test_assert.h"
31*890232f2SAndroid Build Coastguard Worker 
32*890232f2SAndroid Build Coastguard Worker // Embed generated code into an isolated namespace.
33*890232f2SAndroid Build Coastguard Worker namespace cpp17 {
34*890232f2SAndroid Build Coastguard Worker #include "generated_cpp17/monster_test_generated.h"
35*890232f2SAndroid Build Coastguard Worker #include "generated_cpp17/optional_scalars_generated.h"
36*890232f2SAndroid Build Coastguard Worker #include "generated_cpp17/union_vector_generated.h"
37*890232f2SAndroid Build Coastguard Worker }  // namespace cpp17
38*890232f2SAndroid Build Coastguard Worker 
39*890232f2SAndroid Build Coastguard Worker namespace cpp11 {
40*890232f2SAndroid Build Coastguard Worker #include "../monster_test_generated.h"
41*890232f2SAndroid Build Coastguard Worker #include "../optional_scalars_generated.h"
42*890232f2SAndroid Build Coastguard Worker }  // namespace cpp11
43*890232f2SAndroid Build Coastguard Worker 
44*890232f2SAndroid Build Coastguard Worker using ::cpp17::MyGame::Example::Monster;
45*890232f2SAndroid Build Coastguard Worker using ::cpp17::MyGame::Example::Vec3;
46*890232f2SAndroid Build Coastguard Worker 
47*890232f2SAndroid Build Coastguard Worker /*******************************************************************************
48*890232f2SAndroid Build Coastguard Worker ** Build some FB objects.
49*890232f2SAndroid Build Coastguard Worker *******************************************************************************/
50*890232f2SAndroid Build Coastguard Worker namespace {
BuildMonster(flatbuffers::FlatBufferBuilder & fbb)51*890232f2SAndroid Build Coastguard Worker const Monster *BuildMonster(flatbuffers::FlatBufferBuilder &fbb) {
52*890232f2SAndroid Build Coastguard Worker   using ::cpp17::MyGame::Example::Color;
53*890232f2SAndroid Build Coastguard Worker   using ::cpp17::MyGame::Example::MonsterBuilder;
54*890232f2SAndroid Build Coastguard Worker   using ::cpp17::MyGame::Example::Test;
55*890232f2SAndroid Build Coastguard Worker   auto name = fbb.CreateString("my_monster");
56*890232f2SAndroid Build Coastguard Worker   auto inventory = fbb.CreateVector(std::vector<uint8_t>{ 4, 5, 6, 7 });
57*890232f2SAndroid Build Coastguard Worker   MonsterBuilder builder(fbb);
58*890232f2SAndroid Build Coastguard Worker   auto vec3 = Vec3{ /*x=*/1.1f,
59*890232f2SAndroid Build Coastguard Worker                     /*y=*/2.2f,
60*890232f2SAndroid Build Coastguard Worker                     /*z=*/3.3f,
61*890232f2SAndroid Build Coastguard Worker                     /*test1=*/6.6,
62*890232f2SAndroid Build Coastguard Worker                     /*test2=*/Color::Green,
63*890232f2SAndroid Build Coastguard Worker                     /*test3=*/
64*890232f2SAndroid Build Coastguard Worker                     Test(
65*890232f2SAndroid Build Coastguard Worker                         /*a=*/11,
66*890232f2SAndroid Build Coastguard Worker                         /*b=*/90) };
67*890232f2SAndroid Build Coastguard Worker   builder.add_pos(&vec3);
68*890232f2SAndroid Build Coastguard Worker   builder.add_name(name);
69*890232f2SAndroid Build Coastguard Worker   builder.add_mana(1);
70*890232f2SAndroid Build Coastguard Worker   builder.add_hp(2);
71*890232f2SAndroid Build Coastguard Worker   builder.add_testbool(true);
72*890232f2SAndroid Build Coastguard Worker   builder.add_testhashs32_fnv1(4);
73*890232f2SAndroid Build Coastguard Worker   builder.add_testhashu32_fnv1(5);
74*890232f2SAndroid Build Coastguard Worker   builder.add_testhashs64_fnv1(6);
75*890232f2SAndroid Build Coastguard Worker   builder.add_testhashu64_fnv1(7);
76*890232f2SAndroid Build Coastguard Worker   builder.add_testhashs32_fnv1a(8);
77*890232f2SAndroid Build Coastguard Worker   builder.add_testhashu32_fnv1a(9);
78*890232f2SAndroid Build Coastguard Worker   builder.add_testhashs64_fnv1a(10);
79*890232f2SAndroid Build Coastguard Worker   builder.add_testhashu64_fnv1a(11);
80*890232f2SAndroid Build Coastguard Worker   builder.add_testf(12.1f);
81*890232f2SAndroid Build Coastguard Worker   builder.add_testf2(13.1f);
82*890232f2SAndroid Build Coastguard Worker   builder.add_testf3(14.1f);
83*890232f2SAndroid Build Coastguard Worker   builder.add_single_weak_reference(15);
84*890232f2SAndroid Build Coastguard Worker   builder.add_co_owning_reference(16);
85*890232f2SAndroid Build Coastguard Worker   builder.add_non_owning_reference(17);
86*890232f2SAndroid Build Coastguard Worker   builder.add_inventory(inventory);
87*890232f2SAndroid Build Coastguard Worker   fbb.Finish(builder.Finish());
88*890232f2SAndroid Build Coastguard Worker   const Monster *monster =
89*890232f2SAndroid Build Coastguard Worker       flatbuffers::GetRoot<Monster>(fbb.GetBufferPointer());
90*890232f2SAndroid Build Coastguard Worker   return monster;
91*890232f2SAndroid Build Coastguard Worker }
92*890232f2SAndroid Build Coastguard Worker 
93*890232f2SAndroid Build Coastguard Worker /*******************************************************************************
94*890232f2SAndroid Build Coastguard Worker ** Test Case: Static Field Reflection Traits for Table & Structs.
95*890232f2SAndroid Build Coastguard Worker *******************************************************************************/
96*890232f2SAndroid Build Coastguard Worker // This test tests & demonstrates the power of the static reflection. Using it,
97*890232f2SAndroid Build Coastguard Worker // we can given any Flatbuffer type to a generic function and it will be able to
98*890232f2SAndroid Build Coastguard Worker // produce is full recursive string representation of it.
99*890232f2SAndroid Build Coastguard Worker //
100*890232f2SAndroid Build Coastguard Worker // This test covers all types: primitive types, structs, tables, Vectors, etc.
101*890232f2SAndroid Build Coastguard Worker //
StringifyAnyFlatbuffersTypeTest()102*890232f2SAndroid Build Coastguard Worker void StringifyAnyFlatbuffersTypeTest() {
103*890232f2SAndroid Build Coastguard Worker   flatbuffers::FlatBufferBuilder fbb;
104*890232f2SAndroid Build Coastguard Worker   // We are using a Monster here, but we could have used any type, because the
105*890232f2SAndroid Build Coastguard Worker   // code that follows is totally generic!
106*890232f2SAndroid Build Coastguard Worker   const auto *monster = BuildMonster(fbb);
107*890232f2SAndroid Build Coastguard Worker 
108*890232f2SAndroid Build Coastguard Worker   std::string expected = R"(MyGame.Example.Monster{
109*890232f2SAndroid Build Coastguard Worker         pos = MyGame.Example.Vec3{
110*890232f2SAndroid Build Coastguard Worker           x = 1.1
111*890232f2SAndroid Build Coastguard Worker           y = 2.2
112*890232f2SAndroid Build Coastguard Worker           z = 3.3
113*890232f2SAndroid Build Coastguard Worker           test1 = 6.6
114*890232f2SAndroid Build Coastguard Worker           test2 = 2
115*890232f2SAndroid Build Coastguard Worker           test3 = MyGame.Example.Test{
116*890232f2SAndroid Build Coastguard Worker             a = 11
117*890232f2SAndroid Build Coastguard Worker             b = 90
118*890232f2SAndroid Build Coastguard Worker           }
119*890232f2SAndroid Build Coastguard Worker         }
120*890232f2SAndroid Build Coastguard Worker         mana = 1
121*890232f2SAndroid Build Coastguard Worker         hp = 2
122*890232f2SAndroid Build Coastguard Worker         name = "my_monster"
123*890232f2SAndroid Build Coastguard Worker         inventory = [
124*890232f2SAndroid Build Coastguard Worker           4,
125*890232f2SAndroid Build Coastguard Worker           5,
126*890232f2SAndroid Build Coastguard Worker           6,
127*890232f2SAndroid Build Coastguard Worker           7
128*890232f2SAndroid Build Coastguard Worker         ]
129*890232f2SAndroid Build Coastguard Worker         color = 8
130*890232f2SAndroid Build Coastguard Worker         test_type = 0
131*890232f2SAndroid Build Coastguard Worker         testbool = 1
132*890232f2SAndroid Build Coastguard Worker         testhashs32_fnv1 = 4
133*890232f2SAndroid Build Coastguard Worker         testhashu32_fnv1 = 5
134*890232f2SAndroid Build Coastguard Worker         testhashs64_fnv1 = 6
135*890232f2SAndroid Build Coastguard Worker         testhashu64_fnv1 = 7
136*890232f2SAndroid Build Coastguard Worker         testhashs32_fnv1a = 8
137*890232f2SAndroid Build Coastguard Worker         testhashu32_fnv1a = 9
138*890232f2SAndroid Build Coastguard Worker         testhashs64_fnv1a = 10
139*890232f2SAndroid Build Coastguard Worker         testhashu64_fnv1a = 11
140*890232f2SAndroid Build Coastguard Worker         testf = 12.1
141*890232f2SAndroid Build Coastguard Worker         testf2 = 13.1
142*890232f2SAndroid Build Coastguard Worker         testf3 = 14.1
143*890232f2SAndroid Build Coastguard Worker         single_weak_reference = 15
144*890232f2SAndroid Build Coastguard Worker         co_owning_reference = 16
145*890232f2SAndroid Build Coastguard Worker         non_owning_reference = 17
146*890232f2SAndroid Build Coastguard Worker         any_unique_type = 0
147*890232f2SAndroid Build Coastguard Worker         any_ambiguous_type = 0
148*890232f2SAndroid Build Coastguard Worker         signed_enum = -1
149*890232f2SAndroid Build Coastguard Worker       })";
150*890232f2SAndroid Build Coastguard Worker 
151*890232f2SAndroid Build Coastguard Worker   // Call a generic function that has no specific knowledge of the flatbuffer we
152*890232f2SAndroid Build Coastguard Worker   // are passing in; it should use only static reflection to produce a string
153*890232f2SAndroid Build Coastguard Worker   // representations of the field names and values recursively. We give it an
154*890232f2SAndroid Build Coastguard Worker   // initial indentation so that the result can be compared with our raw string
155*890232f2SAndroid Build Coastguard Worker   // above, which we wanted to indent so that it will look nicer in this code.
156*890232f2SAndroid Build Coastguard Worker   //
157*890232f2SAndroid Build Coastguard Worker   // A note about JSON: as can be seen from the string above, this produces a
158*890232f2SAndroid Build Coastguard Worker   // JSON-like notation, but we are not using any of Flatbuffers' JSON infra to
159*890232f2SAndroid Build Coastguard Worker   // produce this! It is produced entirely using compile-time reflection, and
160*890232f2SAndroid Build Coastguard Worker   // thus does not require any runtime access to the *.fbs definition files!
161*890232f2SAndroid Build Coastguard Worker   std::optional<std::string> result =
162*890232f2SAndroid Build Coastguard Worker       cpp17::StringifyFlatbufferValue(*monster, /*indent=*/"      ");
163*890232f2SAndroid Build Coastguard Worker 
164*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(result.has_value());
165*890232f2SAndroid Build Coastguard Worker   TEST_EQ_STR(expected.c_str(), result->c_str());
166*890232f2SAndroid Build Coastguard Worker }
167*890232f2SAndroid Build Coastguard Worker 
168*890232f2SAndroid Build Coastguard Worker /*******************************************************************************
169*890232f2SAndroid Build Coastguard Worker ** Test Traits::FieldType
170*890232f2SAndroid Build Coastguard Worker *******************************************************************************/
171*890232f2SAndroid Build Coastguard Worker using pos_type = Monster::Traits::FieldType<0>;
172*890232f2SAndroid Build Coastguard Worker static_assert(std::is_same_v<pos_type, const Vec3 *>);
173*890232f2SAndroid Build Coastguard Worker 
174*890232f2SAndroid Build Coastguard Worker using mana_type = Monster::Traits::FieldType<1>;
175*890232f2SAndroid Build Coastguard Worker static_assert(std::is_same_v<mana_type, int16_t>);
176*890232f2SAndroid Build Coastguard Worker 
177*890232f2SAndroid Build Coastguard Worker using name_type = Monster::Traits::FieldType<3>;
178*890232f2SAndroid Build Coastguard Worker static_assert(std::is_same_v<name_type, const flatbuffers::String *>);
179*890232f2SAndroid Build Coastguard Worker 
180*890232f2SAndroid Build Coastguard Worker /*******************************************************************************
181*890232f2SAndroid Build Coastguard Worker ** Generic Create Function Test.
182*890232f2SAndroid Build Coastguard Worker *******************************************************************************/
CreateTableByTypeTest()183*890232f2SAndroid Build Coastguard Worker void CreateTableByTypeTest() {
184*890232f2SAndroid Build Coastguard Worker   flatbuffers::FlatBufferBuilder builder;
185*890232f2SAndroid Build Coastguard Worker 
186*890232f2SAndroid Build Coastguard Worker   // We will create an object of this type using only the type.
187*890232f2SAndroid Build Coastguard Worker   using type_to_create_t = cpp17::MyGame::Example::Stat;
188*890232f2SAndroid Build Coastguard Worker 
189*890232f2SAndroid Build Coastguard Worker   [&builder] {
190*890232f2SAndroid Build Coastguard Worker     auto id_str = builder.CreateString("my_id");
191*890232f2SAndroid Build Coastguard Worker     auto table = type_to_create_t::Traits::Create(builder, id_str, 42, 7);
192*890232f2SAndroid Build Coastguard Worker     // Be sure that the correct return type was inferred.
193*890232f2SAndroid Build Coastguard Worker     static_assert(
194*890232f2SAndroid Build Coastguard Worker         std::is_same_v<decltype(table), flatbuffers::Offset<type_to_create_t>>);
195*890232f2SAndroid Build Coastguard Worker     builder.Finish(table);
196*890232f2SAndroid Build Coastguard Worker   }();
197*890232f2SAndroid Build Coastguard Worker 
198*890232f2SAndroid Build Coastguard Worker   // Access it.
199*890232f2SAndroid Build Coastguard Worker   auto stat =
200*890232f2SAndroid Build Coastguard Worker       flatbuffers::GetRoot<type_to_create_t>(builder.GetBufferPointer());
201*890232f2SAndroid Build Coastguard Worker   TEST_EQ_STR(stat->id()->c_str(), "my_id");
202*890232f2SAndroid Build Coastguard Worker   TEST_EQ(stat->val(), 42);
203*890232f2SAndroid Build Coastguard Worker   TEST_EQ(stat->count(), 7);
204*890232f2SAndroid Build Coastguard Worker }
205*890232f2SAndroid Build Coastguard Worker 
OptionalScalarsTest()206*890232f2SAndroid Build Coastguard Worker void OptionalScalarsTest() {
207*890232f2SAndroid Build Coastguard Worker   static_assert(
208*890232f2SAndroid Build Coastguard Worker       std::is_same<flatbuffers::Optional<float>, std::optional<float>>::value);
209*890232f2SAndroid Build Coastguard Worker   static_assert(std::is_same<flatbuffers::nullopt_t, std::nullopt_t>::value);
210*890232f2SAndroid Build Coastguard Worker 
211*890232f2SAndroid Build Coastguard Worker   // test C++ nullable
212*890232f2SAndroid Build Coastguard Worker   flatbuffers::FlatBufferBuilder fbb;
213*890232f2SAndroid Build Coastguard Worker   FinishScalarStuffBuffer(fbb, cpp17::optional_scalars::CreateScalarStuff(
214*890232f2SAndroid Build Coastguard Worker                                    fbb, 1, static_cast<int8_t>(2)));
215*890232f2SAndroid Build Coastguard Worker   auto opts =
216*890232f2SAndroid Build Coastguard Worker       cpp17::optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
217*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(!opts->maybe_bool());
218*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(!opts->maybe_f32().has_value());
219*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(opts->maybe_i8().has_value());
220*890232f2SAndroid Build Coastguard Worker   TEST_EQ(opts->maybe_i8().value(), 2);
221*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(opts->mutate_maybe_i8(3));
222*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(opts->maybe_i8().has_value());
223*890232f2SAndroid Build Coastguard Worker   TEST_EQ(opts->maybe_i8().value(), 3);
224*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(!opts->mutate_maybe_i16(-10));
225*890232f2SAndroid Build Coastguard Worker 
226*890232f2SAndroid Build Coastguard Worker   cpp17::optional_scalars::ScalarStuffT obj;
227*890232f2SAndroid Build Coastguard Worker   opts->UnPackTo(&obj);
228*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(!obj.maybe_bool);
229*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(!obj.maybe_f32.has_value());
230*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(obj.maybe_i8.has_value() && obj.maybe_i8.value() == 3);
231*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(obj.maybe_i8 && *obj.maybe_i8 == 3);
232*890232f2SAndroid Build Coastguard Worker   obj.maybe_i32 = -1;
233*890232f2SAndroid Build Coastguard Worker 
234*890232f2SAndroid Build Coastguard Worker   fbb.Clear();
235*890232f2SAndroid Build Coastguard Worker   FinishScalarStuffBuffer(
236*890232f2SAndroid Build Coastguard Worker       fbb, cpp17::optional_scalars::ScalarStuff::Pack(fbb, &obj));
237*890232f2SAndroid Build Coastguard Worker   opts = cpp17::optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
238*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(opts->maybe_i8().has_value());
239*890232f2SAndroid Build Coastguard Worker   TEST_EQ(opts->maybe_i8().value(), 3);
240*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(opts->maybe_i32().has_value());
241*890232f2SAndroid Build Coastguard Worker   TEST_EQ(opts->maybe_i32().value(), -1);
242*890232f2SAndroid Build Coastguard Worker 
243*890232f2SAndroid Build Coastguard Worker   TEST_EQ(std::optional<int32_t>(opts->maybe_i32()).value(), -1);
244*890232f2SAndroid Build Coastguard Worker   TEST_EQ(std::optional<int64_t>(opts->maybe_i32()).value(), -1);
245*890232f2SAndroid Build Coastguard Worker   TEST_ASSERT(opts->maybe_i32() == std::optional<int64_t>(-1));
246*890232f2SAndroid Build Coastguard Worker }
247*890232f2SAndroid Build Coastguard Worker 
FlatBufferCpp17Tests()248*890232f2SAndroid Build Coastguard Worker int FlatBufferCpp17Tests() {
249*890232f2SAndroid Build Coastguard Worker   CreateTableByTypeTest();
250*890232f2SAndroid Build Coastguard Worker   OptionalScalarsTest();
251*890232f2SAndroid Build Coastguard Worker   StringifyAnyFlatbuffersTypeTest();
252*890232f2SAndroid Build Coastguard Worker   return 0;
253*890232f2SAndroid Build Coastguard Worker }
254*890232f2SAndroid Build Coastguard Worker } // namespace
255*890232f2SAndroid Build Coastguard Worker 
main(int,const char * [])256*890232f2SAndroid Build Coastguard Worker int main(int /*argc*/, const char * /*argv*/[]) {
257*890232f2SAndroid Build Coastguard Worker   InitTestEngine();
258*890232f2SAndroid Build Coastguard Worker 
259*890232f2SAndroid Build Coastguard Worker   FlatBufferCpp17Tests();
260*890232f2SAndroid Build Coastguard Worker 
261*890232f2SAndroid Build Coastguard Worker   if (!testing_fails) {
262*890232f2SAndroid Build Coastguard Worker     TEST_OUTPUT_LINE("C++17: ALL TESTS PASSED");
263*890232f2SAndroid Build Coastguard Worker   } else {
264*890232f2SAndroid Build Coastguard Worker     TEST_OUTPUT_LINE("C++17: %d FAILED TESTS", testing_fails);
265*890232f2SAndroid Build Coastguard Worker   }
266*890232f2SAndroid Build Coastguard Worker   return CloseTestEngine();
267*890232f2SAndroid Build Coastguard Worker }
268