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 false, /* generate_traces */
84 io_delegate_,
85 types,
86 &ret,
87 &imports);
88 if (error != nullptr) {
89 *error = actual_error;
90 }
91 return ret;
92 }
93
94 FakeIoDelegate io_delegate_;
95 vector<string> preprocessed_files_;
96 vector<string> import_paths_;
97 java::JavaTypeNamespace java_types_;
98 cpp::TypeNamespace cpp_types_;
99 };
100
TEST_F(AidlTest,JavaAcceptsMissingPackage)101 TEST_F(AidlTest, JavaAcceptsMissingPackage) {
102 EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_));
103 }
104
TEST_F(AidlTest,RejectsArraysOfBinders)105 TEST_F(AidlTest, RejectsArraysOfBinders) {
106 import_paths_.push_back("");
107 io_delegate_.SetFileContents("bar/IBar.aidl",
108 "package bar; interface IBar {}");
109 string path = "foo/IFoo.aidl";
110 string contents = "package foo;\n"
111 "import bar.IBar;\n"
112 "interface IFoo { void f(in IBar[] input); }";
113 EXPECT_EQ(nullptr, Parse(path, contents, &java_types_));
114 EXPECT_EQ(nullptr, Parse(path, contents, &cpp_types_));
115 }
116
TEST_F(AidlTest,CppRejectsMissingPackage)117 TEST_F(AidlTest, CppRejectsMissingPackage) {
118 EXPECT_EQ(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &cpp_types_));
119 EXPECT_NE(nullptr,
120 Parse("a/IFoo.aidl", "package a; interface IFoo { }", &cpp_types_));
121 }
122
TEST_F(AidlTest,RejectsOnewayOutParameters)123 TEST_F(AidlTest, RejectsOnewayOutParameters) {
124 string oneway_interface =
125 "package a; oneway interface IFoo { void f(out int bar); }";
126 string oneway_method =
127 "package a; interface IBar { oneway void f(out int bar); }";
128 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &cpp_types_));
129 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &java_types_));
130 EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &cpp_types_));
131 EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &java_types_));
132 }
133
TEST_F(AidlTest,RejectsOnewayNonVoidReturn)134 TEST_F(AidlTest, RejectsOnewayNonVoidReturn) {
135 string oneway_method = "package a; interface IFoo { oneway int f(); }";
136 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
137 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
138 }
139
TEST_F(AidlTest,RejectsNullablePrimitive)140 TEST_F(AidlTest, RejectsNullablePrimitive) {
141 string oneway_method = "package a; interface IFoo { @nullable int f(); }";
142 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
143 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
144 }
145
TEST_F(AidlTest,ParsesNullableAnnotation)146 TEST_F(AidlTest, ParsesNullableAnnotation) {
147 for (auto is_nullable: {true, false}) {
148 auto parse_result = Parse(
149 "a/IFoo.aidl",
150 StringPrintf( "package a; interface IFoo {%s String f(); }",
151 (is_nullable) ? "@nullable" : ""),
152 &cpp_types_);
153 ASSERT_NE(nullptr, parse_result);
154 ASSERT_FALSE(parse_result->GetMethods().empty());
155 EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsNullable(),
156 is_nullable);
157 }
158 }
159
TEST_F(AidlTest,ParsesUtf8Annotations)160 TEST_F(AidlTest, ParsesUtf8Annotations) {
161 for (auto is_utf8: {true, false}) {
162 auto parse_result = Parse(
163 "a/IFoo.aidl",
164 StringPrintf( "package a; interface IFoo {%s String f(); }",
165 (is_utf8) ? "@utf8InCpp" : ""),
166 &cpp_types_);
167 ASSERT_NE(nullptr, parse_result);
168 ASSERT_FALSE(parse_result->GetMethods().empty());
169 EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsUtf8InCpp(),
170 is_utf8);
171 }
172 }
173
TEST_F(AidlTest,AcceptsOneway)174 TEST_F(AidlTest, AcceptsOneway) {
175 string oneway_method = "package a; interface IFoo { oneway void f(int a); }";
176 string oneway_interface =
177 "package a; oneway interface IBar { void f(int a); }";
178 EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
179 EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
180 EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &cpp_types_));
181 EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &java_types_));
182 }
183
TEST_F(AidlTest,ParsesPreprocessedFile)184 TEST_F(AidlTest, ParsesPreprocessedFile) {
185 string simple_content = "parcelable a.Foo;\ninterface b.IBar;";
186 io_delegate_.SetFileContents("path", simple_content);
187 EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
188 EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
189 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
190 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
191 }
192
TEST_F(AidlTest,ParsesPreprocessedFileWithWhitespace)193 TEST_F(AidlTest, ParsesPreprocessedFileWithWhitespace) {
194 string simple_content = "parcelable a.Foo;\n interface b.IBar ;\t";
195 io_delegate_.SetFileContents("path", simple_content);
196 EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
197 EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
198 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
199 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
200 }
201
TEST_F(AidlTest,PreferImportToPreprocessed)202 TEST_F(AidlTest, PreferImportToPreprocessed) {
203 io_delegate_.SetFileContents("preprocessed", "interface another.IBar;");
204 io_delegate_.SetFileContents("one/IBar.aidl", "package one; "
205 "interface IBar {}");
206 preprocessed_files_.push_back("preprocessed");
207 import_paths_.push_back("");
208 auto parse_result = Parse(
209 "p/IFoo.aidl", "package p; import one.IBar; interface IFoo {}",
210 &java_types_);
211 EXPECT_NE(nullptr, parse_result);
212 // We expect to know about both kinds of IBar
213 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("one.IBar"));
214 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("another.IBar"));
215 // But if we request just "IBar" we should get our imported one.
216 AidlType ambiguous_type("IBar", 0, "", false /* not an array */);
217 const java::Type* type = java_types_.Find(ambiguous_type);
218 ASSERT_TRUE(type);
219 EXPECT_EQ("one.IBar", type->CanonicalName());
220 }
221
TEST_F(AidlTest,WritePreprocessedFile)222 TEST_F(AidlTest, WritePreprocessedFile) {
223 io_delegate_.SetFileContents("p/Outer.aidl",
224 "package p; parcelable Outer.Inner;");
225 io_delegate_.SetFileContents("one/IBar.aidl", "package one; import p.Outer;"
226 "interface IBar {}");
227
228 JavaOptions options;
229 options.output_file_name_ = "preprocessed";
230 options.files_to_preprocess_.resize(2);
231 options.files_to_preprocess_[0] = "p/Outer.aidl";
232 options.files_to_preprocess_[1] = "one/IBar.aidl";
233 EXPECT_TRUE(::android::aidl::preprocess_aidl(options, io_delegate_));
234
235 string output;
236 EXPECT_TRUE(io_delegate_.GetWrittenContents("preprocessed", &output));
237 EXPECT_EQ("parcelable p.Outer.Inner;\ninterface one.IBar;\n", output);
238 }
239
TEST_F(AidlTest,RequireOuterClass)240 TEST_F(AidlTest, RequireOuterClass) {
241 io_delegate_.SetFileContents("p/Outer.aidl",
242 "package p; parcelable Outer.Inner;");
243 import_paths_.push_back("");
244 auto parse_result = Parse(
245 "p/IFoo.aidl",
246 "package p; import p.Outer; interface IFoo { void f(in Inner c); }",
247 &java_types_);
248 EXPECT_EQ(nullptr, parse_result);
249 }
250
TEST_F(AidlTest,ParseCompoundParcelableFromPreprocess)251 TEST_F(AidlTest, ParseCompoundParcelableFromPreprocess) {
252 io_delegate_.SetFileContents("preprocessed",
253 "parcelable p.Outer.Inner;");
254 preprocessed_files_.push_back("preprocessed");
255 auto parse_result = Parse(
256 "p/IFoo.aidl",
257 "package p; interface IFoo { void f(in Inner c); }",
258 &java_types_);
259 // TODO(wiley): This should actually return nullptr because we require
260 // the outer class name. However, for legacy reasons,
261 // this behavior must be maintained. b/17415692
262 EXPECT_NE(nullptr, parse_result);
263 }
264
TEST_F(AidlTest,FailOnParcelable)265 TEST_F(AidlTest, FailOnParcelable) {
266 JavaOptions options;
267 options.input_file_name_ = "p/IFoo.aidl";
268 io_delegate_.SetFileContents(options.input_file_name_,
269 "package p; parcelable IFoo;");
270 // By default, we shouldn't fail on parcelable.
271 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
272 options.fail_on_parcelable_ = true;
273 EXPECT_NE(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
274 }
275
TEST_F(AidlTest,FailOnDuplicateConstantNames)276 TEST_F(AidlTest, FailOnDuplicateConstantNames) {
277 AidlError reported_error;
278 EXPECT_EQ(nullptr,
279 Parse("p/IFoo.aidl",
280 R"(package p;
281 interface IFoo {
282 const String DUPLICATED = "d";
283 const int DUPLICATED = 1;
284 }
285 )",
286 &cpp_types_,
287 &reported_error));
288 EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
289 }
290
TEST_F(AidlTest,FailOnMalformedConstHexValue)291 TEST_F(AidlTest, FailOnMalformedConstHexValue) {
292 AidlError reported_error;
293 EXPECT_EQ(nullptr,
294 Parse("p/IFoo.aidl",
295 R"(package p;
296 interface IFoo {
297 const int BAD_HEX_VALUE = 0xffffffffffffffffff;
298 }
299 )",
300 &cpp_types_,
301 &reported_error));
302 EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
303 }
304
TEST_F(AidlTest,ParsePositiveConstHexValue)305 TEST_F(AidlTest, ParsePositiveConstHexValue) {
306 AidlError reported_error;
307 auto cpp_parse_result =
308 Parse("p/IFoo.aidl",
309 R"(package p;
310 interface IFoo {
311 const int POSITIVE_HEX_VALUE = 0xf5;
312 }
313 )",
314 &cpp_types_,
315 &reported_error);
316 EXPECT_NE(nullptr, cpp_parse_result);
317 const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
318 EXPECT_EQ((size_t)1, cpp_int_constants.size());
319 EXPECT_EQ("POSITIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
320 EXPECT_EQ(245, cpp_int_constants[0]->GetValue());
321 }
322
TEST_F(AidlTest,ParseNegativeConstHexValue)323 TEST_F(AidlTest, ParseNegativeConstHexValue) {
324 AidlError reported_error;
325 auto cpp_parse_result =
326 Parse("p/IFoo.aidl",
327 R"(package p;
328 interface IFoo {
329 const int NEGATIVE_HEX_VALUE = 0xffffffff;
330 }
331 )",
332 &cpp_types_,
333 &reported_error);
334 EXPECT_NE(nullptr, cpp_parse_result);
335 const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
336 EXPECT_EQ((size_t)1, cpp_int_constants.size());
337 EXPECT_EQ("NEGATIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
338 EXPECT_EQ(-1, cpp_int_constants[0]->GetValue());
339 }
340
TEST_F(AidlTest,UnderstandsNestedParcelables)341 TEST_F(AidlTest, UnderstandsNestedParcelables) {
342 io_delegate_.SetFileContents(
343 "p/Outer.aidl",
344 "package p; parcelable Outer.Inner cpp_header \"baz/header\";");
345 import_paths_.push_back("");
346 const string input_path = "p/IFoo.aidl";
347 const string input = "package p; import p.Outer; interface IFoo"
348 " { Outer.Inner get(); }";
349
350 auto cpp_parse_result = Parse(input_path, input, &cpp_types_);
351 EXPECT_NE(nullptr, cpp_parse_result);
352 auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Outer.Inner");
353 ASSERT_NE(nullptr, cpp_type);
354 // C++ uses "::" instead of "." to refer to a inner class.
355 EXPECT_EQ("::p::Outer::Inner", cpp_type->CppType());
356 }
357
TEST_F(AidlTest,UnderstandsNativeParcelables)358 TEST_F(AidlTest, UnderstandsNativeParcelables) {
359 io_delegate_.SetFileContents(
360 "p/Bar.aidl",
361 "package p; parcelable Bar cpp_header \"baz/header\";");
362 import_paths_.push_back("");
363 const string input_path = "p/IFoo.aidl";
364 const string input = "package p; import p.Bar; interface IFoo { }";
365
366 // C++ understands C++ specific stuff
367 auto cpp_parse_result = Parse(input_path, input, &cpp_types_);
368 EXPECT_NE(nullptr, cpp_parse_result);
369 auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Bar");
370 ASSERT_NE(nullptr, cpp_type);
371 EXPECT_EQ("::p::Bar", cpp_type->CppType());
372 set<string> headers;
373 cpp_type->GetHeaders(&headers);
374 EXPECT_EQ(1u, headers.size());
375 EXPECT_EQ(1u, headers.count("baz/header"));
376
377 // Java ignores C++ specific stuff
378 auto java_parse_result = Parse(input_path, input, &java_types_);
379 EXPECT_NE(nullptr, java_parse_result);
380 auto java_type = java_types_.FindTypeByCanonicalName("p.Bar");
381 ASSERT_NE(nullptr, java_type);
382 EXPECT_EQ("p.Bar", java_type->InstantiableName());
383 }
384
TEST_F(AidlTest,WritesCorrectDependencyFile)385 TEST_F(AidlTest, WritesCorrectDependencyFile) {
386 // While the in tree build system always gives us an output file name,
387 // other android tools take advantage of our ability to infer the intended
388 // file name. This test makes sure we handle this correctly.
389 JavaOptions options;
390 options.input_file_name_ = "p/IFoo.aidl";
391 options.output_base_folder_ = "place/for/output";
392 options.dep_file_name_ = "dep/file/path";
393 io_delegate_.SetFileContents(options.input_file_name_,
394 "package p; interface IFoo {}");
395 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
396 string actual_dep_file_contents;
397 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
398 &actual_dep_file_contents));
399 EXPECT_EQ(actual_dep_file_contents, kExpectedDepFileContents);
400 }
401
TEST_F(AidlTest,WritesCorrectDependencyFileNinja)402 TEST_F(AidlTest, WritesCorrectDependencyFileNinja) {
403 // While the in tree build system always gives us an output file name,
404 // other android tools take advantage of our ability to infer the intended
405 // file name. This test makes sure we handle this correctly.
406 JavaOptions options;
407 options.input_file_name_ = "p/IFoo.aidl";
408 options.output_base_folder_ = "place/for/output";
409 options.dep_file_name_ = "dep/file/path";
410 options.dep_file_ninja_ = true;
411 io_delegate_.SetFileContents(options.input_file_name_,
412 "package p; interface IFoo {}");
413 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
414 string actual_dep_file_contents;
415 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
416 &actual_dep_file_contents));
417 EXPECT_EQ(actual_dep_file_contents, kExpectedNinjaDepFileContents);
418 }
419
TEST_F(AidlTest,WritesTrivialDependencyFileForParcelable)420 TEST_F(AidlTest, WritesTrivialDependencyFileForParcelable) {
421 // The SDK uses aidl to decide whether a .aidl file is a parcelable. It does
422 // this by calling aidl with every .aidl file it finds, then parsing the
423 // generated dependency files. Those that reference .java output files are
424 // for interfaces and those that do not are parcelables. However, for both
425 // parcelables and interfaces, we *must* generate a non-empty dependency file.
426 JavaOptions options;
427 options.input_file_name_ = "p/Foo.aidl";
428 options.output_base_folder_ = "place/for/output";
429 options.dep_file_name_ = "dep/file/path";
430 io_delegate_.SetFileContents(options.input_file_name_,
431 "package p; parcelable Foo;");
432 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
433 string actual_dep_file_contents;
434 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
435 &actual_dep_file_contents));
436 EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDepFileContents);
437 }
438
439 } // namespace aidl
440 } // namespace android
441