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
17namespace {
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).
22static const int kRepeatTestCount = 100;
23
24static 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            })
31                .base(),
32            s.end());
33}
34
35bool checkJSONGenerator(std::string raw_source_code, std::string expected_json) {
36    TestLibrary library("json.fidl", raw_source_code);
37    EXPECT_TRUE(library.Compile());
38
39    // actual
40    auto actual = library.GenerateJSON();
41    trim(actual);
42
43    // expected
44    trim(expected_json);
45
46    if (actual.compare(expected_json) == 0) {
47        return true;
48    }
49
50    // On error, we output both the actual and expected to allow simple
51    // diffing to debug the test.
52
53    std::ofstream output_actual("json_generator_tests_actual.txt");
54    output_actual << actual;
55    output_actual.close();
56
57    std::ofstream output_expected("json_generator_tests_expected.txt");
58    output_expected << expected_json;
59    output_expected.close();
60
61    return false;
62}
63
64bool json_generator_test_struct() {
65    BEGIN_TEST;
66
67    for (int i = 0; i < kRepeatTestCount; i++) {
68        EXPECT_TRUE(checkJSONGenerator(R"FIDL(
69library fidl.test.json;
70
71struct Simple {
72    uint8 f1;
73    bool f2;
74};
75
76)FIDL",
77                                       R"JSON(
78{
79  "version": "0.0.1",
80  "name": "fidl.test.json",
81  "library_dependencies": [],
82  "const_declarations": [],
83  "enum_declarations": [],
84  "interface_declarations": [],
85  "struct_declarations": [
86    {
87      "name": "fidl.test.json/Simple",
88      "members": [
89        {
90          "type": {
91            "kind": "primitive",
92            "subtype": "uint8"
93          },
94          "name": "f1",
95          "size": 1,
96          "alignment": 1,
97          "offset": 0,
98          "max_handles": 0
99        },
100        {
101          "type": {
102            "kind": "primitive",
103            "subtype": "bool"
104          },
105          "name": "f2",
106          "size": 1,
107          "alignment": 1,
108          "offset": 1,
109          "max_handles": 0
110        }
111      ],
112      "size": 2,
113      "alignment": 1,
114      "max_handles": 0
115    }
116  ],
117  "table_declarations": [],
118  "union_declarations": [],
119  "declaration_order": [
120    "fidl.test.json/Simple"
121  ],
122  "declarations": {
123    "fidl.test.json/Simple": "struct"
124  }
125}
126)JSON"));
127    }
128
129    END_TEST;
130}
131
132bool json_generator_test_table() {
133    BEGIN_TEST;
134
135    for (int i = 0; i < kRepeatTestCount; i++) {
136        EXPECT_TRUE(checkJSONGenerator(R"FIDL(
137library fidl.test.json;
138
139table Simple {
140    1: uint8 f1;
141    2: bool f2;
142    3: reserved;
143};
144
145)FIDL",
146                                       R"JSON(
147{
148  "version": "0.0.1",
149  "name": "fidl.test.json",
150  "library_dependencies": [],
151  "const_declarations": [],
152  "enum_declarations": [],
153  "interface_declarations": [],
154  "struct_declarations": [],
155  "table_declarations": [
156    {
157      "name": "fidl.test.json/Simple",
158      "members": [
159        {
160          "ordinal": 1,
161          "reserved": false,
162          "type": {
163            "kind": "primitive",
164            "subtype": "uint8"
165          },
166          "name": "f1",
167          "size": 1,
168          "alignment": 1,
169          "max_handles": 0
170        },
171        {
172          "ordinal": 2,
173          "reserved": false,
174          "type": {
175            "kind": "primitive",
176            "subtype": "bool"
177          },
178          "name": "f2",
179          "size": 1,
180          "alignment": 1,
181          "max_handles": 0
182        },
183        {
184          "ordinal": 3,
185          "reserved": true
186        }
187      ],
188      "size": 16,
189      "alignment": 8,
190      "max_handles": 0
191    }
192  ],
193  "union_declarations": [],
194  "declaration_order": [
195    "fidl.test.json/Simple"
196  ],
197  "declarations": {
198    "fidl.test.json/Simple": "table"
199  }
200}
201)JSON"));
202    }
203
204    END_TEST;
205}
206
207bool json_generator_test_union() {
208    BEGIN_TEST;
209
210    for (int i = 0; i < kRepeatTestCount; i++) {
211        EXPECT_TRUE(checkJSONGenerator(R"FIDL(
212library fidl.test.json;
213
214struct Pizza {
215    vector<string:16> toppings;
216};
217
218struct Pasta {
219    string:16 sauce;
220};
221
222union PizzaOrPasta {
223    Pizza pizza;
224    Pasta pasta;
225};
226
227)FIDL",
228                                       R"JSON(
229{
230  "version": "0.0.1",
231  "name": "fidl.test.json",
232  "library_dependencies": [],
233  "const_declarations": [],
234  "enum_declarations": [],
235  "interface_declarations": [],
236  "struct_declarations": [
237    {
238      "name": "fidl.test.json/Pizza",
239      "members": [
240        {
241          "type": {
242            "kind": "vector",
243            "element_type": {
244              "kind": "string",
245              "maybe_element_count": 16,
246              "nullable": false
247            },
248            "nullable": false
249          },
250          "name": "toppings",
251          "size": 16,
252          "alignment": 8,
253          "offset": 0,
254          "max_handles": 0
255        }
256      ],
257      "size": 16,
258      "alignment": 8,
259      "max_handles": 0
260    },
261    {
262      "name": "fidl.test.json/Pasta",
263      "members": [
264        {
265          "type": {
266            "kind": "string",
267            "maybe_element_count": 16,
268            "nullable": false
269          },
270          "name": "sauce",
271          "size": 16,
272          "alignment": 8,
273          "offset": 0,
274          "max_handles": 0
275        }
276      ],
277      "size": 16,
278      "alignment": 8,
279      "max_handles": 0
280    }
281  ],
282  "table_declarations": [],
283  "union_declarations": [
284    {
285      "name": "fidl.test.json/PizzaOrPasta",
286      "members": [
287        {
288          "type": {
289            "kind": "identifier",
290            "identifier": "fidl.test.json/Pizza",
291            "nullable": false
292          },
293          "name": "pizza",
294          "size": 16,
295          "alignment": 8,
296          "offset": 8
297        },
298        {
299          "type": {
300            "kind": "identifier",
301            "identifier": "fidl.test.json/Pasta",
302            "nullable": false
303          },
304          "name": "pasta",
305          "size": 16,
306          "alignment": 8,
307          "offset": 8
308        }
309      ],
310      "size": 24,
311      "alignment": 8,
312      "max_handles": 0
313    }
314  ],
315  "declaration_order": [
316    "fidl.test.json/Pizza",
317    "fidl.test.json/Pasta",
318    "fidl.test.json/PizzaOrPasta"
319  ],
320  "declarations": {
321    "fidl.test.json/Pizza": "struct",
322    "fidl.test.json/Pasta": "struct",
323    "fidl.test.json/PizzaOrPasta": "union"
324  }
325}
326)JSON"));
327    }
328
329    END_TEST;
330}
331
332} // namespace
333
334BEGIN_TEST_CASE(json_generator_tests);
335RUN_TEST(json_generator_test_struct);
336RUN_TEST(json_generator_test_table);
337RUN_TEST(json_generator_test_union);
338END_TEST_CASE(json_generator_tests);
339