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 "Util.h"
18
19 #include "android-base/stringprintf.h"
20
21 #include "AppInfo.h"
22 #include "split/TableSplitter.h"
23 #include "test/Builders.h"
24 #include "test/Test.h"
25 #include "util/Files.h"
26
27 using ::android::ConfigDescription;
28 using testing::UnorderedElementsAre;
29
30 namespace aapt {
31
32 #ifdef _WIN32
33 #define CREATE_PATH(path) android::base::StringPrintf(";%s", path)
34 #else
35 #define CREATE_PATH(path) android::base::StringPrintf(":%s", path)
36 #endif
37
38 #define EXPECT_CONFIG_EQ(constraints, config) \
39 EXPECT_EQ(constraints.configs.size(), 1); \
40 EXPECT_EQ(*constraints.configs.begin(), config); \
41 constraints.configs.clear();
42
TEST(UtilTest,SplitNamesAreSanitized)43 TEST(UtilTest, SplitNamesAreSanitized) {
44 AppInfo app_info{"com.pkg"};
45 SplitConstraints split_constraints{
46 {test::ParseConfigOrDie("en-rUS-land"), test::ParseConfigOrDie("b+sr+Latn")}};
47
48 const auto doc = GenerateSplitManifest(app_info, split_constraints);
49 const auto &root = doc->root;
50 EXPECT_EQ(root->name, "manifest");
51 // split names cannot contain hyphens or plus signs.
52 EXPECT_EQ(root->FindAttribute("", "split")->value, "config.b_sr_Latn_en_rUS_land");
53 // but we should use resource qualifiers verbatim in 'targetConfig'.
54 EXPECT_EQ(root->FindAttribute("", "targetConfig")->value, "b+sr+Latn,en-rUS-land");
55 }
56
TEST(UtilTest,LongVersionCodeDefined)57 TEST (UtilTest, LongVersionCodeDefined) {
58 auto doc = test::BuildXmlDom(R"(
59 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
60 package="com.android.aapt.test" android:versionCode="0x1" android:versionCodeMajor="0x1">
61 </manifest>)");
62 SetLongVersionCode(doc->root.get(), 42);
63
64 auto version_code = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
65 ASSERT_NE(version_code, nullptr);
66 EXPECT_EQ(version_code->value, "0x0000002a");
67
68 ASSERT_NE(version_code->compiled_value, nullptr);
69 auto compiled_version_code = ValueCast<BinaryPrimitive>(version_code->compiled_value.get());
70 ASSERT_NE(compiled_version_code, nullptr);
71 EXPECT_EQ(compiled_version_code->value.data, 42U);
72
73 auto version_code_major = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor");
74 EXPECT_EQ(version_code_major, nullptr);
75 }
76
77 TEST (UtilTest, LongVersionCodeUndefined) {
78 auto doc = test::BuildXmlDom(R"(
79 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
80 package="com.android.aapt.test">
81 </manifest>)");
82 SetLongVersionCode(doc->root.get(), 420000000000);
83
84 auto version_code = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
85 ASSERT_NE(version_code, nullptr);
86 EXPECT_EQ(version_code->value, "0xc9f36800");
87
88 ASSERT_NE(version_code->compiled_value, nullptr);
89 auto compiled_version_code = ValueCast<BinaryPrimitive>(version_code->compiled_value.get());
90 ASSERT_NE(compiled_version_code, nullptr);
91 EXPECT_EQ(compiled_version_code->value.data, 0xc9f36800);
92
93 auto version_code_major = doc->root->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor");
94 ASSERT_NE(version_code_major, nullptr);
95 EXPECT_EQ(version_code_major->value, "0x00000061");
96
97 ASSERT_NE(version_code_major->compiled_value, nullptr);
98 auto compiled_version_code_major = ValueCast<BinaryPrimitive>(
99 version_code_major->compiled_value.get());
100 ASSERT_NE(compiled_version_code_major, nullptr);
101 EXPECT_EQ(compiled_version_code_major->value.data, 0x61);
102 }
103
104
105 TEST (UtilTest, ParseSplitParameters) {
106 android::IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
107 std::string path;
108 SplitConstraints constraints;
109 ConfigDescription expected_configuration;
110
111 // ========== Test IMSI ==========
112 // mcc: 'mcc[0-9]{3}'
113 // mnc: 'mnc[0-9]{1,3}'
114 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("mcc310"),
115 diagnostics, &path, &constraints));
116 expected_configuration = test::ConfigDescriptionBuilder()
117 .setMcc(0x0136)
118 .Build();
119 EXPECT_CONFIG_EQ(constraints, expected_configuration);
120
121 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("mcc310-mnc004"),
122 diagnostics, &path, &constraints));
123 expected_configuration = test::ConfigDescriptionBuilder()
124 .setMcc(0x0136)
125 .setMnc(0x0004)
126 .Build();
127 EXPECT_CONFIG_EQ(constraints, expected_configuration);
128
129 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("mcc310-mnc000"),
130 diagnostics, &path, &constraints));
131 expected_configuration = test::ConfigDescriptionBuilder()
132 .setMcc(0x0136)
133 .setMnc(0xFFFF)
134 .Build();
135 EXPECT_CONFIG_EQ(constraints, expected_configuration);
136
137 // ========== Test LOCALE ==========
138 // locale: '[a-z]{2,3}(-r[a-z]{2})?'
139 // locale: 'b+[a-z]{2,3}(+[a-z[0-9]]{2})?'
140 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("es"),
141 diagnostics, &path, &constraints));
142 expected_configuration = test::ConfigDescriptionBuilder()
143 .setLanguage(0x6573)
144 .Build();
145 EXPECT_CONFIG_EQ(constraints, expected_configuration);
146
147 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("fr-rCA"),
148 diagnostics, &path, &constraints));
149 expected_configuration = test::ConfigDescriptionBuilder()
150 .setLanguage(0x6672)
151 .setCountry(0x4341)
152 .Build();
153 EXPECT_CONFIG_EQ(constraints, expected_configuration);
154
155 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("b+es+419"),
156 diagnostics, &path, &constraints));
157 expected_configuration = test::ConfigDescriptionBuilder()
158 .setLanguage(0x6573)
159 .setCountry(0xA424)
160 .Build();
161 EXPECT_CONFIG_EQ(constraints, expected_configuration);
162
163 // ========== Test SCREEN_TYPE ==========
164 // orientation: '(port|land|square)'
165 // touchscreen: '(notouch|stylus|finger)'
166 // density" '(anydpi|nodpi|ldpi|mdpi|tvdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|[0-9]*dpi)'
167 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("square"),
168 diagnostics, &path, &constraints));
169 expected_configuration = test::ConfigDescriptionBuilder()
170 .setOrientation(0x03)
171 .Build();
172 EXPECT_CONFIG_EQ(constraints, expected_configuration);
173
174 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("stylus"),
175 diagnostics, &path, &constraints));
176 expected_configuration = test::ConfigDescriptionBuilder()
177 .setTouchscreen(0x02)
178 .Build();
179 EXPECT_CONFIG_EQ(constraints, expected_configuration);
180
181 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("xxxhdpi"),
182 diagnostics, &path, &constraints));
183 expected_configuration = test::ConfigDescriptionBuilder()
184 .setDensity(0x0280)
185 .setSdkVersion(0x0004) // version [any density requires donut]
186 .Build();
187 EXPECT_CONFIG_EQ(constraints, expected_configuration);
188
189 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("land-xhdpi-finger"),
190 diagnostics, &path, &constraints));
191 expected_configuration = test::ConfigDescriptionBuilder()
192 .setOrientation(0x02)
193 .setTouchscreen(0x03)
194 .setDensity(0x0140)
195 .setSdkVersion(0x0004) // version [any density requires donut]
196 .Build();
197 EXPECT_CONFIG_EQ(constraints, expected_configuration);
198
199 // ========== Test INPUT ==========
200 // keyboard: '(nokeys|qwerty|12key)'
201 // navigation: '(nonav|dpad|trackball|wheel)'
202 // inputFlags: '(keysexposed|keyshidden|keyssoft)'
203 // inputFlags: '(navexposed|navhidden)'
204 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("qwerty"),
205 diagnostics, &path, &constraints));
206 expected_configuration = test::ConfigDescriptionBuilder()
207 .setKeyboard(0x02)
208 .Build();
209 EXPECT_CONFIG_EQ(constraints, expected_configuration);
210
211 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("dpad"),
212 diagnostics, &path, &constraints));
213 expected_configuration = test::ConfigDescriptionBuilder()
214 .setNavigation(0x02)
215 .Build();
216 EXPECT_CONFIG_EQ(constraints, expected_configuration);
217
218 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("keyssoft-navhidden"),
219 diagnostics, &path, &constraints));
220 expected_configuration = test::ConfigDescriptionBuilder()
221 .setInputFlags(0x0B)
222 .Build();
223 EXPECT_CONFIG_EQ(constraints, expected_configuration);
224
225 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("keyshidden-nokeys-navexposed-trackball"),
226 diagnostics, &path, &constraints));
227 expected_configuration = test::ConfigDescriptionBuilder()
228 .setKeyboard(0x01)
229 .setNavigation(0x03)
230 .setInputFlags(0x06)
231 .Build();
232 EXPECT_CONFIG_EQ(constraints, expected_configuration);
233
234 // ========== Test SCREEN_SIZE ==========
235 // screenWidth/screenHeight: '[0-9]+x[0-9]+'
236 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("1920x1080"),
237 diagnostics, &path, &constraints));
238 expected_configuration = test::ConfigDescriptionBuilder()
239 .setScreenWidth(0x0780)
240 .setScreenHeight(0x0438)
241 .Build();
242 EXPECT_CONFIG_EQ(constraints, expected_configuration);
243
244 // ========== Test VERSION ==========
245 // version 'v[0-9]+'
246
247 // ========== Test SCREEN_CONFIG ==========
248 // screenLayout [direction]: '(ldltr|ldrtl)'
249 // screenLayout [size]: '(small|normal|large|xlarge)'
250 // screenLayout [long]: '(long|notlong)'
251 // uiMode [type]: '(desk|car|television|appliance|watch|vrheadset)'
252 // uiMode [night]: '(night|notnight)'
253 // smallestScreenWidthDp: 'sw[0-9]dp'
254 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("ldrtl"),
255 diagnostics, &path, &constraints));
256 expected_configuration = test::ConfigDescriptionBuilder()
257 .setScreenLayout(0x80)
258 .Build();
259 EXPECT_CONFIG_EQ(constraints, expected_configuration);
260
261 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("small"),
262 diagnostics, &path, &constraints));
263 expected_configuration = test::ConfigDescriptionBuilder()
264 .setScreenLayout(0x01)
265 .setSdkVersion(0x0004) // screenLayout (size) requires donut
266 .Build();
267 EXPECT_CONFIG_EQ(constraints, expected_configuration);
268
269 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("notlong"),
270 diagnostics, &path, &constraints));
271 expected_configuration = test::ConfigDescriptionBuilder()
272 .setScreenLayout(0x10)
273 .setSdkVersion(0x0004) // screenLayout (long) requires donut
274 .Build();
275 EXPECT_CONFIG_EQ(constraints, expected_configuration);
276
277 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("ldltr-normal-long"),
278 diagnostics, &path, &constraints));
279 expected_configuration = test::ConfigDescriptionBuilder()
280 .setScreenLayout(0x62)
281 .setSdkVersion(0x0004) // screenLayout (size|long) requires donut
282 .Build();
283 EXPECT_CONFIG_EQ(constraints, expected_configuration);
284
285 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("car"),
286 diagnostics, &path, &constraints));
287 expected_configuration = test::ConfigDescriptionBuilder()
288 .setUiMode(0x03)
289 .setSdkVersion(0x0008) // uiMode requires froyo
290 .Build();
291 EXPECT_CONFIG_EQ(constraints, expected_configuration);
292
293 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("vrheadset"),
294 diagnostics, &path, &constraints));
295 expected_configuration = test::ConfigDescriptionBuilder()
296 .setUiMode(0x07)
297 .setSdkVersion(0x001A) // uiMode 'vrheadset' requires oreo
298 .Build();
299 EXPECT_CONFIG_EQ(constraints, expected_configuration);
300
301 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("television-night"),
302 diagnostics, &path, &constraints));
303 expected_configuration = test::ConfigDescriptionBuilder()
304 .setUiMode(0x24)
305 .setSdkVersion(0x0008) // uiMode requires froyo
306 .Build();
307 EXPECT_CONFIG_EQ(constraints, expected_configuration);
308
309 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("sw1920dp"),
310 diagnostics, &path, &constraints));
311 expected_configuration = test::ConfigDescriptionBuilder()
312 .setSmallestScreenWidthDp(0x0780)
313 .setSdkVersion(0x000D) // smallestScreenWidthDp requires honeycomb mr2
314 .Build();
315 EXPECT_CONFIG_EQ(constraints, expected_configuration);
316
317 // ========== Test SCREEN_SIZE_DP ==========
318 // screenWidthDp: 'w[0-9]dp'
319 // screenHeightDp: 'h[0-9]dp'
320 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("w1920dp"),
321 diagnostics, &path, &constraints));
322 expected_configuration = test::ConfigDescriptionBuilder()
323 .setScreenWidthDp(0x0780)
324 .setSdkVersion(0x000D) // screenWidthDp requires honeycomb mr2
325 .Build();
326 EXPECT_CONFIG_EQ(constraints, expected_configuration);
327
328 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("h1080dp"),
329 diagnostics, &path, &constraints));
330 expected_configuration = test::ConfigDescriptionBuilder()
331 .setScreenHeightDp(0x0438)
332 .setSdkVersion(0x000D) // screenHeightDp requires honeycomb mr2
333 .Build();
334 EXPECT_CONFIG_EQ(constraints, expected_configuration);
335
336 // ========== Test SCREEN_CONFIG_2 ==========
337 // screenLayout2: '(round|notround)'
338 // colorMode: '(widecg|nowidecg)'
339 // colorMode: '(highhdr|lowdr)'
340 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("round"),
341 diagnostics, &path, &constraints));
342 expected_configuration = test::ConfigDescriptionBuilder()
343 .setScreenLayout2(0x02)
344 .setSdkVersion(0x0017) // screenLayout2 (round) requires marshmallow
345 .Build();
346 EXPECT_CONFIG_EQ(constraints, expected_configuration);
347
348 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("widecg-highdr"),
349 diagnostics, &path, &constraints));
350 expected_configuration = test::ConfigDescriptionBuilder()
351 .setColorMode(0x0A)
352 .setSdkVersion(0x001A) // colorMode (hdr|colour gamut) requires oreo
353 .Build();
354 EXPECT_CONFIG_EQ(constraints, expected_configuration);
355 }
356
TEST(UtilTest,AdjustSplitConstraintsForMinSdk)357 TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
358 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
359
360 android::IDiagnostics* diagnostics = context.get()->GetDiagnostics();
361 std::vector<SplitConstraints> test_constraints;
362 std::string path;
363
364 test_constraints.push_back({});
365 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("v7"),
366 diagnostics, &path, &test_constraints.back()));
367 test_constraints.push_back({});
368 ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("xhdpi"),
369 diagnostics, &path, &test_constraints.back()));
370 EXPECT_EQ(test_constraints.size(), 2);
371 EXPECT_EQ(test_constraints[0].name, "v7");
372 EXPECT_EQ(test_constraints[0].configs.size(), 1);
373 EXPECT_NE(*test_constraints[0].configs.begin(), ConfigDescription::DefaultConfig());
374 EXPECT_EQ(test_constraints[1].name, "xhdpi");
375 EXPECT_EQ(test_constraints[1].configs.size(), 1);
376 EXPECT_NE(*test_constraints[0].configs.begin(), ConfigDescription::DefaultConfig());
377
378 auto adjusted_contraints = AdjustSplitConstraintsForMinSdk(26, test_constraints);
379 EXPECT_EQ(adjusted_contraints.size(), 2);
380 EXPECT_EQ(adjusted_contraints[0].name, "v7");
381 EXPECT_EQ(adjusted_contraints[0].configs.size(), 0);
382 EXPECT_EQ(adjusted_contraints[1].name, "xhdpi");
383 EXPECT_EQ(adjusted_contraints[1].configs.size(), 1);
384 EXPECT_NE(*adjusted_contraints[1].configs.begin(), ConfigDescription::DefaultConfig());
385 }
386
TEST(UtilTest,RegularExperssionsSimple)387 TEST (UtilTest, RegularExperssionsSimple) {
388 std::string valid(".bc$");
389 std::regex expression = GetRegularExpression(valid);
390 EXPECT_TRUE(std::regex_search("file.abc", expression));
391 EXPECT_TRUE(std::regex_search("file.123bc", expression));
392 EXPECT_FALSE(std::regex_search("abc.zip", expression));
393 }
394
TEST(UtilTest,RegularExpressionComplex)395 TEST (UtilTest, RegularExpressionComplex) {
396 std::string valid("\\.(d|D)(e|E)(x|X)$");
397 std::regex expression = GetRegularExpression(valid);
398 EXPECT_TRUE(std::regex_search("file.dex", expression));
399 EXPECT_TRUE(std::regex_search("file.DEX", expression));
400 EXPECT_TRUE(std::regex_search("file.dEx", expression));
401 EXPECT_FALSE(std::regex_search("file.dexx", expression));
402 EXPECT_FALSE(std::regex_search("dex.file", expression));
403 EXPECT_FALSE(std::regex_search("file.adex", expression));
404 }
405
TEST(UtilTest,RegularExpressionNonEnglish)406 TEST (UtilTest, RegularExpressionNonEnglish) {
407 std::string valid("\\.(k|K)(o|O)(ń|Ń)(c|C)(ó|Ó)(w|W)(k|K)(a|A)$");
408 std::regex expression = GetRegularExpression(valid);
409 EXPECT_TRUE(std::regex_search("file.końcówka", expression));
410 EXPECT_TRUE(std::regex_search("file.KOŃCÓWKA", expression));
411 EXPECT_TRUE(std::regex_search("file.kOńcÓwkA", expression));
412 EXPECT_FALSE(std::regex_search("file.koncowka", expression));
413 }
414
TEST(UtilTest,ParseConfigWithDirectives)415 TEST(UtilTest, ParseConfigWithDirectives) {
416 const std::string& content = R"(
417 bool/remove_me#remove
418 bool/keep_name#no_collapse
419 layout/keep_path#no_path_shorten
420 string/foo#no_obfuscate
421 dimen/bar#no_obfuscate
422 layout/keep_name_and_path#no_collapse,no_path_shorten
423 )";
424 aapt::test::Context context;
425 std::unordered_set<ResourceName> resource_exclusion;
426 std::set<ResourceName> name_collapse_exemptions;
427 std::set<ResourceName> path_shorten_exemptions;
428
429 EXPECT_TRUE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
430 path_shorten_exemptions));
431
432 EXPECT_THAT(name_collapse_exemptions,
433 UnorderedElementsAre(ResourceName({}, ResourceType::kString, "foo"),
434 ResourceName({}, ResourceType::kDimen, "bar"),
435 ResourceName({}, ResourceType::kBool, "keep_name"),
436 ResourceName({}, ResourceType::kLayout, "keep_name_and_path")));
437 EXPECT_THAT(path_shorten_exemptions,
438 UnorderedElementsAre(ResourceName({}, ResourceType::kLayout, "keep_path"),
439 ResourceName({}, ResourceType::kLayout, "keep_name_and_path")));
440 EXPECT_THAT(resource_exclusion,
441 UnorderedElementsAre(ResourceName({}, ResourceType::kBool, "remove_me")));
442 }
443
TEST(UtilTest,ParseConfigResourceWithPackage)444 TEST(UtilTest, ParseConfigResourceWithPackage) {
445 const std::string& content = R"(
446 package:bool/remove_me#remove
447 )";
448 aapt::test::Context context;
449 std::unordered_set<ResourceName> resource_exclusion;
450 std::set<ResourceName> name_collapse_exemptions;
451 std::set<ResourceName> path_shorten_exemptions;
452
453 EXPECT_FALSE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
454 path_shorten_exemptions));
455 }
456
TEST(UtilTest,ParseConfigInvalidName)457 TEST(UtilTest, ParseConfigInvalidName) {
458 const std::string& content = R"(
459 package:bool/1231#remove
460 )";
461 aapt::test::Context context;
462 std::unordered_set<ResourceName> resource_exclusion;
463 std::set<ResourceName> name_collapse_exemptions;
464 std::set<ResourceName> path_shorten_exemptions;
465
466 EXPECT_FALSE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
467 path_shorten_exemptions));
468 }
469
TEST(UtilTest,ParseConfigNoHash)470 TEST(UtilTest, ParseConfigNoHash) {
471 const std::string& content = R"(
472 package:bool/my_bool
473 )";
474 aapt::test::Context context;
475 std::unordered_set<ResourceName> resource_exclusion;
476 std::set<ResourceName> name_collapse_exemptions;
477 std::set<ResourceName> path_shorten_exemptions;
478
479 EXPECT_FALSE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
480 path_shorten_exemptions));
481 }
482
483 } // namespace aapt
484