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