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 26 TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) { 27 StringPool pool; 28 StyleString original_style; 29 original_style.str = "Hello world!"; 30 original_style.spans = {Span{"i", 1, 10}, Span{"b", 2, 3}, Span{"b", 6, 7}}; 31 32 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString( 33 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(), 34 Pseudolocalizer::Method::kNone, &pool); 35 36 EXPECT_EQ(original_style.str, new_string->value->value); 37 ASSERT_EQ(original_style.spans.size(), new_string->value->spans.size()); 38 39 EXPECT_EQ(std::string("i"), *new_string->value->spans[0].name); 40 EXPECT_EQ(std::u16string(u"H").size(), new_string->value->spans[0].first_char); 41 EXPECT_EQ(std::u16string(u"Hello worl").size(), new_string->value->spans[0].last_char); 42 43 EXPECT_EQ(std::string("b"), *new_string->value->spans[1].name); 44 EXPECT_EQ(std::u16string(u"He").size(), new_string->value->spans[1].first_char); 45 EXPECT_EQ(std::u16string(u"Hel").size(), new_string->value->spans[1].last_char); 46 47 EXPECT_EQ(std::string("b"), *new_string->value->spans[2].name); 48 EXPECT_EQ(std::u16string(u"Hello ").size(), new_string->value->spans[2].first_char); 49 EXPECT_EQ(std::u16string(u"Hello w").size(), new_string->value->spans[2].last_char); 50 51 original_style.spans.insert(original_style.spans.begin(), Span{"em", 0, 11u}); 52 53 new_string = PseudolocalizeStyledString( 54 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(), 55 Pseudolocalizer::Method::kAccent, &pool); 56 57 EXPECT_EQ(std::string("[ one two]"), new_string->value->value); 58 ASSERT_EQ(original_style.spans.size(), new_string->value->spans.size()); 59 60 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char); 61 EXPECT_EQ(std::u16string(u"[ ").size(), new_string->value->spans[0].last_char); 62 63 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[1].first_char); 64 EXPECT_EQ(std::u16string(u"[ ").size(), new_string->value->spans[1].last_char); 65 66 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[2].first_char); 67 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[2].last_char); 68 69 EXPECT_EQ(std::u16string(u"[ ").size(), new_string->value->spans[3].first_char); 70 EXPECT_EQ(std::u16string(u"[ ").size(), new_string->value->spans[3].last_char); 71 } 72 73 TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentNestedTags) { 74 StringPool pool; 75 StyleString original_style; 76 original_style.str = "bold"; 77 original_style.spans = {Span{"b", 0, 3}, Span{"i", 0, 3}}; 78 79 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString( 80 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(), 81 Pseudolocalizer::Method::kAccent, &pool); 82 ASSERT_NE(nullptr, new_string); 83 ASSERT_EQ(2u, new_string->value->spans.size()); 84 EXPECT_EQ(std::string("[ one]"), new_string->value->value); 85 86 EXPECT_EQ(std::string("b"), *new_string->value->spans[0].name); 87 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char); 88 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].last_char); 89 90 EXPECT_EQ(std::string("i"), *new_string->value->spans[1].name); 91 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[1].first_char); 92 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[1].last_char); 93 } 94 95 TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentTagsUnsorted) { 96 StringPool pool; 97 StyleString original_style; 98 original_style.str = "bold"; 99 original_style.spans = {Span{"i", 2, 3}, Span{"b", 0, 1}}; 100 101 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString( 102 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(), 103 Pseudolocalizer::Method::kAccent, &pool); 104 ASSERT_NE(nullptr, new_string); 105 ASSERT_EQ(2u, new_string->value->spans.size()); 106 EXPECT_EQ(std::string("[ one]"), new_string->value->value); 107 108 EXPECT_EQ(std::string("b"), *new_string->value->spans[0].name); 109 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char); 110 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].last_char); 111 112 EXPECT_EQ(std::string("i"), *new_string->value->spans[1].name); 113 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[1].first_char); 114 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[1].last_char); 115 } 116 117 TEST(PseudolocaleGeneratorTest, PseudolocalizeNestedAndAdjacentTags) { 118 StringPool pool; 119 StyleString original_style; 120 original_style.str = "This sentence is not what you think it is at all."; 121 original_style.spans = {Span{"b", 16u, 19u}, Span{"em", 29u, 47u}, Span{"i", 38u, 40u}, 122 Span{"b", 44u, 47u}}; 123 124 std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString( 125 util::make_unique<StyledString>(pool.MakeRef(original_style)).get(), 126 Pseudolocalizer::Method::kAccent, &pool); 127 ASSERT_NE(nullptr, new_string); 128 ASSERT_EQ(4u, new_string->value->spans.size()); 129 EXPECT_EQ(std::string( 130 "[ . one two three four five six]"), 131 new_string->value->value); 132 133 EXPECT_EQ(std::string("b"), *new_string->value->spans[0].name); 134 EXPECT_EQ(std::u16string(u"[ ").size(), new_string->value->spans[0].first_char); 135 EXPECT_EQ(std::u16string(u"[ ").size(), new_string->value->spans[0].last_char); 136 137 EXPECT_EQ(std::string("em"), *new_string->value->spans[1].name); 138 EXPECT_EQ(std::u16string(u"[ ").size(), 139 new_string->value->spans[1].first_char); 140 EXPECT_EQ(std::u16string(u"[ ").size(), 141 new_string->value->spans[1].last_char); 142 143 EXPECT_EQ(std::string("i"), *new_string->value->spans[2].name); 144 EXPECT_EQ(std::u16string(u"[ ").size(), 145 new_string->value->spans[2].first_char); 146 EXPECT_EQ(std::u16string(u"[ ").size(), 147 new_string->value->spans[2].last_char); 148 149 EXPECT_EQ(std::string("b"), *new_string->value->spans[3].name); 150 EXPECT_EQ(std::u16string(u"[ ").size(), 151 new_string->value->spans[3].first_char); 152 EXPECT_EQ(std::u16string(u"[ ").size(), 153 new_string->value->spans[3].last_char); 154 } 155 156 TEST(PseudolocaleGeneratorTest, PseudolocalizePartsOfString) { 157 StringPool pool; 158 StyleString original_style; 159 original_style.str = "This should NOT be pseudolocalized."; 160 original_style.spans = {Span{"em", 4u, 14u}, Span{"i", 18u, 33u}}; 161 std::unique_ptr<StyledString> original_string = 162 util::make_unique<StyledString>(pool.MakeRef(original_style)); 163 original_string->untranslatable_sections = {UntranslatableSection{11u, 15u}}; 164 165 std::unique_ptr<StyledString> new_string = 166 PseudolocalizeStyledString(original_string.get(), Pseudolocalizer::Method::kAccent, &pool); 167 ASSERT_NE(nullptr, new_string); 168 ASSERT_EQ(2u, new_string->value->spans.size()); 169 EXPECT_EQ(std::string("[ NOT . one two three four]"), 170 new_string->value->value); 171 172 EXPECT_EQ(std::string("em"), *new_string->value->spans[0].name); 173 EXPECT_EQ(std::u16string(u"[").size(), new_string->value->spans[0].first_char); 174 EXPECT_EQ(std::u16string(u"[ NO").size(), new_string->value->spans[0].last_char); 175 176 EXPECT_EQ(std::string("i"), *new_string->value->spans[1].name); 177 EXPECT_EQ(std::u16string(u"[ NOT ").size(), new_string->value->spans[1].first_char); 178 EXPECT_EQ(std::u16string(u"[ NOT ").size(), 179 new_string->value->spans[1].last_char); 180 } 181 182 TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) { 183 std::unique_ptr<ResourceTable> table = 184 test::ResourceTableBuilder() 185 .AddString("android:string/one", "one") 186 .AddString("android:string/two", ResourceId{}, 187 test::ParseConfigOrDie("en"), "two") 188 .AddString("android:string/three", "three") 189 .AddString("android:string/three", ResourceId{}, 190 test::ParseConfigOrDie("en-rXA"), "three") 191 .AddString("android:string/four", "four") 192 .Build(); 193 194 String* val = test::GetValue<String>(table.get(), "android:string/four"); 195 ASSERT_NE(nullptr, val); 196 val->SetTranslatable(false); 197 198 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 199 PseudolocaleGenerator generator; 200 ASSERT_TRUE(generator.Consume(context.get(), table.get())); 201 202 // Normal pseudolocalization should take place. 203 ASSERT_NE(nullptr, 204 test::GetValueForConfig<String>(table.get(), "android:string/one", 205 test::ParseConfigOrDie("en-rXA"))); 206 ASSERT_NE(nullptr, 207 test::GetValueForConfig<String>(table.get(), "android:string/one", 208 test::ParseConfigOrDie("ar-rXB"))); 209 210 // No default config for android:string/two, so no pseudlocales should exist. 211 ASSERT_EQ(nullptr, 212 test::GetValueForConfig<String>(table.get(), "android:string/two", 213 test::ParseConfigOrDie("en-rXA"))); 214 ASSERT_EQ(nullptr, 215 test::GetValueForConfig<String>(table.get(), "android:string/two", 216 test::ParseConfigOrDie("ar-rXB"))); 217 218 // Check that we didn't override manual pseudolocalization. 219 val = test::GetValueForConfig<String>(table.get(), "android:string/three", 220 test::ParseConfigOrDie("en-rXA")); 221 ASSERT_NE(nullptr, val); 222 EXPECT_EQ(std::string("three"), *val->value); 223 224 ASSERT_NE(nullptr, 225 test::GetValueForConfig<String>(table.get(), "android:string/three", 226 test::ParseConfigOrDie("ar-rXB"))); 227 228 // Check that four's translateable marker was honored. 229 ASSERT_EQ(nullptr, 230 test::GetValueForConfig<String>(table.get(), "android:string/four", 231 test::ParseConfigOrDie("en-rXA"))); 232 ASSERT_EQ(nullptr, 233 test::GetValueForConfig<String>(table.get(), "android:string/four", 234 test::ParseConfigOrDie("ar-rXB"))); 235 } 236 237 TEST(PseudolocaleGeneratorTest, RespectUntranslateableSections) { 238 std::unique_ptr<IAaptContext> context = 239 test::ContextBuilder().SetCompilationPackage("android").Build(); 240 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); 241 242 { 243 StyleString original_style; 244 original_style.str = "Hello world!"; 245 original_style.spans = {Span{"i", 1, 10}, Span{"b", 2, 3}, Span{"b", 6, 7}}; 246 247 auto styled_string = 248 util::make_unique<StyledString>(table->string_pool.MakeRef(original_style)); 249 styled_string->untranslatable_sections.push_back(UntranslatableSection{6u, 8u}); 250 styled_string->untranslatable_sections.push_back(UntranslatableSection{8u, 11u}); 251 252 auto string = util::make_unique<String>(table->string_pool.MakeRef(original_style.str)); 253 string->untranslatable_sections.push_back(UntranslatableSection{6u, 11u}); 254 255 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("android:string/foo"), ConfigDescription{}, 256 {} /* product */, std::move(styled_string), 257 context->GetDiagnostics())); 258 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("android:string/bar"), ConfigDescription{}, 259 {} /* product */, std::move(string), context->GetDiagnostics())); 260 } 261 262 PseudolocaleGenerator generator; 263 ASSERT_TRUE(generator.Consume(context.get(), table.get())); 264 265 StyledString* new_styled_string = test::GetValueForConfig<StyledString>( 266 table.get(), "android:string/foo", test::ParseConfigOrDie("en-rXA")); 267 ASSERT_NE(nullptr, new_styled_string); 268 269 // "world" should be untranslated. 270 EXPECT_NE(std::string::npos, new_styled_string->value->value.find("world")); 271 272 String* new_string = test::GetValueForConfig<String>(table.get(), "android:string/bar", 273 test::ParseConfigOrDie("en-rXA")); 274 ASSERT_NE(nullptr, new_string); 275 276 // "world" should be untranslated. 277 EXPECT_NE(std::string::npos, new_string->value->find("world")); 278 } 279 280 } // namespace aapt 281