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: 67 void SetUp() override { 68 java_types_.Init(); 69 cpp_types_.Init(); 70 } 71 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 101 TEST_F(AidlTest, JavaAcceptsMissingPackage) { 102 EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_)); 103 } 104 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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