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