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 "link/ManifestFixer.h"
18#include "test/Builders.h"
19#include "test/Context.h"
20
21#include <gtest/gtest.h>
22
23namespace aapt {
24
25struct ManifestFixerTest : public ::testing::Test {
26    std::unique_ptr<IAaptContext> mContext;
27
28    void SetUp() override {
29        mContext = test::ContextBuilder()
30                .setCompilationPackage(u"android")
31                .setPackageId(0x01)
32                .setNameManglerPolicy(NameManglerPolicy{ u"android" })
33                .addSymbolSource(test::StaticSymbolSourceBuilder()
34                        .addSymbol(u"@android:attr/package", ResourceId(0x01010000),
35                                   test::AttributeBuilder()
36                                        .setTypeMask(android::ResTable_map::TYPE_STRING)
37                                        .build())
38                        .addSymbol(u"@android:attr/minSdkVersion", ResourceId(0x01010001),
39                                   test::AttributeBuilder()
40                                        .setTypeMask(android::ResTable_map::TYPE_STRING |
41                                                     android::ResTable_map::TYPE_INTEGER)
42                                        .build())
43                        .addSymbol(u"@android:attr/targetSdkVersion", ResourceId(0x01010002),
44                                   test::AttributeBuilder()
45                                        .setTypeMask(android::ResTable_map::TYPE_STRING |
46                                                     android::ResTable_map::TYPE_INTEGER)
47                                        .build())
48                        .addSymbol(u"@android:string/str", ResourceId(0x01060000))
49                        .build())
50                .build();
51    }
52
53    std::unique_ptr<xml::XmlResource> verify(const StringPiece& str) {
54        return verifyWithOptions(str, {});
55    }
56
57    std::unique_ptr<xml::XmlResource> verifyWithOptions(const StringPiece& str,
58                                                        const ManifestFixerOptions& options) {
59        std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(str);
60        ManifestFixer fixer(options);
61        if (fixer.consume(mContext.get(), doc.get())) {
62            return doc;
63        }
64        return {};
65    }
66};
67
68TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) {
69    EXPECT_EQ(nullptr, verify("<other-tag />"));
70    EXPECT_EQ(nullptr, verify("<ns:manifest xmlns:ns=\"com\" />"));
71    EXPECT_NE(nullptr, verify("<manifest package=\"android\"></manifest>"));
72}
73
74TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
75    EXPECT_NE(nullptr, verify("<manifest package=\"android\" />"));
76    EXPECT_NE(nullptr, verify("<manifest package=\"com.android\" />"));
77    EXPECT_NE(nullptr, verify("<manifest package=\"com.android.google\" />"));
78    EXPECT_EQ(nullptr, verify("<manifest package=\"com.android.google.Class$1\" />"));
79    EXPECT_EQ(nullptr,
80              verify("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
81                     "android:package=\"com.android\" />"));
82    EXPECT_EQ(nullptr, verify("<manifest package=\"@string/str\" />"));
83}
84
85TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
86    ManifestFixerOptions options = { std::u16string(u"8"), std::u16string(u"22") };
87
88    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
89      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
90                package="android">
91        <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
92      </manifest>)EOF", options);
93    ASSERT_NE(nullptr, doc);
94
95    xml::Element* el;
96    xml::Attribute* attr;
97
98    el = xml::findRootElement(doc.get());
99    ASSERT_NE(nullptr, el);
100    el = el->findChild({}, u"uses-sdk");
101    ASSERT_NE(nullptr, el);
102    attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
103    ASSERT_NE(nullptr, attr);
104    EXPECT_EQ(u"7", attr->value);
105    attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
106    ASSERT_NE(nullptr, attr);
107    EXPECT_EQ(u"21", attr->value);
108
109    doc = verifyWithOptions(R"EOF(
110      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
111                package="android">
112        <uses-sdk android:targetSdkVersion="21" />
113      </manifest>)EOF", options);
114    ASSERT_NE(nullptr, doc);
115
116    el = xml::findRootElement(doc.get());
117    ASSERT_NE(nullptr, el);
118    el = el->findChild({}, u"uses-sdk");
119    ASSERT_NE(nullptr, el);
120    attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
121    ASSERT_NE(nullptr, attr);
122    EXPECT_EQ(u"8", attr->value);
123    attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
124    ASSERT_NE(nullptr, attr);
125    EXPECT_EQ(u"21", attr->value);
126
127    doc = verifyWithOptions(R"EOF(
128      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
129                package="android">
130        <uses-sdk />
131      </manifest>)EOF", options);
132    ASSERT_NE(nullptr, doc);
133
134    el = xml::findRootElement(doc.get());
135    ASSERT_NE(nullptr, el);
136    el = el->findChild({}, u"uses-sdk");
137    ASSERT_NE(nullptr, el);
138    attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
139    ASSERT_NE(nullptr, attr);
140    EXPECT_EQ(u"8", attr->value);
141    attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
142    ASSERT_NE(nullptr, attr);
143    EXPECT_EQ(u"22", attr->value);
144
145    doc = verifyWithOptions(R"EOF(
146      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
147                package="android" />)EOF", options);
148    ASSERT_NE(nullptr, doc);
149
150    el = xml::findRootElement(doc.get());
151    ASSERT_NE(nullptr, el);
152    el = el->findChild({}, u"uses-sdk");
153    ASSERT_NE(nullptr, el);
154    attr = el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion");
155    ASSERT_NE(nullptr, attr);
156    EXPECT_EQ(u"8", attr->value);
157    attr = el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion");
158    ASSERT_NE(nullptr, attr);
159    EXPECT_EQ(u"22", attr->value);
160}
161
162TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
163    ManifestFixerOptions options;
164    options.renameManifestPackage = std::u16string(u"com.android");
165
166    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
167      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
168                package="android">
169        <application android:name=".MainApplication" text="hello">
170          <activity android:name=".activity.Start" />
171          <receiver android:name="com.google.android.Receiver" />
172        </application>
173      </manifest>)EOF", options);
174    ASSERT_NE(nullptr, doc);
175
176    xml::Element* manifestEl = xml::findRootElement(doc.get());
177    ASSERT_NE(nullptr, manifestEl);
178
179    xml::Attribute* attr = nullptr;
180
181    attr = manifestEl->findAttribute({}, u"package");
182    ASSERT_NE(nullptr, attr);
183    EXPECT_EQ(std::u16string(u"com.android"), attr->value);
184
185    xml::Element* applicationEl = manifestEl->findChild({}, u"application");
186    ASSERT_NE(nullptr, applicationEl);
187
188    attr = applicationEl->findAttribute(xml::kSchemaAndroid, u"name");
189    ASSERT_NE(nullptr, attr);
190    EXPECT_EQ(std::u16string(u"android.MainApplication"), attr->value);
191
192    attr = applicationEl->findAttribute({}, u"text");
193    ASSERT_NE(nullptr, attr);
194    EXPECT_EQ(std::u16string(u"hello"), attr->value);
195
196    xml::Element* el;
197    el = applicationEl->findChild({}, u"activity");
198    ASSERT_NE(nullptr, el);
199
200    attr = el->findAttribute(xml::kSchemaAndroid, u"name");
201    ASSERT_NE(nullptr, el);
202    EXPECT_EQ(std::u16string(u"android.activity.Start"), attr->value);
203
204    el = applicationEl->findChild({}, u"receiver");
205    ASSERT_NE(nullptr, el);
206
207    attr = el->findAttribute(xml::kSchemaAndroid, u"name");
208    ASSERT_NE(nullptr, el);
209    EXPECT_EQ(std::u16string(u"com.google.android.Receiver"), attr->value);
210}
211
212TEST_F(ManifestFixerTest, RenameManifestInstrumentationPackageAndFullyQualifyTarget) {
213    ManifestFixerOptions options;
214    options.renameInstrumentationTargetPackage = std::u16string(u"com.android");
215
216    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
217      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
218                package="android">
219        <instrumentation android:targetPackage="android" />
220      </manifest>)EOF", options);
221    ASSERT_NE(nullptr, doc);
222
223    xml::Element* manifestEl = xml::findRootElement(doc.get());
224    ASSERT_NE(nullptr, manifestEl);
225
226    xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
227    ASSERT_NE(nullptr, instrumentationEl);
228
229    xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
230    ASSERT_NE(nullptr, attr);
231    EXPECT_EQ(std::u16string(u"com.android"), attr->value);
232}
233
234TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
235    ManifestFixerOptions options;
236    options.versionNameDefault = std::u16string(u"Beta");
237    options.versionCodeDefault = std::u16string(u"0x10000000");
238
239    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
240      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
241                package="android" />)EOF", options);
242    ASSERT_NE(nullptr, doc);
243
244    xml::Element* manifestEl = xml::findRootElement(doc.get());
245    ASSERT_NE(nullptr, manifestEl);
246
247    xml::Attribute* attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName");
248    ASSERT_NE(nullptr, attr);
249    EXPECT_EQ(std::u16string(u"Beta"), attr->value);
250
251    attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode");
252    ASSERT_NE(nullptr, attr);
253    EXPECT_EQ(std::u16string(u"0x10000000"), attr->value);
254}
255
256} // namespace aapt
257