16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Linker.h" 186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h" 1924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski#include "ResourceTableResolver.h" 206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h" 216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Util.h" 226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <androidfw/AssetManager.h> 246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <gtest/gtest.h> 256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string> 266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistruct LinkerTest : public ::testing::Test { 306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski virtual void SetUp() override { 316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTable = std::make_shared<ResourceTable>(); 326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTable->setPackage(u"android"); 33769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski mTable->setPackageId(0x01); 3424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski mLinker = std::make_shared<Linker>(mTable, std::make_shared<ResourceTableResolver>( 35330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski mTable, std::vector<std::shared_ptr<const android::AssetManager>>()), 36330edcdf1316ed599fe0eb16a64330821fd92f18Adam Lesinski Linker::Options{}); 376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Create a few attributes for use in the tests. 396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski addResource(ResourceName{ {}, ResourceType::kAttr, u"integer" }, 416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<Attribute>(false, android::ResTable_map::TYPE_INTEGER)); 426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski addResource(ResourceName{ {}, ResourceType::kAttr, u"string" }, 446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<Attribute>(false, android::ResTable_map::TYPE_STRING)); 456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski addResource(ResourceName{ {}, ResourceType::kId, u"apple" }, util::make_unique<Id>()); 476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski addResource(ResourceName{ {}, ResourceType::kId, u"banana" }, util::make_unique<Id>()); 496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::unique_ptr<Attribute> flagAttr = util::make_unique<Attribute>( 516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski false, android::ResTable_map::TYPE_FLAGS); 526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski flagAttr->symbols.push_back(Attribute::Symbol{ 536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ResourceNameRef{ u"android", ResourceType::kId, u"apple" }, 1 }); 546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski flagAttr->symbols.push_back(Attribute::Symbol{ 556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ResourceNameRef{ u"android", ResourceType::kId, u"banana" }, 2 }); 566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski addResource(ResourceName{ {}, ResourceType::kAttr, u"flags" }, std::move(flagAttr)); 576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski /* 606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Convenience method for adding resources with the default configuration and some 616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * bogus source line. 626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski bool addResource(const ResourceNameRef& name, std::unique_ptr<Value> value) { 646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return mTable->addResource(name, {}, SourceLine{ "test.xml", 21 }, std::move(value)); 656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::shared_ptr<ResourceTable> mTable; 686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::shared_ptr<Linker> mLinker; 696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}; 706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(LinkerTest, DoNotInterpretEscapedStringAsReference) { 726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kString, u"foo" }, 736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<String>(mTable->getValueStringPool().makeRef(u"?123")))); 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(mLinker->linkAndValidate()); 766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_TRUE(mLinker->getUnresolvedReferences().empty()); 776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(LinkerTest, EscapeAndConvertRawString) { 80bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::unique_ptr<Style> style = util::make_unique<Style>(); 816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski style->entries.push_back(Style::Entry{ 826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ResourceNameRef{ u"android", ResourceType::kAttr, u"integer" }, 836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u" 123")) 846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski }); 856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const Style* result = style.get(); 866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" }, 876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::move(style))); 886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(mLinker->linkAndValidate()); 906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_TRUE(mLinker->getUnresolvedReferences().empty()); 916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_NE(nullptr, dynamic_cast<BinaryPrimitive*>(result->entries.front().value.get())); 936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(LinkerTest, FailToConvertRawString) { 96bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::unique_ptr<Style> style = util::make_unique<Style>(); 976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski style->entries.push_back(Style::Entry{ 986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ResourceNameRef{ u"android", ResourceType::kAttr, u"integer" }, 996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"yo what is up?")) 1006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski }); 1016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" }, 1026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::move(style))); 1036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_FALSE(mLinker->linkAndValidate()); 1056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(LinkerTest, ConvertRawStringToString) { 108bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::unique_ptr<Style> style = util::make_unique<Style>(); 1096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski style->entries.push_back(Style::Entry{ 1106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ResourceNameRef{ u"android", ResourceType::kAttr, u"string" }, 1116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<RawString>( 1126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski mTable->getValueStringPool().makeRef(u" \"this is \\u00fa\".")) 1136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski }); 1146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const Style* result = style.get(); 1156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" }, 1166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::move(style))); 1176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(mLinker->linkAndValidate()); 1196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_TRUE(mLinker->getUnresolvedReferences().empty()); 1206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const String* str = dynamic_cast<const String*>(result->entries.front().value.get()); 1226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, str); 1236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(*str->value, u"this is \u00fa."); 1246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(LinkerTest, ConvertRawStringToFlags) { 127bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::unique_ptr<Style> style = util::make_unique<Style>(); 1286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski style->entries.push_back(Style::Entry{ 1296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ResourceNameRef{ u"android", ResourceType::kAttr, u"flags" }, 1306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"banana | apple")) 1316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski }); 1326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const Style* result = style.get(); 1336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" }, 1346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::move(style))); 1356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(mLinker->linkAndValidate()); 1376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_TRUE(mLinker->getUnresolvedReferences().empty()); 1386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const BinaryPrimitive* bin = dynamic_cast<const BinaryPrimitive*>( 1406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski result->entries.front().value.get()); 1416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, bin); 1426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(bin->value.data, 1u | 2u); 1436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 145769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(LinkerTest, AllowReferenceWithOnlyResourceIdPointingToDifferentPackage) { 146769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kInteger, u"foo" }, 147769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski util::make_unique<Reference>(ResourceId{ 0x02, 0x01, 0x01 }))); 148769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 149769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski ASSERT_TRUE(mLinker->linkAndValidate()); 150769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski EXPECT_TRUE(mLinker->getUnresolvedReferences().empty()); 151769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 152769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 1536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt 154