1c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski/*
2c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * Copyright (C) 2017 The Android Open Source Project
3c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski *
4c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * you may not use this file except in compliance with the License.
6c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * You may obtain a copy of the License at
7c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski *
8c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski *
10c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * Unless required by applicable law or agreed to in writing, software
11c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * See the License for the specific language governing permissions and
14c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * limitations under the License.
15c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski */
16c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
17c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski#include "link/XmlCompatVersioner.h"
18c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
19c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski#include "Linkers.h"
20c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski#include "test/Test.h"
21c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
22c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinskinamespace aapt {
23c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
24c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinskiconstexpr auto TYPE_DIMENSION = android::ResTable_map::TYPE_DIMENSION;
25c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinskiconstexpr auto TYPE_STRING = android::ResTable_map::TYPE_STRING;
26c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
27c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinskistruct R {
28c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  struct attr {
29c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski    enum : uint32_t {
30c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      paddingLeft = 0x010100d6u,         // (API 1)
31c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      paddingRight = 0x010100d8u,        // (API 1)
32c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      progressBarPadding = 0x01010319u,  // (API 11)
33c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      paddingStart = 0x010103b3u,        // (API 17)
34c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      paddingHorizontal = 0x0101053du,   // (API 26)
35c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski    };
36c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  };
37c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski};
38c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
39c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinskiclass XmlCompatVersionerTest : public ::testing::Test {
40c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski public:
41c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  void SetUp() override {
42c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski    context_ =
43c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski        test::ContextBuilder()
44c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski            .SetCompilationPackage("com.app")
45c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski            .SetPackageId(0x7f)
46c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski            .SetPackageType(PackageType::kApp)
47c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski            .SetMinSdkVersion(SDK_GINGERBREAD)
48c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski            .AddSymbolSource(
49c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                test::StaticSymbolSourceBuilder()
50c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .AddPublicSymbol("android:attr/paddingLeft", R::attr::paddingLeft,
51c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
52c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .AddPublicSymbol("android:attr/paddingRight", R::attr::paddingRight,
53c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
54c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .AddPublicSymbol("android:attr/progressBarPadding", R::attr::progressBarPadding,
55c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
56c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .AddPublicSymbol("android:attr/paddingStart", R::attr::paddingStart,
57c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
58c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .AddPublicSymbol("android:attr/paddingHorizontal", R::attr::paddingHorizontal,
59c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                     util::make_unique<Attribute>(false, TYPE_DIMENSION))
60c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .AddSymbol("com.app:attr/foo", ResourceId(0x7f010000),
61c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                               util::make_unique<Attribute>(false, TYPE_STRING))
62c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                    .Build())
63c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski            .Build();
64c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  }
65c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
66c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski protected:
67c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  std::unique_ptr<IAaptContext> context_;
68c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski};
69c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
70c744ae8aca97edfb2422598ea620e8219449fa9bAdam LesinskiTEST_F(XmlCompatVersionerTest, NoRulesOnlyStripsAndCopies) {
71c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  auto doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF(
72c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      <View xmlns:android="http://schemas.android.com/apk/res/android"
73c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          xmlns:app="http://schemas.android.com/apk/res-auto"
74c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          android:paddingHorizontal="24dp"
75c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          app:foo="16dp"
76c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          foo="bar"/>)EOF");
77c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
78c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlReferenceLinker linker;
79c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(linker.Consume(context_.get(), doc.get()));
80c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
81c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner::Rules rules;
82c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
83c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
84c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner versioner(&rules);
85c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  std::vector<std::unique_ptr<xml::XmlResource>> versioned_docs =
86c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      versioner.Process(context_.get(), doc.get(), api_range);
87c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_EQ(2u, versioned_docs.size());
88c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
89c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Element* el;
90c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
91c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  // Source XML file's sdkVersion == 0, so the first one must also have the same sdkVersion.
92c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(0), versioned_docs[0]->file.config.sdkVersion);
93c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[0].get());
94c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
95c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(2u, el->attributes.size());
96c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
97c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute(xml::kSchemaAuto, "foo"));
98c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute({}, "foo"));
99c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
100c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(SDK_LOLLIPOP_MR1), versioned_docs[1]->file.config.sdkVersion);
101c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[1].get());
102c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
103c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(3u, el->attributes.size());
104c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
105c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute(xml::kSchemaAuto, "foo"));
106c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute({}, "foo"));
107c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski}
108c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
109c744ae8aca97edfb2422598ea620e8219449fa9bAdam LesinskiTEST_F(XmlCompatVersionerTest, SingleRule) {
110c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  auto doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF(
111c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      <View xmlns:android="http://schemas.android.com/apk/res/android"
112c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          xmlns:app="http://schemas.android.com/apk/res-auto"
113c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          android:paddingHorizontal="24dp"
114c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          app:foo="16dp"
115c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          foo="bar"/>)EOF");
116c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
117c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlReferenceLinker linker;
118c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(linker.Consume(context_.get(), doc.get()));
119c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
120c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner::Rules rules;
121c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  rules[R::attr::paddingHorizontal] =
122c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>(
123c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(false, TYPE_DIMENSION)},
124c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski           ReplacementAttr{"paddingRight", R::attr::paddingRight,
125c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                           Attribute(false, TYPE_DIMENSION)}}));
126c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
127c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
128c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
129c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner versioner(&rules);
130c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  std::vector<std::unique_ptr<xml::XmlResource>> versioned_docs =
131c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      versioner.Process(context_.get(), doc.get(), api_range);
132c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_EQ(2u, versioned_docs.size());
133c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
134c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Element* el;
135c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
136c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(0), versioned_docs[0]->file.config.sdkVersion);
137c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[0].get());
138c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
139c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(4u, el->attributes.size());
140c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
141c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute(xml::kSchemaAuto, "foo"));
142c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute({}, "foo"));
143c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
144c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
145c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
146c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
147c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
148c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
149c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
150c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
151c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
152c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
153c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
154c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(SDK_LOLLIPOP_MR1), versioned_docs[1]->file.config.sdkVersion);
155c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[1].get());
156c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
157c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(5u, el->attributes.size());
158c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
159c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute(xml::kSchemaAuto, "foo"));
160c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_NE(nullptr, el->FindAttribute({}, "foo"));
161c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
162c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
163c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
164c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
165c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
166c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
167c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
168c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
169c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
170c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
171c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski}
172c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
173c744ae8aca97edfb2422598ea620e8219449fa9bAdam LesinskiTEST_F(XmlCompatVersionerTest, ChainedRule) {
174c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  auto doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF(
175c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      <View xmlns:android="http://schemas.android.com/apk/res/android"
176c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          android:paddingHorizontal="24dp" />)EOF");
177c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
178c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlReferenceLinker linker;
179c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(linker.Consume(context_.get(), doc.get()));
180c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
181c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner::Rules rules;
182c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  rules[R::attr::progressBarPadding] =
183c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>(
184c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(false, TYPE_DIMENSION)},
185c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski           ReplacementAttr{"paddingRight", R::attr::paddingRight,
186c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                           Attribute(false, TYPE_DIMENSION)}}));
187c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  rules[R::attr::paddingHorizontal] =
188c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>({ReplacementAttr{
189c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          "progressBarPadding", R::attr::progressBarPadding, Attribute(false, TYPE_DIMENSION)}}));
190c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
191c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
192c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
193c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner versioner(&rules);
194c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  std::vector<std::unique_ptr<xml::XmlResource>> versioned_docs =
195c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      versioner.Process(context_.get(), doc.get(), api_range);
196c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_EQ(3u, versioned_docs.size());
197c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
198c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Element* el;
199c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
200c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(0), versioned_docs[0]->file.config.sdkVersion);
201c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[0].get());
202c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
203c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(2u, el->attributes.size());
204c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
205c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
206c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
207c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
208c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
209c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
210c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
211c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
212c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
213c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
214c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
215c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
216c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(SDK_HONEYCOMB), versioned_docs[1]->file.config.sdkVersion);
217c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[1].get());
218c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
219c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(1u, el->attributes.size());
220c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
221c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingLeft"));
222c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingRight"));
223c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
224c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "progressBarPadding");
225c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
226c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
227c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
228c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
229c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(SDK_LOLLIPOP_MR1), versioned_docs[2]->file.config.sdkVersion);
230c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[2].get());
231c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
232c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(2u, el->attributes.size());
233c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingLeft"));
234c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingRight"));
235c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
236c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal");
237c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
238c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
239c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
240c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
241c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "progressBarPadding");
242c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
243c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
244c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
245c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski}
246c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
247c744ae8aca97edfb2422598ea620e8219449fa9bAdam LesinskiTEST_F(XmlCompatVersionerTest, DegradeRuleOverridesExistingAttribute) {
248c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  auto doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF(
249c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      <View xmlns:android="http://schemas.android.com/apk/res/android"
250c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          android:paddingHorizontal="24dp"
251c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          android:paddingLeft="16dp"
252c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          android:paddingRight="16dp"/>)EOF");
253c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
254c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlReferenceLinker linker;
255c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(linker.Consume(context_.get(), doc.get()));
256c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
257c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  Item* padding_horizontal_value = xml::FindRootElement(doc.get())
258c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                       ->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal")
259c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                                       ->compiled_value.get();
260c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, padding_horizontal_value);
261c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
262c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner::Rules rules;
263c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  rules[R::attr::paddingHorizontal] =
264c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      util::make_unique<DegradeToManyRule>(std::vector<ReplacementAttr>(
265c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski          {ReplacementAttr{"paddingLeft", R::attr::paddingLeft, Attribute(false, TYPE_DIMENSION)},
266c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski           ReplacementAttr{"paddingRight", R::attr::paddingRight,
267c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski                           Attribute(false, TYPE_DIMENSION)}}));
268c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
269c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  const util::Range<ApiVersion> api_range{SDK_GINGERBREAD, SDK_O + 1};
270c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
271c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  XmlCompatVersioner versioner(&rules);
272c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  std::vector<std::unique_ptr<xml::XmlResource>> versioned_docs =
273c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski      versioner.Process(context_.get(), doc.get(), api_range);
274c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_EQ(2u, versioned_docs.size());
275c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
276c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Element* el;
277c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
278c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(0), versioned_docs[0]->file.config.sdkVersion);
279c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[0].get());
280c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
281c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(2u, el->attributes.size());
282c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(nullptr, el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal"));
283c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
284c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
285c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
286c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
287c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(padding_horizontal_value->Equals(attr->compiled_value.get()));
288c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
289c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
290c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
291c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
292c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
293c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(padding_horizontal_value->Equals(attr->compiled_value.get()));
294c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
295c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
296c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(static_cast<uint16_t>(SDK_LOLLIPOP_MR1), versioned_docs[1]->file.config.sdkVersion);
297c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  el = xml::FindRootElement(versioned_docs[1].get());
298c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, el);
299c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  EXPECT_EQ(3u, el->attributes.size());
300c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
301c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal");
302c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
303c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
304c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(padding_horizontal_value->Equals(attr->compiled_value.get()));
305c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
306c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
307c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
308c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
309c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
310c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(padding_horizontal_value->Equals(attr->compiled_value.get()));
311c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
312c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
313c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
314c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr);
315c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_NE(nullptr, attr->compiled_value);
316c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(padding_horizontal_value->Equals(attr->compiled_value.get()));
317c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski  ASSERT_TRUE(attr->compiled_attribute);
318c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski}
319c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
320c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski}  // namespace aapt
321