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 "test_library.h"
13
14 namespace {
15
16 // Test that a duplicate attribute is caught, and nicely reported.
no_two_same_attribute_test()17 bool no_two_same_attribute_test() {
18 BEGIN_TEST;
19
20 TestLibrary library("dup_attributes.fidl", R"FIDL(
21 library fidl.test.dupattributes;
22
23 [dup = "first", dup = "second"]
24 interface A {
25 1: MethodA();
26 };
27
28 )FIDL");
29 EXPECT_FALSE(library.Compile());
30 auto errors = library.errors();
31 ASSERT_EQ(errors.size(), 1);
32 ASSERT_STR_STR(errors[0].c_str(), "duplicate attribute with name 'dup'");
33
34 END_TEST;
35 }
36
37 // Test that doc comments and doc attributes clash are properly checked.
no_two_same_doc_attribute_test()38 bool no_two_same_doc_attribute_test() {
39 BEGIN_TEST;
40
41 TestLibrary library("dup_attributes.fidl", R"FIDL(
42 library fidl.test.dupattributes;
43
44 /// first
45 [Doc = "second"]
46 interface A {
47 1: MethodA();
48 };
49
50 )FIDL");
51 EXPECT_FALSE(library.Compile());
52 auto errors = library.errors();
53 ASSERT_EQ(errors.size(), 1);
54 ASSERT_STR_STR(errors[0].c_str(), "duplicate attribute with name 'Doc'");
55
56 END_TEST;
57 }
58
59 // Test that TODO
no_two_same_attribute_on_library_test()60 bool no_two_same_attribute_on_library_test() {
61 BEGIN_TEST;
62
63 TestLibrary library("dup_attributes.fidl", R"FIDL(
64 [dup = "first"]
65 library fidl.test.dupattributes;
66
67 )FIDL");
68 EXPECT_TRUE(library.Compile());
69
70 EXPECT_FALSE(library.AddSourceFile("dup_attributes_second.fidl", R"FIDL(
71 [dup = "second"]
72 library fidl.test.dupattributes;
73
74 )FIDL"));
75 auto errors = library.errors();
76 ASSERT_EQ(errors.size(), 1);
77 ASSERT_STR_STR(errors[0].c_str(), "duplicate attribute with name 'dup'");
78
79 END_TEST;
80 }
81
82 // Test that a close attribute is caught.
warn_on_close_attribute_test()83 bool warn_on_close_attribute_test() {
84 BEGIN_TEST;
85
86 TestLibrary library("dup_attributes.fidl", R"FIDL(
87 library fidl.test.dupattributes;
88
89 [Duc = "should be Doc"]
90 interface A {
91 1: MethodA();
92 };
93
94 )FIDL");
95 EXPECT_TRUE(library.Compile());
96 auto warnings = library.warnings();
97 ASSERT_EQ(warnings.size(), 1);
98 ASSERT_STR_STR(warnings[0].c_str(), "suspect attribute with name 'Duc'; did you mean 'Doc'?");
99
100 END_TEST;
101 }
102
empty_transport()103 bool empty_transport() {
104 BEGIN_TEST;
105
106 TestLibrary library("transport_attribuets.fidl", R"FIDL(
107 library fidl.test.transportattributes;
108
109 [Transport]
110 interface A {
111 1: MethodA();
112 };
113
114 )FIDL");
115 EXPECT_FALSE(library.Compile());
116 auto errors = library.errors();
117 ASSERT_EQ(errors.size(), 1);
118 ASSERT_STR_STR(errors[0].c_str(), "invalid value");
119
120 END_TEST;
121 }
122
bogus_transport()123 bool bogus_transport() {
124 BEGIN_TEST;
125
126 TestLibrary library("transport_attribuets.fidl", R"FIDL(
127 library fidl.test.transportattributes;
128
129 [Transport = "Bogus"]
130 interface A {
131 1: MethodA();
132 };
133
134 )FIDL");
135 EXPECT_FALSE(library.Compile());
136 auto errors = library.errors();
137 ASSERT_EQ(errors.size(), 1);
138 ASSERT_STR_STR(errors[0].c_str(), "invalid value");
139
140 END_TEST;
141 }
142
channel_transport()143 bool channel_transport() {
144 BEGIN_TEST;
145
146 TestLibrary library("transport_attribuets.fidl", R"FIDL(
147 library fidl.test.transportattributes;
148
149 [Transport = "Channel"]
150 interface A {
151 1: MethodA();
152 };
153
154 )FIDL");
155 EXPECT_TRUE(library.Compile());
156 ASSERT_EQ(library.errors().size(), 0);
157 ASSERT_EQ(library.warnings().size(), 0);
158
159 END_TEST;
160 }
161
socket_control_transport()162 bool socket_control_transport() {
163 BEGIN_TEST;
164
165 TestLibrary library("transport_attribuets.fidl", R"FIDL(
166 library fidl.test.transportattributes;
167
168 [Transport = "SocketControl"]
169 interface A {
170 1: MethodA();
171 };
172
173 )FIDL");
174 EXPECT_TRUE(library.Compile());
175 ASSERT_EQ(library.errors().size(), 0);
176 ASSERT_EQ(library.warnings().size(), 0);
177
178 END_TEST;
179 }
180
incorrect_placement_layout()181 bool incorrect_placement_layout() {
182 BEGIN_TEST;
183
184 TestLibrary library(R"FIDL(
185 [Layout = "Simple"]
186 library fidl.test;
187
188 [Layout = "Simple"]
189 const int32 MyConst = 0;
190
191 [Layout = "Simple"]
192 enum MyEnum {
193 [Layout = "Simple"]
194 MyMember = 5;
195 };
196
197 [Layout = "Simple"]
198 struct MyStruct {
199 [Layout = "Simple"]
200 int32 MyMember;
201 };
202
203 [Layout = "Simple"]
204 union MyUnion {
205 [Layout = "Simple"]
206 int32 MyMember;
207 };
208
209 [Layout = "Simple"]
210 table MyTable {
211 [Layout = "Simple"]
212 1: int32 MyMember;
213 };
214
215 [Layout = "Simple"]
216 interface MyInterface {
217 [Layout = "Simple"]
218 1: MyMethod();
219 };
220
221 )FIDL");
222 EXPECT_FALSE(library.Compile());
223 auto errors = library.errors();
224 ASSERT_EQ(errors.size(), 11);
225 ASSERT_STR_STR(errors[0].c_str(), "placement of attribute 'Layout' disallowed here");
226
227 END_TEST;
228 }
229
MustHaveThreeMembers(fidl::ErrorReporter * error_reporter,const fidl::raw::Attribute * attribute,const fidl::flat::Decl * decl)230 bool MustHaveThreeMembers(fidl::ErrorReporter* error_reporter,
231 const fidl::raw::Attribute* attribute,
232 const fidl::flat::Decl* decl) {
233 switch (decl->kind) {
234 case fidl::flat::Decl::Kind::kStruct: {
235 auto struct_decl = static_cast<const fidl::flat::Struct*>(decl);
236 return struct_decl->members.size() == 3;
237 }
238 default:
239 return false;
240 }
241 }
242
constraint_only_three_members_on_struct()243 bool constraint_only_three_members_on_struct() {
244 BEGIN_TEST;
245
246 TestLibrary library(R"FIDL(
247 library fidl.test;
248
249 [MustHaveThreeMembers]
250 struct MyStruct {
251 int64 one;
252 int64 two;
253 int64 three;
254 int64 oh_no_four;
255 };
256
257 )FIDL");
258 library.AddAttributeSchema("MustHaveThreeMembers", fidl::flat::AttributeSchema({
259 fidl::flat::AttributeSchema::Placement::kStructDecl,
260 }, {
261 "",
262 },
263 MustHaveThreeMembers));
264 EXPECT_FALSE(library.Compile());
265 auto errors = library.errors();
266 ASSERT_EQ(errors.size(), 1);
267 ASSERT_STR_STR(errors[0].c_str(),
268 "declaration did not satisfy constraint of attribute 'MustHaveThreeMembers' with value ''");
269
270 END_TEST;
271 }
272
constraint_only_three_members_on_method()273 bool constraint_only_three_members_on_method() {
274 BEGIN_TEST;
275
276 TestLibrary library(R"FIDL(
277 library fidl.test;
278
279 interface MyInterface {
280 [MustHaveThreeMembers] MyMethod();
281 };
282
283 )FIDL");
284 library.AddAttributeSchema("MustHaveThreeMembers", fidl::flat::AttributeSchema({
285 fidl::flat::AttributeSchema::Placement::kMethod,
286 }, {
287 "",
288 },
289 MustHaveThreeMembers));
290 EXPECT_FALSE(library.Compile());
291 auto errors = library.errors();
292 ASSERT_EQ(errors.size(), 1);
293 ASSERT_STR_STR(errors[0].c_str(),
294 "declaration did not satisfy constraint of attribute 'MustHaveThreeMembers' with value ''");
295
296 END_TEST;
297 }
298
constraint_only_three_members_on_interface()299 bool constraint_only_three_members_on_interface() {
300 BEGIN_TEST;
301
302 TestLibrary library(R"FIDL(
303 library fidl.test;
304
305 [MustHaveThreeMembers]
306 interface MyInterface {
307 MyMethod();
308 MySecondMethod();
309 };
310
311 )FIDL");
312 library.AddAttributeSchema("MustHaveThreeMembers", fidl::flat::AttributeSchema({
313 fidl::flat::AttributeSchema::Placement::kInterfaceDecl,
314 }, {
315 "",
316 },
317 MustHaveThreeMembers));
318 EXPECT_FALSE(library.Compile());
319 auto errors = library.errors();
320 ASSERT_EQ(errors.size(), 2); // 2 because there are two methods
321 ASSERT_STR_STR(errors[0].c_str(),
322 "declaration did not satisfy constraint of attribute 'MustHaveThreeMembers' with value ''");
323
324 END_TEST;
325 }
326
max_bytes()327 bool max_bytes() {
328 BEGIN_TEST;
329
330 TestLibrary library(R"FIDL(
331 library fidl.test;
332
333 [MaxBytes = "27"]
334 table MyTable {
335 1: bool here;
336 };
337
338 )FIDL");
339 EXPECT_FALSE(library.Compile());
340 auto errors = library.errors();
341 ASSERT_EQ(errors.size(), 1);
342 ASSERT_STR_STR(errors[0].c_str(),
343 "too large: only 27 bytes allowed, but 40 bytes found");
344
345 END_TEST;
346 }
347
max_handles()348 bool max_handles() {
349 BEGIN_TEST;
350
351 TestLibrary library(R"FIDL(
352 library fidl.test;
353
354 [MaxHandles = "2"]
355 union MyUnion {
356 uint8 hello;
357 array<uint8>:8 world;
358 vector<handle>:6 foo;
359 };
360
361 )FIDL");
362 EXPECT_FALSE(library.Compile());
363 auto errors = library.errors();
364 ASSERT_EQ(errors.size(), 1);
365 ASSERT_STR_STR(errors[0].c_str(),
366 "too many handles: only 2 allowed, but 6 found");
367
368 END_TEST;
369 }
370
371 } // namespace
372
373 BEGIN_TEST_CASE(attributes_tests);
374 RUN_TEST(no_two_same_attribute_test);
375 RUN_TEST(no_two_same_doc_attribute_test);
376 RUN_TEST(no_two_same_attribute_on_library_test);
377 RUN_TEST(warn_on_close_attribute_test);
378 RUN_TEST(empty_transport);
379 RUN_TEST(bogus_transport);
380 RUN_TEST(channel_transport);
381 RUN_TEST(socket_control_transport);
382 RUN_TEST(incorrect_placement_layout);
383 RUN_TEST(constraint_only_three_members_on_struct);
384 RUN_TEST(constraint_only_three_members_on_method);
385 RUN_TEST(constraint_only_three_members_on_interface);
386 RUN_TEST(max_bytes);
387 RUN_TEST(max_handles);
388 END_TEST_CASE(attributes_tests);
389