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 "filter/ConfigFilter.h" 18#include "io/FileSystem.h" 19#include "link/TableMerger.h" 20#include "test/Builders.h" 21#include "test/Context.h" 22 23#include <gtest/gtest.h> 24 25namespace aapt { 26 27struct TableMergerTest : public ::testing::Test { 28 std::unique_ptr<IAaptContext> mContext; 29 30 void SetUp() override { 31 mContext = test::ContextBuilder() 32 // We are compiling this package. 33 .setCompilationPackage(u"com.app.a") 34 35 // Merge all packages that have this package ID. 36 .setPackageId(0x7f) 37 38 // Mangle all packages that do not have this package name. 39 .setNameManglerPolicy(NameManglerPolicy{ u"com.app.a", { u"com.app.b" } }) 40 41 .build(); 42 } 43}; 44 45TEST_F(TableMergerTest, SimpleMerge) { 46 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder() 47 .setPackageId(u"com.app.a", 0x7f) 48 .addReference(u"@com.app.a:id/foo", u"@com.app.a:id/bar") 49 .addReference(u"@com.app.a:id/bar", u"@com.app.b:id/foo") 50 .addValue(u"@com.app.a:styleable/view", test::StyleableBuilder() 51 .addItem(u"@com.app.b:id/foo") 52 .build()) 53 .build(); 54 55 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder() 56 .setPackageId(u"com.app.b", 0x7f) 57 .addSimple(u"@com.app.b:id/foo") 58 .build(); 59 60 ResourceTable finalTable; 61 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{}); 62 io::FileCollection collection; 63 64 ASSERT_TRUE(merger.merge({}, tableA.get())); 65 ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection)); 66 67 EXPECT_TRUE(merger.getMergedPackages().count(u"com.app.b") != 0); 68 69 // Entries from com.app.a should not be mangled. 70 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/foo"))); 71 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/bar"))); 72 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:styleable/view"))); 73 74 // The unmangled name should not be present. 75 AAPT_EXPECT_FALSE(finalTable.findResource(test::parseNameOrDie(u"@com.app.b:id/foo"))); 76 77 // Look for the mangled name. 78 AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/com.app.b$foo"))); 79} 80 81TEST_F(TableMergerTest, MergeFile) { 82 ResourceTable finalTable; 83 TableMergerOptions options; 84 options.autoAddOverlay = false; 85 TableMerger merger(mContext.get(), &finalTable, options); 86 87 ResourceFile fileDesc; 88 fileDesc.config = test::parseConfigOrDie("hdpi-v4"); 89 fileDesc.name = test::parseNameOrDie(u"@layout/main"); 90 fileDesc.source = Source("res/layout-hdpi/main.xml"); 91 test::TestFile testFile("path/to/res/layout-hdpi/main.xml.flat"); 92 93 ASSERT_TRUE(merger.mergeFile(fileDesc, &testFile)); 94 95 FileReference* file = test::getValueForConfig<FileReference>(&finalTable, 96 u"@com.app.a:layout/main", 97 test::parseConfigOrDie("hdpi-v4")); 98 ASSERT_NE(nullptr, file); 99 EXPECT_EQ(std::u16string(u"res/layout-hdpi-v4/main.xml"), *file->path); 100} 101 102TEST_F(TableMergerTest, MergeFileOverlay) { 103 ResourceTable finalTable; 104 TableMergerOptions tableMergerOptions; 105 tableMergerOptions.autoAddOverlay = false; 106 TableMerger merger(mContext.get(), &finalTable, tableMergerOptions); 107 108 ResourceFile fileDesc; 109 fileDesc.name = test::parseNameOrDie(u"@xml/foo"); 110 test::TestFile fileA("path/to/fileA.xml.flat"); 111 test::TestFile fileB("path/to/fileB.xml.flat"); 112 113 ASSERT_TRUE(merger.mergeFile(fileDesc, &fileA)); 114 ASSERT_TRUE(merger.mergeFileOverlay(fileDesc, &fileB)); 115} 116 117TEST_F(TableMergerTest, MergeFileReferences) { 118 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder() 119 .setPackageId(u"com.app.a", 0x7f) 120 .addFileReference(u"@com.app.a:xml/file", u"res/xml/file.xml") 121 .build(); 122 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder() 123 .setPackageId(u"com.app.b", 0x7f) 124 .addFileReference(u"@com.app.b:xml/file", u"res/xml/file.xml") 125 .build(); 126 127 ResourceTable finalTable; 128 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{}); 129 io::FileCollection collection; 130 collection.insertFile("res/xml/file.xml"); 131 132 ASSERT_TRUE(merger.merge({}, tableA.get())); 133 ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection)); 134 135 FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file"); 136 ASSERT_NE(f, nullptr); 137 EXPECT_EQ(std::u16string(u"res/xml/file.xml"), *f->path); 138 139 f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/com.app.b$file"); 140 ASSERT_NE(f, nullptr); 141 EXPECT_EQ(std::u16string(u"res/xml/com.app.b$file.xml"), *f->path); 142} 143 144TEST_F(TableMergerTest, OverrideResourceWithOverlay) { 145 std::unique_ptr<ResourceTable> base = test::ResourceTableBuilder() 146 .setPackageId(u"", 0x00) 147 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true")) 148 .build(); 149 std::unique_ptr<ResourceTable> overlay = test::ResourceTableBuilder() 150 .setPackageId(u"", 0x00) 151 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"false")) 152 .build(); 153 154 ResourceTable finalTable; 155 TableMergerOptions tableMergerOptions; 156 tableMergerOptions.autoAddOverlay = false; 157 TableMerger merger(mContext.get(), &finalTable, tableMergerOptions); 158 159 ASSERT_TRUE(merger.merge({}, base.get())); 160 ASSERT_TRUE(merger.mergeOverlay({}, overlay.get())); 161 162 BinaryPrimitive* foo = test::getValue<BinaryPrimitive>(&finalTable, u"@com.app.a:bool/foo"); 163 ASSERT_NE(nullptr, foo); 164 EXPECT_EQ(0x0u, foo->value.data); 165} 166 167TEST_F(TableMergerTest, MergeAddResourceFromOverlay) { 168 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder() 169 .setPackageId(u"", 0x7f) 170 .setSymbolState(u"@bool/foo", {}, SymbolState::kUndefined) 171 .build(); 172 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder() 173 .setPackageId(u"", 0x7f) 174 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true")) 175 .build(); 176 177 ResourceTable finalTable; 178 TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{}); 179 180 ASSERT_TRUE(merger.merge({}, tableA.get())); 181 ASSERT_TRUE(merger.mergeOverlay({}, tableB.get())); 182} 183 184TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) { 185 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder() 186 .setPackageId(u"", 0x7f) 187 .build(); 188 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder() 189 .setPackageId(u"", 0x7f) 190 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true")) 191 .build(); 192 193 ResourceTable finalTable; 194 TableMergerOptions options; 195 options.autoAddOverlay = true; 196 TableMerger merger(mContext.get(), &finalTable, options); 197 198 ASSERT_TRUE(merger.merge({}, tableA.get())); 199 ASSERT_TRUE(merger.mergeOverlay({}, tableB.get())); 200} 201 202TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) { 203 std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder() 204 .setPackageId(u"", 0x7f) 205 .build(); 206 std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder() 207 .setPackageId(u"", 0x7f) 208 .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true")) 209 .build(); 210 211 ResourceTable finalTable; 212 TableMergerOptions options; 213 options.autoAddOverlay = false; 214 TableMerger merger(mContext.get(), &finalTable, options); 215 216 ASSERT_TRUE(merger.merge({}, tableA.get())); 217 ASSERT_FALSE(merger.mergeOverlay({}, tableB.get())); 218} 219 220} // namespace aapt 221