Home | History | Annotate | Download | only in aapt2
      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 "ResourceTable.h"
     18 #include "Diagnostics.h"
     19 #include "ResourceValues.h"
     20 #include "test/Test.h"
     21 #include "util/Util.h"
     22 
     23 #include <algorithm>
     24 #include <ostream>
     25 #include <string>
     26 
     27 using ::android::StringPiece;
     28 using ::testing::Eq;
     29 using ::testing::NotNull;
     30 using ::testing::StrEq;
     31 
     32 namespace aapt {
     33 
     34 TEST(ResourceTableTest, FailToAddResourceWithBadName) {
     35   ResourceTable table;
     36 
     37   EXPECT_FALSE(table.AddResource(
     38       test::ParseNameOrDie("android:id/hey,there"), ConfigDescription{}, "",
     39       test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(),
     40       test::GetDiagnostics()));
     41 
     42   EXPECT_FALSE(table.AddResource(
     43       test::ParseNameOrDie("android:id/hey:there"), ConfigDescription{}, "",
     44       test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(),
     45       test::GetDiagnostics()));
     46 }
     47 
     48 TEST(ResourceTableTest, AddResourceWithWeirdNameWhenAddingMangledResources) {
     49   ResourceTable table;
     50 
     51   EXPECT_TRUE(table.AddResourceMangled(
     52       test::ParseNameOrDie("android:id/heythere       "), ConfigDescription{}, "",
     53       test::ValueBuilder<Id>().SetSource("test.xml", 21u).Build(), test::GetDiagnostics()));
     54 }
     55 
     56 TEST(ResourceTableTest, AddOneResource) {
     57   ResourceTable table;
     58 
     59   EXPECT_TRUE(table.AddResource(
     60       test::ParseNameOrDie("android:attr/id"), ConfigDescription{}, "",
     61       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 23u).Build(),
     62       test::GetDiagnostics()));
     63 
     64   EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/id"), NotNull());
     65 }
     66 
     67 TEST(ResourceTableTest, AddMultipleResources) {
     68   ResourceTable table;
     69 
     70   ConfigDescription config;
     71   ConfigDescription language_config;
     72   memcpy(language_config.language, "pl", sizeof(language_config.language));
     73 
     74   EXPECT_TRUE(table.AddResource(
     75       test::ParseNameOrDie("android:attr/layout_width"), config, "",
     76       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 10u).Build(),
     77       test::GetDiagnostics()));
     78 
     79   EXPECT_TRUE(table.AddResource(
     80       test::ParseNameOrDie("android:attr/id"), config, "",
     81       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 12u).Build(),
     82       test::GetDiagnostics()));
     83 
     84   EXPECT_TRUE(table.AddResource(
     85       test::ParseNameOrDie("android:string/ok"), config, "",
     86       test::ValueBuilder<Id>().SetSource("test/path/file.xml", 14u).Build(),
     87       test::GetDiagnostics()));
     88 
     89   EXPECT_TRUE(table.AddResource(
     90       test::ParseNameOrDie("android:string/ok"), language_config, "",
     91       test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
     92           .SetSource("test/path/file.xml", 20u)
     93           .Build(),
     94       test::GetDiagnostics()));
     95 
     96   EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/layout_width"), NotNull());
     97   EXPECT_THAT(test::GetValue<Id>(&table, "android:attr/id"), NotNull());
     98   EXPECT_THAT(test::GetValue<Id>(&table, "android:string/ok"), NotNull());
     99   EXPECT_THAT(test::GetValueForConfig<BinaryPrimitive>(&table, "android:string/ok", language_config), NotNull());
    100 }
    101 
    102 TEST(ResourceTableTest, OverrideWeakResourceValue) {
    103   ResourceTable table;
    104 
    105   ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
    106                                 test::AttributeBuilder().SetWeak(true).Build(),
    107                                 test::GetDiagnostics()));
    108 
    109   Attribute* attr = test::GetValue<Attribute>(&table, "android:attr/foo");
    110   ASSERT_THAT(attr, NotNull());
    111   EXPECT_TRUE(attr->IsWeak());
    112 
    113   ASSERT_TRUE(table.AddResource(test::ParseNameOrDie("android:attr/foo"), ConfigDescription{}, "",
    114                                 util::make_unique<Attribute>(), test::GetDiagnostics()));
    115 
    116   attr = test::GetValue<Attribute>(&table, "android:attr/foo");
    117   ASSERT_THAT(attr, NotNull());
    118   EXPECT_FALSE(attr->IsWeak());
    119 }
    120 
    121 TEST(ResourceTableTest, AllowCompatibleDuplicateAttributes) {
    122   ResourceTable table;
    123 
    124   const ResourceName name = test::ParseNameOrDie("android:attr/foo");
    125   Attribute attr_one(android::ResTable_map::TYPE_STRING);
    126   attr_one.SetWeak(true);
    127   Attribute attr_two(android::ResTable_map::TYPE_STRING | android::ResTable_map::TYPE_REFERENCE);
    128   attr_two.SetWeak(true);
    129 
    130   ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
    131                                 util::make_unique<Attribute>(attr_one), test::GetDiagnostics()));
    132   ASSERT_TRUE(table.AddResource(name, ConfigDescription{}, "",
    133                                 util::make_unique<Attribute>(attr_two), test::GetDiagnostics()));
    134 }
    135 
    136 TEST(ResourceTableTest, ProductVaryingValues) {
    137   ResourceTable table;
    138 
    139   EXPECT_TRUE(table.AddResource(test::ParseNameOrDie("android:string/foo"),
    140                                 test::ParseConfigOrDie("land"), "tablet",
    141                                 util::make_unique<Id>(),
    142                                 test::GetDiagnostics()));
    143   EXPECT_TRUE(table.AddResource(test::ParseNameOrDie("android:string/foo"),
    144                                 test::ParseConfigOrDie("land"), "phone",
    145                                 util::make_unique<Id>(),
    146                                 test::GetDiagnostics()));
    147 
    148   EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "tablet"), NotNull());
    149   EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "phone"), NotNull());
    150 
    151   Maybe<ResourceTable::SearchResult> sr =
    152       table.FindResource(test::ParseNameOrDie("android:string/foo"));
    153   ASSERT_TRUE(sr);
    154   std::vector<ResourceConfigValue*> values =
    155       sr.value().entry->FindAllValues(test::ParseConfigOrDie("land"));
    156   ASSERT_EQ(2u, values.size());
    157   EXPECT_EQ(std::string("phone"), values[0]->product);
    158   EXPECT_EQ(std::string("tablet"), values[1]->product);
    159 }
    160 
    161 static StringPiece LevelToString(Visibility::Level level) {
    162   switch (level) {
    163     case Visibility::Level::kPrivate:
    164       return "private";
    165     case Visibility::Level::kPublic:
    166       return "private";
    167     default:
    168       return "undefined";
    169   }
    170 }
    171 
    172 static ::testing::AssertionResult VisibilityOfResource(const ResourceTable& table,
    173                                                        const ResourceNameRef& name,
    174                                                        Visibility::Level level,
    175                                                        const StringPiece& comment) {
    176   Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
    177   if (!result) {
    178     return ::testing::AssertionFailure() << "no resource '" << name << "' found in table";
    179   }
    180 
    181   const Visibility& visibility = result.value().entry->visibility;
    182   if (visibility.level != level) {
    183     return ::testing::AssertionFailure() << "expected visibility " << LevelToString(level)
    184                                          << " but got " << LevelToString(visibility.level);
    185   }
    186 
    187   if (visibility.comment != comment) {
    188     return ::testing::AssertionFailure() << "expected visibility comment '" << comment
    189                                          << "' but got '" << visibility.comment << "'";
    190   }
    191   return ::testing::AssertionSuccess();
    192 }
    193 
    194 TEST(ResourceTableTest, SetVisibility) {
    195   using Level = Visibility::Level;
    196 
    197   ResourceTable table;
    198   const ResourceName name = test::ParseNameOrDie("android:string/foo");
    199 
    200   Visibility visibility;
    201   visibility.level = Visibility::Level::kPrivate;
    202   visibility.comment = "private";
    203   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
    204   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPrivate, "private"));
    205 
    206   visibility.level = Visibility::Level::kUndefined;
    207   visibility.comment = "undefined";
    208   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
    209   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPrivate, "private"));
    210 
    211   visibility.level = Visibility::Level::kPublic;
    212   visibility.comment = "public";
    213   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
    214   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPublic, "public"));
    215 
    216   visibility.level = Visibility::Level::kPrivate;
    217   visibility.comment = "private";
    218   ASSERT_TRUE(table.SetVisibility(name, visibility, test::GetDiagnostics()));
    219   ASSERT_TRUE(VisibilityOfResource(table, name, Level::kPublic, "public"));
    220 }
    221 
    222 TEST(ResourceTableTest, SetAllowNew) {
    223   ResourceTable table;
    224   const ResourceName name = test::ParseNameOrDie("android:string/foo");
    225 
    226   AllowNew allow_new;
    227   Maybe<ResourceTable::SearchResult> result;
    228 
    229   allow_new.comment = "first";
    230   ASSERT_TRUE(table.SetAllowNew(name, allow_new, test::GetDiagnostics()));
    231   result = table.FindResource(name);
    232   ASSERT_TRUE(result);
    233   ASSERT_TRUE(result.value().entry->allow_new);
    234   ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("first"));
    235 
    236   allow_new.comment = "second";
    237   ASSERT_TRUE(table.SetAllowNew(name, allow_new, test::GetDiagnostics()));
    238   result = table.FindResource(name);
    239   ASSERT_TRUE(result);
    240   ASSERT_TRUE(result.value().entry->allow_new);
    241   ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second"));
    242 }
    243 
    244 TEST(ResourceTableTest, SetOverlayable) {
    245   ResourceTable table;
    246   const ResourceName name = test::ParseNameOrDie("android:string/foo");
    247 
    248   Overlayable overlayable;
    249 
    250   overlayable.comment = "first";
    251   ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
    252   Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
    253   ASSERT_TRUE(result);
    254   ASSERT_TRUE(result.value().entry->overlayable);
    255   ASSERT_THAT(result.value().entry->overlayable.value().comment, StrEq("first"));
    256 
    257   overlayable.comment = "second";
    258   ASSERT_FALSE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
    259 }
    260 
    261 }  // namespace aapt
    262