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: 62 void SetUp() override { 63 java_types_.Init(); 64 cpp_types_.Init(); 65 } 66 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 91 TEST_F(AidlTest, JavaAcceptsMissingPackage) { 92 EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_)); 93 } 94 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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