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