1 /*
2 * Copyright (C) 2016 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 "compile/PseudolocaleGenerator.h"
18
19 #include "test/Test.h"
20 #include "util/Util.h"
21
22 using ::android::ConfigDescription;
23
24 namespace aapt {
25
TEST(PseudolocaleGeneratorTest,PseudolocalizeStyledString)26 TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
27 android::StringPool pool;
28 android::StyleString original_style;
29 original_style.str = "Hello world!";
30 original_style.spans = {android::Span{"i", 1, 10}, android::Span{"b", 2, 3},
31 android::Span{"b", 6, 7}};
32
33 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
34 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
35 Pseudolocalizer::Method::kNone, &pool);
36
37 EXPECT_EQ(original_style.str, new_string->value->value);
38 ASSERT_EQ(original_style.spans.size(), new_string->value->spans.size());
39
40 EXPECT_EQ(std::string("i"), *new_string->value->spans[0].name);
41 EXPECT_EQ(std::u16string(u"H").size(), new_string->value->spans[0].first_char);
42 EXPECT_EQ(std::u16string(u"Hello worl").size(), new_string->value->spans[0].last_char);
43
44 EXPECT_EQ(std::string("b"), *new_string->value->spans[1].name);
45 EXPECT_EQ(std::u16string(u"He").size(), new_string->value->spans[1].first_char);
46 EXPECT_EQ(std::u16string(u"Hel").size(), new_string->value->spans[1].last_char);
47
48 EXPECT_EQ(std::string("b"), *new_string->value->spans[2].name);
49 EXPECT_EQ(std::u16string(u"Hello ").size(), new_string->value->spans[2].first_char);
50 EXPECT_EQ(std::u16string(u"Hello w").size(), new_string->value->spans[2].last_char);
51
52 original_style.spans.insert(original_style.spans.begin(), android::Span{"em", 0, 11u});
53
54 new_string = PseudolocalizeStyledString(
55 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
56 Pseudolocalizer::Method::kAccent, &pool);
57
58 EXPECT_EQ(std::string("[Ĥéļļö ŵöŕļð¡ one two]"), new_string->value->value);
59 ASSERT_EQ(original_style.spans.size(), new_string->value->spans.size());
60
61 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char);
62 EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļð").size(), new_string->value->spans[0].last_char);
63
64 EXPECT_EQ(std::u16string(u"[Ĥ").size(), new_string->value->spans[1].first_char);
65 EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļ").size(), new_string->value->spans[1].last_char);
66
67 EXPECT_EQ(std::u16string(u"[Ĥé").size(), new_string->value->spans[2].first_char);
68 EXPECT_EQ(std::u16string(u"[Ĥéļ").size(), new_string->value->spans[2].last_char);
69
70 EXPECT_EQ(std::u16string(u"[Ĥéļļö ").size(), new_string->value->spans[3].first_char);
71 EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵ").size(), new_string->value->spans[3].last_char);
72 }
73
TEST(PseudolocaleGeneratorTest,PseudolocalizeAdjacentNestedTags)74 TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentNestedTags) {
75 android::StringPool pool;
76 android::StyleString original_style;
77 original_style.str = "bold";
78 original_style.spans = {android::Span{"b", 0, 3}, android::Span{"i", 0, 3}};
79
80 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
81 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
82 Pseudolocalizer::Method::kAccent, &pool);
83 ASSERT_NE(nullptr, new_string);
84 ASSERT_EQ(2u, new_string->value->spans.size());
85 EXPECT_EQ(std::string("[ɓöļð one]"), new_string->value->value);
86
87 EXPECT_EQ(std::string("b"), *new_string->value->spans[0].name);
88 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char);
89 EXPECT_EQ(std::u16string(u"[ɓöļ").size(), new_string->value->spans[0].last_char);
90
91 EXPECT_EQ(std::string("i"), *new_string->value->spans[1].name);
92 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[1].first_char);
93 EXPECT_EQ(std::u16string(u"[ɓöļ").size(), new_string->value->spans[1].last_char);
94 }
95
TEST(PseudolocaleGeneratorTest,PseudolocalizeAdjacentTagsUnsorted)96 TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentTagsUnsorted) {
97 android::StringPool pool;
98 android::StyleString original_style;
99 original_style.str = "bold";
100 original_style.spans = {android::Span{"i", 2, 3}, android::Span{"b", 0, 1}};
101
102 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
103 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
104 Pseudolocalizer::Method::kAccent, &pool);
105 ASSERT_NE(nullptr, new_string);
106 ASSERT_EQ(2u, new_string->value->spans.size());
107 EXPECT_EQ(std::string("[ɓöļð one]"), new_string->value->value);
108
109 EXPECT_EQ(std::string("b"), *new_string->value->spans[0].name);
110 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char);
111 EXPECT_EQ(std::u16string(u"[ɓ").size(), new_string->value->spans[0].last_char);
112
113 EXPECT_EQ(std::string("i"), *new_string->value->spans[1].name);
114 EXPECT_EQ(std::u16string(u"[ɓö").size(), new_string->value->spans[1].first_char);
115 EXPECT_EQ(std::u16string(u"[ɓöļ").size(), new_string->value->spans[1].last_char);
116 }
117
TEST(PseudolocaleGeneratorTest,PseudolocalizeNestedAndAdjacentTags)118 TEST(PseudolocaleGeneratorTest, PseudolocalizeNestedAndAdjacentTags) {
119 android::StringPool pool;
120 android::StyleString original_style;
121 original_style.str = "This sentence is not what you think it is at all.";
122 original_style.spans = {android::Span{"b", 16u, 19u}, android::Span{"em", 29u, 47u},
123 android::Span{"i", 38u, 40u}, android::Span{"b", 44u, 47u}};
124
125 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
126 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
127 Pseudolocalizer::Method::kAccent, &pool);
128 ASSERT_NE(nullptr, new_string);
129 ASSERT_EQ(4u, new_string->value->spans.size());
130 EXPECT_EQ(std::string(
131 "[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû ţĥîñķ îţ îš åţ åļļ. one two three four five six]"),
132 new_string->value->value);
133
134 EXPECT_EQ(std::string("b"), *new_string->value->spans[0].name);
135 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš").size(), new_string->value->spans[0].first_char);
136 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñö").size(), new_string->value->spans[0].last_char);
137
138 EXPECT_EQ(std::string("em"), *new_string->value->spans[1].name);
139 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû").size(),
140 new_string->value->spans[1].first_char);
141 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû ţĥîñķ îţ îš åţ åļ").size(),
142 new_string->value->spans[1].last_char);
143
144 EXPECT_EQ(std::string("i"), *new_string->value->spans[2].name);
145 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû ţĥîñķ îţ").size(),
146 new_string->value->spans[2].first_char);
147 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû ţĥîñķ îţ î").size(),
148 new_string->value->spans[2].last_char);
149
150 EXPECT_EQ(std::string("b"), *new_string->value->spans[3].name);
151 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû ţĥîñķ îţ îš åţ").size(),
152 new_string->value->spans[3].first_char);
153 EXPECT_EQ(std::u16string(u"[Ţĥîš šéñţéñçé îš ñöţ ŵĥåţ ýöû ţĥîñķ îţ îš åţ åļ").size(),
154 new_string->value->spans[3].last_char);
155 }
156
TEST(PseudolocaleGeneratorTest,PseudolocalizePartsOfString)157 TEST(PseudolocaleGeneratorTest, PseudolocalizePartsOfString) {
158 android::StringPool pool;
159 android::StyleString original_style;
160 original_style.str = "This should NOT be pseudolocalized.";
161 original_style.spans = {android::Span{"em", 4u, 14u}, android::Span{"i", 18u, 33u}};
162 std::unique_ptr<StyledString> original_string =
163 util::make_unique<StyledString>(pool.MakeRef(original_style));
164 original_string->untranslatable_sections = {UntranslatableSection{11u, 15u}};
165
166 std::unique_ptr<StyledString> new_string =
167 PseudolocalizeStyledString(original_string.get(), Pseudolocalizer::Method::kAccent, &pool);
168 ASSERT_NE(nullptr, new_string);
169 ASSERT_EQ(2u, new_string->value->spans.size());
170 EXPECT_EQ(std::string("[Ţĥîš šĥöûļð NOT ɓé þšéûðöļöçåļîžéð. one two three four]"),
171 new_string->value->value);
172
173 EXPECT_EQ(std::string("em"), *new_string->value->spans[0].name);
174 EXPECT_EQ(std::u16string(u"[Ţĥîš").size(), new_string->value->spans[0].first_char);
175 EXPECT_EQ(std::u16string(u"[Ţĥîš šĥöûļð NO").size(), new_string->value->spans[0].last_char);
176
177 EXPECT_EQ(std::string("i"), *new_string->value->spans[1].name);
178 EXPECT_EQ(std::u16string(u"[Ţĥîš šĥöûļð NOT ɓé").size(), new_string->value->spans[1].first_char);
179 EXPECT_EQ(std::u16string(u"[Ţĥîš šĥöûļð NOT ɓé þšéûðöļöçåļîžé").size(),
180 new_string->value->spans[1].last_char);
181 }
182
TEST(PseudolocaleGeneratorTest,PseudolocalizeOnlyDefaultConfigs)183 TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) {
184 std::unique_ptr<ResourceTable> table =
185 test::ResourceTableBuilder()
186 .AddString("android:string/one", "one")
187 .AddString("android:string/two", ResourceId{},
188 test::ParseConfigOrDie("en"), "two")
189 .AddString("android:string/three", "three")
190 .AddString("android:string/three", ResourceId{},
191 test::ParseConfigOrDie("en-rXA"), "three")
192 .AddString("android:string/four", "four")
193 .Build();
194
195 String* val = test::GetValue<String>(table.get(), "android:string/four");
196 ASSERT_NE(nullptr, val);
197 val->SetTranslatable(false);
198
199 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
200 PseudolocaleGenerator generator(std::string("f,m,n"), std::string("1.0"));
201 ASSERT_TRUE(generator.Consume(context.get(), table.get()));
202
203 // Normal pseudolocalization should take place.
204 ASSERT_NE(nullptr,
205 test::GetValueForConfig<String>(table.get(), "android:string/one",
206 test::ParseConfigOrDie("en-rXA")));
207 ASSERT_NE(nullptr,
208 test::GetValueForConfig<String>(table.get(), "android:string/one",
209 test::ParseConfigOrDie("ar-rXB")));
210
211 // No default config for android:string/two, so no pseudlocales should exist.
212 ASSERT_EQ(nullptr,
213 test::GetValueForConfig<String>(table.get(), "android:string/two",
214 test::ParseConfigOrDie("en-rXA")));
215 ASSERT_EQ(nullptr,
216 test::GetValueForConfig<String>(table.get(), "android:string/two",
217 test::ParseConfigOrDie("ar-rXB")));
218
219 // Check that we didn't override manual pseudolocalization.
220 val = test::GetValueForConfig<String>(table.get(), "android:string/three",
221 test::ParseConfigOrDie("en-rXA"));
222 ASSERT_NE(nullptr, val);
223 EXPECT_EQ(std::string("three"), *val->value);
224
225 ASSERT_NE(nullptr,
226 test::GetValueForConfig<String>(table.get(), "android:string/three",
227 test::ParseConfigOrDie("ar-rXB")));
228
229 // Check that four's translateable marker was honored.
230 ASSERT_EQ(nullptr,
231 test::GetValueForConfig<String>(table.get(), "android:string/four",
232 test::ParseConfigOrDie("en-rXA")));
233 ASSERT_EQ(nullptr,
234 test::GetValueForConfig<String>(table.get(), "android:string/four",
235 test::ParseConfigOrDie("ar-rXB")));
236 }
237
TEST(PseudolocaleGeneratorTest,PluralsArePseudolocalized)238 TEST(PseudolocaleGeneratorTest, PluralsArePseudolocalized) {
239 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
240 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder().Build();
241 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
242 plural->values = {util::make_unique<String>(table->string_pool.MakeRef("zero")),
243 util::make_unique<String>(table->string_pool.MakeRef("one"))};
244 ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.pkg:plurals/foo"))
245 .SetValue(std::move(plural))
246 .Build(),
247 context->GetDiagnostics()));
248 std::unique_ptr<Plural> expected = util::make_unique<Plural>();
249 expected->values = {util::make_unique<String>(table->string_pool.MakeRef("[žéŕö one]")),
250 util::make_unique<String>(table->string_pool.MakeRef("[öñé one]"))};
251
252 PseudolocaleGenerator generator(std::string("f,m,n"), std::string("1.0"));
253 ASSERT_TRUE(generator.Consume(context.get(), table.get()));
254
255 const auto* actual = test::GetValueForConfig<Plural>(table.get(), "com.pkg:plurals/foo",
256 test::ParseConfigOrDie("en-rXA"));
257 ASSERT_NE(nullptr, actual);
258 EXPECT_TRUE(actual->Equals(expected.get()));
259 }
260
TEST(PseudolocaleGeneratorTest,RespectUntranslateableSections)261 TEST(PseudolocaleGeneratorTest, RespectUntranslateableSections) {
262 std::unique_ptr<IAaptContext> context =
263 test::ContextBuilder().SetCompilationPackage("android").Build();
264 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
265
266 {
267 android::StyleString original_style;
268 original_style.str = "Hello world!";
269 original_style.spans = {android::Span{"i", 1, 10}, android::Span{"b", 2, 3},
270 android::Span{"b", 6, 7}};
271
272 auto styled_string =
273 util::make_unique<StyledString>(table->string_pool.MakeRef(original_style));
274 styled_string->untranslatable_sections.push_back(UntranslatableSection{6u, 8u});
275 styled_string->untranslatable_sections.push_back(UntranslatableSection{8u, 11u});
276
277 auto string = util::make_unique<String>(table->string_pool.MakeRef(original_style.str));
278 string->untranslatable_sections.push_back(UntranslatableSection{6u, 11u});
279
280 ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("android:string/foo"))
281 .SetValue(std::move(styled_string))
282 .Build(),
283 context->GetDiagnostics()));
284 ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("android:string/bar"))
285 .SetValue(std::move(string))
286 .Build(),
287 context->GetDiagnostics()));
288 }
289
290 PseudolocaleGenerator generator(std::string("f,m,n"), std::string("1.0"));
291 ASSERT_TRUE(generator.Consume(context.get(), table.get()));
292
293 StyledString* new_styled_string = test::GetValueForConfig<StyledString>(
294 table.get(), "android:string/foo", test::ParseConfigOrDie("en-rXA"));
295 ASSERT_NE(nullptr, new_styled_string);
296
297 // "world" should be untranslated.
298 EXPECT_NE(std::string::npos, new_styled_string->value->value.find("world"));
299
300 String* new_string = test::GetValueForConfig<String>(table.get(), "android:string/bar",
301 test::ParseConfigOrDie("en-rXA"));
302 ASSERT_NE(nullptr, new_string);
303
304 // "world" should be untranslated.
305 EXPECT_NE(std::string::npos, new_string->value->find("world"));
306 }
307
TEST(PseudolocaleGeneratorTest,PseudolocalizeGrammaticalGenderForString)308 TEST(PseudolocaleGeneratorTest, PseudolocalizeGrammaticalGenderForString) {
309 std::unique_ptr<ResourceTable> table =
310 test::ResourceTableBuilder().AddString("android:string/foo", "foo").Build();
311
312 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
313 PseudolocaleGenerator generator(std::string("f,m,n"), std::string("1.0"));
314 ASSERT_TRUE(generator.Consume(context.get(), table.get()));
315
316 String* locale = test::GetValueForConfig<String>(table.get(), "android:string/foo",
317 test::ParseConfigOrDie("en-rXA"));
318 ASSERT_NE(nullptr, locale);
319
320 // Grammatical gendered string
321 auto config_feminine = test::ParseConfigOrDie("en-rXA-feminine");
322 config_feminine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
323 String* feminine =
324 test::GetValueForConfig<String>(table.get(), "android:string/foo", config_feminine);
325 ASSERT_NE(nullptr, feminine);
326 EXPECT_EQ(std::string("(F)") + *locale->value, *feminine->value);
327
328 auto config_masculine = test::ParseConfigOrDie("en-rXA-masculine");
329 config_masculine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
330 String* masculine =
331 test::GetValueForConfig<String>(table.get(), "android:string/foo", config_masculine);
332 ASSERT_NE(nullptr, masculine);
333 EXPECT_EQ(std::string("(M)") + *locale->value, *masculine->value);
334
335 auto config_neuter = test::ParseConfigOrDie("en-rXA-neuter");
336 config_neuter.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
337 String* neuter =
338 test::GetValueForConfig<String>(table.get(), "android:string/foo", config_neuter);
339 ASSERT_NE(nullptr, neuter);
340 EXPECT_EQ(std::string("(N)") + *locale->value, *neuter->value);
341 }
342
TEST(PseudolocaleGeneratorTest,PseudolocalizeGrammaticalGenderForPlural)343 TEST(PseudolocaleGeneratorTest, PseudolocalizeGrammaticalGenderForPlural) {
344 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
345 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder().Build();
346 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
347 plural->values = {util::make_unique<String>(table->string_pool.MakeRef("zero")),
348 util::make_unique<String>(table->string_pool.MakeRef("one"))};
349 ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.pkg:plurals/foo"))
350 .SetValue(std::move(plural))
351 .Build(),
352 context->GetDiagnostics()));
353 PseudolocaleGenerator generator(std::string("f,m,n"), std::string("1.0"));
354 ASSERT_TRUE(generator.Consume(context.get(), table.get()));
355
356 Plural* actual = test::GetValueForConfig<Plural>(table.get(), "com.pkg:plurals/foo",
357 test::ParseConfigOrDie("en-rXA"));
358 ASSERT_NE(nullptr, actual);
359
360 // Grammatical gendered Plural
361 auto config_feminine = test::ParseConfigOrDie("en-rXA-feminine");
362 config_feminine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
363 Plural* actual_feminine =
364 test::GetValueForConfig<Plural>(table.get(), "com.pkg:plurals/foo", config_feminine);
365 for (size_t i = 0; i < actual->values.size(); i++) {
366 if (actual->values[i]) {
367 String* locale = ValueCast<String>(actual->values[i].get());
368 String* feminine = ValueCast<String>(actual_feminine->values[i].get());
369 EXPECT_EQ(std::string("(F)") + *locale->value, *feminine->value);
370 }
371 }
372
373 auto config_masculine = test::ParseConfigOrDie("en-rXA-masculine");
374 config_masculine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
375 Plural* actual_masculine =
376 test::GetValueForConfig<Plural>(table.get(), "com.pkg:plurals/foo", config_masculine);
377 ASSERT_NE(nullptr, actual_masculine);
378 for (size_t i = 0; i < actual->values.size(); i++) {
379 if (actual->values[i]) {
380 String* locale = ValueCast<String>(actual->values[i].get());
381 String* masculine = ValueCast<String>(actual_masculine->values[i].get());
382 EXPECT_EQ(std::string("(M)") + *locale->value, *masculine->value);
383 }
384 }
385
386 auto config_neuter = test::ParseConfigOrDie("en-rXA-neuter");
387 config_neuter.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
388 Plural* actual_neuter =
389 test::GetValueForConfig<Plural>(table.get(), "com.pkg:plurals/foo", config_neuter);
390 for (size_t i = 0; i < actual->values.size(); i++) {
391 if (actual->values[i]) {
392 String* locale = ValueCast<String>(actual->values[i].get());
393 String* neuter = ValueCast<String>(actual_neuter->values[i].get());
394 EXPECT_EQ(std::string("(N)") + *locale->value, *neuter->value);
395 }
396 }
397 }
398
TEST(PseudolocaleGeneratorTest,PseudolocalizeGrammaticalGenderForStyledString)399 TEST(PseudolocaleGeneratorTest, PseudolocalizeGrammaticalGenderForStyledString) {
400 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
401 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder().Build();
402 android::StyleString original_style;
403 original_style.str = "Hello world!";
404 original_style.spans = {android::Span{"i", 1, 10}};
405
406 std::unique_ptr<StyledString> original =
407 util::make_unique<StyledString>(table->string_pool.MakeRef(original_style));
408 ASSERT_TRUE(table->AddResource(NewResourceBuilder(test::ParseNameOrDie("android:string/foo"))
409 .SetValue(std::move(original))
410 .Build(),
411 context->GetDiagnostics()));
412 PseudolocaleGenerator generator(std::string("f,m,n"), std::string("1.0"));
413 ASSERT_TRUE(generator.Consume(context.get(), table.get()));
414
415 StyledString* locale = test::GetValueForConfig<StyledString>(table.get(), "android:string/foo",
416 test::ParseConfigOrDie("en-rXA"));
417 ASSERT_NE(nullptr, locale);
418 EXPECT_EQ(1, locale->value->spans.size());
419 EXPECT_EQ(std::string("i"), *locale->value->spans[0].name);
420
421 // Grammatical gendered StyledString
422 auto config_feminine = test::ParseConfigOrDie("en-rXA-feminine");
423 config_feminine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
424 StyledString* feminine =
425 test::GetValueForConfig<StyledString>(table.get(), "android:string/foo", config_feminine);
426 ASSERT_NE(nullptr, feminine);
427 EXPECT_EQ(1, feminine->value->spans.size());
428 EXPECT_EQ(std::string("i"), *feminine->value->spans[0].name);
429 EXPECT_EQ(std::string("(F)") + locale->value->value, feminine->value->value);
430
431 auto config_masculine = test::ParseConfigOrDie("en-rXA-masculine");
432 config_masculine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
433 StyledString* masculine =
434 test::GetValueForConfig<StyledString>(table.get(), "android:string/foo", config_masculine);
435 ASSERT_NE(nullptr, masculine);
436 EXPECT_EQ(1, masculine->value->spans.size());
437 EXPECT_EQ(std::string("i"), *masculine->value->spans[0].name);
438 EXPECT_EQ(std::string("(M)") + locale->value->value, masculine->value->value);
439
440 auto config_neuter = test::ParseConfigOrDie("en-rXA-neuter");
441 config_neuter.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
442 StyledString* neuter =
443 test::GetValueForConfig<StyledString>(table.get(), "android:string/foo", config_neuter);
444 ASSERT_NE(nullptr, neuter);
445 EXPECT_EQ(1, neuter->value->spans.size());
446 EXPECT_EQ(std::string("i"), *neuter->value->spans[0].name);
447 EXPECT_EQ(std::string("(N)") + locale->value->value, neuter->value->value);
448 }
449
TEST(PseudolocaleGeneratorTest,GrammaticalGenderForCertainValues)450 TEST(PseudolocaleGeneratorTest, GrammaticalGenderForCertainValues) {
451 // single gender value
452 std::unique_ptr<ResourceTable> table_0 =
453 test::ResourceTableBuilder().AddString("android:string/foo", "foo").Build();
454
455 std::unique_ptr<IAaptContext> context_0 = test::ContextBuilder().Build();
456 PseudolocaleGenerator generator_0(std::string("f"), std::string("1.0"));
457 ASSERT_TRUE(generator_0.Consume(context_0.get(), table_0.get()));
458
459 String* locale_0 = test::GetValueForConfig<String>(table_0.get(), "android:string/foo",
460 test::ParseConfigOrDie("en-rXA"));
461 ASSERT_NE(nullptr, locale_0);
462
463 auto config_feminine = test::ParseConfigOrDie("en-rXA-feminine");
464 config_feminine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
465 String* feminine_0 =
466 test::GetValueForConfig<String>(table_0.get(), "android:string/foo", config_feminine);
467 ASSERT_NE(nullptr, feminine_0);
468 EXPECT_EQ(std::string("(F)") + *locale_0->value, *feminine_0->value);
469
470 auto config_masculine = test::ParseConfigOrDie("en-rXA-masculine");
471 config_masculine.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
472 String* masculine_0 =
473 test::GetValueForConfig<String>(table_0.get(), "android:string/foo", config_masculine);
474 EXPECT_EQ(nullptr, masculine_0);
475
476 auto config_neuter = test::ParseConfigOrDie("en-rXA-neuter");
477 config_neuter.sdkVersion = android::ResTable_config::SDKVERSION_ANY;
478 String* neuter_0 =
479 test::GetValueForConfig<String>(table_0.get(), "android:string/foo", config_neuter);
480 EXPECT_EQ(nullptr, neuter_0);
481
482 // multiple gender values
483 std::unique_ptr<ResourceTable> table_1 =
484 test::ResourceTableBuilder().AddString("android:string/foo", "foo").Build();
485
486 std::unique_ptr<IAaptContext> context_1 = test::ContextBuilder().Build();
487 PseudolocaleGenerator generator_1(std::string("f,n"), std::string("1.0"));
488 ASSERT_TRUE(generator_1.Consume(context_1.get(), table_1.get()));
489
490 String* locale_1 = test::GetValueForConfig<String>(table_1.get(), "android:string/foo",
491 test::ParseConfigOrDie("en-rXA"));
492 ASSERT_NE(nullptr, locale_1);
493
494 String* feminine_1 =
495 test::GetValueForConfig<String>(table_1.get(), "android:string/foo", config_feminine);
496 ASSERT_NE(nullptr, feminine_1);
497 EXPECT_EQ(std::string("(F)") + *locale_1->value, *feminine_1->value);
498
499 String* masculine_1 =
500 test::GetValueForConfig<String>(table_1.get(), "android:string/foo", config_masculine);
501 EXPECT_EQ(nullptr, masculine_1);
502
503 String* neuter_1 =
504 test::GetValueForConfig<String>(table_1.get(), "android:string/foo", config_neuter);
505 ASSERT_NE(nullptr, neuter_1);
506 EXPECT_EQ(std::string("(N)") + *locale_1->value, *neuter_1->value);
507
508 // invalid gender value
509 std::unique_ptr<ResourceTable> table_2 =
510 test::ResourceTableBuilder().AddString("android:string/foo", "foo").Build();
511
512 std::unique_ptr<IAaptContext> context_2 = test::ContextBuilder().Build();
513 PseudolocaleGenerator generator_2(std::string("invald,"), std::string("1.0"));
514 ASSERT_FALSE(generator_2.Consume(context_2.get(), table_2.get()));
515 }
516
517 } // namespace aapt
518