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