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 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