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