Home | History | Annotate | Download | only in aidl
      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