xref: /aosp_15_r20/external/libtextclassifier/native/utils/resources_test.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1 /*
2  * Copyright (C) 2018 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 "utils/resources.h"
18 
19 #include "utils/i18n/locale.h"
20 #include "utils/resources_generated.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 
24 namespace libtextclassifier3 {
25 namespace {
26 
27 class ResourcesTest : public testing::Test {
28  protected:
ResourcesTest()29   ResourcesTest() {}
30 
BuildTestResources(bool add_default_language=true) const31   std::string BuildTestResources(bool add_default_language = true) const {
32     ResourcePoolT test_resources;
33 
34     // Test locales.
35     test_resources.locale.emplace_back(new LanguageTagT);
36     test_resources.locale.back()->language = "en";
37     test_resources.locale.back()->region = "US";
38     test_resources.locale.emplace_back(new LanguageTagT);
39     test_resources.locale.back()->language = "en";
40     test_resources.locale.back()->region = "GB";
41     test_resources.locale.emplace_back(new LanguageTagT);
42     test_resources.locale.back()->language = "de";
43     test_resources.locale.back()->region = "DE";
44     test_resources.locale.emplace_back(new LanguageTagT);
45     test_resources.locale.back()->language = "fr";
46     test_resources.locale.back()->region = "FR";
47     test_resources.locale.emplace_back(new LanguageTagT);
48     test_resources.locale.back()->language = "pt";
49     test_resources.locale.back()->region = "PT";
50     test_resources.locale.emplace_back(new LanguageTagT);
51     test_resources.locale.back()->language = "pt";
52     test_resources.locale.emplace_back(new LanguageTagT);
53     test_resources.locale.back()->language = "zh";
54     test_resources.locale.back()->script = "Hans";
55     test_resources.locale.back()->region = "CN";
56     test_resources.locale.emplace_back(new LanguageTagT);
57     test_resources.locale.back()->language = "zh";
58     test_resources.locale.emplace_back(new LanguageTagT);
59     test_resources.locale.back()->language = "fr";
60     test_resources.locale.back()->region = "CA";
61     test_resources.locale.emplace_back(new LanguageTagT);
62     test_resources.locale.back()->language = "in";
63     if (add_default_language) {
64       test_resources.locale.emplace_back(new LanguageTagT);  // default
65     }
66 
67     // Test entries.
68     test_resources.resource_entry.emplace_back(new ResourceEntryT);
69     test_resources.resource_entry.back()->name = /*resource_name=*/"A";
70 
71     // en-US, default
72     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
73     test_resources.resource_entry.back()->resource.back()->content = "localize";
74     test_resources.resource_entry.back()->resource.back()->locale.push_back(0);
75     if (add_default_language) {
76       test_resources.resource_entry.back()->resource.back()->locale.push_back(
77           10);
78     }
79 
80     // en-GB
81     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
82     test_resources.resource_entry.back()->resource.back()->content = "localise";
83     test_resources.resource_entry.back()->resource.back()->locale.push_back(1);
84 
85     // de-DE
86     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
87     test_resources.resource_entry.back()->resource.back()->content =
88         "lokalisieren";
89     test_resources.resource_entry.back()->resource.back()->locale.push_back(2);
90 
91     // fr-FR, fr-CA
92     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
93     test_resources.resource_entry.back()->resource.back()->content =
94         "localiser";
95     test_resources.resource_entry.back()->resource.back()->locale.push_back(3);
96     test_resources.resource_entry.back()->resource.back()->locale.push_back(8);
97 
98     // pt-PT
99     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
100     test_resources.resource_entry.back()->resource.back()->content =
101         "localizar";
102     test_resources.resource_entry.back()->resource.back()->locale.push_back(4);
103 
104     // pt
105     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
106     test_resources.resource_entry.back()->resource.back()->content =
107         "concentrar";
108     test_resources.resource_entry.back()->resource.back()->locale.push_back(5);
109 
110     // zh-Hans-CN
111     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
112     test_resources.resource_entry.back()->resource.back()->content = "龙";
113     test_resources.resource_entry.back()->resource.back()->locale.push_back(6);
114 
115     // zh
116     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
117     test_resources.resource_entry.back()->resource.back()->content = "龍";
118     test_resources.resource_entry.back()->resource.back()->locale.push_back(7);
119 
120     // in
121     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
122     test_resources.resource_entry.back()->resource.back()->content =
123         "Apa kabar";
124     test_resources.resource_entry.back()->resource.back()->locale.push_back(9);
125 
126     flatbuffers::FlatBufferBuilder builder;
127     builder.Finish(ResourcePool::Pack(builder, &test_resources));
128 
129     return std::string(
130         reinterpret_cast<const char*>(builder.GetBufferPointer()),
131         builder.GetSize());
132   }
133 };
134 
TEST_F(ResourcesTest,CorrectlyHandlesExactMatch)135 TEST_F(ResourcesTest, CorrectlyHandlesExactMatch) {
136   std::string test_resources = BuildTestResources();
137   Resources resources(
138       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
139   std::string content;
140   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("en-US")},
141                                            /*resource_name=*/"A", &content));
142   EXPECT_EQ("localize", content);
143   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("en-GB")},
144                                            /*resource_name=*/"A", &content));
145   EXPECT_EQ("localise", content);
146   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("pt-PT")},
147                                            /*resource_name=*/"A", &content));
148   EXPECT_EQ("localizar", content);
149   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hans-CN")},
150                                            /*resource_name=*/"A", &content));
151   EXPECT_EQ("龙", content);
152   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh")},
153                                            /*resource_name=*/"A", &content));
154   EXPECT_EQ("龍", content);
155   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("fr-CA")},
156                                            /*resource_name=*/"A", &content));
157   EXPECT_EQ("localiser", content);
158   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("id")},
159                                            /*resource_name=*/"A", &content));
160   EXPECT_EQ("Apa kabar", content);
161 }
162 
TEST_F(ResourcesTest,CorrectlyHandlesTie)163 TEST_F(ResourcesTest, CorrectlyHandlesTie) {
164   std::string test_resources = BuildTestResources();
165   Resources resources(
166       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
167   // Uses first best match in case of a tie.
168   std::string content;
169   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("en-CA")},
170                                            /*resource_name=*/"A", &content));
171   EXPECT_EQ("localize", content);
172 }
173 
TEST_F(ResourcesTest,RequiresLanguageMatch)174 TEST_F(ResourcesTest, RequiresLanguageMatch) {
175   {
176     std::string test_resources =
177         BuildTestResources(/*add_default_language=*/false);
178     Resources resources(
179         flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
180     EXPECT_FALSE(resources.GetResourceContent({Locale::FromBCP47("es-US")},
181                                               /*resource_name=*/"A",
182                                               /*result=*/nullptr));
183   }
184   {
185     std::string test_resources =
186         BuildTestResources(/*add_default_language=*/true);
187     Resources resources(
188         flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
189     std::string content;
190     EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("es-US")},
191                                              /*resource_name=*/"A",
192                                              /*result=*/&content));
193     EXPECT_EQ("localize", content);
194   }
195 }
196 
TEST_F(ResourcesTest,HandlesFallback)197 TEST_F(ResourcesTest, HandlesFallback) {
198   std::string test_resources = BuildTestResources();
199   Resources resources(
200       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
201   std::string content;
202   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("fr-CH")},
203                                            /*resource_name=*/"A", &content));
204   EXPECT_EQ("localiser", content);
205   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hans")},
206                                            /*resource_name=*/"A", &content));
207   EXPECT_EQ("龙", content);
208   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hans-ZZ")},
209                                            /*resource_name=*/"A", &content));
210   EXPECT_EQ("龙", content);
211 
212   // Fallback to default, en-US.
213   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("ru")},
214                                            /*resource_name=*/"A", &content));
215   EXPECT_EQ("localize", content);
216 }
217 
TEST_F(ResourcesTest,HandlesFallbackMultipleLocales)218 TEST_F(ResourcesTest, HandlesFallbackMultipleLocales) {
219   std::string test_resources = BuildTestResources();
220   Resources resources(
221       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
222   std::string content;
223 
224   // Still use inexact match with primary locale if language matches,
225   // even though secondary locale would match exactly.
226   EXPECT_TRUE(resources.GetResourceContent(
227       {Locale::FromBCP47("fr-CH"), Locale::FromBCP47("en-US")},
228       /*resource_name=*/"A", &content));
229   EXPECT_EQ("localiser", content);
230 
231   // Use secondary language instead of default fallback if that is an exact
232   // language match.
233   EXPECT_TRUE(resources.GetResourceContent(
234       {Locale::FromBCP47("ru"), Locale::FromBCP47("de")},
235       /*resource_name=*/"A", &content));
236   EXPECT_EQ("lokalisieren", content);
237 
238   // Use tertiary language.
239   EXPECT_TRUE(resources.GetResourceContent(
240       {Locale::FromBCP47("ru"), Locale::FromBCP47("it-IT"),
241        Locale::FromBCP47("de")},
242       /*resource_name=*/"A", &content));
243   EXPECT_EQ("lokalisieren", content);
244 
245   // Default fallback if no locale matches.
246   EXPECT_TRUE(resources.GetResourceContent(
247       {Locale::FromBCP47("ru"), Locale::FromBCP47("it-IT"),
248        Locale::FromBCP47("es")},
249       /*resource_name=*/"A", &content));
250   EXPECT_EQ("localize", content);
251 }
252 
TEST_F(ResourcesTest,PreferGenericCallback)253 TEST_F(ResourcesTest, PreferGenericCallback) {
254   std::string test_resources = BuildTestResources();
255   Resources resources(
256       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
257   std::string content;
258   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("pt-BR")},
259                                            /*resource_name=*/"A", &content));
260   EXPECT_EQ("concentrar", content);  // Falls back to pt, not pt-PT.
261   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hant")},
262                                            /*resource_name=*/"A", &content));
263   EXPECT_EQ("龍", content);  // Falls back to zh, not zh-Hans-CN.
264   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hant-CN")},
265                                            /*resource_name=*/"A", &content));
266   EXPECT_EQ("龍", content);  // Falls back to zh, not zh-Hans-CN.
267   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-CN")},
268                                            /*resource_name=*/"A", &content));
269   EXPECT_EQ("龍", content);  // Falls back to zh, not zh-Hans-CN.
270 }
271 
TEST_F(ResourcesTest,PreferGenericWhenGeneric)272 TEST_F(ResourcesTest, PreferGenericWhenGeneric) {
273   std::string test_resources = BuildTestResources();
274   Resources resources(
275       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
276   std::string content;
277   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("pt")},
278                                            /*resource_name=*/"A", &content));
279 
280   // Uses pt, not pt-PT.
281   EXPECT_EQ("concentrar", content);
282 }
283 
284 }  // namespace
285 }  // namespace libtextclassifier3
286