Home | History | Annotate | Download | only in compile
      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