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