ManifestFixer_test.cpp revision 63699b128e009c65affe50995bd8f86eca1a8694
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
19#include "test/Test.h"
20
21using android::StringPiece;
22
23namespace aapt {
24
25struct ManifestFixerTest : public ::testing::Test {
26  std::unique_ptr<IAaptContext> mContext;
27
28  void SetUp() override {
29    mContext =
30        test::ContextBuilder()
31            .SetCompilationPackage("android")
32            .SetPackageId(0x01)
33            .SetNameManglerPolicy(NameManglerPolicy{"android"})
34            .AddSymbolSource(
35                test::StaticSymbolSourceBuilder()
36                    .AddSymbol(
37                        "android:attr/package", ResourceId(0x01010000),
38                        test::AttributeBuilder()
39                            .SetTypeMask(android::ResTable_map::TYPE_STRING)
40                            .Build())
41                    .AddSymbol(
42                        "android:attr/minSdkVersion", ResourceId(0x01010001),
43                        test::AttributeBuilder()
44                            .SetTypeMask(android::ResTable_map::TYPE_STRING |
45                                         android::ResTable_map::TYPE_INTEGER)
46                            .Build())
47                    .AddSymbol(
48                        "android:attr/targetSdkVersion", ResourceId(0x01010002),
49                        test::AttributeBuilder()
50                            .SetTypeMask(android::ResTable_map::TYPE_STRING |
51                                         android::ResTable_map::TYPE_INTEGER)
52                            .Build())
53                    .AddSymbol("android:string/str", ResourceId(0x01060000))
54                    .Build())
55            .Build();
56  }
57
58  std::unique_ptr<xml::XmlResource> Verify(const StringPiece& str) {
59    return VerifyWithOptions(str, {});
60  }
61
62  std::unique_ptr<xml::XmlResource> VerifyWithOptions(
63      const StringPiece& str, const ManifestFixerOptions& options) {
64    std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(str);
65    ManifestFixer fixer(options);
66    if (fixer.Consume(mContext.get(), doc.get())) {
67      return doc;
68    }
69    return {};
70  }
71};
72
73TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) {
74  EXPECT_EQ(nullptr, Verify("<other-tag />"));
75  EXPECT_EQ(nullptr, Verify("<ns:manifest xmlns:ns=\"com\" />"));
76  EXPECT_NE(nullptr, Verify("<manifest package=\"android\"></manifest>"));
77}
78
79TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
80  EXPECT_NE(nullptr, Verify("<manifest package=\"android\" />"));
81  EXPECT_NE(nullptr, Verify("<manifest package=\"com.android\" />"));
82  EXPECT_NE(nullptr, Verify("<manifest package=\"com.android.google\" />"));
83  EXPECT_EQ(nullptr,
84            Verify("<manifest package=\"com.android.google.Class$1\" />"));
85  EXPECT_EQ(nullptr, Verify("<manifest "
86                            "xmlns:android=\"http://schemas.android.com/apk/"
87                            "res/android\" "
88                            "android:package=\"com.android\" />"));
89  EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />"));
90}
91
92TEST_F(ManifestFixerTest, AllowMetaData) {
93  auto doc = Verify(R"EOF(
94        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
95                  package="android">
96          <meta-data />
97          <application>
98            <meta-data />
99            <activity android:name=".Hi"><meta-data /></activity>
100            <activity-alias android:name=".Ho"><meta-data /></activity-alias>
101            <receiver android:name=".OffTo"><meta-data /></receiver>
102            <provider android:name=".Work"><meta-data /></provider>
103            <service android:name=".We"><meta-data /></service>
104          </application>
105          <instrumentation android:name=".Go"><meta-data /></instrumentation>
106        </manifest>)EOF");
107  ASSERT_NE(nullptr, doc);
108}
109
110TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
111  ManifestFixerOptions options = {std::string("8"), std::string("22")};
112
113  std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
114      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
115                package="android">
116        <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
117      </manifest>)EOF",
118                                                            options);
119  ASSERT_NE(nullptr, doc);
120
121  xml::Element* el;
122  xml::Attribute* attr;
123
124  el = xml::FindRootElement(doc.get());
125  ASSERT_NE(nullptr, el);
126  el = el->FindChild({}, "uses-sdk");
127  ASSERT_NE(nullptr, el);
128  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
129  ASSERT_NE(nullptr, attr);
130  EXPECT_EQ("7", attr->value);
131  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
132  ASSERT_NE(nullptr, attr);
133  EXPECT_EQ("21", attr->value);
134
135  doc = VerifyWithOptions(R"EOF(
136      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
137                package="android">
138        <uses-sdk android:targetSdkVersion="21" />
139      </manifest>)EOF",
140                          options);
141  ASSERT_NE(nullptr, doc);
142
143  el = xml::FindRootElement(doc.get());
144  ASSERT_NE(nullptr, el);
145  el = el->FindChild({}, "uses-sdk");
146  ASSERT_NE(nullptr, el);
147  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
148  ASSERT_NE(nullptr, attr);
149  EXPECT_EQ("8", attr->value);
150  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
151  ASSERT_NE(nullptr, attr);
152  EXPECT_EQ("21", attr->value);
153
154  doc = VerifyWithOptions(R"EOF(
155      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
156                package="android">
157        <uses-sdk />
158      </manifest>)EOF",
159                          options);
160  ASSERT_NE(nullptr, doc);
161
162  el = xml::FindRootElement(doc.get());
163  ASSERT_NE(nullptr, el);
164  el = el->FindChild({}, "uses-sdk");
165  ASSERT_NE(nullptr, el);
166  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
167  ASSERT_NE(nullptr, attr);
168  EXPECT_EQ("8", attr->value);
169  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
170  ASSERT_NE(nullptr, attr);
171  EXPECT_EQ("22", attr->value);
172
173  doc = VerifyWithOptions(R"EOF(
174      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
175                package="android" />)EOF",
176                          options);
177  ASSERT_NE(nullptr, doc);
178
179  el = xml::FindRootElement(doc.get());
180  ASSERT_NE(nullptr, el);
181  el = el->FindChild({}, "uses-sdk");
182  ASSERT_NE(nullptr, el);
183  attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
184  ASSERT_NE(nullptr, attr);
185  EXPECT_EQ("8", attr->value);
186  attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
187  ASSERT_NE(nullptr, attr);
188  EXPECT_EQ("22", attr->value);
189}
190
191TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
192  ManifestFixerOptions options = {std::string("8"), std::string("22")};
193  std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
194          <manifest xmlns:android="http://schemas.android.com/apk/res/android"
195                    package="android">
196            <application android:name=".MainApplication" />
197          </manifest>)EOF",
198                                                            options);
199  ASSERT_NE(nullptr, doc);
200
201  xml::Element* manifest_el = xml::FindRootElement(doc.get());
202  ASSERT_NE(nullptr, manifest_el);
203  ASSERT_EQ("manifest", manifest_el->name);
204
205  xml::Element* application_el = manifest_el->FindChild("", "application");
206  ASSERT_NE(nullptr, application_el);
207
208  xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk");
209  ASSERT_NE(nullptr, uses_sdk_el);
210
211  // Check that the uses_sdk_el comes before application_el in the children
212  // vector.
213  // Since there are no namespaces here, these children are direct descendants
214  // of manifest.
215  auto uses_sdk_iter =
216      std::find_if(manifest_el->children.begin(), manifest_el->children.end(),
217                   [&](const std::unique_ptr<xml::Node>& child) {
218                     return child.get() == uses_sdk_el;
219                   });
220
221  auto application_iter =
222      std::find_if(manifest_el->children.begin(), manifest_el->children.end(),
223                   [&](const std::unique_ptr<xml::Node>& child) {
224                     return child.get() == application_el;
225                   });
226
227  ASSERT_NE(manifest_el->children.end(), uses_sdk_iter);
228  ASSERT_NE(manifest_el->children.end(), application_iter);
229
230  // The distance should be positive, meaning uses_sdk_iter comes before
231  // application_iter.
232  EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0);
233}
234
235TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
236  ManifestFixerOptions options;
237  options.rename_manifest_package = std::string("com.android");
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">
242        <application android:name=".MainApplication" text="hello">
243          <activity android:name=".activity.Start" />
244          <receiver android:name="com.google.android.Receiver" />
245        </application>
246      </manifest>)EOF",
247                                                            options);
248  ASSERT_NE(nullptr, doc);
249
250  xml::Element* manifestEl = xml::FindRootElement(doc.get());
251  ASSERT_NE(nullptr, manifestEl);
252
253  xml::Attribute* attr = nullptr;
254
255  attr = manifestEl->FindAttribute({}, "package");
256  ASSERT_NE(nullptr, attr);
257  EXPECT_EQ(std::string("com.android"), attr->value);
258
259  xml::Element* applicationEl = manifestEl->FindChild({}, "application");
260  ASSERT_NE(nullptr, applicationEl);
261
262  attr = applicationEl->FindAttribute(xml::kSchemaAndroid, "name");
263  ASSERT_NE(nullptr, attr);
264  EXPECT_EQ(std::string("android.MainApplication"), attr->value);
265
266  attr = applicationEl->FindAttribute({}, "text");
267  ASSERT_NE(nullptr, attr);
268  EXPECT_EQ(std::string("hello"), attr->value);
269
270  xml::Element* el;
271  el = applicationEl->FindChild({}, "activity");
272  ASSERT_NE(nullptr, el);
273
274  attr = el->FindAttribute(xml::kSchemaAndroid, "name");
275  ASSERT_NE(nullptr, el);
276  EXPECT_EQ(std::string("android.activity.Start"), attr->value);
277
278  el = applicationEl->FindChild({}, "receiver");
279  ASSERT_NE(nullptr, el);
280
281  attr = el->FindAttribute(xml::kSchemaAndroid, "name");
282  ASSERT_NE(nullptr, el);
283  EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value);
284}
285
286TEST_F(ManifestFixerTest,
287       RenameManifestInstrumentationPackageAndFullyQualifyTarget) {
288  ManifestFixerOptions options;
289  options.rename_instrumentation_target_package = std::string("com.android");
290
291  std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
292      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
293                package="android">
294        <instrumentation android:name=".TestRunner" android:targetPackage="android" />
295      </manifest>)EOF",
296                                                            options);
297  ASSERT_NE(nullptr, doc);
298
299  xml::Element* manifest_el = xml::FindRootElement(doc.get());
300  ASSERT_NE(nullptr, manifest_el);
301
302  xml::Element* instrumentation_el =
303      manifest_el->FindChild({}, "instrumentation");
304  ASSERT_NE(nullptr, instrumentation_el);
305
306  xml::Attribute* attr =
307      instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage");
308  ASSERT_NE(nullptr, attr);
309  EXPECT_EQ(std::string("com.android"), attr->value);
310}
311
312TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
313  ManifestFixerOptions options;
314  options.version_name_default = std::string("Beta");
315  options.version_code_default = std::string("0x10000000");
316
317  std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
318      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
319                package="android" />)EOF",
320                                                            options);
321  ASSERT_NE(nullptr, doc);
322
323  xml::Element* manifest_el = xml::FindRootElement(doc.get());
324  ASSERT_NE(nullptr, manifest_el);
325
326  xml::Attribute* attr =
327      manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
328  ASSERT_NE(nullptr, attr);
329  EXPECT_EQ(std::string("Beta"), attr->value);
330
331  attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
332  ASSERT_NE(nullptr, attr);
333  EXPECT_EQ(std::string("0x10000000"), attr->value);
334}
335
336TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
337  EXPECT_EQ(nullptr,
338            Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
339  EXPECT_EQ(nullptr,
340            Verify("<manifest package=\"android\" coreApp=\"1dp\" />"));
341
342  std::unique_ptr<xml::XmlResource> doc =
343      Verify("<manifest package=\"android\" coreApp=\"true\" />");
344  ASSERT_NE(nullptr, doc);
345
346  xml::Element* el = xml::FindRootElement(doc.get());
347  ASSERT_NE(nullptr, el);
348
349  EXPECT_EQ("manifest", el->name);
350
351  xml::Attribute* attr = el->FindAttribute("", "coreApp");
352  ASSERT_NE(nullptr, attr);
353
354  EXPECT_NE(nullptr, attr->compiled_value);
355  EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
356}
357
358TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
359  std::string input = R"EOF(
360        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
361                  package="android">
362          <uses-feature android:name="feature" />
363          <uses-feature android:glEsVersion="1" />
364          <feature-group />
365          <feature-group>
366            <uses-feature android:name="feature_in_group" />
367            <uses-feature android:glEsVersion="2" />
368          </feature-group>
369        </manifest>)EOF";
370  EXPECT_NE(nullptr, Verify(input));
371
372  input = R"EOF(
373        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
374                  package="android">
375          <uses-feature android:name="feature" android:glEsVersion="1" />
376        </manifest>)EOF";
377  EXPECT_EQ(nullptr, Verify(input));
378
379  input = R"EOF(
380        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
381                  package="android">
382          <uses-feature />
383        </manifest>)EOF";
384  EXPECT_EQ(nullptr, Verify(input));
385
386  input = R"EOF(
387        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
388                  package="android">
389          <feature-group>
390            <uses-feature android:name="feature" android:glEsVersion="1" />
391          </feature-group>
392        </manifest>)EOF";
393  EXPECT_EQ(nullptr, Verify(input));
394
395  input = R"EOF(
396        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
397                  package="android">
398          <feature-group>
399            <uses-feature />
400          </feature-group>
401        </manifest>)EOF";
402  EXPECT_EQ(nullptr, Verify(input));
403}
404
405TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
406  std::string input = R"EOF(
407      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
408                package="android">
409        <special:tag whoo="true" xmlns:special="http://google.com" />
410      </manifest>)EOF";
411  EXPECT_NE(nullptr, Verify(input));
412}
413
414TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
415  std::string input = R"EOF(
416      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
417                package="android">
418        <tag whoo="true" />
419      </manifest>)EOF";
420  EXPECT_EQ(nullptr, Verify(input));
421}
422
423}  // namespace aapt
424