1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <unittest/unittest.h>
6
7 #include <fidl/flat_ast.h>
8 #include <fidl/lexer.h>
9 #include <fidl/parser.h>
10 #include <fidl/source_file.h>
11
12 #include <fstream>
13
14 #include "examples.h"
15 #include "test_library.h"
16
17 namespace {
18
19 // We repeat each test in a loop in order to catch situations where memory layout
20 // determines what JSON is produced (this is often manifested due to using a std::map<Foo*,...>
21 // in compiler source code).
22 static const int kRepeatTestCount = 100;
23
trim(std::string & s)24 static inline void trim(std::string& s) {
25 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
26 return !std::isspace(ch) && ch != '\n';
27 }));
28 s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
29 return !std::isspace(ch) && ch != '\n';
30 }).base(),
31 s.end());
32 }
33
checkJSONGenerator(std::string raw_source_code,std::string expected_json)34 bool checkJSONGenerator(std::string raw_source_code, std::string expected_json) {
35 TestLibrary library("json.fidl", raw_source_code);
36 EXPECT_TRUE(library.Compile());
37
38 // actual
39 auto actual = library.GenerateJSON();
40 trim(actual);
41
42 // expected
43 trim(expected_json);
44
45 if (actual.compare(expected_json) == 0) {
46 return true;
47 }
48
49 // On error, we output both the actual and expected to allow simple
50 // diffing to debug the test.
51
52 std::ofstream output_actual("json_generator_tests_actual.txt");
53 output_actual << actual;
54 output_actual.close();
55
56 std::ofstream output_expected("json_generator_tests_expected.txt");
57 output_expected << expected_json;
58 output_expected.close();
59
60 return false;
61 }
62
json_generator_test_struct()63 bool json_generator_test_struct() {
64 BEGIN_TEST;
65
66 for (int i = 0; i < kRepeatTestCount; i++) {
67 EXPECT_TRUE(checkJSONGenerator(R"FIDL(
68 library fidl.test.json;
69
70 struct Simple {
71 uint8 f1;
72 bool f2;
73 };
74
75 )FIDL",
76 R"JSON(
77 {
78 "version": "0.0.1",
79 "name": "fidl.test.json",
80 "library_dependencies": [],
81 "const_declarations": [],
82 "enum_declarations": [],
83 "interface_declarations": [],
84 "struct_declarations": [
85 {
86 "name": "fidl.test.json/Simple",
87 "anonymous": false,
88 "members": [
89 {
90 "type": {
91 "kind": "primitive",
92 "subtype": "uint8"
93 },
94 "name": "f1",
95 "size": 1,
96 "max_out_of_line": 0,
97 "alignment": 1,
98 "offset": 0,
99 "max_handles": 0
100 },
101 {
102 "type": {
103 "kind": "primitive",
104 "subtype": "bool"
105 },
106 "name": "f2",
107 "size": 1,
108 "max_out_of_line": 0,
109 "alignment": 1,
110 "offset": 1,
111 "max_handles": 0
112 }
113 ],
114 "size": 2,
115 "max_out_of_line": 0,
116 "alignment": 1,
117 "max_handles": 0
118 }
119 ],
120 "table_declarations": [],
121 "union_declarations": [],
122 "declaration_order": [
123 "fidl.test.json/Simple"
124 ],
125 "declarations": {
126 "fidl.test.json/Simple": "struct"
127 }
128 }
129 )JSON"));
130 }
131
132 END_TEST;
133 }
134
json_generator_test_empty_struct()135 bool json_generator_test_empty_struct() {
136 BEGIN_TEST;
137
138 for (int i = 0; i < kRepeatTestCount; i++) {
139 EXPECT_TRUE(checkJSONGenerator(R"FIDL(
140 library fidl.test.json;
141
142 struct Empty {
143 };
144
145 interface EmptyInterface {
146 Send(Empty e);
147 -> Receive (Empty e);
148 SendAndReceive(Empty e) -> (Empty e);
149 };
150 )FIDL",
151 R"JSON(
152 {
153 "version": "0.0.1",
154 "name": "fidl.test.json",
155 "library_dependencies": [],
156 "const_declarations": [],
157 "enum_declarations": [],
158 "interface_declarations": [
159 {
160 "name": "fidl.test.json/EmptyInterface",
161 "methods": [
162 {
163 "ordinal": 296942602,
164 "name": "Send",
165 "has_request": true,
166 "maybe_request": [
167 {
168 "type": {
169 "kind": "identifier",
170 "identifier": "fidl.test.json/Empty",
171 "nullable": false
172 },
173 "name": "e",
174 "size": 1,
175 "max_out_of_line": 0,
176 "alignment": 1,
177 "offset": 16,
178 "max_handles": 0
179 }
180 ],
181 "maybe_request_size": 24,
182 "maybe_request_alignment": 8,
183 "has_response": false
184 },
185 {
186 "ordinal": 939543845,
187 "name": "Receive",
188 "has_request": false,
189 "has_response": true,
190 "maybe_response": [
191 {
192 "type": {
193 "kind": "identifier",
194 "identifier": "fidl.test.json/Empty",
195 "nullable": false
196 },
197 "name": "e",
198 "size": 1,
199 "max_out_of_line": 0,
200 "alignment": 1,
201 "offset": 16,
202 "max_handles": 0
203 }
204 ],
205 "maybe_response_size": 24,
206 "maybe_response_alignment": 8
207 },
208 {
209 "ordinal": 556045674,
210 "name": "SendAndReceive",
211 "has_request": true,
212 "maybe_request": [
213 {
214 "type": {
215 "kind": "identifier",
216 "identifier": "fidl.test.json/Empty",
217 "nullable": false
218 },
219 "name": "e",
220 "size": 1,
221 "max_out_of_line": 0,
222 "alignment": 1,
223 "offset": 16,
224 "max_handles": 0
225 }
226 ],
227 "maybe_request_size": 24,
228 "maybe_request_alignment": 8,
229 "has_response": true,
230 "maybe_response": [
231 {
232 "type": {
233 "kind": "identifier",
234 "identifier": "fidl.test.json/Empty",
235 "nullable": false
236 },
237 "name": "e",
238 "size": 1,
239 "max_out_of_line": 0,
240 "alignment": 1,
241 "offset": 16,
242 "max_handles": 0
243 }
244 ],
245 "maybe_response_size": 24,
246 "maybe_response_alignment": 8
247 }
248 ]
249 }
250 ],
251 "struct_declarations": [
252 {
253 "name": "fidl.test.json/Empty",
254 "anonymous": false,
255 "members": [],
256 "size": 1,
257 "max_out_of_line": 0,
258 "alignment": 1,
259 "max_handles": 0
260 }
261 ],
262 "table_declarations": [],
263 "union_declarations": [],
264 "declaration_order": [
265 "fidl.test.json/Empty",
266 "fidl.test.json/EmptyInterface"
267 ],
268 "declarations": {
269 "fidl.test.json/EmptyInterface": "interface",
270 "fidl.test.json/Empty": "struct"
271 }
272 }
273 )JSON"));
274 }
275
276 END_TEST;
277 }
278
json_generator_test_table()279 bool json_generator_test_table() {
280 BEGIN_TEST;
281
282 for (int i = 0; i < kRepeatTestCount; i++) {
283 EXPECT_TRUE(checkJSONGenerator(R"FIDL(
284 library fidl.test.json;
285
286 table Simple {
287 1: uint8 f1;
288 2: bool f2;
289 3: reserved;
290 };
291
292 )FIDL",
293 R"JSON(
294 {
295 "version": "0.0.1",
296 "name": "fidl.test.json",
297 "library_dependencies": [],
298 "const_declarations": [],
299 "enum_declarations": [],
300 "interface_declarations": [],
301 "struct_declarations": [],
302 "table_declarations": [
303 {
304 "name": "fidl.test.json/Simple",
305 "members": [
306 {
307 "ordinal": 1,
308 "reserved": false,
309 "type": {
310 "kind": "primitive",
311 "subtype": "uint8"
312 },
313 "name": "f1",
314 "size": 1,
315 "max_out_of_line": 0,
316 "alignment": 1,
317 "max_handles": 0
318 },
319 {
320 "ordinal": 2,
321 "reserved": false,
322 "type": {
323 "kind": "primitive",
324 "subtype": "bool"
325 },
326 "name": "f2",
327 "size": 1,
328 "max_out_of_line": 0,
329 "alignment": 1,
330 "max_handles": 0
331 },
332 {
333 "ordinal": 3,
334 "reserved": true
335 }
336 ],
337 "size": 16,
338 "max_out_of_line": 48,
339 "alignment": 8,
340 "max_handles": 0
341 }
342 ],
343 "union_declarations": [],
344 "declaration_order": [
345 "fidl.test.json/Simple"
346 ],
347 "declarations": {
348 "fidl.test.json/Simple": "table"
349 }
350 }
351 )JSON"));
352 }
353
354 END_TEST;
355 }
356
json_generator_test_union()357 bool json_generator_test_union() {
358 BEGIN_TEST;
359
360 for (int i = 0; i < kRepeatTestCount; i++) {
361 EXPECT_TRUE(checkJSONGenerator(R"FIDL(
362 library fidl.test.json;
363
364 struct Pizza {
365 vector<string:16> toppings;
366 };
367
368 struct Pasta {
369 string:16 sauce;
370 };
371
372 union PizzaOrPasta {
373 Pizza pizza;
374 Pasta pasta;
375 };
376
377 )FIDL",
378 R"JSON(
379 {
380 "version": "0.0.1",
381 "name": "fidl.test.json",
382 "library_dependencies": [],
383 "const_declarations": [],
384 "enum_declarations": [],
385 "interface_declarations": [],
386 "struct_declarations": [
387 {
388 "name": "fidl.test.json/Pizza",
389 "anonymous": false,
390 "members": [
391 {
392 "type": {
393 "kind": "vector",
394 "element_type": {
395 "kind": "string",
396 "maybe_element_count": 16,
397 "nullable": false
398 },
399 "nullable": false
400 },
401 "name": "toppings",
402 "size": 16,
403 "max_out_of_line": 4294967295,
404 "alignment": 8,
405 "offset": 0,
406 "max_handles": 0
407 }
408 ],
409 "size": 16,
410 "max_out_of_line": 4294967295,
411 "alignment": 8,
412 "max_handles": 0
413 },
414 {
415 "name": "fidl.test.json/Pasta",
416 "anonymous": false,
417 "members": [
418 {
419 "type": {
420 "kind": "string",
421 "maybe_element_count": 16,
422 "nullable": false
423 },
424 "name": "sauce",
425 "size": 16,
426 "max_out_of_line": 16,
427 "alignment": 8,
428 "offset": 0,
429 "max_handles": 0
430 }
431 ],
432 "size": 16,
433 "max_out_of_line": 16,
434 "alignment": 8,
435 "max_handles": 0
436 }
437 ],
438 "table_declarations": [],
439 "union_declarations": [
440 {
441 "name": "fidl.test.json/PizzaOrPasta",
442 "members": [
443 {
444 "type": {
445 "kind": "identifier",
446 "identifier": "fidl.test.json/Pizza",
447 "nullable": false
448 },
449 "name": "pizza",
450 "size": 16,
451 "max_out_of_line": 4294967295,
452 "alignment": 8,
453 "offset": 8
454 },
455 {
456 "type": {
457 "kind": "identifier",
458 "identifier": "fidl.test.json/Pasta",
459 "nullable": false
460 },
461 "name": "pasta",
462 "size": 16,
463 "max_out_of_line": 16,
464 "alignment": 8,
465 "offset": 8
466 }
467 ],
468 "size": 24,
469 "max_out_of_line": 4294967295,
470 "alignment": 8,
471 "max_handles": 0
472 }
473 ],
474 "declaration_order": [
475 "fidl.test.json/Pizza",
476 "fidl.test.json/Pasta",
477 "fidl.test.json/PizzaOrPasta"
478 ],
479 "declarations": {
480 "fidl.test.json/Pizza": "struct",
481 "fidl.test.json/Pasta": "struct",
482 "fidl.test.json/PizzaOrPasta": "union"
483 }
484 }
485 )JSON"));
486 }
487
488 END_TEST;
489 }
490
491 // This test ensures that inherited methods have the same ordinal / signature /
492 // etc as the method from which they are inheriting.
json_generator_test_inheritance()493 bool json_generator_test_inheritance() {
494 BEGIN_TEST;
495
496 for (int i = 0; i < kRepeatTestCount; i++) {
497 EXPECT_TRUE(checkJSONGenerator(R"FIDL(
498 library fidl.test.json;
499
500 [FragileBase]
501 interface super {
502 foo(string s) -> (int64 y);
503 };
504
505 interface sub : super {
506 };
507
508 )FIDL",
509 R"JSON({
510 "version": "0.0.1",
511 "name": "fidl.test.json",
512 "library_dependencies": [],
513 "const_declarations": [],
514 "enum_declarations": [],
515 "interface_declarations": [
516 {
517 "name": "fidl.test.json/super",
518 "maybe_attributes": [
519 {
520 "name": "FragileBase",
521 "value": ""
522 }
523 ],
524 "methods": [
525 {
526 "ordinal": 790020540,
527 "name": "foo",
528 "has_request": true,
529 "maybe_request": [
530 {
531 "type": {
532 "kind": "string",
533 "nullable": false
534 },
535 "name": "s",
536 "size": 16,
537 "max_out_of_line": 4294967295,
538 "alignment": 8,
539 "offset": 16,
540 "max_handles": 0
541 }
542 ],
543 "maybe_request_size": 32,
544 "maybe_request_alignment": 8,
545 "has_response": true,
546 "maybe_response": [
547 {
548 "type": {
549 "kind": "primitive",
550 "subtype": "int64"
551 },
552 "name": "y",
553 "size": 8,
554 "max_out_of_line": 0,
555 "alignment": 8,
556 "offset": 16,
557 "max_handles": 0
558 }
559 ],
560 "maybe_response_size": 24,
561 "maybe_response_alignment": 8
562 }
563 ]
564 },
565 {
566 "name": "fidl.test.json/sub",
567 "methods": [
568 {
569 "ordinal": 790020540,
570 "name": "foo",
571 "has_request": true,
572 "maybe_request": [
573 {
574 "type": {
575 "kind": "string",
576 "nullable": false
577 },
578 "name": "s",
579 "size": 16,
580 "max_out_of_line": 4294967295,
581 "alignment": 8,
582 "offset": 16,
583 "max_handles": 0
584 }
585 ],
586 "maybe_request_size": 32,
587 "maybe_request_alignment": 8,
588 "has_response": true,
589 "maybe_response": [
590 {
591 "type": {
592 "kind": "primitive",
593 "subtype": "int64"
594 },
595 "name": "y",
596 "size": 8,
597 "max_out_of_line": 0,
598 "alignment": 8,
599 "offset": 16,
600 "max_handles": 0
601 }
602 ],
603 "maybe_response_size": 24,
604 "maybe_response_alignment": 8
605 }
606 ]
607 }
608 ],
609 "struct_declarations": [],
610 "table_declarations": [],
611 "union_declarations": [],
612 "declaration_order": [
613 "fidl.test.json/super",
614 "fidl.test.json/sub"
615 ],
616 "declarations": {
617 "fidl.test.json/super": "interface",
618 "fidl.test.json/sub": "interface"
619 }
620 })JSON"));
621 }
622
623 END_TEST;
624 }
625 } // namespace
626
627 BEGIN_TEST_CASE(json_generator_tests);
628 RUN_TEST(json_generator_test_empty_struct);
629 RUN_TEST(json_generator_test_struct);
630 RUN_TEST(json_generator_test_table);
631 RUN_TEST(json_generator_test_union);
632 RUN_TEST(json_generator_test_inheritance);
633 END_TEST_CASE(json_generator_tests);
634