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 #include "util/Util.h" 19 20 #include <gtest/gtest.h> 21 #include <string> 22 23 namespace aapt { 24 25 TEST(StringPoolTest, InsertOneString) { 26 StringPool pool; 27 28 StringPool::Ref ref = pool.makeRef(u"wut"); 29 EXPECT_EQ(*ref, u"wut"); 30 } 31 32 TEST(StringPoolTest, InsertTwoUniqueStrings) { 33 StringPool pool; 34 35 StringPool::Ref ref = pool.makeRef(u"wut"); 36 StringPool::Ref ref2 = pool.makeRef(u"hey"); 37 38 EXPECT_EQ(*ref, u"wut"); 39 EXPECT_EQ(*ref2, u"hey"); 40 } 41 42 TEST(StringPoolTest, DoNotInsertNewDuplicateString) { 43 StringPool pool; 44 45 StringPool::Ref ref = pool.makeRef(u"wut"); 46 StringPool::Ref ref2 = pool.makeRef(u"wut"); 47 48 EXPECT_EQ(*ref, u"wut"); 49 EXPECT_EQ(*ref2, u"wut"); 50 EXPECT_EQ(1u, pool.size()); 51 } 52 53 TEST(StringPoolTest, MaintainInsertionOrderIndex) { 54 StringPool pool; 55 56 StringPool::Ref ref = pool.makeRef(u"z"); 57 StringPool::Ref ref2 = pool.makeRef(u"a"); 58 StringPool::Ref ref3 = pool.makeRef(u"m"); 59 60 EXPECT_EQ(0u, ref.getIndex()); 61 EXPECT_EQ(1u, ref2.getIndex()); 62 EXPECT_EQ(2u, ref3.getIndex()); 63 } 64 65 TEST(StringPoolTest, PruneStringsWithNoReferences) { 66 StringPool pool; 67 68 StringPool::Ref refA = pool.makeRef(u"foo"); 69 { 70 StringPool::Ref ref = pool.makeRef(u"wut"); 71 EXPECT_EQ(*ref, u"wut"); 72 EXPECT_EQ(2u, pool.size()); 73 } 74 StringPool::Ref refB = pool.makeRef(u"bar"); 75 76 EXPECT_EQ(3u, pool.size()); 77 pool.prune(); 78 EXPECT_EQ(2u, pool.size()); 79 StringPool::const_iterator iter = begin(pool); 80 EXPECT_EQ((*iter)->value, u"foo"); 81 EXPECT_LT((*iter)->index, 2u); 82 ++iter; 83 EXPECT_EQ((*iter)->value, u"bar"); 84 EXPECT_LT((*iter)->index, 2u); 85 } 86 87 TEST(StringPoolTest, SortAndMaintainIndexesInReferences) { 88 StringPool pool; 89 90 StringPool::Ref ref = pool.makeRef(u"z"); 91 StringPool::StyleRef ref2 = pool.makeRef(StyleString{ {u"a"} }); 92 StringPool::Ref ref3 = pool.makeRef(u"m"); 93 94 EXPECT_EQ(*ref, u"z"); 95 EXPECT_EQ(0u, ref.getIndex()); 96 97 EXPECT_EQ(*(ref2->str), u"a"); 98 EXPECT_EQ(1u, ref2.getIndex()); 99 100 EXPECT_EQ(*ref3, u"m"); 101 EXPECT_EQ(2u, ref3.getIndex()); 102 103 pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool { 104 return a.value < b.value; 105 }); 106 107 108 EXPECT_EQ(*ref, u"z"); 109 EXPECT_EQ(2u, ref.getIndex()); 110 111 EXPECT_EQ(*(ref2->str), u"a"); 112 EXPECT_EQ(0u, ref2.getIndex()); 113 114 EXPECT_EQ(*ref3, u"m"); 115 EXPECT_EQ(1u, ref3.getIndex()); 116 } 117 118 TEST(StringPoolTest, SortAndStillDedupe) { 119 StringPool pool; 120 121 StringPool::Ref ref = pool.makeRef(u"z"); 122 StringPool::Ref ref2 = pool.makeRef(u"a"); 123 StringPool::Ref ref3 = pool.makeRef(u"m"); 124 125 pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool { 126 return a.value < b.value; 127 }); 128 129 StringPool::Ref ref4 = pool.makeRef(u"z"); 130 StringPool::Ref ref5 = pool.makeRef(u"a"); 131 StringPool::Ref ref6 = pool.makeRef(u"m"); 132 133 EXPECT_EQ(ref4.getIndex(), ref.getIndex()); 134 EXPECT_EQ(ref5.getIndex(), ref2.getIndex()); 135 EXPECT_EQ(ref6.getIndex(), ref3.getIndex()); 136 } 137 138 TEST(StringPoolTest, AddStyles) { 139 StringPool pool; 140 141 StyleString str { 142 { u"android" }, 143 { 144 Span{ { u"b" }, 2, 6 } 145 } 146 }; 147 148 StringPool::StyleRef ref = pool.makeRef(str); 149 150 EXPECT_EQ(0u, ref.getIndex()); 151 EXPECT_EQ(std::u16string(u"android"), *(ref->str)); 152 ASSERT_EQ(1u, ref->spans.size()); 153 154 const StringPool::Span& span = ref->spans.front(); 155 EXPECT_EQ(*(span.name), u"b"); 156 EXPECT_EQ(2u, span.firstChar); 157 EXPECT_EQ(6u, span.lastChar); 158 } 159 160 TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) { 161 StringPool pool; 162 163 StringPool::Ref ref = pool.makeRef(u"android"); 164 165 StyleString str { { u"android" } }; 166 StringPool::StyleRef styleRef = pool.makeRef(str); 167 168 EXPECT_NE(ref.getIndex(), styleRef.getIndex()); 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(u"\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 char16_t* sLongString = u"SMS OFF"; 202 203 TEST(StringPoolTest, FlattenUtf8) { 204 using namespace android; // For NO_ERROR on Windows. 205 206 StringPool pool; 207 208 StringPool::Ref ref1 = pool.makeRef(u"hello"); 209 StringPool::Ref ref2 = pool.makeRef(u"goodbye"); 210 StringPool::Ref ref3 = pool.makeRef(sLongString); 211 StringPool::StyleRef ref4 = pool.makeRef(StyleString{ 212 { u"style" }, 213 { Span{ { u"b" }, 0, 1 }, Span{ { u"i" }, 2, 3 } } 214 }); 215 216 EXPECT_EQ(0u, ref1.getIndex()); 217 EXPECT_EQ(1u, ref2.getIndex()); 218 EXPECT_EQ(2u, ref3.getIndex()); 219 EXPECT_EQ(3u, ref4.getIndex()); 220 221 BigBuffer buffer(1024); 222 StringPool::flattenUtf8(&buffer, pool); 223 224 std::unique_ptr<uint8_t[]> data = util::copy(buffer); 225 { 226 ResStringPool test; 227 ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR); 228 229 EXPECT_EQ(util::getString(test, 0), u"hello"); 230 EXPECT_EQ(util::getString(test, 1), u"goodbye"); 231 EXPECT_EQ(util::getString(test, 2), sLongString); 232 EXPECT_EQ(util::getString(test, 3), u"style"); 233 234 const ResStringPool_span* span = test.styleAt(3); 235 ASSERT_NE(nullptr, span); 236 EXPECT_EQ(util::getString(test, span->name.index), u"b"); 237 EXPECT_EQ(0u, span->firstChar); 238 EXPECT_EQ(1u, span->lastChar); 239 span++; 240 241 ASSERT_NE(ResStringPool_span::END, span->name.index); 242 EXPECT_EQ(util::getString(test, span->name.index), u"i"); 243 EXPECT_EQ(2u, span->firstChar); 244 EXPECT_EQ(3u, span->lastChar); 245 span++; 246 247 EXPECT_EQ(ResStringPool_span::END, span->name.index); 248 } 249 } 250 251 } // namespace aapt 252