• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (add_default_language) {
62       test_resources.locale.emplace_back(new LanguageTagT);  // default
63     }
64 
65     // Test entries.
66     test_resources.resource_entry.emplace_back(new ResourceEntryT);
67     test_resources.resource_entry.back()->name = /*resource_name=*/"A";
68 
69     // en-US, default
70     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
71     test_resources.resource_entry.back()->resource.back()->content = "localize";
72     test_resources.resource_entry.back()->resource.back()->locale.push_back(0);
73     if (add_default_language) {
74       test_resources.resource_entry.back()->resource.back()->locale.push_back(
75           9);
76     }
77 
78     // en-GB
79     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
80     test_resources.resource_entry.back()->resource.back()->content = "localise";
81     test_resources.resource_entry.back()->resource.back()->locale.push_back(1);
82 
83     // de-DE
84     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
85     test_resources.resource_entry.back()->resource.back()->content =
86         "lokalisieren";
87     test_resources.resource_entry.back()->resource.back()->locale.push_back(2);
88 
89     // fr-FR, fr-CA
90     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
91     test_resources.resource_entry.back()->resource.back()->content =
92         "localiser";
93     test_resources.resource_entry.back()->resource.back()->locale.push_back(3);
94     test_resources.resource_entry.back()->resource.back()->locale.push_back(8);
95 
96     // pt-PT
97     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
98     test_resources.resource_entry.back()->resource.back()->content =
99         "localizar";
100     test_resources.resource_entry.back()->resource.back()->locale.push_back(4);
101 
102     // pt
103     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
104     test_resources.resource_entry.back()->resource.back()->content =
105         "concentrar";
106     test_resources.resource_entry.back()->resource.back()->locale.push_back(5);
107 
108     // zh-Hans-CN
109     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
110     test_resources.resource_entry.back()->resource.back()->content = "龙";
111     test_resources.resource_entry.back()->resource.back()->locale.push_back(6);
112 
113     // zh
114     test_resources.resource_entry.back()->resource.emplace_back(new ResourceT);
115     test_resources.resource_entry.back()->resource.back()->content = "龍";
116     test_resources.resource_entry.back()->resource.back()->locale.push_back(7);
117 
118     flatbuffers::FlatBufferBuilder builder;
119     builder.Finish(ResourcePool::Pack(builder, &test_resources));
120 
121     return std::string(
122         reinterpret_cast<const char*>(builder.GetBufferPointer()),
123         builder.GetSize());
124   }
125 };
126 
TEST_F(ResourcesTest,CorrectlyHandlesExactMatch)127 TEST_F(ResourcesTest, CorrectlyHandlesExactMatch) {
128   std::string test_resources = BuildTestResources();
129   Resources resources(
130       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
131   std::string content;
132   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("en-US")},
133                                            /*resource_name=*/"A", &content));
134   EXPECT_EQ("localize", content);
135   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("en-GB")},
136                                            /*resource_name=*/"A", &content));
137   EXPECT_EQ("localise", content);
138   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("pt-PT")},
139                                            /*resource_name=*/"A", &content));
140   EXPECT_EQ("localizar", content);
141   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hans-CN")},
142                                            /*resource_name=*/"A", &content));
143   EXPECT_EQ("龙", content);
144   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh")},
145                                            /*resource_name=*/"A", &content));
146   EXPECT_EQ("龍", content);
147   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("fr-CA")},
148                                            /*resource_name=*/"A", &content));
149   EXPECT_EQ("localiser", content);
150 }
151 
TEST_F(ResourcesTest,CorrectlyHandlesTie)152 TEST_F(ResourcesTest, CorrectlyHandlesTie) {
153   std::string test_resources = BuildTestResources();
154   Resources resources(
155       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
156   // Uses first best match in case of a tie.
157   std::string content;
158   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("en-CA")},
159                                            /*resource_name=*/"A", &content));
160   EXPECT_EQ("localize", content);
161 }
162 
TEST_F(ResourcesTest,RequiresLanguageMatch)163 TEST_F(ResourcesTest, RequiresLanguageMatch) {
164   {
165     std::string test_resources =
166         BuildTestResources(/*add_default_language=*/false);
167     Resources resources(
168         flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
169     EXPECT_FALSE(resources.GetResourceContent({Locale::FromBCP47("es-US")},
170                                               /*resource_name=*/"A",
171                                               /*result=*/nullptr));
172   }
173   {
174     std::string test_resources =
175         BuildTestResources(/*add_default_language=*/true);
176     Resources resources(
177         flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
178     std::string content;
179     EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("es-US")},
180                                              /*resource_name=*/"A",
181                                              /*result=*/&content));
182     EXPECT_EQ("localize", content);
183   }
184 }
185 
TEST_F(ResourcesTest,HandlesFallback)186 TEST_F(ResourcesTest, HandlesFallback) {
187   std::string test_resources = BuildTestResources();
188   Resources resources(
189       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
190   std::string content;
191   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("fr-CH")},
192                                            /*resource_name=*/"A", &content));
193   EXPECT_EQ("localiser", content);
194   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hans")},
195                                            /*resource_name=*/"A", &content));
196   EXPECT_EQ("龙", content);
197   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hans-ZZ")},
198                                            /*resource_name=*/"A", &content));
199   EXPECT_EQ("龙", content);
200 
201   // Fallback to default, en-US.
202   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("ru")},
203                                            /*resource_name=*/"A", &content));
204   EXPECT_EQ("localize", content);
205 }
206 
TEST_F(ResourcesTest,HandlesFallbackMultipleLocales)207 TEST_F(ResourcesTest, HandlesFallbackMultipleLocales) {
208   std::string test_resources = BuildTestResources();
209   Resources resources(
210       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
211   std::string content;
212 
213   // Still use inexact match with primary locale if language matches,
214   // even though secondary locale would match exactly.
215   EXPECT_TRUE(resources.GetResourceContent(
216       {Locale::FromBCP47("fr-CH"), Locale::FromBCP47("en-US")},
217       /*resource_name=*/"A", &content));
218   EXPECT_EQ("localiser", content);
219 
220   // Use secondary language instead of default fallback if that is an exact
221   // language match.
222   EXPECT_TRUE(resources.GetResourceContent(
223       {Locale::FromBCP47("ru"), Locale::FromBCP47("de")},
224       /*resource_name=*/"A", &content));
225   EXPECT_EQ("lokalisieren", content);
226 
227   // Use tertiary language.
228   EXPECT_TRUE(resources.GetResourceContent(
229       {Locale::FromBCP47("ru"), Locale::FromBCP47("it-IT"),
230        Locale::FromBCP47("de")},
231       /*resource_name=*/"A", &content));
232   EXPECT_EQ("lokalisieren", content);
233 
234   // Default fallback if no locale matches.
235   EXPECT_TRUE(resources.GetResourceContent(
236       {Locale::FromBCP47("ru"), Locale::FromBCP47("it-IT"),
237        Locale::FromBCP47("es")},
238       /*resource_name=*/"A", &content));
239   EXPECT_EQ("localize", content);
240 }
241 
TEST_F(ResourcesTest,PreferGenericCallback)242 TEST_F(ResourcesTest, PreferGenericCallback) {
243   std::string test_resources = BuildTestResources();
244   Resources resources(
245       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
246   std::string content;
247   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("pt-BR")},
248                                            /*resource_name=*/"A", &content));
249   EXPECT_EQ("concentrar", content);  // Falls back to pt, not pt-PT.
250   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hant")},
251                                            /*resource_name=*/"A", &content));
252   EXPECT_EQ("龍", content);  // Falls back to zh, not zh-Hans-CN.
253   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-Hant-CN")},
254                                            /*resource_name=*/"A", &content));
255   EXPECT_EQ("龍", content);  // Falls back to zh, not zh-Hans-CN.
256   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("zh-CN")},
257                                            /*resource_name=*/"A", &content));
258   EXPECT_EQ("龍", content);  // Falls back to zh, not zh-Hans-CN.
259 }
260 
TEST_F(ResourcesTest,PreferGenericWhenGeneric)261 TEST_F(ResourcesTest, PreferGenericWhenGeneric) {
262   std::string test_resources = BuildTestResources();
263   Resources resources(
264       flatbuffers::GetRoot<ResourcePool>(test_resources.data()));
265   std::string content;
266   EXPECT_TRUE(resources.GetResourceContent({Locale::FromBCP47("pt")},
267                                            /*resource_name=*/"A", &content));
268 
269   // Uses pt, not pt-PT.
270   EXPECT_EQ("concentrar", content);
271 }
272 
273 }  // namespace
274 }  // namespace libtextclassifier3
275