1 /*
2 * Copyright (C) 2024 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/LocaleDataLookup.h"
18
19 #include <cstddef>
20 #include <string>
21
22 #include "gtest/gtest.h"
23 #include "gmock/gmock.h"
24
25
26 namespace android {
27
28 constexpr const char NULL_SCRIPT[4] = {'\0', '\0', '\0','\0' };
29
30 #define EXPECT_SCEIPT_EQ(ex, s) EXPECT_EQ(0, s == nullptr ? -1 : memcmp(ex, s, 4))
31
32 // Similar to packLanguageOrRegion() in ResourceTypes.cpp
encodeLanguageOrRegionLiteral(const char * in,const char base)33 static uint32_t encodeLanguageOrRegionLiteral(const char* in, const char base) {
34 size_t len = strlen(in);
35 if (len <= 1) {
36 return 0;
37 }
38
39 if (len == 2) {
40 return (((uint8_t) in[0]) << 8) | ((uint8_t) in[1]);
41 }
42 uint8_t first = (in[0] - base) & 0x007f;
43 uint8_t second = (in[1] - base) & 0x007f;
44 uint8_t third = (in[2] - base) & 0x007f;
45
46 return ((uint8_t) (0x80 | (third << 2) | (second >> 3)) << 8) | ((second << 5) | first);
47 }
48
encodeLocale(const char * language,const char * region)49 static uint32_t encodeLocale(const char* language, const char* region) {
50 return (encodeLanguageOrRegionLiteral(language, 'a') << 16) |
51 encodeLanguageOrRegionLiteral(region, '0');
52 }
53
TEST(LocaleDataLookupTest,lookupLikelyScript)54 TEST(LocaleDataLookupTest, lookupLikelyScript) {
55 EXPECT_EQ(nullptr, lookupLikelyScript(encodeLocale("", "")));
56 EXPECT_SCEIPT_EQ("Latn", lookupLikelyScript(encodeLocale("en", "")));
57 EXPECT_EQ(nullptr, lookupLikelyScript(encodeLocale("en", "US")));
58 EXPECT_EQ(nullptr, lookupLikelyScript(encodeLocale("en", "GB")));
59 EXPECT_SCEIPT_EQ("Latn", lookupLikelyScript(encodeLocale("fr", "")));
60 EXPECT_EQ(nullptr, lookupLikelyScript(encodeLocale("fr", "FR")));
61
62
63 EXPECT_SCEIPT_EQ("~~~A", lookupLikelyScript(encodeLocale("en", "XA")));
64 EXPECT_SCEIPT_EQ("Latn", lookupLikelyScript(encodeLocale("ha", "")));
65 EXPECT_SCEIPT_EQ("Arab", lookupLikelyScript(encodeLocale("ha", "SD")));
66 EXPECT_EQ(nullptr, lookupLikelyScript(encodeLocale("ha", "Sd"))); // case sensitive
67 EXPECT_SCEIPT_EQ("Hans", lookupLikelyScript(encodeLocale("zh", "")));
68 EXPECT_EQ(nullptr, lookupLikelyScript(encodeLocale("zh", "CN")));
69 EXPECT_SCEIPT_EQ("Hant", lookupLikelyScript(encodeLocale("zh", "HK")));
70
71 EXPECT_SCEIPT_EQ("Nshu", lookupLikelyScript(encodeLocale("zhx", "")));
72 EXPECT_SCEIPT_EQ("Nshu", lookupLikelyScript(0xDCF90000u)); // encoded "zhx"
73 }
74
TEST(LocaleDataLookupTest,isLocaleRepresentative)75 TEST(LocaleDataLookupTest, isLocaleRepresentative) {
76 EXPECT_TRUE(isLocaleRepresentative(encodeLocale("en", "US"), "Latn"));
77 EXPECT_TRUE(isLocaleRepresentative(encodeLocale("en", "GB"), "Latn"));
78 EXPECT_FALSE(isLocaleRepresentative(encodeLocale("en", "US"), NULL_SCRIPT));
79 EXPECT_FALSE(isLocaleRepresentative(encodeLocale("en", ""), "Latn"));
80 EXPECT_FALSE(isLocaleRepresentative(encodeLocale("en", ""), NULL_SCRIPT));
81 EXPECT_FALSE(isLocaleRepresentative(encodeLocale("en", "US"), "Arab"));
82
83 EXPECT_TRUE(isLocaleRepresentative(encodeLocale("fr", "FR"), "Latn"));
84
85 EXPECT_TRUE(isLocaleRepresentative(encodeLocale("zh", "CN"), "Hans"));
86 EXPECT_FALSE(isLocaleRepresentative(encodeLocale("zh", "TW"), "Hans"));
87 EXPECT_FALSE(isLocaleRepresentative(encodeLocale("zhx", "CN"), "Hans"));
88 EXPECT_FALSE(isLocaleRepresentative(0xDCF9434E, "Hans"));
89 EXPECT_TRUE(isLocaleRepresentative(encodeLocale("zhx", "CN"), "Nshu"));
90 EXPECT_TRUE(isLocaleRepresentative(0xDCF9434E, "Nshu"));
91 }
92
TEST(LocaleDataLookupTest,findParentLocalePackedKey)93 TEST(LocaleDataLookupTest, findParentLocalePackedKey) {
94 EXPECT_EQ(encodeLocale("en", "001"), findParentLocalePackedKey("Latn", encodeLocale("en", "GB")));
95 EXPECT_EQ(0x656E8400u, findParentLocalePackedKey("Latn", encodeLocale("en", "GB")));
96
97 EXPECT_EQ(encodeLocale("en", "IN"), findParentLocalePackedKey("Deva", encodeLocale("hi", "")));
98
99 EXPECT_EQ(encodeLocale("ar", "015"), findParentLocalePackedKey("Arab", encodeLocale("ar", "AE")));
100 EXPECT_EQ(0x61729420u, findParentLocalePackedKey("Arab", encodeLocale("ar", "AE")));
101
102 EXPECT_EQ(encodeLocale("ar", "015"), findParentLocalePackedKey("~~~B", encodeLocale("ar", "XB")));
103 EXPECT_EQ(0x61729420u, findParentLocalePackedKey("Arab", encodeLocale("ar", "AE")));
104
105 EXPECT_EQ(encodeLocale("zh", "HK"), findParentLocalePackedKey("Hant", encodeLocale("zh", "MO")));
106 }
107
108 } // namespace android
109