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 <locale.h>
8 
9 #include <fidl/flat_ast.h>
10 #include <fidl/lexer.h>
11 #include <fidl/parser.h>
12 #include <fidl/source_file.h>
13 
14 #include "test_library.h"
15 
16 namespace {
17 
18 // Test that an invalid compound identifier fails parsing. Regression
19 // test for FIDL-263.
bad_compound_identifier_test()20 bool bad_compound_identifier_test() {
21     BEGIN_TEST;
22 
23     // The leading 0 in the library name causes parsing an Identifier
24     // to fail, and then parsing a CompoundIdentifier to fail.
25     TestLibrary library(R"FIDL(
26 library 0fidl.test.badcompoundidentifier;
27 )FIDL");
28     EXPECT_FALSE(library.Compile());
29     auto errors = library.errors();
30     ASSERT_EQ(errors.size(), 1);
31     ASSERT_STR_STR(errors[0].c_str(), "unexpected token");
32 
33     END_TEST;
34 }
35 
36 // Test that otherwise reserved words can be appropriarely parsed when context
37 // is clear.
parsing_reserved_words_in_struct_test()38 bool parsing_reserved_words_in_struct_test() {
39     BEGIN_TEST;
40 
41     TestLibrary library(R"FIDL(
42 library example;
43 
44 struct InStruct {
45     bool as;
46     bool library;
47     bool using;
48 
49     bool array;
50     bool handle;
51     bool request;
52     bool string;
53     bool vector;
54 
55     bool bool;
56     bool int8;
57     bool int16;
58     bool int32;
59     bool int64;
60     bool uint8;
61     bool uint16;
62     bool uint32;
63     bool uint64;
64     bool float32;
65     bool float64;
66 
67     bool true;
68     bool false;
69 
70     bool reserved;
71 };
72 )FIDL");
73     EXPECT_TRUE(library.Compile());
74 
75     END_TEST;
76 }
77 
78 // Test that otherwise reserved words can be appropriarely parsed when context
79 // is clear.
parsing_reserved_words_in_interface_test()80 bool parsing_reserved_words_in_interface_test() {
81     BEGIN_TEST;
82 
83     TestLibrary library(R"FIDL(
84 library example;
85 
86 interface InInterface {
87     01: as(bool as);
88     02: library(bool library);
89     03: using(bool using);
90 
91     11: array(bool array);
92     12: handle(bool handle);
93     13: request(bool request);
94     14: string(bool string);
95     15: vector(bool vector);
96 
97     31: bool(bool bool);
98     32: int8(bool int8);
99     33: int16(bool int16);
100     34: int32(bool int32);
101     35: int64(bool int64);
102     36: uint8(bool uint8);
103     37: uint16(bool uint16);
104     38: uint32(bool uint32);
105     39: uint64(bool uint64);
106     40: float32(bool float32);
107     41: float64(bool float64);
108 
109     51: true(bool true);
110     52: false(bool false);
111 
112     61: reserved(bool reserved);
113 };
114 )FIDL");
115     EXPECT_TRUE(library.Compile());
116 
117     END_TEST;
118 }
119 
bad_char_at_sign_test()120 bool bad_char_at_sign_test() {
121     BEGIN_TEST;
122 
123     TestLibrary library(R"FIDL(
124 library test;
125 
126 struct Test {
127     uint8 @uint8;
128 };
129 )FIDL");
130     EXPECT_FALSE(library.Compile());
131     auto errors = library.errors();
132     ASSERT_EQ(errors.size(), 1);
133     ASSERT_STR_STR(errors[0].c_str(), "invalid character '@'");
134 
135     END_TEST;
136 }
137 
bad_char_slash_test()138 bool bad_char_slash_test() {
139     BEGIN_TEST;
140 
141     TestLibrary library(R"FIDL(
142 library test;
143 
144 struct Test / {
145     uint8 uint8;
146 };
147 )FIDL");
148     EXPECT_FALSE(library.Compile());
149     auto errors = library.errors();
150     ASSERT_EQ(errors.size(), 1);
151     ASSERT_STR_STR(errors[0].c_str(), "invalid character '/'");
152 
153     END_TEST;
154 }
155 
bad_identifier_test()156 bool bad_identifier_test() {
157     BEGIN_TEST;
158 
159     TestLibrary library(R"FIDL(
160 library test;
161 
162 struct test_ {
163     uint8 uint8;
164 };
165 )FIDL");
166     EXPECT_FALSE(library.Compile());
167     auto errors = library.errors();
168     ASSERT_EQ(errors.size(), 1);
169     ASSERT_STR_STR(errors[0].c_str(), "invalid identifier 'test_'");
170 
171     END_TEST;
172 }
173 
174 class LocaleSwapper {
175 public:
LocaleSwapper(const char * new_locale)176     explicit LocaleSwapper(const char* new_locale) {
177         old_locale_ = setlocale(LC_ALL, new_locale);
178     }
~LocaleSwapper()179     ~LocaleSwapper() {
180         setlocale(LC_ALL, old_locale_);
181     }
182 
183 private:
184     const char* old_locale_;
185 };
186 
invalid_character_test(void)187 static bool invalid_character_test(void) {
188     BEGIN_TEST;
189 
190     class InvalidCharacterLibrary : public TestLibrary {
191     public:
192         InvalidCharacterLibrary()
193             : TestLibrary("invalid.character.fidl", R"FIDL(
194 library fidl.test.maxbytes;
195 
196 // This is all alphanumeric in the appropriate locale, but not a valid
197 // identifier.
198 struct ß {
199     int32 x;
200 };
201 
202 )FIDL") {}
203     } test_library;
204 
205     {
206         LocaleSwapper("de_DE.iso88591");
207         EXPECT_FALSE(test_library.Compile());
208     }
209 
210     const auto& errors = test_library.errors();
211     EXPECT_NE(errors.size(), 0);
212     ASSERT_STR_STR(errors[0].data(), "invalid character");
213 
214     END_TEST;
215 }
216 
empty_struct_test()217 bool empty_struct_test() {
218     BEGIN_TEST;
219 
220     TestLibrary library("empty_struct.fidl", R"FIDL(
221 library fidl.test.emptystruct;
222 
223 struct Empty {
224 };
225 
226 )FIDL");
227     EXPECT_TRUE(library.Compile());
228 
229     END_TEST;
230 }
231 
232 } // namespace
233 
234 BEGIN_TEST_CASE(parser_tests);
235 RUN_TEST(bad_compound_identifier_test);
236 RUN_TEST(parsing_reserved_words_in_struct_test);
237 RUN_TEST(parsing_reserved_words_in_interface_test);
238 RUN_TEST(bad_char_at_sign_test);
239 RUN_TEST(bad_char_slash_test);
240 RUN_TEST(bad_identifier_test);
241 RUN_TEST(invalid_character_test);
242 RUN_TEST(empty_struct_test);
243 END_TEST_CASE(parser_tests);
244