• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "proto_test.h"
2 
3 #include "flatbuffers/code_generator.h"
4 #include "idl_gen_fbs.h"
5 #include "test_assert.h"
6 
7 namespace flatbuffers {
8 namespace tests {
9 
RunTest(const flatbuffers::IDLOptions & opts,const std::string & proto_path,const std::string & proto_file,const std::string & golden_file,const std::string import_proto_file)10 void RunTest(const flatbuffers::IDLOptions &opts, const std::string &proto_path,
11              const std::string &proto_file, const std::string &golden_file,
12              const std::string import_proto_file) {
13   const char *include_directories[] = { proto_path.c_str(), nullptr };
14 
15   // Parse proto.
16   flatbuffers::Parser parser(opts);
17   TEST_EQ(parser.Parse(proto_file.c_str(), include_directories), true);
18 
19   // Generate fbs.
20   std::unique_ptr<CodeGenerator> fbs_generator = NewFBSCodeGenerator(true);
21   std::string fbs;
22   TEST_EQ(fbs_generator->GenerateCodeString(parser, "test", fbs),
23           CodeGenerator::Status::OK);
24 
25   // Ensure generated file is parsable.
26   flatbuffers::Parser parser2;
27 
28   if (!import_proto_file.empty()) {
29     // Generate fbs from import.proto
30     flatbuffers::Parser import_parser(opts);
31     TEST_EQ(import_parser.Parse(import_proto_file.c_str(), include_directories),
32             true);
33     std::string import_fbs;
34     TEST_EQ(
35         fbs_generator->GenerateCodeString(import_parser, "test", import_fbs),
36         CodeGenerator::Status::OK);
37     // auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test", true);
38     // Since `imported.fbs` isn't in the filesystem AbsolutePath can't figure it
39     // out by itself. We manually construct it so Parser works.
40     std::string imported_fbs = flatbuffers::PosixPath(
41         flatbuffers::AbsolutePath(proto_path) + "/imported.fbs");
42     TEST_EQ(parser2.Parse(import_fbs.c_str(), include_directories,
43                           imported_fbs.c_str()),
44             true);
45   }
46 
47   TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
48   TEST_EQ_STR(fbs.c_str(), golden_file.c_str());
49 }
50 
proto_test(const std::string & proto_path,const std::string & proto_file)51 void proto_test(const std::string &proto_path, const std::string &proto_file) {
52   flatbuffers::IDLOptions opts;
53   opts.include_dependence_headers = false;
54   opts.proto_mode = true;
55   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
56 
57   // load the .proto and the golden file from disk
58   std::string golden_file;
59   TEST_EQ(flatbuffers::LoadFile((proto_path + "test.golden.fbs").c_str(), false,
60                                 &golden_file),
61           true);
62 
63   RunTest(opts, proto_path, proto_file, golden_file);
64 }
65 
proto_test_id(const std::string & proto_path,const std::string & proto_file)66 void proto_test_id(const std::string &proto_path,
67                    const std::string &proto_file) {
68   flatbuffers::IDLOptions opts;
69   opts.include_dependence_headers = false;
70   opts.proto_mode = true;
71   opts.keep_proto_id = true;
72   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
73 
74   // load the .proto and the golden file from disk
75   std::string golden_file;
76   TEST_EQ(flatbuffers::LoadFile((proto_path + "test_id.golden.fbs").c_str(),
77                                 false, &golden_file),
78           true);
79 
80   RunTest(opts, proto_path, proto_file, golden_file);
81 }
82 
proto_test_union(const std::string & proto_path,const std::string & proto_file)83 void proto_test_union(const std::string &proto_path,
84                       const std::string &proto_file) {
85   // Parse proto with --oneof-union option.
86   flatbuffers::IDLOptions opts;
87   opts.include_dependence_headers = false;
88   opts.proto_mode = true;
89   opts.proto_oneof_union = true;
90   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
91 
92   std::string golden_file;
93   TEST_EQ(flatbuffers::LoadFile((proto_path + "test_union.golden.fbs").c_str(),
94                                 false, &golden_file),
95           true);
96   RunTest(opts, proto_path, proto_file, golden_file);
97 }
98 
proto_test_union_id(const std::string & proto_path,const std::string & proto_file)99 void proto_test_union_id(const std::string &proto_path,
100                          const std::string &proto_file) {
101   // Parse proto with --oneof-union option.
102   flatbuffers::IDLOptions opts;
103   opts.include_dependence_headers = false;
104   opts.proto_mode = true;
105   opts.proto_oneof_union = true;
106   opts.keep_proto_id = true;
107   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
108 
109   std::string golden_file;
110   TEST_EQ(
111       flatbuffers::LoadFile((proto_path + "test_union_id.golden.fbs").c_str(),
112                             false, &golden_file),
113       true);
114   RunTest(opts, proto_path, proto_file, golden_file);
115 }
116 
proto_test_union_suffix(const std::string & proto_path,const std::string & proto_file)117 void proto_test_union_suffix(const std::string &proto_path,
118                              const std::string &proto_file) {
119   flatbuffers::IDLOptions opts;
120   opts.include_dependence_headers = false;
121   opts.proto_mode = true;
122   opts.proto_namespace_suffix = "test_namespace_suffix";
123   opts.proto_oneof_union = true;
124   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
125 
126   std::string golden_file;
127   TEST_EQ(flatbuffers::LoadFile(
128               (proto_path + "test_union_suffix.golden.fbs").c_str(), false,
129               &golden_file),
130           true);
131   RunTest(opts, proto_path, proto_file, golden_file);
132 }
133 
proto_test_union_suffix_id(const std::string & proto_path,const std::string & proto_file)134 void proto_test_union_suffix_id(const std::string &proto_path,
135                                 const std::string &proto_file) {
136   flatbuffers::IDLOptions opts;
137   opts.include_dependence_headers = false;
138   opts.proto_mode = true;
139   opts.proto_namespace_suffix = "test_namespace_suffix";
140   opts.proto_oneof_union = true;
141   opts.keep_proto_id = true;
142   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
143 
144   std::string golden_file;
145   TEST_EQ(flatbuffers::LoadFile(
146               (proto_path + "test_union_suffix_id.golden.fbs").c_str(), false,
147               &golden_file),
148           true);
149   RunTest(opts, proto_path, proto_file, golden_file);
150 }
151 
proto_test_include(const std::string & proto_path,const std::string & proto_file,const std::string & import_proto_file)152 void proto_test_include(const std::string &proto_path,
153                         const std::string &proto_file,
154                         const std::string &import_proto_file) {
155   flatbuffers::IDLOptions opts;
156   opts.include_dependence_headers = true;
157   opts.proto_mode = true;
158   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
159 
160   std::string golden_file;
161   TEST_EQ(
162       flatbuffers::LoadFile((proto_path + "test_include.golden.fbs").c_str(),
163                             false, &golden_file),
164       true);
165 
166   RunTest(opts, proto_path, proto_file, golden_file, import_proto_file);
167 }
168 
proto_test_include_id(const std::string & proto_path,const std::string & proto_file,const std::string & import_proto_file)169 void proto_test_include_id(const std::string &proto_path,
170                            const std::string &proto_file,
171                            const std::string &import_proto_file) {
172   flatbuffers::IDLOptions opts;
173   opts.include_dependence_headers = true;
174   opts.proto_mode = true;
175   opts.keep_proto_id = true;
176   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
177 
178   std::string golden_file;
179   TEST_EQ(
180       flatbuffers::LoadFile((proto_path + "test_include_id.golden.fbs").c_str(),
181                             false, &golden_file),
182       true);
183 
184   RunTest(opts, proto_path, proto_file, golden_file, import_proto_file);
185 }
186 
proto_test_include_union(const std::string & proto_path,const std::string & proto_file,const std::string & import_proto_file)187 void proto_test_include_union(const std::string &proto_path,
188                               const std::string &proto_file,
189                               const std::string &import_proto_file) {
190   flatbuffers::IDLOptions opts;
191   opts.include_dependence_headers = true;
192   opts.proto_mode = true;
193   opts.proto_oneof_union = true;
194   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
195 
196   std::string golden_file;
197   TEST_EQ(flatbuffers::LoadFile(
198               (proto_path + "test_union_include.golden.fbs").c_str(), false,
199               &golden_file),
200           true);
201 
202   RunTest(opts, proto_path, proto_file, golden_file, import_proto_file);
203 }
204 
proto_test_include_union_id(const std::string & proto_path,const std::string & proto_file,const std::string & import_proto_file)205 void proto_test_include_union_id(const std::string &proto_path,
206                                  const std::string &proto_file,
207                                  const std::string &import_proto_file) {
208   flatbuffers::IDLOptions opts;
209   opts.include_dependence_headers = true;
210   opts.proto_mode = true;
211   opts.proto_oneof_union = true;
212   opts.keep_proto_id = true;
213   opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::NO_OP;
214 
215   std::string golden_file;
216   TEST_EQ(flatbuffers::LoadFile(
217               (proto_path + "test_union_include_id.golden.fbs").c_str(), false,
218               &golden_file),
219           true);
220 
221   RunTest(opts, proto_path, proto_file, golden_file, import_proto_file);
222 }
223 
ParseCorruptedProto(const std::string & proto_path)224 void ParseCorruptedProto(const std::string &proto_path) {
225   const char *include_directories[] = { proto_path.c_str(), nullptr };
226 
227   flatbuffers::IDLOptions opts;
228   opts.include_dependence_headers = true;
229   opts.proto_mode = true;
230   opts.proto_oneof_union = true;
231 
232   std::string proto_file;
233 
234   std::unique_ptr<CodeGenerator> fbs_generator = NewFBSCodeGenerator(true);
235 
236   // Parse proto with non positive id.
237   {
238     flatbuffers::Parser parser(opts);
239     TEST_EQ(
240         flatbuffers::LoadFile((proto_path + "non-positive-id.proto").c_str(),
241                               false, &proto_file),
242         true);
243     TEST_EQ(parser.Parse(proto_file.c_str(), include_directories), true);
244     TEST_NE(fbs_generator->GenerateCode(parser, "temp.fbs", "test"),
245             CodeGenerator::Status::OK);
246   }
247 
248   // Parse proto with twice id.
249   {
250     flatbuffers::Parser parser(opts);
251     TEST_EQ(flatbuffers::LoadFile((proto_path + "twice-id.proto").c_str(),
252                                   false, &proto_file),
253             true);
254     TEST_EQ(parser.Parse(proto_file.c_str(), include_directories), true);
255     TEST_NE(fbs_generator->GenerateCode(parser, "temp.fbs", "test"),
256             CodeGenerator::Status::OK);
257   }
258 
259   // Parse proto with using reserved id.
260   {
261     flatbuffers::Parser parser(opts);
262     TEST_EQ(flatbuffers::LoadFile((proto_path + "twice-id.proto").c_str(),
263                                   false, &proto_file),
264             true);
265     TEST_EQ(parser.Parse(proto_file.c_str(), include_directories), true);
266     TEST_NE(fbs_generator->GenerateCode(parser, "temp.fbs", "test"),
267             CodeGenerator::Status::OK);
268   }
269 
270   // Parse proto with error on gap.
271   {
272     opts.proto_id_gap_action = IDLOptions::ProtoIdGapAction::ERROR;
273     flatbuffers::Parser parser(opts);
274     TEST_EQ(flatbuffers::LoadFile((proto_path + "test.proto").c_str(), false,
275                                   &proto_file),
276             true);
277     TEST_EQ(parser.Parse(proto_file.c_str(), include_directories), true);
278 
279     TEST_NE(fbs_generator->GenerateCode(parser, "temp.fbs", "test"),
280             CodeGenerator::Status::OK);
281   }
282 }
283 
284 // Parse a .proto schema, output as .fbs
ParseProtoTest(const std::string & tests_data_path)285 void ParseProtoTest(const std::string &tests_data_path) {
286   auto proto_path = tests_data_path + "prototest/";
287   std::string proto_file;
288   TEST_EQ(
289       flatbuffers::LoadFile((tests_data_path + "prototest/test.proto").c_str(),
290                             false, &proto_file),
291       true);
292 
293   std::string import_proto_file;
294   TEST_EQ(flatbuffers::LoadFile(
295               (tests_data_path + "prototest/imported.proto").c_str(), false,
296               &import_proto_file),
297           true);
298 
299   proto_test(proto_path, proto_file);
300   proto_test_union(proto_path, proto_file);
301   proto_test_union_suffix(proto_path, proto_file);
302   proto_test_include(proto_path, proto_file, import_proto_file);
303   proto_test_include_union(proto_path, proto_file, import_proto_file);
304 
305   proto_test_id(proto_path, proto_file);
306   proto_test_union_id(proto_path, proto_file);
307   proto_test_union_suffix_id(proto_path, proto_file);
308   proto_test_include_id(proto_path, proto_file, import_proto_file);
309   proto_test_include_union_id(proto_path, proto_file, import_proto_file);
310 
311   ParseCorruptedProto(proto_path);
312 }
313 
ParseProtoBufAsciiTest()314 void ParseProtoBufAsciiTest() {
315   // We can put the parser in a mode where it will accept JSON that looks more
316   // like Protobuf ASCII, for users that have data in that format.
317   // This uses no "" for field names (which we already support by default,
318   // omits `,`, `:` before `{` and a couple of other features.
319   flatbuffers::Parser parser;
320   parser.opts.protobuf_ascii_alike = true;
321   TEST_EQ(
322       parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
323       true);
324   TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
325   // Similarly, in text output, it should omit these.
326   std::string text;
327   auto err =
328       flatbuffers::GenText(
329       parser, parser.builder_.GetBufferPointer(), &text);
330   TEST_NULL(err);
331   TEST_EQ_STR(text.c_str(),
332               "{\n  A [\n    1\n    2\n  ]\n  C {\n    B: 2\n  }\n}\n");
333 }
334 
335 }  // namespace tests
336 }  // namespace flatbuffers
337