Home | History | Annotate | Download | only in java
      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 "java/JavaClassGenerator.h"
     18 
     19 #include <sstream>
     20 #include <string>
     21 
     22 #include "test/Test.h"
     23 #include "util/Util.h"
     24 
     25 using android::StringPiece;
     26 
     27 namespace aapt {
     28 
     29 TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
     30   std::unique_ptr<ResourceTable> table =
     31       test::ResourceTableBuilder()
     32           .SetPackageId("android", 0x01)
     33           .AddSimple("android:id/class", ResourceId(0x01020000))
     34           .Build();
     35 
     36   std::unique_ptr<IAaptContext> context =
     37       test::ContextBuilder()
     38           .AddSymbolSource(
     39               util::make_unique<ResourceTableSymbolSource>(table.get()))
     40           .SetNameManglerPolicy(NameManglerPolicy{"android"})
     41           .Build();
     42   JavaClassGenerator generator(context.get(), table.get(), {});
     43 
     44   std::stringstream out;
     45   EXPECT_FALSE(generator.Generate("android", &out));
     46 }
     47 
     48 TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
     49   std::unique_ptr<ResourceTable> table =
     50       test::ResourceTableBuilder()
     51           .SetPackageId("android", 0x01)
     52           .AddSimple("android:id/hey-man", ResourceId(0x01020000))
     53           .AddValue("android:attr/cool.attr", ResourceId(0x01010000),
     54                     test::AttributeBuilder(false).Build())
     55           .AddValue(
     56               "android:styleable/hey.dude", ResourceId(0x01030000),
     57               test::StyleableBuilder()
     58                   .AddItem("android:attr/cool.attr", ResourceId(0x01010000))
     59                   .Build())
     60           .Build();
     61 
     62   std::unique_ptr<IAaptContext> context =
     63       test::ContextBuilder()
     64           .AddSymbolSource(
     65               util::make_unique<ResourceTableSymbolSource>(table.get()))
     66           .SetNameManglerPolicy(NameManglerPolicy{"android"})
     67           .Build();
     68   JavaClassGenerator generator(context.get(), table.get(), {});
     69 
     70   std::stringstream out;
     71   EXPECT_TRUE(generator.Generate("android", &out));
     72 
     73   std::string output = out.str();
     74 
     75   EXPECT_NE(std::string::npos,
     76             output.find("public static final int hey_man=0x01020000;"));
     77 
     78   EXPECT_NE(std::string::npos,
     79             output.find("public static final int[] hey_dude={"));
     80 
     81   EXPECT_NE(std::string::npos,
     82             output.find("public static final int hey_dude_cool_attr=0;"));
     83 }
     84 
     85 TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
     86   std::unique_ptr<ResourceTable> table =
     87       test::ResourceTableBuilder()
     88           .SetPackageId("android", 0x01)
     89           .AddSimple("android:id/one", ResourceId(0x01020000))
     90           .AddSimple("android:id/com.foo$two", ResourceId(0x01020001))
     91           .Build();
     92 
     93   std::unique_ptr<IAaptContext> context =
     94       test::ContextBuilder()
     95           .AddSymbolSource(
     96               util::make_unique<ResourceTableSymbolSource>(table.get()))
     97           .SetNameManglerPolicy(NameManglerPolicy{"android"})
     98           .Build();
     99   JavaClassGenerator generator(context.get(), table.get(), {});
    100   std::stringstream out;
    101   ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
    102 
    103   std::string output = out.str();
    104   EXPECT_NE(std::string::npos, output.find("package com.android.internal;"));
    105   EXPECT_NE(std::string::npos,
    106             output.find("public static final int one=0x01020000;"));
    107   EXPECT_EQ(std::string::npos, output.find("two"));
    108   EXPECT_EQ(std::string::npos, output.find("com_foo$two"));
    109 }
    110 
    111 TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
    112   std::unique_ptr<ResourceTable> table =
    113       test::ResourceTableBuilder()
    114           .SetPackageId("android", 0x01)
    115           .AddSimple("android:attr/two", ResourceId(0x01010001))
    116           .AddSimple("android:^attr-private/one", ResourceId(0x01010000))
    117           .Build();
    118 
    119   std::unique_ptr<IAaptContext> context =
    120       test::ContextBuilder()
    121           .AddSymbolSource(
    122               util::make_unique<ResourceTableSymbolSource>(table.get()))
    123           .SetNameManglerPolicy(NameManglerPolicy{"android"})
    124           .Build();
    125   JavaClassGenerator generator(context.get(), table.get(), {});
    126   std::stringstream out;
    127   ASSERT_TRUE(generator.Generate("android", &out));
    128 
    129   std::string output = out.str();
    130   EXPECT_NE(std::string::npos, output.find("public static final class attr"));
    131   EXPECT_EQ(std::string::npos,
    132             output.find("public static final class ^attr-private"));
    133 }
    134 
    135 TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
    136   StdErrDiagnostics diag;
    137   std::unique_ptr<ResourceTable> table =
    138       test::ResourceTableBuilder()
    139           .SetPackageId("android", 0x01)
    140           .AddSimple("android:id/one", ResourceId(0x01020000))
    141           .AddSimple("android:id/two", ResourceId(0x01020001))
    142           .AddSimple("android:id/three", ResourceId(0x01020002))
    143           .SetSymbolState("android:id/one", ResourceId(0x01020000),
    144                           SymbolState::kPublic)
    145           .SetSymbolState("android:id/two", ResourceId(0x01020001),
    146                           SymbolState::kPrivate)
    147           .Build();
    148 
    149   std::unique_ptr<IAaptContext> context =
    150       test::ContextBuilder()
    151           .AddSymbolSource(
    152               util::make_unique<ResourceTableSymbolSource>(table.get()))
    153           .SetNameManglerPolicy(NameManglerPolicy{"android"})
    154           .Build();
    155 
    156   JavaClassGeneratorOptions options;
    157   options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
    158   {
    159     JavaClassGenerator generator(context.get(), table.get(), options);
    160     std::stringstream out;
    161     ASSERT_TRUE(generator.Generate("android", &out));
    162     std::string output = out.str();
    163     EXPECT_NE(std::string::npos,
    164               output.find("public static final int one=0x01020000;"));
    165     EXPECT_EQ(std::string::npos, output.find("two"));
    166     EXPECT_EQ(std::string::npos, output.find("three"));
    167   }
    168 
    169   options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
    170   {
    171     JavaClassGenerator generator(context.get(), table.get(), options);
    172     std::stringstream out;
    173     ASSERT_TRUE(generator.Generate("android", &out));
    174     std::string output = out.str();
    175     EXPECT_NE(std::string::npos,
    176               output.find("public static final int one=0x01020000;"));
    177     EXPECT_NE(std::string::npos,
    178               output.find("public static final int two=0x01020001;"));
    179     EXPECT_EQ(std::string::npos, output.find("three"));
    180   }
    181 
    182   options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
    183   {
    184     JavaClassGenerator generator(context.get(), table.get(), options);
    185     std::stringstream out;
    186     ASSERT_TRUE(generator.Generate("android", &out));
    187     std::string output = out.str();
    188     EXPECT_NE(std::string::npos,
    189               output.find("public static final int one=0x01020000;"));
    190     EXPECT_NE(std::string::npos,
    191               output.find("public static final int two=0x01020001;"));
    192     EXPECT_NE(std::string::npos,
    193               output.find("public static final int three=0x01020002;"));
    194   }
    195 }
    196 
    197 /*
    198  * TODO(adamlesinski): Re-enable this once we get merging working again.
    199  * TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
    200     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"foo" },
    201                             ResourceId{ 0x01, 0x02, 0x0000 }));
    202     ResourceTable table;
    203     table.setPackage(u"com.lib");
    204     ASSERT_TRUE(table.addResource(ResourceName{ {}, ResourceType::kId, u"test"
    205 }, {},
    206                                   Source{ "lib.xml", 33 },
    207 util::make_unique<Id>()));
    208     ASSERT_TRUE(mTable->merge(std::move(table)));
    209 
    210     Linker linker(mTable,
    211                   std::make_shared<MockResolver>(mTable, std::map<ResourceName,
    212 ResourceId>()),
    213                   {});
    214     ASSERT_TRUE(linker.linkAndValidate());
    215 
    216     JavaClassGenerator generator(mTable, {});
    217 
    218     std::stringstream out;
    219     EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
    220     std::string output = out.str();
    221     EXPECT_NE(std::string::npos, output.find("int foo ="));
    222     EXPECT_EQ(std::string::npos, output.find("int test ="));
    223 
    224     out.str("");
    225     EXPECT_TRUE(generator.generate(u"com.lib", out));
    226     output = out.str();
    227     EXPECT_NE(std::string::npos, output.find("int test ="));
    228     EXPECT_EQ(std::string::npos, output.find("int foo ="));
    229 }*/
    230 
    231 TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
    232   std::unique_ptr<ResourceTable> table =
    233       test::ResourceTableBuilder()
    234           .SetPackageId("android", 0x01)
    235           .SetPackageId("com.lib", 0x02)
    236           .AddValue("android:attr/bar", ResourceId(0x01010000),
    237                     test::AttributeBuilder(false).Build())
    238           .AddValue("com.lib:attr/bar", ResourceId(0x02010000),
    239                     test::AttributeBuilder(false).Build())
    240           .AddValue("android:styleable/foo", ResourceId(0x01030000),
    241                     test::StyleableBuilder()
    242                         .AddItem("android:attr/bar", ResourceId(0x01010000))
    243                         .AddItem("com.lib:attr/bar", ResourceId(0x02010000))
    244                         .Build())
    245           .Build();
    246 
    247   std::unique_ptr<IAaptContext> context =
    248       test::ContextBuilder()
    249           .AddSymbolSource(
    250               util::make_unique<ResourceTableSymbolSource>(table.get()))
    251           .SetNameManglerPolicy(NameManglerPolicy{"android"})
    252           .Build();
    253   JavaClassGenerator generator(context.get(), table.get(), {});
    254 
    255   std::stringstream out;
    256   EXPECT_TRUE(generator.Generate("android", &out));
    257 
    258   std::string output = out.str();
    259   EXPECT_NE(std::string::npos, output.find("int foo_bar="));
    260   EXPECT_NE(std::string::npos, output.find("int foo_com_lib_bar="));
    261 }
    262 
    263 TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
    264   std::unique_ptr<ResourceTable> table =
    265       test::ResourceTableBuilder()
    266           .SetPackageId("android", 0x01)
    267           .AddSimple("android:id/foo", ResourceId(0x01010000))
    268           .Build();
    269   test::GetValue<Id>(table.get(), "android:id/foo")
    270       ->SetComment(std::string("This is a comment\n@deprecated"));
    271 
    272   std::unique_ptr<IAaptContext> context =
    273       test::ContextBuilder()
    274           .AddSymbolSource(
    275               util::make_unique<ResourceTableSymbolSource>(table.get()))
    276           .SetNameManglerPolicy(NameManglerPolicy{"android"})
    277           .Build();
    278   JavaClassGenerator generator(context.get(), table.get(), {});
    279   std::stringstream out;
    280   ASSERT_TRUE(generator.Generate("android", &out));
    281   std::string actual = out.str();
    282 
    283   const char* expectedText =
    284       R"EOF(/**
    285      * This is a comment
    286      * @deprecated
    287      */
    288     @Deprecated
    289     public static final int foo=0x01010000;)EOF";
    290 
    291   EXPECT_NE(std::string::npos, actual.find(expectedText));
    292 }
    293 
    294 TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {}
    295 
    296 TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
    297   Attribute attr(false);
    298   attr.SetComment(StringPiece("This is an attribute"));
    299 
    300   Styleable styleable;
    301   styleable.entries.push_back(
    302       Reference(test::ParseNameOrDie("android:attr/one")));
    303   styleable.SetComment(StringPiece("This is a styleable"));
    304 
    305   std::unique_ptr<ResourceTable> table =
    306       test::ResourceTableBuilder()
    307           .SetPackageId("android", 0x01)
    308           .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
    309           .AddValue("android:styleable/Container",
    310                     std::unique_ptr<Styleable>(styleable.Clone(nullptr)))
    311           .Build();
    312 
    313   std::unique_ptr<IAaptContext> context =
    314       test::ContextBuilder()
    315           .AddSymbolSource(
    316               util::make_unique<ResourceTableSymbolSource>(table.get()))
    317           .SetNameManglerPolicy(NameManglerPolicy{"android"})
    318           .Build();
    319   JavaClassGeneratorOptions options;
    320   options.use_final = false;
    321   JavaClassGenerator generator(context.get(), table.get(), options);
    322   std::stringstream out;
    323   ASSERT_TRUE(generator.Generate("android", &out));
    324   std::string actual = out.str();
    325 
    326   EXPECT_NE(std::string::npos, actual.find("attr name android:one"));
    327   EXPECT_NE(std::string::npos, actual.find("attr description"));
    328   EXPECT_NE(std::string::npos, actual.find(attr.GetComment().data()));
    329   EXPECT_NE(std::string::npos, actual.find(styleable.GetComment().data()));
    330 }
    331 
    332 TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
    333   Attribute attr(false);
    334   attr.SetComment(StringPiece("removed"));
    335 
    336   std::unique_ptr<ResourceTable> table =
    337       test::ResourceTableBuilder()
    338           .SetPackageId("android", 0x01)
    339           .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
    340           .Build();
    341 
    342   std::unique_ptr<IAaptContext> context =
    343       test::ContextBuilder()
    344           .AddSymbolSource(
    345               util::make_unique<ResourceTableSymbolSource>(table.get()))
    346           .SetNameManglerPolicy(NameManglerPolicy{"android"})
    347           .Build();
    348   JavaClassGeneratorOptions options;
    349   options.use_final = false;
    350   JavaClassGenerator generator(context.get(), table.get(), options);
    351   std::stringstream out;
    352   ASSERT_TRUE(generator.Generate("android", &out));
    353   std::string actual = out.str();
    354 
    355   EXPECT_EQ(std::string::npos, actual.find("@attr name android:one"));
    356   EXPECT_EQ(std::string::npos, actual.find("@attr description"));
    357 
    358   // We should find @removed only in the attribute javadoc and not anywhere else
    359   // (i.e. the class
    360   // javadoc).
    361   const size_t pos = actual.find("removed");
    362   EXPECT_NE(std::string::npos, pos);
    363   EXPECT_EQ(std::string::npos, actual.find("removed", pos + 1));
    364 }
    365 
    366 TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) {
    367   std::unique_ptr<ResourceTable> table =
    368       test::ResourceTableBuilder()
    369           .SetPackageId("android", 0x00)
    370           .AddValue("android:attr/foo", ResourceId(0x00010000), util::make_unique<Attribute>(false))
    371           .AddValue("android:id/foo", ResourceId(0x00020000), util::make_unique<Id>())
    372           .AddValue(
    373               "android:style/foo", ResourceId(0x00030000),
    374               test::StyleBuilder()
    375                   .AddItem("android:attr/foo", ResourceId(0x00010000), util::make_unique<Id>())
    376                   .Build())
    377           .Build();
    378 
    379   std::unique_ptr<IAaptContext> context =
    380       test::ContextBuilder().SetPackageId(0x00).SetCompilationPackage("android").Build();
    381 
    382   JavaClassGeneratorOptions options;
    383   options.use_final = false;
    384   options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{
    385       {"com.foo", "com.boo"},
    386   };
    387   JavaClassGenerator generator(context.get(), table.get(), options);
    388 
    389   std::stringstream out;
    390   ASSERT_TRUE(generator.Generate("android", &out));
    391 
    392   std::string actual = out.str();
    393 
    394   EXPECT_NE(std::string::npos, actual.find("void onResourcesLoaded"));
    395   EXPECT_NE(std::string::npos, actual.find("com.foo.R.onResourcesLoaded"));
    396   EXPECT_NE(std::string::npos, actual.find("com.boo.R.onResourcesLoaded"));
    397 }
    398 
    399 }  // namespace aapt
    400