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 "test/Test.h"
     24 #include "util/Util.h"
     25 
     26 using android::StringPiece;
     27 using android::StringPiece16;
     28 
     29 namespace aapt {
     30 
     31 TEST(StringPoolTest, InsertOneString) {
     32   StringPool pool;
     33 
     34   StringPool::Ref ref = pool.MakeRef("wut");
     35   EXPECT_EQ(*ref, "wut");
     36 }
     37 
     38 TEST(StringPoolTest, InsertTwoUniqueStrings) {
     39   StringPool pool;
     40 
     41   StringPool::Ref ref = pool.MakeRef("wut");
     42   StringPool::Ref ref2 = pool.MakeRef("hey");
     43 
     44   EXPECT_EQ(*ref, "wut");
     45   EXPECT_EQ(*ref2, "hey");
     46 }
     47 
     48 TEST(StringPoolTest, DoNotInsertNewDuplicateString) {
     49   StringPool pool;
     50 
     51   StringPool::Ref ref = pool.MakeRef("wut");
     52   StringPool::Ref ref2 = pool.MakeRef("wut");
     53 
     54   EXPECT_EQ(*ref, "wut");
     55   EXPECT_EQ(*ref2, "wut");
     56   EXPECT_EQ(1u, pool.size());
     57 }
     58 
     59 TEST(StringPoolTest, MaintainInsertionOrderIndex) {
     60   StringPool pool;
     61 
     62   StringPool::Ref ref = pool.MakeRef("z");
     63   StringPool::Ref ref2 = pool.MakeRef("a");
     64   StringPool::Ref ref3 = pool.MakeRef("m");
     65 
     66   EXPECT_EQ(0u, ref.index());
     67   EXPECT_EQ(1u, ref2.index());
     68   EXPECT_EQ(2u, ref3.index());
     69 }
     70 
     71 TEST(StringPoolTest, PruneStringsWithNoReferences) {
     72   StringPool pool;
     73 
     74   StringPool::Ref refA = pool.MakeRef("foo");
     75   {
     76     StringPool::Ref ref = pool.MakeRef("wut");
     77     EXPECT_EQ(*ref, "wut");
     78     EXPECT_EQ(2u, pool.size());
     79   }
     80   StringPool::Ref refB = pool.MakeRef("bar");
     81 
     82   EXPECT_EQ(3u, pool.size());
     83   pool.Prune();
     84   EXPECT_EQ(2u, pool.size());
     85   StringPool::const_iterator iter = begin(pool);
     86   EXPECT_EQ((*iter)->value, "foo");
     87   EXPECT_LT((*iter)->index, 2u);
     88   ++iter;
     89   EXPECT_EQ((*iter)->value, "bar");
     90   EXPECT_LT((*iter)->index, 2u);
     91 }
     92 
     93 TEST(StringPoolTest, SortAndMaintainIndexesInReferences) {
     94   StringPool pool;
     95 
     96   StringPool::Ref ref = pool.MakeRef("z");
     97   StringPool::StyleRef ref2 = pool.MakeRef(StyleString{{"a"}});
     98   StringPool::Ref ref3 = pool.MakeRef("m");
     99 
    100   EXPECT_EQ(*ref, "z");
    101   EXPECT_EQ(0u, ref.index());
    102 
    103   EXPECT_EQ(*(ref2->str), "a");
    104   EXPECT_EQ(1u, ref2.index());
    105 
    106   EXPECT_EQ(*ref3, "m");
    107   EXPECT_EQ(2u, ref3.index());
    108 
    109   pool.Sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
    110     return a.value < b.value;
    111   });
    112 
    113   EXPECT_EQ(*ref, "z");
    114   EXPECT_EQ(2u, ref.index());
    115 
    116   EXPECT_EQ(*(ref2->str), "a");
    117   EXPECT_EQ(0u, ref2.index());
    118 
    119   EXPECT_EQ(*ref3, "m");
    120   EXPECT_EQ(1u, ref3.index());
    121 }
    122 
    123 TEST(StringPoolTest, SortAndStillDedupe) {
    124   StringPool pool;
    125 
    126   StringPool::Ref ref = pool.MakeRef("z");
    127   StringPool::Ref ref2 = pool.MakeRef("a");
    128   StringPool::Ref ref3 = pool.MakeRef("m");
    129 
    130   pool.Sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
    131     return a.value < b.value;
    132   });
    133 
    134   StringPool::Ref ref4 = pool.MakeRef("z");
    135   StringPool::Ref ref5 = pool.MakeRef("a");
    136   StringPool::Ref ref6 = pool.MakeRef("m");
    137 
    138   EXPECT_EQ(ref4.index(), ref.index());
    139   EXPECT_EQ(ref5.index(), ref2.index());
    140   EXPECT_EQ(ref6.index(), ref3.index());
    141 }
    142 
    143 TEST(StringPoolTest, AddStyles) {
    144   StringPool pool;
    145 
    146   StyleString str{{"android"}, {Span{{"b"}, 2, 6}}};
    147 
    148   StringPool::StyleRef ref = pool.MakeRef(str);
    149 
    150   EXPECT_EQ(0u, ref.index());
    151   EXPECT_EQ(std::string("android"), *(ref->str));
    152   ASSERT_EQ(1u, ref->spans.size());
    153 
    154   const StringPool::Span& span = ref->spans.front();
    155   EXPECT_EQ(*(span.name), "b");
    156   EXPECT_EQ(2u, span.first_char);
    157   EXPECT_EQ(6u, span.last_char);
    158 }
    159 
    160 TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
    161   StringPool pool;
    162 
    163   StringPool::Ref ref = pool.MakeRef("android");
    164 
    165   StyleString str{{"android"}};
    166   StringPool::StyleRef styleRef = pool.MakeRef(str);
    167 
    168   EXPECT_NE(ref.index(), styleRef.index());
    169 }
    170 
    171 TEST(StringPoolTest, FlattenEmptyStringPoolUtf8) {
    172   using namespace android;  // For NO_ERROR on Windows.
    173 
    174   StringPool pool;
    175   BigBuffer buffer(1024);
    176   StringPool::FlattenUtf8(&buffer, pool);
    177 
    178   std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
    179   ResStringPool test;
    180   ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
    181 }
    182 
    183 TEST(StringPoolTest, FlattenOddCharactersUtf16) {
    184   using namespace android;  // For NO_ERROR on Windows.
    185 
    186   StringPool pool;
    187   pool.MakeRef("\u093f");
    188   BigBuffer buffer(1024);
    189   StringPool::FlattenUtf16(&buffer, pool);
    190 
    191   std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
    192   ResStringPool test;
    193   ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
    194   size_t len = 0;
    195   const char16_t* str = test.stringAt(0, &len);
    196   EXPECT_EQ(1u, len);
    197   EXPECT_EQ(u'\u093f', *str);
    198   EXPECT_EQ(0u, str[1]);
    199 }
    200 
    201 constexpr const char* sLongString =
    202     ""
    203     ""
    204     "SMS "
    205     ""
    206     "OFF";
    207 
    208 TEST(StringPoolTest, Flatten) {
    209   using namespace android;  // For NO_ERROR on Windows.
    210 
    211   StringPool pool;
    212 
    213   StringPool::Ref ref1 = pool.MakeRef("hello");
    214   StringPool::Ref ref2 = pool.MakeRef("goodbye");
    215   StringPool::Ref ref3 = pool.MakeRef(sLongString);
    216   StringPool::Ref ref4 = pool.MakeRef("");
    217   StringPool::StyleRef ref5 = pool.MakeRef(
    218       StyleString{{"style"}, {Span{{"b"}, 0, 1}, Span{{"i"}, 2, 3}}});
    219 
    220   EXPECT_EQ(0u, ref1.index());
    221   EXPECT_EQ(1u, ref2.index());
    222   EXPECT_EQ(2u, ref3.index());
    223   EXPECT_EQ(3u, ref4.index());
    224   EXPECT_EQ(4u, ref5.index());
    225 
    226   BigBuffer buffers[2] = {BigBuffer(1024), BigBuffer(1024)};
    227   StringPool::FlattenUtf8(&buffers[0], pool);
    228   StringPool::FlattenUtf16(&buffers[1], pool);
    229 
    230   // Test both UTF-8 and UTF-16 buffers.
    231   for (const BigBuffer& buffer : buffers) {
    232     std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
    233 
    234     ResStringPool test;
    235     ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
    236 
    237     EXPECT_EQ(std::string("hello"), util::GetString(test, 0));
    238     EXPECT_EQ(StringPiece16(u"hello"), util::GetString16(test, 0));
    239 
    240     EXPECT_EQ(std::string("goodbye"), util::GetString(test, 1));
    241     EXPECT_EQ(StringPiece16(u"goodbye"), util::GetString16(test, 1));
    242 
    243     EXPECT_EQ(StringPiece(sLongString), util::GetString(test, 2));
    244     EXPECT_EQ(util::Utf8ToUtf16(sLongString), util::GetString16(test, 2).to_string());
    245 
    246     size_t len;
    247     EXPECT_TRUE(test.stringAt(3, &len) != nullptr ||
    248                 test.string8At(3, &len) != nullptr);
    249 
    250     EXPECT_EQ(std::string("style"), util::GetString(test, 4));
    251     EXPECT_EQ(StringPiece16(u"style"), util::GetString16(test, 4));
    252 
    253     const ResStringPool_span* span = test.styleAt(4);
    254     ASSERT_NE(nullptr, span);
    255     EXPECT_EQ(std::string("b"), util::GetString(test, span->name.index));
    256     EXPECT_EQ(StringPiece16(u"b"), util::GetString16(test, span->name.index));
    257     EXPECT_EQ(0u, span->firstChar);
    258     EXPECT_EQ(1u, span->lastChar);
    259     span++;
    260 
    261     ASSERT_NE(ResStringPool_span::END, span->name.index);
    262     EXPECT_EQ(std::string("i"), util::GetString(test, span->name.index));
    263     EXPECT_EQ(StringPiece16(u"i"), util::GetString16(test, span->name.index));
    264     EXPECT_EQ(2u, span->firstChar);
    265     EXPECT_EQ(3u, span->lastChar);
    266     span++;
    267 
    268     EXPECT_EQ(ResStringPool_span::END, span->name.index);
    269   }
    270 }
    271 
    272 }  // namespace aapt
    273