1 /*
2 * Copyright (C) 2015, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <memory>
18 #include <set>
19 #include <string>
20 #include <vector>
21
22 #include <android-base/stringprintf.h>
23 #include <gtest/gtest.h>
24
25 #include "aidl.h"
26 #include "aidl_language.h"
27 #include "tests/fake_io_delegate.h"
28 #include "type_cpp.h"
29 #include "type_java.h"
30 #include "type_namespace.h"
31
32 using android::aidl::test::FakeIoDelegate;
33 using android::base::StringPrintf;
34 using std::set;
35 using std::string;
36 using std::unique_ptr;
37 using std::vector;
38 using android::aidl::internals::parse_preprocessed_file;
39
40 namespace android {
41 namespace aidl {
42 namespace {
43
44 const char kExpectedDepFileContents[] =
45 R"(place/for/output/p/IFoo.java : \
46 p/IFoo.aidl
47
48 p/IFoo.aidl :
49 )";
50
51 const char kExpectedNinjaDepFileContents[] =
52 R"(place/for/output/p/IFoo.java : \
53 p/IFoo.aidl
54 )";
55
56 const char kExpectedParcelableDepFileContents[] =
57 R"( : \
58 p/Foo.aidl
59
60 p/Foo.aidl :
61 )";
62
63 } // namespace
64
65 class AidlTest : public ::testing::Test {
66 protected:
SetUp()67 void SetUp() override {
68 java_types_.Init();
69 cpp_types_.Init();
70 }
71
Parse(const string & path,const string & contents,TypeNamespace * types,AidlError * error=nullptr)72 unique_ptr<AidlInterface> Parse(const string& path,
73 const string& contents,
74 TypeNamespace* types,
75 AidlError* error = nullptr) {
76 io_delegate_.SetFileContents(path, contents);
77 unique_ptr<AidlInterface> ret;
78 std::vector<std::unique_ptr<AidlImport>> imports;
79 AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl(
80 preprocessed_files_,
81 import_paths_,
82 path,
83 io_delegate_,
84 types,
85 &ret,
86 &imports);
87 if (error != nullptr) {
88 *error = actual_error;
89 }
90 return ret;
91 }
92
93 FakeIoDelegate io_delegate_;
94 vector<string> preprocessed_files_;
95 vector<string> import_paths_;
96 java::JavaTypeNamespace java_types_;
97 cpp::TypeNamespace cpp_types_;
98 };
99
TEST_F(AidlTest,JavaAcceptsMissingPackage)100 TEST_F(AidlTest, JavaAcceptsMissingPackage) {
101 EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_));
102 }
103
TEST_F(AidlTest,RejectsArraysOfBinders)104 TEST_F(AidlTest, RejectsArraysOfBinders) {
105 import_paths_.push_back("");
106 io_delegate_.SetFileContents("bar/IBar.aidl",
107 "package bar; interface IBar {}");
108 string path = "foo/IFoo.aidl";
109 string contents = "package foo;\n"
110 "import bar.IBar;\n"
111 "interface IFoo { void f(in IBar[] input); }";
112 EXPECT_EQ(nullptr, Parse(path, contents, &java_types_));
113 EXPECT_EQ(nullptr, Parse(path, contents, &cpp_types_));
114 }
115
TEST_F(AidlTest,CppRejectsMissingPackage)116 TEST_F(AidlTest, CppRejectsMissingPackage) {
117 EXPECT_EQ(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &cpp_types_));
118 EXPECT_NE(nullptr,
119 Parse("a/IFoo.aidl", "package a; interface IFoo { }", &cpp_types_));
120 }
121
TEST_F(AidlTest,RejectsOnewayOutParameters)122 TEST_F(AidlTest, RejectsOnewayOutParameters) {
123 string oneway_interface =
124 "package a; oneway interface IFoo { void f(out int bar); }";
125 string oneway_method =
126 "package a; interface IBar { oneway void f(out int bar); }";
127 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &cpp_types_));
128 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &java_types_));
129 EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &cpp_types_));
130 EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &java_types_));
131 }
132
TEST_F(AidlTest,RejectsOnewayNonVoidReturn)133 TEST_F(AidlTest, RejectsOnewayNonVoidReturn) {
134 string oneway_method = "package a; interface IFoo { oneway int f(); }";
135 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
136 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
137 }
138
TEST_F(AidlTest,RejectsNullablePrimitive)139 TEST_F(AidlTest, RejectsNullablePrimitive) {
140 string oneway_method = "package a; interface IFoo { @nullable int f(); }";
141 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
142 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
143 }
144
TEST_F(AidlTest,ParsesNullableAnnotation)145 TEST_F(AidlTest, ParsesNullableAnnotation) {
146 for (auto is_nullable: {true, false}) {
147 auto parse_result = Parse(
148 "a/IFoo.aidl",
149 StringPrintf( "package a; interface IFoo {%s String f(); }",
150 (is_nullable) ? "@nullable" : ""),
151 &cpp_types_);
152 ASSERT_NE(nullptr, parse_result);
153 ASSERT_FALSE(parse_result->GetMethods().empty());
154 EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsNullable(),
155 is_nullable);
156 }
157 }
158
TEST_F(AidlTest,ParsesUtf8Annotations)159 TEST_F(AidlTest, ParsesUtf8Annotations) {
160 for (auto is_utf8: {true, false}) {
161 auto parse_result = Parse(
162 "a/IFoo.aidl",
163 StringPrintf( "package a; interface IFoo {%s String f(); }",
164 (is_utf8) ? "@utf8InCpp" : ""),
165 &cpp_types_);
166 ASSERT_NE(nullptr, parse_result);
167 ASSERT_FALSE(parse_result->GetMethods().empty());
168 EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsUtf8InCpp(),
169 is_utf8);
170 }
171 }
172
TEST_F(AidlTest,AcceptsOneway)173 TEST_F(AidlTest, AcceptsOneway) {
174 string oneway_method = "package a; interface IFoo { oneway void f(int a); }";
175 string oneway_interface =
176 "package a; oneway interface IBar { void f(int a); }";
177 EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
178 EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
179 EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &cpp_types_));
180 EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &java_types_));
181 }
182
TEST_F(AidlTest,ParsesPreprocessedFile)183 TEST_F(AidlTest, ParsesPreprocessedFile) {
184 string simple_content = "parcelable a.Foo;\ninterface b.IBar;";
185 io_delegate_.SetFileContents("path", simple_content);
186 EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
187 EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
188 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
189 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
190 }
191
TEST_F(AidlTest,ParsesPreprocessedFileWithWhitespace)192 TEST_F(AidlTest, ParsesPreprocessedFileWithWhitespace) {
193 string simple_content = "parcelable a.Foo;\n interface b.IBar ;\t";
194 io_delegate_.SetFileContents("path", simple_content);
195 EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
196 EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
197 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
198 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
199 }
200
TEST_F(AidlTest,PreferImportToPreprocessed)201 TEST_F(AidlTest, PreferImportToPreprocessed) {
202 io_delegate_.SetFileContents("preprocessed", "interface another.IBar;");
203 io_delegate_.SetFileContents("one/IBar.aidl", "package one; "
204 "interface IBar {}");
205 preprocessed_files_.push_back("preprocessed");
206 import_paths_.push_back("");
207 auto parse_result = Parse(
208 "p/IFoo.aidl", "package p; import one.IBar; interface IFoo {}",
209 &java_types_);
210 EXPECT_NE(nullptr, parse_result);
211 // We expect to know about both kinds of IBar
212 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("one.IBar"));
213 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("another.IBar"));
214 // But if we request just "IBar" we should get our imported one.
215 AidlType ambiguous_type("IBar", 0, "", false /* not an array */);
216 const java::Type* type = java_types_.Find(ambiguous_type);
217 ASSERT_TRUE(type);
218 EXPECT_EQ("one.IBar", type->CanonicalName());
219 }
220
TEST_F(AidlTest,WritePreprocessedFile)221 TEST_F(AidlTest, WritePreprocessedFile) {
222 io_delegate_.SetFileContents("p/Outer.aidl",
223 "package p; parcelable Outer.Inner;");
224 io_delegate_.SetFileContents("one/IBar.aidl", "package one; import p.Outer;"
225 "interface IBar {}");
226
227 JavaOptions options;
228 options.output_file_name_ = "preprocessed";
229 options.files_to_preprocess_.resize(2);
230 options.files_to_preprocess_[0] = "p/Outer.aidl";
231 options.files_to_preprocess_[1] = "one/IBar.aidl";
232 EXPECT_TRUE(::android::aidl::preprocess_aidl(options, io_delegate_));
233
234 string output;
235 EXPECT_TRUE(io_delegate_.GetWrittenContents("preprocessed", &output));
236 EXPECT_EQ("parcelable p.Outer.Inner;\ninterface one.IBar;\n", output);
237 }
238
TEST_F(AidlTest,RequireOuterClass)239 TEST_F(AidlTest, RequireOuterClass) {
240 io_delegate_.SetFileContents("p/Outer.aidl",
241 "package p; parcelable Outer.Inner;");
242 import_paths_.push_back("");
243 auto parse_result = Parse(
244 "p/IFoo.aidl",
245 "package p; import p.Outer; interface IFoo { void f(in Inner c); }",
246 &java_types_);
247 EXPECT_EQ(nullptr, parse_result);
248 }
249
TEST_F(AidlTest,ParseCompoundParcelableFromPreprocess)250 TEST_F(AidlTest, ParseCompoundParcelableFromPreprocess) {
251 io_delegate_.SetFileContents("preprocessed",
252 "parcelable p.Outer.Inner;");
253 preprocessed_files_.push_back("preprocessed");
254 auto parse_result = Parse(
255 "p/IFoo.aidl",
256 "package p; interface IFoo { void f(in Inner c); }",
257 &java_types_);
258 // TODO(wiley): This should actually return nullptr because we require
259 // the outer class name. However, for legacy reasons,
260 // this behavior must be maintained. b/17415692
261 EXPECT_NE(nullptr, parse_result);
262 }
263
TEST_F(AidlTest,FailOnParcelable)264 TEST_F(AidlTest, FailOnParcelable) {
265 JavaOptions options;
266 options.input_file_name_ = "p/IFoo.aidl";
267 io_delegate_.SetFileContents(options.input_file_name_,
268 "package p; parcelable IFoo;");
269 // By default, we shouldn't fail on parcelable.
270 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
271 options.fail_on_parcelable_ = true;
272 EXPECT_NE(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
273 }
274
TEST_F(AidlTest,FailOnDuplicateConstantNames)275 TEST_F(AidlTest, FailOnDuplicateConstantNames) {
276 AidlError reported_error;
277 EXPECT_EQ(nullptr,
278 Parse("p/IFoo.aidl",
279 R"(package p;
280 interface IFoo {
281 const String DUPLICATED = "d";
282 const int DUPLICATED = 1;
283 }
284 )",
285 &cpp_types_,
286 &reported_error));
287 EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
288 }
289
TEST_F(AidlTest,FailOnMalformedConstHexValue)290 TEST_F(AidlTest, FailOnMalformedConstHexValue) {
291 AidlError reported_error;
292 EXPECT_EQ(nullptr,
293 Parse("p/IFoo.aidl",
294 R"(package p;
295 interface IFoo {
296 const int BAD_HEX_VALUE = 0xffffffffffffffffff;
297 }
298 )",
299 &cpp_types_,
300 &reported_error));
301 EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
302 }
303
TEST_F(AidlTest,ParsePositiveConstHexValue)304 TEST_F(AidlTest, ParsePositiveConstHexValue) {
305 AidlError reported_error;
306 auto cpp_parse_result =
307 Parse("p/IFoo.aidl",
308 R"(package p;
309 interface IFoo {
310 const int POSITIVE_HEX_VALUE = 0xf5;
311 }
312 )",
313 &cpp_types_,
314 &reported_error);
315 EXPECT_NE(nullptr, cpp_parse_result);
316 const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
317 EXPECT_EQ((size_t)1, cpp_int_constants.size());
318 EXPECT_EQ("POSITIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
319 EXPECT_EQ(245, cpp_int_constants[0]->GetValue());
320 }
321
TEST_F(AidlTest,ParseNegativeConstHexValue)322 TEST_F(AidlTest, ParseNegativeConstHexValue) {
323 AidlError reported_error;
324 auto cpp_parse_result =
325 Parse("p/IFoo.aidl",
326 R"(package p;
327 interface IFoo {
328 const int NEGATIVE_HEX_VALUE = 0xffffffff;
329 }
330 )",
331 &cpp_types_,
332 &reported_error);
333 EXPECT_NE(nullptr, cpp_parse_result);
334 const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
335 EXPECT_EQ((size_t)1, cpp_int_constants.size());
336 EXPECT_EQ("NEGATIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
337 EXPECT_EQ(-1, cpp_int_constants[0]->GetValue());
338 }
339
TEST_F(AidlTest,UnderstandsNestedParcelables)340 TEST_F(AidlTest, UnderstandsNestedParcelables) {
341 io_delegate_.SetFileContents(
342 "p/Outer.aidl",
343 "package p; parcelable Outer.Inner cpp_header \"baz/header\";");
344 import_paths_.push_back("");
345 const string input_path = "p/IFoo.aidl";
346 const string input = "package p; import p.Outer; interface IFoo"
347 " { Outer.Inner get(); }";
348
349 auto cpp_parse_result = Parse(input_path, input, &cpp_types_);
350 EXPECT_NE(nullptr, cpp_parse_result);
351 auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Outer.Inner");
352 ASSERT_NE(nullptr, cpp_type);
353 // C++ uses "::" instead of "." to refer to a inner class.
354 EXPECT_EQ("::p::Outer::Inner", cpp_type->CppType());
355 }
356
TEST_F(AidlTest,UnderstandsNativeParcelables)357 TEST_F(AidlTest, UnderstandsNativeParcelables) {
358 io_delegate_.SetFileContents(
359 "p/Bar.aidl",
360 "package p; parcelable Bar cpp_header \"baz/header\";");
361 import_paths_.push_back("");
362 const string input_path = "p/IFoo.aidl";
363 const string input = "package p; import p.Bar; interface IFoo { }";
364
365 // C++ understands C++ specific stuff
366 auto cpp_parse_result = Parse(input_path, input, &cpp_types_);
367 EXPECT_NE(nullptr, cpp_parse_result);
368 auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Bar");
369 ASSERT_NE(nullptr, cpp_type);
370 EXPECT_EQ("::p::Bar", cpp_type->CppType());
371 set<string> headers;
372 cpp_type->GetHeaders(&headers);
373 EXPECT_EQ(1u, headers.size());
374 EXPECT_EQ(1u, headers.count("baz/header"));
375
376 // Java ignores C++ specific stuff
377 auto java_parse_result = Parse(input_path, input, &java_types_);
378 EXPECT_NE(nullptr, java_parse_result);
379 auto java_type = java_types_.FindTypeByCanonicalName("p.Bar");
380 ASSERT_NE(nullptr, java_type);
381 EXPECT_EQ("p.Bar", java_type->InstantiableName());
382 }
383
TEST_F(AidlTest,WritesCorrectDependencyFile)384 TEST_F(AidlTest, WritesCorrectDependencyFile) {
385 // While the in tree build system always gives us an output file name,
386 // other android tools take advantage of our ability to infer the intended
387 // file name. This test makes sure we handle this correctly.
388 JavaOptions options;
389 options.input_file_name_ = "p/IFoo.aidl";
390 options.output_base_folder_ = "place/for/output";
391 options.dep_file_name_ = "dep/file/path";
392 io_delegate_.SetFileContents(options.input_file_name_,
393 "package p; interface IFoo {}");
394 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
395 string actual_dep_file_contents;
396 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
397 &actual_dep_file_contents));
398 EXPECT_EQ(actual_dep_file_contents, kExpectedDepFileContents);
399 }
400
TEST_F(AidlTest,WritesCorrectDependencyFileNinja)401 TEST_F(AidlTest, WritesCorrectDependencyFileNinja) {
402 // While the in tree build system always gives us an output file name,
403 // other android tools take advantage of our ability to infer the intended
404 // file name. This test makes sure we handle this correctly.
405 JavaOptions options;
406 options.input_file_name_ = "p/IFoo.aidl";
407 options.output_base_folder_ = "place/for/output";
408 options.dep_file_name_ = "dep/file/path";
409 options.dep_file_ninja_ = true;
410 io_delegate_.SetFileContents(options.input_file_name_,
411 "package p; interface IFoo {}");
412 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
413 string actual_dep_file_contents;
414 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
415 &actual_dep_file_contents));
416 EXPECT_EQ(actual_dep_file_contents, kExpectedNinjaDepFileContents);
417 }
418
TEST_F(AidlTest,WritesTrivialDependencyFileForParcelable)419 TEST_F(AidlTest, WritesTrivialDependencyFileForParcelable) {
420 // The SDK uses aidl to decide whether a .aidl file is a parcelable. It does
421 // this by calling aidl with every .aidl file it finds, then parsing the
422 // generated dependency files. Those that reference .java output files are
423 // for interfaces and those that do not are parcelables. However, for both
424 // parcelables and interfaces, we *must* generate a non-empty dependency file.
425 JavaOptions options;
426 options.input_file_name_ = "p/Foo.aidl";
427 options.output_base_folder_ = "place/for/output";
428 options.dep_file_name_ = "dep/file/path";
429 io_delegate_.SetFileContents(options.input_file_name_,
430 "package p; parcelable Foo;");
431 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
432 string actual_dep_file_contents;
433 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
434 &actual_dep_file_contents));
435 EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDepFileContents);
436 }
437
438 } // namespace aidl
439 } // namespace android
440