1 /*
2  * Copyright (C) 2014 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 <androidfw/LocaleData.h>
18 #include <androidfw/ResourceTypes.h>
19 #include <utils/Log.h>
20 #include <utils/String8.h>
21 
22 #include <gtest/gtest.h>
23 namespace android {
24 
TEST(ConfigLocaleTest,packAndUnpack2LetterLanguage)25 TEST(ConfigLocaleTest, packAndUnpack2LetterLanguage) {
26      ResTable_config config;
27      config.packLanguage("en");
28 
29      EXPECT_EQ('e', config.language[0]);
30      EXPECT_EQ('n', config.language[1]);
31 
32      char out[4] = {1, 1, 1, 1};
33      config.unpackLanguage(out);
34      EXPECT_EQ('e', out[0]);
35      EXPECT_EQ('n', out[1]);
36      EXPECT_EQ(0, out[2]);
37      EXPECT_EQ(0, out[3]);
38 
39      memset(out, 1, sizeof(out));
40      config.locale = 0;
41      config.unpackLanguage(out);
42      EXPECT_EQ(0, out[0]);
43      EXPECT_EQ(0, out[1]);
44      EXPECT_EQ(0, out[2]);
45      EXPECT_EQ(0, out[3]);
46 }
47 
TEST(ConfigLocaleTest,packAndUnpack2LetterRegion)48 TEST(ConfigLocaleTest, packAndUnpack2LetterRegion) {
49      ResTable_config config;
50      config.packRegion("US");
51 
52      EXPECT_EQ('U', config.country[0]);
53      EXPECT_EQ('S', config.country[1]);
54 
55      char out[4] = {1, 1, 1, 1};
56      config.unpackRegion(out);
57      EXPECT_EQ('U', out[0]);
58      EXPECT_EQ('S', out[1]);
59      EXPECT_EQ(0, out[2]);
60      EXPECT_EQ(0, out[3]);
61 }
62 
TEST(ConfigLocaleTest,packAndUnpack3LetterLanguage)63 TEST(ConfigLocaleTest, packAndUnpack3LetterLanguage) {
64      ResTable_config config;
65      config.packLanguage("eng");
66 
67      // 1-00110-01 101-00100
68      EXPECT_EQ('\x99', config.language[0]);
69      EXPECT_EQ('\xA4', config.language[1]);
70 
71      char out[4] = {1, 1, 1, 1};
72      config.unpackLanguage(out);
73      EXPECT_EQ('e', out[0]);
74      EXPECT_EQ('n', out[1]);
75      EXPECT_EQ('g', out[2]);
76      EXPECT_EQ(0, out[3]);
77 }
78 
TEST(ConfigLocaleTest,packAndUnpack3LetterLanguageAtOffset16)79 TEST(ConfigLocaleTest, packAndUnpack3LetterLanguageAtOffset16) {
80      ResTable_config config;
81      config.packLanguage("tgp");
82 
83      // We had a bug where we would accidentally mask
84      // the 5th bit of both bytes
85      //
86      // packed[0] = 1011 1100
87      // packed[1] = 1101 0011
88      //
89      // which is equivalent to:
90      // 1  [0]   [1]   [2]
91      // 1-01111-00110-10011
92      EXPECT_EQ(char(0xbc), config.language[0]);
93      EXPECT_EQ(char(0xd3), config.language[1]);
94 
95      char out[4] = {1, 1, 1, 1};
96      config.unpackLanguage(out);
97      EXPECT_EQ('t', out[0]);
98      EXPECT_EQ('g', out[1]);
99      EXPECT_EQ('p', out[2]);
100      EXPECT_EQ(0, out[3]);
101 }
102 
TEST(ConfigLocaleTest,packAndUnpack3LetterRegion)103 TEST(ConfigLocaleTest, packAndUnpack3LetterRegion) {
104      ResTable_config config;
105      config.packRegion("419");
106 
107      char out[4] = {1, 1, 1, 1};
108      config.unpackRegion(out);
109 
110      EXPECT_EQ('4', out[0]);
111      EXPECT_EQ('1', out[1]);
112      EXPECT_EQ('9', out[2]);
113 }
114 
fillIn(const char * lang,const char * country,const char * script,const char * variant,ResTable_config * out)115 /* static */ void fillIn(const char* lang, const char* country,
116         const char* script, const char* variant, ResTable_config* out) {
117      memset(out, 0, sizeof(ResTable_config));
118      if (lang != NULL) {
119          out->packLanguage(lang);
120      }
121 
122      if (country != NULL) {
123          out->packRegion(country);
124      }
125 
126      if (script != NULL) {
127          memcpy(out->localeScript, script, 4);
128          out->localeScriptWasComputed = false;
129      } else {
130          out->computeScript();
131          out->localeScriptWasComputed = true;
132      }
133 
134      if (variant != NULL) {
135          memcpy(out->localeVariant, variant, strlen(variant));
136      }
137 }
138 
TEST(ConfigLocaleTest,IsMoreSpecificThan)139 TEST(ConfigLocaleTest, IsMoreSpecificThan) {
140     ResTable_config l;
141     ResTable_config r;
142 
143     fillIn("en", NULL, NULL, NULL, &l);
144     fillIn(NULL, NULL, NULL, NULL, &r);
145 
146     EXPECT_TRUE(l.isMoreSpecificThan(r));
147     EXPECT_FALSE(r.isMoreSpecificThan(l));
148 
149     fillIn("eng", NULL, NULL, NULL, &l);
150     EXPECT_TRUE(l.isMoreSpecificThan(r));
151     EXPECT_FALSE(r.isMoreSpecificThan(l));
152 
153     fillIn("eng", "419", NULL, NULL, &r);
154     EXPECT_FALSE(l.isMoreSpecificThan(r));
155     EXPECT_TRUE(r.isMoreSpecificThan(l));
156 
157     fillIn("en", NULL, NULL, NULL, &l);
158     fillIn("en", "US", NULL, NULL, &r);
159     EXPECT_FALSE(l.isMoreSpecificThan(r));
160     EXPECT_TRUE(r.isMoreSpecificThan(l));
161 
162     fillIn("en", "US", NULL, NULL, &l);
163     fillIn("en", "US", "Latn", NULL, &r);
164     EXPECT_FALSE(l.isMoreSpecificThan(r));
165     EXPECT_TRUE(r.isMoreSpecificThan(l));
166 
167     fillIn("en", "US", NULL, NULL, &l);
168     fillIn("en", "US", NULL, "POSIX", &r);
169     EXPECT_FALSE(l.isMoreSpecificThan(r));
170     EXPECT_TRUE(r.isMoreSpecificThan(l));
171 
172     fillIn("en", "US", "Latn", NULL, &l);
173     fillIn("en", "US", NULL, "POSIX", &r);
174     EXPECT_FALSE(l.isMoreSpecificThan(r));
175     EXPECT_TRUE(r.isMoreSpecificThan(l));
176 
177     fillIn("ar", "EG", NULL, NULL, &l);
178     fillIn("ar", "EG", NULL, NULL, &r);
179     memcpy(&r.localeNumberingSystem, "latn", 4);
180     EXPECT_FALSE(l.isMoreSpecificThan(r));
181     EXPECT_TRUE(r.isMoreSpecificThan(l));
182 
183     fillIn("en", "US", NULL, NULL, &l);
184     fillIn("es", "ES", NULL, NULL, &r);
185 
186     EXPECT_FALSE(l.isMoreSpecificThan(r));
187     EXPECT_FALSE(r.isMoreSpecificThan(l));
188 }
189 
TEST(ConfigLocaleTest,setLocale)190 TEST(ConfigLocaleTest, setLocale) {
191     ResTable_config test;
192     test.setBcp47Locale("en-US");
193     EXPECT_EQ('e', test.language[0]);
194     EXPECT_EQ('n', test.language[1]);
195     EXPECT_EQ('U', test.country[0]);
196     EXPECT_EQ('S', test.country[1]);
197     EXPECT_TRUE(test.localeScriptWasComputed);
198     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
199     EXPECT_EQ(0, test.localeVariant[0]);
200     EXPECT_EQ(0, test.localeNumberingSystem[0]);
201 
202     test.setBcp47Locale("eng-419");
203     char out[4] = {1, 1, 1, 1};
204     test.unpackLanguage(out);
205     EXPECT_EQ('e', out[0]);
206     EXPECT_EQ('n', out[1]);
207     EXPECT_EQ('g', out[2]);
208     EXPECT_EQ(0, out[3]);
209     memset(out, 1, 4);
210     test.unpackRegion(out);
211     EXPECT_EQ('4', out[0]);
212     EXPECT_EQ('1', out[1]);
213     EXPECT_EQ('9', out[2]);
214     EXPECT_EQ(0, test.localeNumberingSystem[0]);
215 
216     test.setBcp47Locale("en-Latn-419");
217     EXPECT_EQ('e', test.language[0]);
218     EXPECT_EQ('n', test.language[1]);
219     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
220     EXPECT_FALSE(test.localeScriptWasComputed);
221     memset(out, 1, 4);
222     test.unpackRegion(out);
223     EXPECT_EQ('4', out[0]);
224     EXPECT_EQ('1', out[1]);
225     EXPECT_EQ('9', out[2]);
226     EXPECT_EQ(0, test.localeNumberingSystem[0]);
227 
228     test.setBcp47Locale("de-1901");
229     memset(out, 1, 4);
230     test.unpackLanguage(out);
231     EXPECT_EQ('d', out[0]);
232     EXPECT_EQ('e', out[1]);
233     EXPECT_EQ('\0', out[2]);
234     EXPECT_TRUE(test.localeScriptWasComputed);
235     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
236     memset(out, 1, 4);
237     test.unpackRegion(out);
238     EXPECT_EQ('\0', out[0]);
239     EXPECT_EQ(0, strcmp("1901", test.localeVariant));
240     EXPECT_EQ(0, test.localeNumberingSystem[0]);
241 
242     test.setBcp47Locale("de-Latn-1901");
243     memset(out, 1, 4);
244     test.unpackLanguage(out);
245     EXPECT_EQ('d', out[0]);
246     EXPECT_EQ('e', out[1]);
247     EXPECT_EQ('\0', out[2]);
248     EXPECT_FALSE(test.localeScriptWasComputed);
249     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
250     memset(out, 1, 4);
251     test.unpackRegion(out);
252     EXPECT_EQ('\0', out[0]);
253     EXPECT_EQ(0, strcmp("1901", test.localeVariant));
254     EXPECT_EQ(0, test.localeNumberingSystem[0]);
255 
256     test.setBcp47Locale("ar-EG-u-nu-latn");
257     EXPECT_EQ('a', test.language[0]);
258     EXPECT_EQ('r', test.language[1]);
259     EXPECT_EQ('E', test.country[0]);
260     EXPECT_EQ('G', test.country[1]);
261     EXPECT_TRUE(test.localeScriptWasComputed);
262     EXPECT_EQ(0, memcmp("Arab", test.localeScript, 4));
263     EXPECT_EQ(0, test.localeVariant[0]);
264     EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
265 
266     test.setBcp47Locale("ar-EG-u");
267     EXPECT_EQ(0, test.localeNumberingSystem[0]);
268 
269     test.setBcp47Locale("ar-EG-u-nu");
270     EXPECT_EQ(0, test.localeNumberingSystem[0]);
271 
272     test.setBcp47Locale("ar-EG-u-attr-nu-latn");
273     EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
274 
275     test.setBcp47Locale("ar-EG-u-ca-gregory-nu-latn");
276     EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
277 
278     test.setBcp47Locale("ar-EG-u-nu-latn-ca-gregory");
279     EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
280 
281     test.setBcp47Locale("ar-EG-u-nu-toolongnumsys");
282     EXPECT_EQ(0, test.localeNumberingSystem[0]);
283 
284     test.setBcp47Locale("ar-EG-u-nu-latn-nu-arab");
285     EXPECT_EQ(0, memcmp("latn", test.localeNumberingSystem, 4));
286 
287     test.setBcp47Locale("ar-EG-u-co-nu-latn");
288     EXPECT_EQ(0, test.localeNumberingSystem[0]);
289 
290     test.setBcp47Locale("ar-u-co-abcd-attr-nu-latn");
291     EXPECT_EQ(0, test.localeNumberingSystem[0]);
292 }
293 
TEST(ConfigLocaleTest,computeScript)294 TEST(ConfigLocaleTest, computeScript) {
295     ResTable_config config;
296 
297     fillIn(NULL, NULL, NULL, NULL, &config);
298     EXPECT_EQ(0, memcmp("\0\0\0\0", config.localeScript, 4));
299 
300     fillIn("zh", "TW", NULL, NULL, &config);
301     EXPECT_EQ(0, memcmp("Hant", config.localeScript, 4));
302 
303     fillIn("zh", "CN", NULL, NULL, &config);
304     EXPECT_EQ(0, memcmp("Hans", config.localeScript, 4));
305 
306     fillIn("az", NULL, NULL, NULL, &config);
307     EXPECT_EQ(0, memcmp("Latn", config.localeScript, 4));
308 
309     fillIn("az", "AZ", NULL, NULL, &config);
310     EXPECT_EQ(0, memcmp("Latn", config.localeScript, 4));
311 
312     fillIn("az", "IR", NULL, NULL, &config);
313     EXPECT_EQ(0, memcmp("Arab", config.localeScript, 4));
314 
315     fillIn("peo", NULL, NULL, NULL, &config);
316     EXPECT_EQ(0, memcmp("Xpeo", config.localeScript, 4));
317 
318     fillIn("qaa", NULL, NULL, NULL, &config);
319     EXPECT_EQ(0, memcmp("\0\0\0\0", config.localeScript, 4));
320 }
321 
TEST(ConfigLocaleTest,getBcp47Locale_script)322 TEST(ConfigLocaleTest, getBcp47Locale_script) {
323     ResTable_config config;
324     fillIn("en", NULL, "Latn", NULL, &config);
325 
326     char out[RESTABLE_MAX_LOCALE_LEN];
327     config.localeScriptWasComputed = false;
328     config.getBcp47Locale(out);
329     EXPECT_EQ(0, strcmp("en-Latn", out));
330 
331     config.localeScriptWasComputed = true;
332     config.getBcp47Locale(out);
333     EXPECT_EQ(0, strcmp("en", out));
334 }
335 
TEST(ConfigLocaleTest,getBcp47Locale_numberingSystem)336 TEST(ConfigLocaleTest, getBcp47Locale_numberingSystem) {
337     ResTable_config config;
338     fillIn("en", NULL, NULL, NULL, &config);
339 
340     char out[RESTABLE_MAX_LOCALE_LEN];
341 
342     memcpy(&config.localeNumberingSystem, "latn", 4);
343     config.getBcp47Locale(out);
344     EXPECT_EQ(0, strcmp("en-u-nu-latn", out));
345 
346     fillIn("sr", "SR", "Latn", NULL, &config);
347     memcpy(&config.localeNumberingSystem, "latn", 4);
348     config.getBcp47Locale(out);
349     EXPECT_EQ(0, strcmp("sr-Latn-SR-u-nu-latn", out));
350 }
351 
TEST(ConfigLocaleTest,getBcp47Locale_canonicalize)352 TEST(ConfigLocaleTest, getBcp47Locale_canonicalize) {
353     ResTable_config config;
354     char out[RESTABLE_MAX_LOCALE_LEN];
355 
356     fillIn("tl", NULL, NULL, NULL, &config);
357     config.getBcp47Locale(out);
358     EXPECT_EQ(0, strcmp("tl", out));
359     config.getBcp47Locale(out, true /* canonicalize */);
360     EXPECT_EQ(0, strcmp("fil", out));
361 
362     fillIn("tl", "PH", NULL, NULL, &config);
363     config.getBcp47Locale(out);
364     EXPECT_EQ(0, strcmp("tl-PH", out));
365     config.getBcp47Locale(out, true /* canonicalize */);
366     EXPECT_EQ(0, strcmp("fil-PH", out));
367 }
368 
TEST(ConfigLocaleTest,match)369 TEST(ConfigLocaleTest, match) {
370     ResTable_config supported, requested;
371 
372     fillIn(NULL, NULL, NULL, NULL, &supported);
373     fillIn("fr", "CA", NULL, NULL, &requested);
374     // Empty locale matches everything (as a default).
375     EXPECT_TRUE(supported.match(requested));
376 
377     fillIn("en", "CA", NULL, NULL, &supported);
378     fillIn("fr", "CA", NULL, NULL, &requested);
379     // Different languages don't match.
380     EXPECT_FALSE(supported.match(requested));
381 
382     fillIn("tl", "PH", NULL, NULL, &supported);
383     fillIn("fil", "PH", NULL, NULL, &requested);
384     // Equivalent languages match.
385     EXPECT_TRUE(supported.match(requested));
386 
387     fillIn("qaa", "FR", NULL, NULL, &supported);
388     fillIn("qaa", "CA", NULL, NULL, &requested);
389     // If we can't infer the scripts, different regions don't match.
390     EXPECT_FALSE(supported.match(requested));
391 
392     fillIn("qaa", "FR", "Latn", NULL, &supported);
393     fillIn("qaa", "CA", NULL, NULL, &requested);
394     // If we can't infer any of the scripts, different regions don't match.
395     EXPECT_FALSE(supported.match(requested));
396 
397     fillIn("qaa", "FR", NULL, NULL, &supported);
398     fillIn("qaa", "CA", "Latn", NULL, &requested);
399     // If we can't infer any of the scripts, different regions don't match.
400     EXPECT_FALSE(supported.match(requested));
401 
402     fillIn("qaa", NULL, NULL, NULL, &supported);
403     fillIn("qaa", "CA", NULL, NULL, &requested);
404     // language-only resources still support language+region requests, even if we can't infer the
405     // script.
406     EXPECT_TRUE(supported.match(requested));
407 
408     fillIn("qaa", "CA", NULL, NULL, &supported);
409     fillIn("qaa", "CA", NULL, NULL, &requested);
410     // Even if we can't infer the scripts, exactly equal locales match.
411     EXPECT_TRUE(supported.match(requested));
412 
413     fillIn("az", NULL, NULL, NULL, &supported);
414     fillIn("az", NULL, "Latn", NULL, &requested);
415     // If the resolved scripts are the same, it doesn't matter if they were explicitly provided
416     // or not, and they match.
417     EXPECT_TRUE(supported.match(requested));
418 
419     fillIn("az", NULL, NULL, NULL, &supported);
420     fillIn("az", NULL, "Cyrl", NULL, &requested);
421     // If the resolved scripts are different, they don't match.
422     EXPECT_FALSE(supported.match(requested));
423 
424     fillIn("az", NULL, NULL, NULL, &supported);
425     fillIn("az", "IR", NULL, NULL, &requested);
426     // If the resolved scripts are different, they don't match.
427     EXPECT_FALSE(supported.match(requested));
428 
429     fillIn("az", "IR", NULL, NULL, &supported);
430     fillIn("az", NULL, "Arab", NULL, &requested);
431     // If the resolved scripts are the same, it doesn't matter if they were explicitly provided
432     // or not, and they match.
433     EXPECT_TRUE(supported.match(requested));
434 
435     fillIn("en", NULL, NULL, NULL, &supported);
436     fillIn("en", "XA", NULL, NULL, &requested);
437     // en-XA is a pseudo-locale, and English resources are not a match for it.
438     EXPECT_FALSE(supported.match(requested));
439 
440     fillIn("en", "XA", NULL, NULL, &supported);
441     fillIn("en", NULL, NULL, NULL, &requested);
442     // en-XA is a pseudo-locale, and its resources don't support English locales.
443     EXPECT_FALSE(supported.match(requested));
444 
445     fillIn("en", "XA", NULL, NULL, &supported);
446     fillIn("en", "XA", NULL, NULL, &requested);
447     // Even if they are pseudo-locales, exactly equal locales match.
448     EXPECT_TRUE(supported.match(requested));
449 
450     fillIn("ar", NULL, NULL, NULL, &supported);
451     fillIn("ar", "XB", NULL, NULL, &requested);
452     // ar-XB is a pseudo-locale, and Arabic resources are not a match for it.
453     EXPECT_FALSE(supported.match(requested));
454 
455     fillIn("ar", "XB", NULL, NULL, &supported);
456     fillIn("ar", NULL, NULL, NULL, &requested);
457     // ar-XB is a pseudo-locale, and its resources don't support Arabic locales.
458     EXPECT_FALSE(supported.match(requested));
459 
460     fillIn("ar", "XB", NULL, NULL, &supported);
461     fillIn("ar", "XB", NULL, NULL, &requested);
462     // Even if they are pseudo-locales, exactly equal locales match.
463     EXPECT_TRUE(supported.match(requested));
464 
465     fillIn("ar", "EG", NULL, NULL, &supported);
466     fillIn("ar", "TN", NULL, NULL, &requested);
467     memcpy(&supported.localeNumberingSystem, "latn", 4);
468     EXPECT_TRUE(supported.match(requested));
469 }
470 
TEST(ConfigLocaleTest,match_emptyScript)471 TEST(ConfigLocaleTest, match_emptyScript) {
472     ResTable_config supported, requested;
473 
474     fillIn("fr", "FR", NULL, NULL, &supported);
475     fillIn("fr", "CA", NULL, NULL, &requested);
476 
477     // emulate packages built with older AAPT
478     memset(supported.localeScript, '\0', 4);
479     supported.localeScriptWasComputed = false;
480 
481     EXPECT_TRUE(supported.match(requested));
482 }
483 
TEST(ConfigLocaleTest,isLocaleBetterThan_basics)484 TEST(ConfigLocaleTest, isLocaleBetterThan_basics) {
485     ResTable_config config1, config2, request;
486 
487     fillIn(NULL, NULL, NULL, NULL, &request);
488     fillIn("fr", "FR", NULL, NULL, &config1);
489     fillIn("fr", "CA", NULL, NULL, &config2);
490     EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
491     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
492 
493     fillIn("fr", "CA", NULL, NULL, &request);
494     fillIn(NULL, NULL, NULL, NULL, &config1);
495     fillIn(NULL, NULL, NULL, NULL, &config2);
496     EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
497     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
498 
499     fillIn("fr", "CA", NULL, NULL, &request);
500     fillIn("fr", "FR", NULL, NULL, &config1);
501     fillIn(NULL, NULL, NULL, NULL, &config2);
502     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
503     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
504 
505     fillIn("de", "DE", NULL, NULL, &request);
506     fillIn("de", "DE", NULL, NULL, &config1);
507     fillIn("de", "DE", NULL, "1901", &config2);
508     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
509     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
510 
511     fillIn("de", "DE", NULL, NULL, &request);
512     fillIn("de", "DE", NULL, "1901", &config1);
513     fillIn("de", "DE", NULL, "1996", &config2);
514     EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
515     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
516 
517     fillIn("de", "DE", NULL, "1901", &request);
518     fillIn("de", "DE", NULL, "1901", &config1);
519     fillIn("de", "DE", NULL, NULL, &config2);
520     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
521     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
522 
523     fillIn("de", "DE", NULL, "1901", &request);
524     fillIn("de", "DE", NULL, "1996", &config1);
525     fillIn("de", "DE", NULL, NULL, &config2);
526     EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
527     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
528 
529     fillIn("fil", "PH", NULL, NULL, &request);
530     fillIn("tl", "PH", NULL, NULL, &config1);
531     fillIn("fil", "US", NULL, NULL, &config2);
532     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
533     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
534 
535     fillIn("fil", "PH", NULL, "fonipa", &request);
536     fillIn("tl", "PH", NULL, "fonipa", &config1);
537     fillIn("fil", "PH", NULL, NULL, &config2);
538     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
539     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
540 
541     fillIn("fil", "PH", NULL, NULL, &request);
542     fillIn("fil", "PH", NULL, NULL, &config1);
543     fillIn("tl", "PH", NULL, NULL, &config2);
544     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
545     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
546 }
547 
TEST(ConfigLocaleTest,isLocaleBetterThan_regionComparison)548 TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) {
549     ResTable_config config1, config2, request;
550 
551     fillIn("es", "AR", NULL, NULL, &request);
552     fillIn("es", "419", NULL, NULL, &config1);
553     fillIn("es", "419", NULL, NULL, &config2);
554     // Both supported locales are the same, so none is better than the other.
555     EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
556     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
557 
558     fillIn("es", "AR", NULL, NULL, &request);
559     fillIn("es", "AR", NULL, NULL, &config1);
560     fillIn("es", "419", NULL, NULL, &config2);
561     // An exact locale match is better than a parent.
562     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
563     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
564 
565     fillIn("es", "AR", NULL, NULL, &request);
566     fillIn("es", "419", NULL, NULL, &config1);
567     fillIn("es", NULL, NULL, NULL, &config2);
568     // A closer parent is better.
569     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
570     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
571 
572     fillIn("es", "AR", NULL, NULL, &request);
573     fillIn("es", "419", NULL, NULL, &config1);
574     fillIn("es", "ES", NULL, NULL, &config2);
575     // A parent is better than a non-parent representative locale.
576     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
577     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
578 
579     fillIn("es", "AR", NULL, NULL, &request);
580     fillIn("es", NULL, NULL, NULL, &config1);
581     fillIn("es", "ES", NULL, NULL, &config2);
582     // A parent is better than a non-parent representative locale.
583     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
584     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
585 
586     fillIn("es", "AR", NULL, NULL, &request);
587     fillIn("es", "PE", NULL, NULL, &config1);
588     fillIn("es", "ES", NULL, NULL, &config2);
589     // A closer locale is better.
590     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
591     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
592 
593     fillIn("es", "AR", NULL, NULL, &request);
594     fillIn("es", "US", NULL, NULL, &config1);
595     fillIn("es", NULL, NULL, NULL, &config2);
596     // Special case for Latin American Spanish: es-MX and es-US are
597     // pseudo-parents of all Latin Ameircan Spanish locales.
598     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
599     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
600 
601     fillIn("es", "MX", NULL, NULL, &request);
602     fillIn("es", "US", NULL, NULL, &config1);
603     fillIn("es", NULL, NULL, NULL, &config2);
604     // Special case for Latin American Spanish: es-MX and es-US are
605     // pseudo-parents of all Latin Ameircan Spanish locales.
606     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
607     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
608 
609     fillIn("es", "AR", NULL, NULL, &request);
610     fillIn("es", "MX", NULL, NULL, &config1);
611     fillIn("es", NULL, NULL, NULL, &config2);
612     // Special case for Latin American Spanish: es-MX and es-US are
613     // pseudo-parents of all Latin Ameircan Spanish locales.
614     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
615     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
616 
617     fillIn("es", "US", NULL, NULL, &request);
618     fillIn("es", "MX", NULL, NULL, &config1);
619     fillIn("es", NULL, NULL, NULL, &config2);
620     // Special case for Latin American Spanish: es-MX and es-US are
621     // pseudo-parents of all Latin Ameircan Spanish locales.
622     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
623     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
624 
625     fillIn("es", "AR", NULL, NULL, &request);
626     fillIn("es", "419", NULL, NULL, &config1);
627     fillIn("es", "MX", NULL, NULL, &config2);
628     // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan
629     // Spanish locales, es-419 is a closer parent.
630     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
631     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
632 
633     fillIn("es", "US", NULL, NULL, &request);
634     fillIn("es", "419", NULL, NULL, &config1);
635     fillIn("es", "MX", NULL, NULL, &config2);
636     // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan
637     // Spanish locales, es-419 is a closer parent.
638     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
639     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
640 
641     fillIn("es", "MX", NULL, NULL, &request);
642     fillIn("es", "419", NULL, NULL, &config1);
643     fillIn("es", "US", NULL, NULL, &config2);
644     // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan
645     // Spanish locales, es-419 is a closer parent.
646     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
647     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
648 
649     fillIn("es", "AR", NULL, NULL, &request);
650     fillIn("es", "MX", NULL, NULL, &config1);
651     fillIn("es", "BO", NULL, NULL, &config2);
652     // Special case for Latin American Spanish: es-MX and es-US are
653     // pseudo-parents of all Latin Ameircan Spanish locales.
654     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
655     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
656 
657     fillIn("es", "AR", NULL, NULL, &request);
658     fillIn("es", "US", NULL, NULL, &config1);
659     fillIn("es", "BO", NULL, NULL, &config2);
660     // Special case for Latin American Spanish: es-MX and es-US are
661     // pseudo-parents of all Latin Ameircan Spanish locales.
662     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
663     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
664 
665     fillIn("es", "IC", NULL, NULL, &request);
666     fillIn("es", "ES", NULL, NULL, &config1);
667     fillIn("es", "GQ", NULL, NULL, &config2);
668     // A representative locale is better if they are equidistant.
669     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
670     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
671 
672     fillIn("es", "AR", NULL, NULL, &request);
673     fillIn("es", "MX", NULL, NULL, &config1);
674     fillIn("es", "US", NULL, NULL, &config2);
675     // If all is equal, the locale earlier in the dictionary is better.
676     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
677     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
678 
679     fillIn("es", "GQ", NULL, NULL, &request);
680     fillIn("es", "IC", NULL, NULL, &config1);
681     fillIn("es", "419", NULL, NULL, &config2);
682     // If all is equal, the locale earlier in the dictionary is better and
683     // letters are better than numbers.
684     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
685     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
686 
687     fillIn("en", "GB", NULL, NULL, &request);
688     fillIn("en", "001", NULL, NULL, &config1);
689     fillIn("en", NULL, NULL, NULL, &config2);
690     // A closer parent is better.
691     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
692     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
693 
694     fillIn("en", "PR", NULL, NULL, &request);
695     fillIn("en", NULL, NULL, NULL, &config1);
696     fillIn("en", "001", NULL, NULL, &config2);
697     // A parent is better than a non-parent.
698     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
699     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
700 
701     fillIn("en", "DE", NULL, NULL, &request);
702     fillIn("en", "150", NULL, NULL, &config1);
703     fillIn("en", "001", NULL, NULL, &config2);
704     // A closer parent is better.
705     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
706     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
707 
708     fillIn("en", "IN", NULL, NULL, &request);
709     fillIn("en", "AU", NULL, NULL, &config1);
710     fillIn("en", "US", NULL, NULL, &config2);
711     // A closer locale is better.
712     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
713     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
714 
715     fillIn("en", "PR", NULL, NULL, &request);
716     fillIn("en", "001", NULL, NULL, &config1);
717     fillIn("en", "GB", NULL, NULL, &config2);
718     // A closer locale is better.
719     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
720     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
721 
722     fillIn("en", "IN", NULL, NULL, &request);
723     fillIn("en", "GB", NULL, NULL, &config1);
724     fillIn("en", "AU", NULL, NULL, &config2);
725     // A representative locale is better if they are equidistant.
726     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
727     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
728 
729     fillIn("en", "IN", NULL, NULL, &request);
730     fillIn("en", "AU", NULL, NULL, &config1);
731     fillIn("en", "CA", NULL, NULL, &config2);
732     // If all is equal, the locale earlier in the dictionary is better.
733     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
734     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
735 
736     fillIn("pt", "MZ", NULL, NULL, &request);
737     fillIn("pt", "PT", NULL, NULL, &config1);
738     fillIn("pt", NULL, NULL, NULL, &config2);
739     // A closer parent is better.
740     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
741     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
742 
743     fillIn("pt", "MZ", NULL, NULL, &request);
744     fillIn("pt", "PT", NULL, NULL, &config1);
745     fillIn("pt", "BR", NULL, NULL, &config2);
746     // A parent is better than a non-parent.
747     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
748     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
749 
750     fillIn("zh", "MO", "Hant", NULL, &request);
751     fillIn("zh", "HK", "Hant", NULL, &config1);
752     fillIn("zh", "TW", "Hant", NULL, &config2);
753     // A parent is better than a non-parent.
754     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
755     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
756 
757     fillIn("zh", "US", "Hant", NULL, &request);
758     fillIn("zh", "TW", "Hant", NULL, &config1);
759     fillIn("zh", "HK", "Hant", NULL, &config2);
760     // A representative locale is better if they are equidistant.
761     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
762     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
763 
764     fillIn("ar", "DZ", NULL, NULL, &request);
765     fillIn("ar", "015", NULL, NULL, &config1);
766     fillIn("ar", NULL, NULL, NULL, &config2);
767     // A closer parent is better.
768     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
769     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
770 
771     fillIn("ar", "EG", NULL, NULL, &request);
772     fillIn("ar", NULL, NULL, NULL, &config1);
773     fillIn("ar", "015", NULL, NULL, &config2);
774     // A parent is better than a non-parent.
775     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
776     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
777 
778     fillIn("ar", "QA", NULL, NULL, &request);
779     fillIn("ar", "EG", NULL, NULL, &config1);
780     fillIn("ar", "BH", NULL, NULL, &config2);
781     // A representative locale is better if they are equidistant.
782     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
783     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
784 
785     fillIn("ar", "QA", NULL, NULL, &request);
786     fillIn("ar", "SA", NULL, NULL, &config1);
787     fillIn("ar", "015", NULL, NULL, &config2);
788     // If all is equal, the locale earlier in the dictionary is better and
789     // letters are better than numbers.
790     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
791     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
792 }
793 
TEST(ConfigLocaleTest,isLocaleBetterThan_numberingSystem)794 TEST(ConfigLocaleTest, isLocaleBetterThan_numberingSystem) {
795     ResTable_config config1, config2, request;
796 
797     fillIn("ar", "EG", NULL, NULL, &request);
798     memcpy(&request.localeNumberingSystem, "latn", 4);
799     fillIn("ar", NULL, NULL, NULL, &config1);
800     memcpy(&config1.localeNumberingSystem, "latn", 4);
801     fillIn("ar", NULL, NULL, NULL, &config2);
802     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
803     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
804 
805     fillIn("ar", "EG", NULL, NULL, &request);
806     memcpy(&request.localeNumberingSystem, "latn", 4);
807     fillIn("ar", "TN", NULL, NULL, &config1);
808     memcpy(&config1.localeNumberingSystem, "latn", 4);
809     fillIn("ar", NULL, NULL, NULL, &config2);
810     EXPECT_TRUE(config2.isLocaleBetterThan(config1, &request));
811     EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
812 }
813 
814 // Default resources are considered better matches for US English
815 // and US-like English locales than International English locales
TEST(ConfigLocaleTest,isLocaleBetterThan_UsEnglishIsSpecial)816 TEST(ConfigLocaleTest, isLocaleBetterThan_UsEnglishIsSpecial) {
817     ResTable_config config1, config2, request;
818 
819     fillIn("en", "US", NULL, NULL, &request);
820     fillIn(NULL, NULL, NULL, NULL, &config1);
821     fillIn("en", "001", NULL, NULL, &config2);
822     // default is better than International English
823     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
824     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
825 
826     fillIn("en", "US", NULL, NULL, &request);
827     fillIn(NULL, NULL, NULL, NULL, &config1);
828     fillIn("en", "GB", NULL, NULL, &config2);
829     // default is better than British English
830     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
831     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
832 
833     fillIn("en", "PR", NULL, NULL, &request);
834     fillIn(NULL, NULL, NULL, NULL, &config1);
835     fillIn("en", "001", NULL, NULL, &config2);
836     // Even for Puerto Rico, default is better than International English
837     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
838     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
839 
840     fillIn("en", "US", NULL, NULL, &request);
841     fillIn("en", NULL, NULL, NULL, &config1);
842     fillIn(NULL, NULL, NULL, NULL, &config2);
843     // "English" is better than default, since it's a parent of US English
844     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
845     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
846 
847     fillIn("en", "PR", NULL, NULL, &request);
848     fillIn("en", NULL, NULL, NULL, &config1);
849     fillIn(NULL, NULL, NULL, NULL, &config2);
850     // "English" is better than default, since it's a parent of Puerto Rico English
851     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
852     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
853 
854     fillIn("en", "US", NULL, NULL, &request);
855     fillIn(NULL, NULL, NULL, NULL, &config1);
856     fillIn("en", "PR", NULL, NULL, &config2);
857     // For US English itself, we prefer default to its siblings in the parent tree
858     EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
859     EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
860 }
861 
862 }  // namespace android
863