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 kExpectedParcelableDepFileContents[] =
52 R"( : \
53 p/Foo.aidl
54
55 p/Foo.aidl :
56 )";
57
58 } // namespace
59
60 class AidlTest : public ::testing::Test {
61 protected:
SetUp()62 void SetUp() override {
63 java_types_.Init();
64 cpp_types_.Init();
65 }
66
Parse(const string & path,const string & contents,TypeNamespace * types)67 unique_ptr<AidlInterface> Parse(const string& path,
68 const string& contents,
69 TypeNamespace* types) {
70 io_delegate_.SetFileContents(path, contents);
71 unique_ptr<AidlInterface> ret;
72 std::vector<std::unique_ptr<AidlImport>> imports;
73 ::android::aidl::internals::load_and_validate_aidl(
74 preprocessed_files_,
75 import_paths_,
76 path,
77 io_delegate_,
78 types,
79 &ret,
80 &imports);
81 return ret;
82 }
83
84 FakeIoDelegate io_delegate_;
85 vector<string> preprocessed_files_;
86 vector<string> import_paths_;
87 java::JavaTypeNamespace java_types_;
88 cpp::TypeNamespace cpp_types_;
89 };
90
TEST_F(AidlTest,JavaAcceptsMissingPackage)91 TEST_F(AidlTest, JavaAcceptsMissingPackage) {
92 EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_));
93 }
94
TEST_F(AidlTest,RejectsArraysOfBinders)95 TEST_F(AidlTest, RejectsArraysOfBinders) {
96 import_paths_.push_back("");
97 io_delegate_.SetFileContents("bar/IBar.aidl",
98 "package bar; interface IBar {}");
99 string path = "foo/IFoo.aidl";
100 string contents = "package foo;\n"
101 "import bar.IBar;\n"
102 "interface IFoo { void f(in IBar[] input); }";
103 EXPECT_EQ(nullptr, Parse(path, contents, &java_types_));
104 EXPECT_EQ(nullptr, Parse(path, contents, &cpp_types_));
105 }
106
TEST_F(AidlTest,CppRejectsMissingPackage)107 TEST_F(AidlTest, CppRejectsMissingPackage) {
108 EXPECT_EQ(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &cpp_types_));
109 EXPECT_NE(nullptr,
110 Parse("a/IFoo.aidl", "package a; interface IFoo { }", &cpp_types_));
111 }
112
TEST_F(AidlTest,RejectsOnewayOutParameters)113 TEST_F(AidlTest, RejectsOnewayOutParameters) {
114 string oneway_interface =
115 "package a; oneway interface IFoo { void f(out int bar); }";
116 string oneway_method =
117 "package a; interface IBar { oneway void f(out int bar); }";
118 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &cpp_types_));
119 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &java_types_));
120 EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &cpp_types_));
121 EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &java_types_));
122 }
123
TEST_F(AidlTest,RejectsOnewayNonVoidReturn)124 TEST_F(AidlTest, RejectsOnewayNonVoidReturn) {
125 string oneway_method = "package a; interface IFoo { oneway int f(); }";
126 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
127 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
128 }
129
TEST_F(AidlTest,RejectsNullablePrimitive)130 TEST_F(AidlTest, RejectsNullablePrimitive) {
131 string oneway_method = "package a; interface IFoo { @nullable int f(); }";
132 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
133 EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
134 }
135
TEST_F(AidlTest,ParsesNullableAnnotation)136 TEST_F(AidlTest, ParsesNullableAnnotation) {
137 for (auto is_nullable: {true, false}) {
138 auto parse_result = Parse(
139 "a/IFoo.aidl",
140 StringPrintf( "package a; interface IFoo {%s String f(); }",
141 (is_nullable) ? "@nullable" : ""),
142 &cpp_types_);
143 ASSERT_NE(nullptr, parse_result);
144 ASSERT_FALSE(parse_result->GetMethods().empty());
145 EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsNullable(),
146 is_nullable);
147 }
148 }
149
TEST_F(AidlTest,ParsesUtf8Annotations)150 TEST_F(AidlTest, ParsesUtf8Annotations) {
151 for (auto is_utf8: {true, false}) {
152 auto parse_result = Parse(
153 "a/IFoo.aidl",
154 StringPrintf( "package a; interface IFoo {%s String f(); }",
155 (is_utf8) ? "@utf8InCpp" : ""),
156 &cpp_types_);
157 ASSERT_NE(nullptr, parse_result);
158 ASSERT_FALSE(parse_result->GetMethods().empty());
159 EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsUtf8InCpp(),
160 is_utf8);
161 }
162 }
163
TEST_F(AidlTest,AcceptsOneway)164 TEST_F(AidlTest, AcceptsOneway) {
165 string oneway_method = "package a; interface IFoo { oneway void f(int a); }";
166 string oneway_interface =
167 "package a; oneway interface IBar { void f(int a); }";
168 EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
169 EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
170 EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &cpp_types_));
171 EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &java_types_));
172 }
173
TEST_F(AidlTest,ParsesPreprocessedFile)174 TEST_F(AidlTest, ParsesPreprocessedFile) {
175 string simple_content = "parcelable a.Foo;\ninterface b.IBar;";
176 io_delegate_.SetFileContents("path", simple_content);
177 EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
178 EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
179 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
180 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
181 }
182
TEST_F(AidlTest,ParsesPreprocessedFileWithWhitespace)183 TEST_F(AidlTest, ParsesPreprocessedFileWithWhitespace) {
184 string simple_content = "parcelable a.Foo;\n interface b.IBar ;\t";
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,PreferImportToPreprocessed)192 TEST_F(AidlTest, PreferImportToPreprocessed) {
193 io_delegate_.SetFileContents("preprocessed", "interface another.IBar;");
194 io_delegate_.SetFileContents("one/IBar.aidl", "package one; "
195 "interface IBar {}");
196 preprocessed_files_.push_back("preprocessed");
197 import_paths_.push_back("");
198 auto parse_result = Parse(
199 "p/IFoo.aidl", "package p; import one.IBar; interface IFoo {}",
200 &java_types_);
201 EXPECT_NE(nullptr, parse_result);
202 // We expect to know about both kinds of IBar
203 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("one.IBar"));
204 EXPECT_TRUE(java_types_.HasTypeByCanonicalName("another.IBar"));
205 // But if we request just "IBar" we should get our imported one.
206 AidlType ambiguous_type("IBar", 0, "", false /* not an array */);
207 const java::Type* type = java_types_.Find(ambiguous_type);
208 ASSERT_TRUE(type);
209 EXPECT_EQ("one.IBar", type->CanonicalName());
210 }
211
TEST_F(AidlTest,WritePreprocessedFile)212 TEST_F(AidlTest, WritePreprocessedFile) {
213 io_delegate_.SetFileContents("p/Outer.aidl",
214 "package p; parcelable Outer.Inner;");
215 io_delegate_.SetFileContents("one/IBar.aidl", "package one; import p.Outer;"
216 "interface IBar {}");
217
218 JavaOptions options;
219 options.output_file_name_ = "preprocessed";
220 options.files_to_preprocess_.resize(2);
221 options.files_to_preprocess_[0] = "p/Outer.aidl";
222 options.files_to_preprocess_[1] = "one/IBar.aidl";
223 EXPECT_TRUE(::android::aidl::preprocess_aidl(options, io_delegate_));
224
225 string output;
226 EXPECT_TRUE(io_delegate_.GetWrittenContents("preprocessed", &output));
227 EXPECT_EQ("parcelable p.Outer.Inner;\ninterface one.IBar;\n", output);
228 }
229
TEST_F(AidlTest,RequireOuterClass)230 TEST_F(AidlTest, RequireOuterClass) {
231 io_delegate_.SetFileContents("p/Outer.aidl",
232 "package p; parcelable Outer.Inner;");
233 import_paths_.push_back("");
234 auto parse_result = Parse(
235 "p/IFoo.aidl",
236 "package p; import p.Outer; interface IFoo { void f(in Inner c); }",
237 &java_types_);
238 EXPECT_EQ(nullptr, parse_result);
239 }
240
TEST_F(AidlTest,ParseCompoundParcelableFromPreprocess)241 TEST_F(AidlTest, ParseCompoundParcelableFromPreprocess) {
242 io_delegate_.SetFileContents("preprocessed",
243 "parcelable p.Outer.Inner;");
244 preprocessed_files_.push_back("preprocessed");
245 auto parse_result = Parse(
246 "p/IFoo.aidl",
247 "package p; interface IFoo { void f(in Inner c); }",
248 &java_types_);
249 // TODO(wiley): This should actually return nullptr because we require
250 // the outer class name. However, for legacy reasons,
251 // this behavior must be maintained. b/17415692
252 EXPECT_NE(nullptr, parse_result);
253 }
254
TEST_F(AidlTest,FailOnParcelable)255 TEST_F(AidlTest, FailOnParcelable) {
256 JavaOptions options;
257 options.input_file_name_ = "p/IFoo.aidl";
258 io_delegate_.SetFileContents(options.input_file_name_,
259 "package p; parcelable IFoo;");
260 // By default, we shouldn't fail on parcelable.
261 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
262 options.fail_on_parcelable_ = true;
263 EXPECT_NE(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
264 }
265
TEST_F(AidlTest,UnderstandsNativeParcelables)266 TEST_F(AidlTest, UnderstandsNativeParcelables) {
267 io_delegate_.SetFileContents(
268 "p/Bar.aidl",
269 "package p; parcelable Bar cpp_header \"baz/header\";");
270 import_paths_.push_back("");
271 const string input_path = "p/IFoo.aidl";
272 const string input = "package p; import p.Bar; interface IFoo { }";
273
274 // C++ understands C++ specific stuff
275 auto cpp_parse_result = Parse(input_path, input, &cpp_types_);
276 EXPECT_NE(nullptr, cpp_parse_result);
277 auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Bar");
278 ASSERT_NE(nullptr, cpp_type);
279 EXPECT_EQ("::p::Bar", cpp_type->CppType());
280 set<string> headers;
281 cpp_type->GetHeaders(&headers);
282 EXPECT_EQ(1u, headers.size());
283 EXPECT_EQ(1u, headers.count("baz/header"));
284
285 // Java ignores C++ specific stuff
286 auto java_parse_result = Parse(input_path, input, &java_types_);
287 EXPECT_NE(nullptr, java_parse_result);
288 auto java_type = java_types_.FindTypeByCanonicalName("p.Bar");
289 ASSERT_NE(nullptr, java_type);
290 EXPECT_EQ("p.Bar", java_type->InstantiableName());
291 }
292
TEST_F(AidlTest,WritesCorrectDependencyFile)293 TEST_F(AidlTest, WritesCorrectDependencyFile) {
294 // While the in tree build system always gives us an output file name,
295 // other android tools take advantage of our ability to infer the intended
296 // file name. This test makes sure we handle this correctly.
297 JavaOptions options;
298 options.input_file_name_ = "p/IFoo.aidl";
299 options.output_base_folder_ = "place/for/output";
300 options.dep_file_name_ = "dep/file/path";
301 io_delegate_.SetFileContents(options.input_file_name_,
302 "package p; interface IFoo {}");
303 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
304 string actual_dep_file_contents;
305 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
306 &actual_dep_file_contents));
307 EXPECT_EQ(actual_dep_file_contents, kExpectedDepFileContents);
308 }
309
TEST_F(AidlTest,WritesTrivialDependencyFileForParcelable)310 TEST_F(AidlTest, WritesTrivialDependencyFileForParcelable) {
311 // The SDK uses aidl to decide whether a .aidl file is a parcelable. It does
312 // this by calling aidl with every .aidl file it finds, then parsing the
313 // generated dependency files. Those that reference .java output files are
314 // for interfaces and those that do not are parcelables. However, for both
315 // parcelables and interfaces, we *must* generate a non-empty dependency file.
316 JavaOptions options;
317 options.input_file_name_ = "p/Foo.aidl";
318 options.output_base_folder_ = "place/for/output";
319 options.dep_file_name_ = "dep/file/path";
320 io_delegate_.SetFileContents(options.input_file_name_,
321 "package p; parcelable Foo;");
322 EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
323 string actual_dep_file_contents;
324 EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
325 &actual_dep_file_contents));
326 EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDepFileContents);
327 }
328
329 } // namespace aidl
330 } // namespace android
331