Home | History | Annotate | Download | only in aapt2
      1 /*
      2  * Copyright (C) 2015 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 "StringPool.h"
     18 
     19 #include <string>
     20 
     21 #include "androidfw/StringPiece.h"
     22 
     23 #include "Diagnostics.h"
     24 #include "test/Test.h"
     25 #include "util/Util.h"
     26 
     27 using ::android::StringPiece;
     28 using ::android::StringPiece16;
     29 using ::testing::Eq;
     30 using ::testing::Ne;
     31 using ::testing::NotNull;
     32 using ::testing::Pointee;
     33 
     34 namespace aapt {
     35 
     36 TEST(StringPoolTest, InsertOneString) {
     37   StringPool pool;
     38 
     39   StringPool::Ref ref = pool.MakeRef("wut");
     40   EXPECT_THAT(*ref, Eq("wut"));
     41 }
     42 
     43 TEST(StringPoolTest, InsertTwoUniqueStrings) {
     44   StringPool pool;
     45 
     46   StringPool::Ref ref_a = pool.MakeRef("wut");
     47   StringPool::Ref ref_b = pool.MakeRef("hey");
     48 
     49   EXPECT_THAT(*ref_a, Eq("wut"));
     50   EXPECT_THAT(*ref_b, Eq("hey"));
     51 }
     52 
     53 TEST(StringPoolTest, DoNotInsertNewDuplicateString) {
     54   StringPool pool;
     55 
     56   StringPool::Ref ref_a = pool.MakeRef("wut");
     57   StringPool::Ref ref_b = pool.MakeRef("wut");
     58 
     59   EXPECT_THAT(*ref_a, Eq("wut"));
     60   EXPECT_THAT(*ref_b, Eq("wut"));
     61   EXPECT_THAT(pool.size(), Eq(1u));
     62 }
     63 
     64 TEST(StringPoolTest, DoNotDedupeSameStringDifferentPriority) {
     65   StringPool pool;
     66 
     67   StringPool::Ref ref_a = pool.MakeRef("wut", StringPool::Context(0x81010001));
     68   StringPool::Ref ref_b = pool.MakeRef("wut", StringPool::Context(0x81010002));
     69 
     70   EXPECT_THAT(*ref_a, Eq("wut"));
     71   EXPECT_THAT(*ref_b, Eq("wut"));
     72   EXPECT_THAT(pool.size(), Eq(2u));
     73 }
     74 
     75 TEST(StringPoolTest, MaintainInsertionOrderIndex) {
     76   StringPool pool;
     77 
     78   StringPool::Ref ref_a = pool.MakeRef("z");
     79   StringPool::Ref ref_b = pool.MakeRef("a");
     80   StringPool::Ref ref_c = pool.MakeRef("m");
     81 
     82   EXPECT_THAT(ref_a.index(), Eq(0u));
     83   EXPECT_THAT(ref_b.index(), Eq(1u));
     84   EXPECT_THAT(ref_c.index(), Eq(2u));
     85 }
     86 
     87 TEST(StringPoolTest, PruneStringsWithNoReferences) {
     88   StringPool pool;
     89 
     90   StringPool::Ref ref_a = pool.MakeRef("foo");
     91 
     92   {
     93     StringPool::Ref ref_b = pool.MakeRef("wut");
     94     EXPECT_THAT(*ref_b, Eq("wut"));
     95     EXPECT_THAT(pool.size(), Eq(2u));
     96     pool.Prune();
     97     EXPECT_THAT(pool.size(), Eq(2u));
     98   }
     99   EXPECT_THAT(pool.size(), Eq(2u));
    100 
    101   {
    102     StringPool::Ref ref_c = pool.MakeRef("bar");
    103     EXPECT_THAT(pool.size(), Eq(3u));
    104 
    105     pool.Prune();
    106     EXPECT_THAT(pool.size(), Eq(2u));
    107   }
    108   EXPECT_THAT(pool.size(), Eq(2u));
    109 
    110   pool.Prune();
    111   EXPECT_THAT(pool.size(), Eq(1u));
    112 }
    113 
    114 TEST(StringPoolTest, SortAndMaintainIndexesInStringReferences) {
    115   StringPool pool;
    116 
    117   StringPool::Ref ref_a = pool.MakeRef("z");
    118   StringPool::Ref ref_b = pool.MakeRef("a");
    119   StringPool::Ref ref_c = pool.MakeRef("m");
    120 
    121   EXPECT_THAT(*ref_a, Eq("z"));
    122   EXPECT_THAT(ref_a.index(), Eq(0u));
    123 
    124   EXPECT_THAT(*ref_b, Eq("a"));
    125   EXPECT_THAT(ref_b.index(), Eq(1u));
    126 
    127   EXPECT_THAT(*ref_c, Eq("m"));
    128   EXPECT_THAT(ref_c.index(), Eq(2u));
    129 
    130   pool.Sort();
    131 
    132   EXPECT_THAT(*ref_a, Eq("z"));
    133   EXPECT_THAT(ref_a.index(), Eq(2u));
    134 
    135   EXPECT_THAT(*ref_b, Eq("a"));
    136   EXPECT_THAT(ref_b.index(), Eq(0u));
    137 
    138   EXPECT_THAT(*ref_c, Eq("m"));
    139   EXPECT_THAT(ref_c.index(), Eq(1u));
    140 }
    141 
    142 TEST(StringPoolTest, SortAndStillDedupe) {
    143   StringPool pool;
    144 
    145   StringPool::Ref ref_a = pool.MakeRef("z");
    146   StringPool::Ref ref_b = pool.MakeRef("a");
    147   StringPool::Ref ref_c = pool.MakeRef("m");
    148 
    149   pool.Sort();
    150 
    151   StringPool::Ref ref_d = pool.MakeRef("z");
    152   StringPool::Ref ref_e = pool.MakeRef("a");
    153   StringPool::Ref ref_f = pool.MakeRef("m");
    154 
    155   EXPECT_THAT(ref_d.index(), Eq(ref_a.index()));
    156   EXPECT_THAT(ref_e.index(), Eq(ref_b.index()));
    157   EXPECT_THAT(ref_f.index(), Eq(ref_c.index()));
    158 }
    159 
    160 TEST(StringPoolTest, AddStyles) {
    161   StringPool pool;
    162 
    163   StringPool::StyleRef ref = pool.MakeRef(StyleString{{"android"}, {Span{{"b"}, 2, 6}}});
    164   EXPECT_THAT(ref.index(), Eq(0u));
    165   EXPECT_THAT(ref->value, Eq("android"));
    166   ASSERT_THAT(ref->spans.size(), Eq(1u));
    167 
    168   const StringPool::Span& span = ref->spans.front();
    169   EXPECT_THAT(*span.name, Eq("b"));
    170   EXPECT_THAT(span.first_char, Eq(2u));
    171   EXPECT_THAT(span.last_char, Eq(6u));
    172 }
    173 
    174 TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
    175   StringPool pool;
    176 
    177   StringPool::Ref ref = pool.MakeRef("android");
    178 
    179   StyleString str{{"android"}};
    180   StringPool::StyleRef style_ref = pool.MakeRef(StyleString{{"android"}});
    181 
    182   EXPECT_THAT(ref.index(), Ne(style_ref.index()));
    183 }
    184 
    185 TEST(StringPoolTest, StylesAndStringsAreSeparateAfterSorting) {
    186   StringPool pool;
    187 
    188   StringPool::StyleRef ref_a = pool.MakeRef(StyleString{{"beta"}});
    189   StringPool::Ref ref_b = pool.MakeRef("alpha");
    190   StringPool::StyleRef ref_c = pool.MakeRef(StyleString{{"alpha"}});
    191 
    192   EXPECT_THAT(ref_b.index(), Ne(ref_c.index()));
    193 
    194   pool.Sort();
    195 
    196   EXPECT_THAT(ref_c.index(), Eq(0u));
    197   EXPECT_THAT(ref_a.index(), Eq(1u));
    198   EXPECT_THAT(ref_b.index(), Eq(2u));
    199 }
    200 
    201 TEST(StringPoolTest, FlattenEmptyStringPoolUtf8) {
    202   using namespace android;  // For NO_ERROR on Windows.
    203   StdErrDiagnostics diag;
    204 
    205   StringPool pool;
    206   BigBuffer buffer(1024);
    207   StringPool::FlattenUtf8(&buffer, pool, &diag);
    208 
    209   std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
    210   ResStringPool test;
    211   ASSERT_THAT(test.setTo(data.get(), buffer.size()), Eq(NO_ERROR));
    212 }
    213 
    214 TEST(StringPoolTest, FlattenOddCharactersUtf16) {
    215   using namespace android;  // For NO_ERROR on Windows.
    216   StdErrDiagnostics diag;
    217 
    218   StringPool pool;
    219   pool.MakeRef("\u093f");
    220   BigBuffer buffer(1024);
    221   StringPool::FlattenUtf16(&buffer, pool, &diag);
    222 
    223   std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
    224   ResStringPool test;
    225   ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
    226   size_t len = 0;
    227   const char16_t* str = test.stringAt(0, &len);
    228   EXPECT_THAT(len, Eq(1u));
    229   EXPECT_THAT(str, Pointee(Eq(u'\u093f')));
    230   EXPECT_THAT(str[1], Eq(0u));
    231 }
    232 
    233 constexpr const char* sLongString =
    234     ""
    235     ""
    236     "SMS "
    237     ""
    238     "OFF";
    239 
    240 TEST(StringPoolTest, Flatten) {
    241   using namespace android;  // For NO_ERROR on Windows.
    242   StdErrDiagnostics diag;
    243 
    244   StringPool pool;
    245 
    246   StringPool::Ref ref_a = pool.MakeRef("hello");
    247   StringPool::Ref ref_b = pool.MakeRef("goodbye");
    248   StringPool::Ref ref_c = pool.MakeRef(sLongString);
    249   StringPool::Ref ref_d = pool.MakeRef("");
    250   StringPool::StyleRef ref_e =
    251       pool.MakeRef(StyleString{{"style"}, {Span{{"b"}, 0, 1}, Span{{"i"}, 2, 3}}});
    252 
    253   // Styles are always first.
    254   EXPECT_THAT(ref_e.index(), Eq(0u));
    255 
    256   EXPECT_THAT(ref_a.index(), Eq(1u));
    257   EXPECT_THAT(ref_b.index(), Eq(2u));
    258   EXPECT_THAT(ref_c.index(), Eq(3u));
    259   EXPECT_THAT(ref_d.index(), Eq(4u));
    260 
    261   BigBuffer buffers[2] = {BigBuffer(1024), BigBuffer(1024)};
    262   StringPool::FlattenUtf8(&buffers[0], pool, &diag);
    263   StringPool::FlattenUtf16(&buffers[1], pool, &diag);
    264 
    265   // Test both UTF-8 and UTF-16 buffers.
    266   for (const BigBuffer& buffer : buffers) {
    267     std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
    268 
    269     ResStringPool test;
    270     ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
    271 
    272     EXPECT_THAT(util::GetString(test, 1), Eq("hello"));
    273     EXPECT_THAT(util::GetString16(test, 1), Eq(u"hello"));
    274 
    275     EXPECT_THAT(util::GetString(test, 2), Eq("goodbye"));
    276     EXPECT_THAT(util::GetString16(test, 2), Eq(u"goodbye"));
    277 
    278     EXPECT_THAT(util::GetString(test, 3), Eq(sLongString));
    279     EXPECT_THAT(util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString)));
    280 
    281     size_t len;
    282     EXPECT_TRUE(test.stringAt(4, &len) != nullptr || test.string8At(4, &len) != nullptr);
    283 
    284     EXPECT_THAT(util::GetString(test, 0), Eq("style"));
    285     EXPECT_THAT(util::GetString16(test, 0), Eq(u"style"));
    286 
    287     const ResStringPool_span* span = test.styleAt(0);
    288     ASSERT_THAT(span, NotNull());
    289     EXPECT_THAT(util::GetString(test, span->name.index), Eq("b"));
    290     EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"b"));
    291     EXPECT_THAT(span->firstChar, Eq(0u));
    292     EXPECT_THAT(span->lastChar, Eq(1u));
    293     span++;
    294 
    295     ASSERT_THAT(span->name.index, Ne(ResStringPool_span::END));
    296     EXPECT_THAT(util::GetString(test, span->name.index), Eq("i"));
    297     EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"i"));
    298     EXPECT_THAT(span->firstChar, Eq(2u));
    299     EXPECT_THAT(span->lastChar, Eq(3u));
    300     span++;
    301 
    302     EXPECT_THAT(span->name.index, Eq(ResStringPool_span::END));
    303   }
    304 }
    305 
    306 
    307 TEST(StringPoolTest, MaxEncodingLength) {
    308   StdErrDiagnostics diag;
    309   using namespace android;  // For NO_ERROR on Windows.
    310   ResStringPool test;
    311 
    312   StringPool pool;
    313   pool.MakeRef("aaaaaaaaaa");
    314   BigBuffer buffers[2] = {BigBuffer(1024), BigBuffer(1024)};
    315 
    316   // Make sure a UTF-8 string under the maximum length does not produce an error
    317   EXPECT_THAT(StringPool::FlattenUtf8(&buffers[0], pool, &diag), Eq(true));
    318   std::unique_ptr<uint8_t[]> data = util::Copy(buffers[0]);
    319   test.setTo(data.get(), buffers[0].size());
    320   EXPECT_THAT(util::GetString(test, 0), Eq("aaaaaaaaaa"));
    321 
    322   // Make sure a UTF-16 string under the maximum length does not produce an error
    323   EXPECT_THAT(StringPool::FlattenUtf16(&buffers[1], pool, &diag), Eq(true));
    324   data = util::Copy(buffers[1]);
    325   test.setTo(data.get(), buffers[1].size());
    326   EXPECT_THAT(util::GetString16(test, 0), Eq(u"aaaaaaaaaa"));
    327 
    328   StringPool pool2;
    329   std::string longStr(50000, 'a');
    330   pool2.MakeRef("this fits1");
    331   pool2.MakeRef(longStr);
    332   pool2.MakeRef("this fits2");
    333   BigBuffer buffers2[2] = {BigBuffer(1024), BigBuffer(1024)};
    334 
    335   // Make sure a string that exceeds the maximum length of UTF-8 produces an
    336   // error and writes a shorter error string instead
    337   EXPECT_THAT(StringPool::FlattenUtf8(&buffers2[0], pool2, &diag), Eq(false));
    338   data = util::Copy(buffers2[0]);
    339   test.setTo(data.get(), buffers2[0].size());
    340   EXPECT_THAT(util::GetString(test, 0), "this fits1");
    341   EXPECT_THAT(util::GetString(test, 1), "STRING_TOO_LARGE");
    342   EXPECT_THAT(util::GetString(test, 2), "this fits2");
    343 
    344   // Make sure a string that a string that exceeds the maximum length of UTF-8
    345   // but not UTF-16 does not error for UTF-16
    346   StringPool pool3;
    347   std::u16string longStr16(50000, 'a');
    348   pool3.MakeRef(longStr);
    349   EXPECT_THAT(StringPool::FlattenUtf16(&buffers2[1], pool3, &diag), Eq(true));
    350   data = util::Copy(buffers2[1]);
    351   test.setTo(data.get(), buffers2[1].size());
    352   EXPECT_THAT(util::GetString16(test, 0), Eq(longStr16));
    353 }
    354 
    355 }  // namespace aapt
    356