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
TEST(StringPoolTest,InsertOneString)31 TEST(StringPoolTest, InsertOneString) {
32 StringPool pool;
33
34 StringPool::Ref ref = pool.MakeRef("wut");
35 EXPECT_EQ(*ref, "wut");
36 }
37
TEST(StringPoolTest,InsertTwoUniqueStrings)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
TEST(StringPoolTest,DoNotInsertNewDuplicateString)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
TEST(StringPoolTest,MaintainInsertionOrderIndex)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
TEST(StringPoolTest,PruneStringsWithNoReferences)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
TEST(StringPoolTest,SortAndMaintainIndexesInReferences)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
TEST(StringPoolTest,SortAndStillDedupe)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
TEST(StringPoolTest,AddStyles)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
TEST(StringPoolTest,DoNotDedupeStyleWithSameStringAsNonStyle)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
TEST(StringPoolTest,FlattenEmptyStringPoolUtf8)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
TEST(StringPoolTest,FlattenOddCharactersUtf16)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
TEST(StringPoolTest,Flatten)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