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
TEST(StringPoolTest,InsertOneString)36 TEST(StringPoolTest, InsertOneString) {
37 StringPool pool;
38
39 StringPool::Ref ref = pool.MakeRef("wut");
40 EXPECT_THAT(*ref, Eq("wut"));
41 }
42
TEST(StringPoolTest,InsertTwoUniqueStrings)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
TEST(StringPoolTest,DoNotInsertNewDuplicateString)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
TEST(StringPoolTest,DoNotDedupeSameStringDifferentPriority)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
TEST(StringPoolTest,MaintainInsertionOrderIndex)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
TEST(StringPoolTest,PruneStringsWithNoReferences)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
TEST(StringPoolTest,SortAndMaintainIndexesInStringReferences)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
TEST(StringPoolTest,SortAndStillDedupe)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
TEST(StringPoolTest,AddStyles)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
TEST(StringPoolTest,DoNotDedupeStyleWithSameStringAsNonStyle)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
TEST(StringPoolTest,StylesAndStringsAreSeparateAfterSorting)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
TEST(StringPoolTest,FlattenEmptyStringPoolUtf8)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
TEST(StringPoolTest,FlattenOddCharactersUtf16)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
TEST(StringPoolTest,Flatten)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
TEST(StringPoolTest,ModifiedUTF8)306 TEST(StringPoolTest, ModifiedUTF8) {
307 using namespace android; // For NO_ERROR on Windows.
308 StdErrDiagnostics diag;
309 StringPool pool;
310 StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // (U+10400)
311 StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // (U+10437)
312 StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7");
313
314 BigBuffer buffer(1024);
315 StringPool::FlattenUtf8(&buffer, pool, &diag);
316 std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
317
318 // Check that the codepoints are encoded using two three-byte surrogate pairs
319 ResStringPool test;
320 ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
321 size_t len;
322 const char* str = test.string8At(0, &len);
323 ASSERT_THAT(str, NotNull());
324 EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80"));
325 str = test.string8At(1, &len);
326 ASSERT_THAT(str, NotNull());
327 EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
328 str = test.string8At(2, &len);
329 ASSERT_THAT(str, NotNull());
330 EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
331
332 // Check that retrieving the strings returns the original UTF-8 character bytes
333 EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
334 EXPECT_THAT(util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar"));
335 EXPECT_THAT(util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7"));
336 }
337
TEST(StringPoolTest,MaxEncodingLength)338 TEST(StringPoolTest, MaxEncodingLength) {
339 StdErrDiagnostics diag;
340 using namespace android; // For NO_ERROR on Windows.
341 ResStringPool test;
342
343 StringPool pool;
344 pool.MakeRef("aaaaaaaaaa");
345 BigBuffer buffers[2] = {BigBuffer(1024), BigBuffer(1024)};
346
347 // Make sure a UTF-8 string under the maximum length does not produce an error
348 EXPECT_THAT(StringPool::FlattenUtf8(&buffers[0], pool, &diag), Eq(true));
349 std::unique_ptr<uint8_t[]> data = util::Copy(buffers[0]);
350 test.setTo(data.get(), buffers[0].size());
351 EXPECT_THAT(util::GetString(test, 0), Eq("aaaaaaaaaa"));
352
353 // Make sure a UTF-16 string under the maximum length does not produce an error
354 EXPECT_THAT(StringPool::FlattenUtf16(&buffers[1], pool, &diag), Eq(true));
355 data = util::Copy(buffers[1]);
356 test.setTo(data.get(), buffers[1].size());
357 EXPECT_THAT(util::GetString16(test, 0), Eq(u"aaaaaaaaaa"));
358
359 StringPool pool2;
360 std::string longStr(50000, 'a');
361 pool2.MakeRef("this fits1");
362 pool2.MakeRef(longStr);
363 pool2.MakeRef("this fits2");
364 BigBuffer buffers2[2] = {BigBuffer(1024), BigBuffer(1024)};
365
366 // Make sure a string that exceeds the maximum length of UTF-8 produces an
367 // error and writes a shorter error string instead
368 EXPECT_THAT(StringPool::FlattenUtf8(&buffers2[0], pool2, &diag), Eq(false));
369 data = util::Copy(buffers2[0]);
370 test.setTo(data.get(), buffers2[0].size());
371 EXPECT_THAT(util::GetString(test, 0), "this fits1");
372 EXPECT_THAT(util::GetString(test, 1), "STRING_TOO_LARGE");
373 EXPECT_THAT(util::GetString(test, 2), "this fits2");
374
375 // Make sure a string that a string that exceeds the maximum length of UTF-8
376 // but not UTF-16 does not error for UTF-16
377 StringPool pool3;
378 std::u16string longStr16(50000, 'a');
379 pool3.MakeRef(longStr);
380 EXPECT_THAT(StringPool::FlattenUtf16(&buffers2[1], pool3, &diag), Eq(true));
381 data = util::Copy(buffers2[1]);
382 test.setTo(data.get(), buffers2[1].size());
383 EXPECT_THAT(util::GetString16(test, 0), Eq(longStr16));
384 }
385
386 } // namespace aapt
387