1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gtest/gtest.h"
6
7 #include "puffin/src/puff_reader.h"
8 #include "puffin/src/puff_writer.h"
9 #include "puffin/src/unittest_common.h"
10
11 namespace puffin {
12
13 namespace {
TestLiteralLength(size_t length)14 void TestLiteralLength(size_t length) {
15 Buffer buf(length + 10);
16 PuffData pd;
17
18 BufferPuffWriter pw(buf.data(), buf.size());
19 // We need to insert a metadata otherwise it will fail.
20 pd.type = PuffData::Type::kBlockMetadata;
21 pd.length = 1;
22 ASSERT_TRUE(pw.Insert(pd));
23
24 BufferPuffReader pr(buf.data(), buf.size());
25 ASSERT_TRUE(pr.GetNext(&pd));
26 ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
27 ASSERT_EQ(pd.length, 1);
28
29 // We insert |length| bytes.
30 pd.type = PuffData::Type::kLiterals;
31 pd.length = length;
32 pd.read_fn = [](uint8_t* buffer, size_t count) {
33 std::fill(buffer, buffer + count, 10);
34 return true;
35 };
36 ASSERT_TRUE(pw.Insert(pd));
37 ASSERT_TRUE(pw.Flush());
38
39 pd.type = PuffData::Type::kLenDist;
40 pd.distance = 1;
41 pd.length = 3;
42 ASSERT_TRUE(pw.Insert(pd));
43
44 ASSERT_TRUE(pr.GetNext(&pd));
45 if (length == 0) {
46 // If length is zero, then nothing should've been inserted.
47 ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
48 } else {
49 // We have to see |length| bytes.
50 ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
51 ASSERT_EQ(pd.length, length);
52 for (size_t i = 0; i < pd.length; i++) {
53 uint8_t byte;
54 pd.read_fn(&byte, 1);
55 EXPECT_EQ(byte, 10);
56 }
57 }
58 }
59 } // namespace
60
61 // Testing read/write from/into a puff buffer using |PuffReader|/|PuffWriter|.
TEST(PuffIOTest,InputOutputTest)62 TEST(PuffIOTest, InputOutputTest) {
63 Buffer buf(100);
64 BufferPuffReader pr(buf.data(), buf.size());
65 BufferPuffWriter pw(buf.data(), buf.size());
66 BufferPuffWriter epw(nullptr, 0);
67 uint8_t block = 123;
68
69 {
70 PuffData pd;
71 pd.type = PuffData::Type::kBlockMetadata;
72 pd.block_metadata[0] = 0xCC; // header
73 memcpy(&pd.block_metadata[1], &block, sizeof(block));
74 pd.length = sizeof(block) + 1;
75 ASSERT_TRUE(pw.Insert(pd));
76 ASSERT_TRUE(epw.Insert(pd));
77 ASSERT_TRUE(pw.Flush());
78 ASSERT_TRUE(epw.Flush());
79 }
80 {
81 PuffData pd;
82 ASSERT_TRUE(pr.GetNext(&pd));
83 ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
84 ASSERT_EQ(pd.length, sizeof(block) + 1);
85 ASSERT_EQ(pd.block_metadata[0], 0xCC);
86 ASSERT_EQ(pd.block_metadata[1], block);
87 }
88 {
89 PuffData pd;
90 pd.type = PuffData::Type::kLenDist;
91 pd.distance = 321;
92 pd.length = 3;
93 ASSERT_TRUE(pw.Insert(pd));
94 ASSERT_TRUE(epw.Insert(pd));
95 pd.length = 127;
96 ASSERT_TRUE(pw.Insert(pd));
97 ASSERT_TRUE(epw.Insert(pd));
98 pd.length = 258;
99 ASSERT_TRUE(pw.Insert(pd));
100 ASSERT_TRUE(epw.Insert(pd));
101 ASSERT_TRUE(pw.Flush());
102 ASSERT_TRUE(epw.Flush());
103
104 pd.length = 259;
105 ASSERT_FALSE(pw.Insert(pd));
106 ASSERT_FALSE(epw.Insert(pd));
107 }
108 {
109 PuffData pd;
110 ASSERT_TRUE(pr.GetNext(&pd));
111 ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
112 ASSERT_EQ(pd.distance, 321);
113 ASSERT_EQ(pd.length, 3);
114 ASSERT_TRUE(pr.GetNext(&pd));
115 ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
116 ASSERT_EQ(pd.length, 127);
117 ASSERT_TRUE(pr.GetNext(&pd));
118 ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
119 ASSERT_EQ(pd.length, 258);
120 }
121 {
122 PuffData pd;
123 pd.type = PuffData::Type::kEndOfBlock;
124 ASSERT_TRUE(pw.Insert(pd));
125 ASSERT_TRUE(epw.Insert(pd));
126 ASSERT_TRUE(pw.Flush());
127 ASSERT_TRUE(epw.Flush());
128 }
129 {
130 PuffData pd;
131 ASSERT_TRUE(pr.GetNext(&pd));
132 ASSERT_EQ(pd.type, PuffData::Type::kEndOfBlock);
133 }
134 {
135 PuffData pd;
136 pd.type = PuffData::Type::kBlockMetadata;
137 block = 123;
138 pd.block_metadata[0] = 0xCC; // header
139 memcpy(&pd.block_metadata[1], &block, sizeof(block));
140 pd.length = sizeof(block) + 1;
141 ASSERT_TRUE(pw.Insert(pd));
142 ASSERT_TRUE(epw.Insert(pd));
143 ASSERT_TRUE(pw.Flush());
144 ASSERT_TRUE(epw.Flush());
145 }
146 {
147 PuffData pd;
148 ASSERT_TRUE(pr.GetNext(&pd));
149 ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
150 ASSERT_EQ(pd.length, sizeof(block) + 1);
151 ASSERT_EQ(pd.block_metadata[0], 0xCC);
152 ASSERT_EQ(pd.block_metadata[1], block);
153 }
154
155 uint8_t tmp[] = {1, 2, 100};
156 {
157 PuffData pd;
158 size_t index = 0;
159 pd.type = PuffData::Type::kLiterals;
160 pd.length = 3;
161 pd.read_fn = [&tmp, &index](uint8_t* buffer, size_t count) {
162 if (count > 3 - index)
163 return false;
164 if (buffer != nullptr) {
165 memcpy(buffer, &tmp[index], count);
166 }
167 index += count;
168 return true;
169 };
170 ASSERT_TRUE(pw.Insert(pd));
171 ASSERT_TRUE(pw.Flush());
172 // We have to refresh the read_fn function for the second insert.
173 index = 0;
174 ASSERT_TRUE(epw.Insert(pd));
175 ASSERT_TRUE(epw.Flush());
176 }
177 {
178 PuffData pd;
179 pd.type = PuffData::Type::kLiteral;
180 pd.byte = 10;
181 ASSERT_TRUE(pw.Insert(pd));
182 ASSERT_TRUE(epw.Insert(pd));
183 ASSERT_TRUE(pw.Flush());
184 ASSERT_TRUE(epw.Flush());
185 }
186
187 uint8_t tmp3[3];
188 {
189 PuffData pd;
190 ASSERT_TRUE(pr.GetNext(&pd));
191 ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
192 ASSERT_EQ(pd.length, 3);
193 ASSERT_TRUE(pd.read_fn(tmp3, 3));
194 ASSERT_FALSE(pd.read_fn(tmp3, 1));
195 ASSERT_EQ(0, memcmp(tmp3, tmp, 3));
196 }
197 {
198 PuffData pd;
199 ASSERT_TRUE(pr.GetNext(&pd));
200 ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
201 ASSERT_EQ(pd.length, 1);
202 ASSERT_TRUE(pd.read_fn(tmp3, 1));
203 ASSERT_EQ(tmp3[0], 10);
204 ASSERT_FALSE(pd.read_fn(tmp3, 2));
205 }
206 {
207 PuffData pd;
208 pd.type = PuffData::Type::kEndOfBlock;
209 ASSERT_TRUE(pw.Insert(pd));
210 ASSERT_TRUE(epw.Insert(pd));
211 ASSERT_TRUE(pw.Flush());
212 ASSERT_TRUE(epw.Flush());
213 }
214 {
215 PuffData pd;
216 ASSERT_TRUE(pr.GetNext(&pd));
217 ASSERT_EQ(pd.type, PuffData::Type::kEndOfBlock);
218 }
219
220 ASSERT_EQ(buf.size() - pr.BytesLeft(), pw.Size());
221 ASSERT_EQ(buf.size() - pr.BytesLeft(), epw.Size());
222 }
223
224 // Testing metadata boundary.
TEST(PuffIOTest,MetadataBoundaryTest)225 TEST(PuffIOTest, MetadataBoundaryTest) {
226 PuffData pd;
227 Buffer buf(3);
228 BufferPuffWriter pw(buf.data(), buf.size());
229
230 // Block metadata takes two + varied bytes, so on a thre byte buffer, only one
231 // bytes is left for the varied part of metadata.
232 pd.type = PuffData::Type::kBlockMetadata;
233 pd.length = 2;
234 ASSERT_FALSE(pw.Insert(pd));
235 pd.length = 0; // length should be at least 1.
236 ASSERT_FALSE(pw.Insert(pd));
237 pd.length = 1;
238 ASSERT_TRUE(pw.Insert(pd));
239
240 Buffer puff_buffer = {0x00, 0x03, 0x02, 0x00, 0x00};
241 BufferPuffReader pr(puff_buffer.data(), puff_buffer.size());
242 ASSERT_FALSE(pr.GetNext(&pd));
243 }
244
TEST(PuffIOTest,InvalidCopyLengthsDistanceTest)245 TEST(PuffIOTest, InvalidCopyLengthsDistanceTest) {
246 PuffData pd;
247 Buffer puff_buffer(20);
248 BufferPuffWriter pw(puff_buffer.data(), puff_buffer.size());
249
250 // Invalid Lenght values.
251 pd.type = PuffData::Type::kLenDist;
252 pd.distance = 1;
253 pd.length = 0;
254 EXPECT_FALSE(pw.Insert(pd));
255 pd.length = 1;
256 EXPECT_FALSE(pw.Insert(pd));
257 pd.length = 2;
258 EXPECT_FALSE(pw.Insert(pd));
259 pd.length = 3;
260 EXPECT_TRUE(pw.Insert(pd));
261 pd.length = 259;
262 EXPECT_FALSE(pw.Insert(pd));
263 pd.length = 258;
264 EXPECT_TRUE(pw.Insert(pd));
265
266 // Invalid distance values.
267 pd.length = 3;
268 pd.distance = 0;
269 EXPECT_FALSE(pw.Insert(pd));
270 pd.distance = 1;
271 EXPECT_TRUE(pw.Insert(pd));
272 pd.distance = 32769;
273 EXPECT_FALSE(pw.Insert(pd));
274 pd.distance = 32768;
275 EXPECT_TRUE(pw.Insert(pd));
276
277 // First three bytes header, four bytes value lit/len, and four bytes
278 // invalid lit/len.
279 puff_buffer = {0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
280 0x00, 0xFF, 0x82, 0x00, 0x00};
281 BufferPuffReader pr(puff_buffer.data(), puff_buffer.size());
282 EXPECT_TRUE(pr.GetNext(&pd));
283 EXPECT_EQ(pd.type, PuffData::Type::kBlockMetadata);
284 EXPECT_TRUE(pr.GetNext(&pd));
285 EXPECT_EQ(pd.type, PuffData::Type::kLenDist);
286 EXPECT_FALSE(pr.GetNext(&pd));
287 }
288
TEST(PuffIOTest,InvalidCopyLenghtDistanceBoundaryTest)289 TEST(PuffIOTest, InvalidCopyLenghtDistanceBoundaryTest) {
290 PuffData pd;
291 Buffer puff_buffer(5);
292
293 pd.type = PuffData::Type::kLenDist;
294 pd.distance = 1;
295 pd.length = 129;
296 for (size_t i = 1; i < 2; i++) {
297 BufferPuffWriter pw(puff_buffer.data(), i);
298 EXPECT_FALSE(pw.Insert(pd));
299 }
300
301 pd.length = 130;
302 for (size_t i = 1; i < 3; i++) {
303 BufferPuffWriter pw(puff_buffer.data(), i);
304 EXPECT_FALSE(pw.Insert(pd));
305 }
306
307 // First three bytes header, three bytes value lit/len.
308 puff_buffer = {0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00};
309 BufferPuffReader pr(puff_buffer.data(), puff_buffer.size());
310 EXPECT_TRUE(pr.GetNext(&pd));
311 EXPECT_EQ(pd.type, PuffData::Type::kBlockMetadata);
312 EXPECT_FALSE(pr.GetNext(&pd));
313 }
314
TEST(PuffIOTest,LiteralsTest)315 TEST(PuffIOTest, LiteralsTest) {
316 TestLiteralLength(0);
317 TestLiteralLength(1);
318 TestLiteralLength(2);
319 TestLiteralLength(126);
320 TestLiteralLength(127);
321 TestLiteralLength(128);
322 }
323
324 // Testing maximum literals length.
TEST(PuffIOTest,MaxLiteralsTest)325 TEST(PuffIOTest, MaxLiteralsTest) {
326 Buffer buf((1 << 16) + 127 + 20);
327 PuffData pd;
328
329 BufferPuffWriter pw(buf.data(), buf.size());
330 // We need to insert a metadata otherwise it will fail.
331 pd.type = PuffData::Type::kBlockMetadata;
332 pd.length = 1;
333 ASSERT_TRUE(pw.Insert(pd));
334
335 pd.type = PuffData::Type::kLiterals;
336 pd.length = (1 << 16);
337 pd.read_fn = [](uint8_t* buffer, size_t count) {
338 std::fill(buffer, buffer + count, 10);
339 return true;
340 };
341 ASSERT_TRUE(pw.Insert(pd));
342 ASSERT_TRUE(pw.Flush());
343
344 BufferPuffReader pr(buf.data(), buf.size());
345 ASSERT_TRUE(pr.GetNext(&pd));
346 ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
347 ASSERT_EQ(pd.length, 1);
348
349 ASSERT_TRUE(pr.GetNext(&pd));
350 ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
351 ASSERT_EQ(pd.length, 1 << 16);
352 for (size_t i = 0; i < pd.length; i++) {
353 uint8_t byte;
354 pd.read_fn(&byte, 1);
355 ASSERT_EQ(byte, 10);
356 }
357
358 BufferPuffWriter pw2(buf.data(), buf.size());
359 pd.type = PuffData::Type::kBlockMetadata;
360 pd.length = 1;
361 ASSERT_TRUE(pw2.Insert(pd));
362
363 pd.type = PuffData::Type::kLiteral;
364 pd.length = 1;
365 pd.byte = 12;
366 // We have to be able to fill 65663 bytes.
367 for (size_t i = 0; i < ((1 << 16) + 127); i++) {
368 ASSERT_TRUE(pw2.Insert(pd));
369 }
370 // If we add one more, then it should have been flushed.
371 pd.byte = 13;
372 ASSERT_TRUE(pw2.Insert(pd));
373 ASSERT_TRUE(pw2.Flush());
374
375 // Now read it back.
376 BufferPuffReader pr2(buf.data(), buf.size());
377 ASSERT_TRUE(pr2.GetNext(&pd));
378 ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
379
380 // Now we should read on kLiterals with lenght 1 << 16 and just one literal
381 // after that.
382 ASSERT_TRUE(pr2.GetNext(&pd));
383 ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
384 ASSERT_EQ(pd.length, (1 << 16) + 127);
385 for (size_t i = 0; i < pd.length; i++) {
386 uint8_t byte;
387 pd.read_fn(&byte, 1);
388 ASSERT_EQ(byte, 12);
389 }
390
391 ASSERT_TRUE(pr2.GetNext(&pd));
392 ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
393 ASSERT_EQ(pd.length, 1);
394 uint8_t byte;
395 pd.read_fn(&byte, 1);
396 ASSERT_EQ(byte, 13);
397 }
398
399 } // namespace puffin
400