/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ResourceTable.h" #include "ResourceValues.h" #include "Util.h" #include #include #include #include namespace aapt { struct TestValue : public Value { std::u16string value; TestValue(StringPiece16 str) : value(str.toString()) { } TestValue* clone(StringPool* /*newPool*/) const override { return new TestValue(value); } void print(std::ostream& out) const override { out << "(test) " << value; } virtual void accept(ValueVisitor&, ValueVisitorArgs&&) override {} virtual void accept(ConstValueVisitor&, ValueVisitorArgs&&) const override {} }; struct TestWeakValue : public Value { bool isWeak() const override { return true; } TestWeakValue* clone(StringPool* /*newPool*/) const override { return new TestWeakValue(); } void print(std::ostream& out) const override { out << "(test) [weak]"; } virtual void accept(ValueVisitor&, ValueVisitorArgs&&) override {} virtual void accept(ConstValueVisitor&, ValueVisitorArgs&&) const override {} }; TEST(ResourceTableTest, FailToAddResourceWithBadName) { ResourceTable table; table.setPackage(u"android"); EXPECT_FALSE(table.addResource( ResourceNameRef{ u"android", ResourceType::kId, u"hey,there" }, {}, SourceLine{ "test.xml", 21 }, util::make_unique(u"rawValue"))); EXPECT_FALSE(table.addResource( ResourceNameRef{ u"android", ResourceType::kId, u"hey:there" }, {}, SourceLine{ "test.xml", 21 }, util::make_unique(u"rawValue"))); } TEST(ResourceTableTest, AddOneResource) { const std::u16string kAndroidPackage = u"android"; ResourceTable table; table.setPackage(kAndroidPackage); const ResourceName name = { kAndroidPackage, ResourceType::kAttr, u"id" }; EXPECT_TRUE(table.addResource(name, {}, SourceLine{ "test/path/file.xml", 23 }, util::make_unique(u"rawValue"))); const ResourceTableType* type; const ResourceEntry* entry; std::tie(type, entry) = table.findResource(name); ASSERT_NE(nullptr, type); ASSERT_NE(nullptr, entry); EXPECT_EQ(name.entry, entry->name); ASSERT_NE(std::end(entry->values), std::find_if(std::begin(entry->values), std::end(entry->values), [](const ResourceConfigValue& val) -> bool { return val.config == ConfigDescription{}; })); } TEST(ResourceTableTest, AddMultipleResources) { const std::u16string kAndroidPackage = u"android"; ResourceTable table; table.setPackage(kAndroidPackage); ConfigDescription config; ConfigDescription languageConfig; memcpy(languageConfig.language, "pl", sizeof(languageConfig.language)); EXPECT_TRUE(table.addResource( ResourceName{ kAndroidPackage, ResourceType::kAttr, u"layout_width" }, config, SourceLine{ "test/path/file.xml", 10 }, util::make_unique(u"rawValue"))); EXPECT_TRUE(table.addResource( ResourceName{ kAndroidPackage, ResourceType::kAttr, u"id" }, config, SourceLine{ "test/path/file.xml", 12 }, util::make_unique(u"rawValue"))); EXPECT_TRUE(table.addResource( ResourceName{ kAndroidPackage, ResourceType::kString, u"ok" }, config, SourceLine{ "test/path/file.xml", 14 }, util::make_unique(u"Ok"))); EXPECT_TRUE(table.addResource( ResourceName{ kAndroidPackage, ResourceType::kString, u"ok" }, languageConfig, SourceLine{ "test/path/file.xml", 20 }, util::make_unique(u"Tak"))); const auto endTypeIter = std::end(table); auto typeIter = std::begin(table); ASSERT_NE(endTypeIter, typeIter); EXPECT_EQ(ResourceType::kAttr, (*typeIter)->type); { const std::unique_ptr& type = *typeIter; const auto endEntryIter = std::end(type->entries); auto entryIter = std::begin(type->entries); ASSERT_NE(endEntryIter, entryIter); EXPECT_EQ(std::u16string(u"id"), (*entryIter)->name); ++entryIter; ASSERT_NE(endEntryIter, entryIter); EXPECT_EQ(std::u16string(u"layout_width"), (*entryIter)->name); ++entryIter; ASSERT_EQ(endEntryIter, entryIter); } ++typeIter; ASSERT_NE(endTypeIter, typeIter); EXPECT_EQ(ResourceType::kString, (*typeIter)->type); { const std::unique_ptr& type = *typeIter; const auto endEntryIter = std::end(type->entries); auto entryIter = std::begin(type->entries); ASSERT_NE(endEntryIter, entryIter); EXPECT_EQ(std::u16string(u"ok"), (*entryIter)->name); { const std::unique_ptr& entry = *entryIter; const auto endConfigIter = std::end(entry->values); auto configIter = std::begin(entry->values); ASSERT_NE(endConfigIter, configIter); EXPECT_EQ(config, configIter->config); const TestValue* value = dynamic_cast(configIter->value.get()); ASSERT_NE(nullptr, value); EXPECT_EQ(std::u16string(u"Ok"), value->value); ++configIter; ASSERT_NE(endConfigIter, configIter); EXPECT_EQ(languageConfig, configIter->config); EXPECT_NE(nullptr, configIter->value); value = dynamic_cast(configIter->value.get()); ASSERT_NE(nullptr, value); EXPECT_EQ(std::u16string(u"Tak"), value->value); ++configIter; EXPECT_EQ(endConfigIter, configIter); } ++entryIter; ASSERT_EQ(endEntryIter, entryIter); } ++typeIter; EXPECT_EQ(endTypeIter, typeIter); } TEST(ResourceTableTest, OverrideWeakResourceValue) { const std::u16string kAndroid = u"android"; ResourceTable table; table.setPackage(kAndroid); table.setPackageId(0x01); ASSERT_TRUE(table.addResource( ResourceName{ kAndroid, ResourceType::kAttr, u"foo" }, {}, {}, util::make_unique())); const ResourceTableType* type; const ResourceEntry* entry; std::tie(type, entry) = table.findResource( ResourceNameRef{ kAndroid, ResourceType::kAttr, u"foo" }); ASSERT_NE(nullptr, type); ASSERT_NE(nullptr, entry); ASSERT_EQ(entry->values.size(), 1u); EXPECT_TRUE(entry->values.front().value->isWeak()); ASSERT_TRUE(table.addResource(ResourceName{ kAndroid, ResourceType::kAttr, u"foo" }, {}, {}, util::make_unique(u"bar"))); std::tie(type, entry) = table.findResource( ResourceNameRef{ kAndroid, ResourceType::kAttr, u"foo" }); ASSERT_NE(nullptr, type); ASSERT_NE(nullptr, entry); ASSERT_EQ(entry->values.size(), 1u); EXPECT_FALSE(entry->values.front().value->isWeak()); } } // namespace aapt