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