blob: 7ad3307832d7adcf4f57825588b36d3820479c20 [file] [log] [blame]
Tao Bao97555da2016-12-15 10:15:06 -08001/*
2 * Copyright (C) 2016 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 <string>
18#include <vector>
19
20#include <android-base/file.h>
21#include <android-base/test_utils.h>
22#include <applypatch/imgdiff.h>
23#include <applypatch/imgpatch.h>
24#include <gtest/gtest.h>
25#include <ziparchive/zip_writer.h>
26
27#include "applypatch/utils.h"
28
29static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
30 std::string* s = static_cast<std::string*>(token);
31 s->append(reinterpret_cast<const char*>(data), len);
32 return len;
33}
34
35// Sanity check for the given imgdiff patch header.
36static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
37 size_t* num_deflate) {
38 const size_t size = patch.size();
39 const char* data = patch.data();
40
41 ASSERT_GE(size, 12U);
42 ASSERT_EQ("IMGDIFF2", std::string(data, 8));
43
44 const int num_chunks = Read4(data + 8);
45 ASSERT_GE(num_chunks, 0);
46
47 size_t normal = 0;
48 size_t raw = 0;
49 size_t deflate = 0;
50
51 size_t pos = 12;
52 for (int i = 0; i < num_chunks; ++i) {
53 ASSERT_LE(pos + 4, size);
54 int type = Read4(data + pos);
55 pos += 4;
56 if (type == CHUNK_NORMAL) {
57 pos += 24;
58 ASSERT_LE(pos, size);
59 normal++;
60 } else if (type == CHUNK_RAW) {
61 ASSERT_LE(pos + 4, size);
62 ssize_t data_len = Read4(data + pos);
63 ASSERT_GT(data_len, 0);
64 pos += 4 + data_len;
65 ASSERT_LE(pos, size);
66 raw++;
67 } else if (type == CHUNK_DEFLATE) {
68 pos += 60;
69 ASSERT_LE(pos, size);
70 deflate++;
71 } else {
72 FAIL() << "Invalid patch type: " << type;
73 }
74 }
75
76 if (num_normal != nullptr) *num_normal = normal;
77 if (num_raw != nullptr) *num_raw = raw;
78 if (num_deflate != nullptr) *num_deflate = deflate;
79}
80
81TEST(ImgdiffTest, invalid_args) {
82 // Insufficient inputs.
83 ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
84 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" }));
85 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" }));
86 ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" }));
87
88 // Failed to read bonus file.
89 ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" }));
90
91 // Failed to read input files.
92 ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" }));
93 ASSERT_EQ(
94 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" }));
95}
96
97TEST(ImgdiffTest, image_mode_smoke) {
98 // Random bytes.
99 const std::string src("abcdefg");
100 TemporaryFile src_file;
101 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
102
103 const std::string tgt("abcdefgxyz");
104 TemporaryFile tgt_file;
105 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
106
107 TemporaryFile patch_file;
108 std::vector<const char*> args = {
109 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
110 };
111 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
112
113 // Verify.
114 std::string patch;
115 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
116
117 // Expect one CHUNK_RAW entry.
118 size_t num_normal;
119 size_t num_raw;
120 size_t num_deflate;
121 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
122 ASSERT_EQ(0U, num_normal);
123 ASSERT_EQ(0U, num_deflate);
124 ASSERT_EQ(1U, num_raw);
125
126 std::string patched;
127 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
128 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
129 MemorySink, &patched));
130 ASSERT_EQ(tgt, patched);
131}
132
133TEST(ImgdiffTest, zip_mode_smoke_store) {
134 // Construct src and tgt zip files.
135 TemporaryFile src_file;
136 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
137 ZipWriter src_writer(src_file_ptr);
138 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode.
139 const std::string src_content("abcdefg");
140 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
141 ASSERT_EQ(0, src_writer.FinishEntry());
142 ASSERT_EQ(0, src_writer.Finish());
143 ASSERT_EQ(0, fclose(src_file_ptr));
144
145 TemporaryFile tgt_file;
146 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
147 ZipWriter tgt_writer(tgt_file_ptr);
148 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode.
149 const std::string tgt_content("abcdefgxyz");
150 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
151 ASSERT_EQ(0, tgt_writer.FinishEntry());
152 ASSERT_EQ(0, tgt_writer.Finish());
153 ASSERT_EQ(0, fclose(tgt_file_ptr));
154
155 // Compute patch.
156 TemporaryFile patch_file;
157 std::vector<const char*> args = {
158 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
159 };
160 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
161
162 // Verify.
163 std::string tgt;
164 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
165 std::string src;
166 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
167 std::string patch;
168 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
169
170 // Expect one CHUNK_RAW entry.
171 size_t num_normal;
172 size_t num_raw;
173 size_t num_deflate;
174 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
175 ASSERT_EQ(0U, num_normal);
176 ASSERT_EQ(0U, num_deflate);
177 ASSERT_EQ(1U, num_raw);
178
179 std::string patched;
180 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
181 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
182 MemorySink, &patched));
183 ASSERT_EQ(tgt, patched);
184}
185
186TEST(ImgdiffTest, zip_mode_smoke_compressed) {
187 // Construct src and tgt zip files.
188 TemporaryFile src_file;
189 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
190 ZipWriter src_writer(src_file_ptr);
191 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
192 const std::string src_content("abcdefg");
193 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
194 ASSERT_EQ(0, src_writer.FinishEntry());
195 ASSERT_EQ(0, src_writer.Finish());
196 ASSERT_EQ(0, fclose(src_file_ptr));
197
198 TemporaryFile tgt_file;
199 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
200 ZipWriter tgt_writer(tgt_file_ptr);
201 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
202 const std::string tgt_content("abcdefgxyz");
203 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
204 ASSERT_EQ(0, tgt_writer.FinishEntry());
205 ASSERT_EQ(0, tgt_writer.Finish());
206 ASSERT_EQ(0, fclose(tgt_file_ptr));
207
208 // Compute patch.
209 TemporaryFile patch_file;
210 std::vector<const char*> args = {
211 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
212 };
213 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
214
215 // Verify.
216 std::string tgt;
217 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
218 std::string src;
219 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
220 std::string patch;
221 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
222
223 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
224 size_t num_normal;
225 size_t num_raw;
226 size_t num_deflate;
227 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
228 ASSERT_EQ(0U, num_normal);
229 ASSERT_EQ(1U, num_deflate);
230 ASSERT_EQ(2U, num_raw);
231
232 std::string patched;
233 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
234 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
235 MemorySink, &patched));
236 ASSERT_EQ(tgt, patched);
237}
238
239TEST(ImgdiffTest, image_mode_simple) {
240 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
241 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
242 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
243 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
244 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
245 '\x00', '\x00', '\x00' };
246 const std::string src(src_data.cbegin(), src_data.cend());
247 TemporaryFile src_file;
248 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
249
250 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
251 const std::vector<char> tgt_data = {
252 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
253 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
254 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
255 };
256 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
257 TemporaryFile tgt_file;
258 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
259
260 TemporaryFile patch_file;
261 std::vector<const char*> args = {
262 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
263 };
264 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
265
266 // Verify.
267 std::string patch;
268 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
269
270 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
271 size_t num_normal;
272 size_t num_raw;
273 size_t num_deflate;
274 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
275 ASSERT_EQ(0U, num_normal);
276 ASSERT_EQ(1U, num_deflate);
277 ASSERT_EQ(2U, num_raw);
278
279 std::string patched;
280 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
281 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
282 MemorySink, &patched));
283 ASSERT_EQ(tgt, patched);
284}
285
286TEST(ImgdiffTest, image_mode_different_num_chunks) {
287 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
288 const std::vector<char> src_data = {
289 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08',
290 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
291 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
292 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
293 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
294 };
295 const std::string src(src_data.cbegin(), src_data.cend());
296 TemporaryFile src_file;
297 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
298
299 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
300 const std::vector<char> tgt_data = {
301 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
302 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
303 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
304 };
305 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
306 TemporaryFile tgt_file;
307 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
308
309 TemporaryFile patch_file;
310 std::vector<const char*> args = {
311 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
312 };
313 ASSERT_EQ(1, imgdiff(args.size(), args.data()));
314}
315
316TEST(ImgdiffTest, image_mode_merge_chunks) {
317 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
318 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
319 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
320 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
321 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
322 '\x00', '\x00', '\x00' };
323 const std::string src(src_data.cbegin(), src_data.cend());
324 TemporaryFile src_file;
325 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
326
327 // tgt: gzipped "xyz" + "abcdefgh".
328 const std::vector<char> tgt_data = {
329 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
330 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
331 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'
332 };
333 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
334 TemporaryFile tgt_file;
335 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
336
337 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
338 // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
339
340 TemporaryFile patch_file;
341 std::vector<const char*> args = {
342 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
343 };
344 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
345
346 // Verify.
347 std::string patch;
348 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
349
350 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
351 size_t num_normal;
352 size_t num_raw;
353 size_t num_deflate;
354 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
355 ASSERT_EQ(0U, num_normal);
356 ASSERT_EQ(1U, num_deflate);
357 ASSERT_EQ(2U, num_raw);
358
359 std::string patched;
360 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
361 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
362 MemorySink, &patched));
363 ASSERT_EQ(tgt, patched);
364}
365
366TEST(ImgdiffTest, image_mode_spurious_magic) {
367 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
368 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
369 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
370 '\x53', '\x58', 't', 'e', 's', 't' };
371 const std::string src(src_data.cbegin(), src_data.cend());
372 TemporaryFile src_file;
373 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
374
375 // tgt: "abcdefgxyz".
376 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
377 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
378 TemporaryFile tgt_file;
379 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
380
381 TemporaryFile patch_file;
382 std::vector<const char*> args = {
383 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
384 };
385 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
386
387 // Verify.
388 std::string patch;
389 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
390
391 // Expect one CHUNK_RAW (header) entry.
392 size_t num_normal;
393 size_t num_raw;
394 size_t num_deflate;
395 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
396 ASSERT_EQ(0U, num_normal);
397 ASSERT_EQ(0U, num_deflate);
398 ASSERT_EQ(1U, num_raw);
399
400 std::string patched;
401 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
402 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
403 MemorySink, &patched));
404 ASSERT_EQ(tgt, patched);
405}
406
Tao Baod37ce8f2016-12-17 17:10:04 -0800407TEST(ImgdiffTest, image_mode_short_input1) {
408 // src: "abcdefgh" + '0x1f8b0b'.
409 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
410 'g', 'h', '\x1f', '\x8b', '\x08' };
411 const std::string src(src_data.cbegin(), src_data.cend());
412 TemporaryFile src_file;
413 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
414
415 // tgt: "abcdefgxyz".
416 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
417 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
418 TemporaryFile tgt_file;
419 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
420
421 TemporaryFile patch_file;
422 std::vector<const char*> args = {
423 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
424 };
425 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
426
427 // Verify.
428 std::string patch;
429 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
430
431 // Expect one CHUNK_RAW (header) entry.
432 size_t num_normal;
433 size_t num_raw;
434 size_t num_deflate;
435 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
436 ASSERT_EQ(0U, num_normal);
437 ASSERT_EQ(0U, num_deflate);
438 ASSERT_EQ(1U, num_raw);
439
440 std::string patched;
441 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
442 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
443 MemorySink, &patched));
444 ASSERT_EQ(tgt, patched);
445}
446
447TEST(ImgdiffTest, image_mode_short_input2) {
448 // src: "abcdefgh" + '0x1f8b0b00'.
449 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
450 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
451 const std::string src(src_data.cbegin(), src_data.cend());
452 TemporaryFile src_file;
453 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
454
455 // tgt: "abcdefgxyz".
456 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
457 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
458 TemporaryFile tgt_file;
459 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
460
461 TemporaryFile patch_file;
462 std::vector<const char*> args = {
463 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
464 };
465 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
466
467 // Verify.
468 std::string patch;
469 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
470
471 // Expect one CHUNK_RAW (header) entry.
472 size_t num_normal;
473 size_t num_raw;
474 size_t num_deflate;
475 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
476 ASSERT_EQ(0U, num_normal);
477 ASSERT_EQ(0U, num_deflate);
478 ASSERT_EQ(1U, num_raw);
479
480 std::string patched;
481 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
482 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
483 MemorySink, &patched));
484 ASSERT_EQ(tgt, patched);
485}
486
Tao Bao97555da2016-12-15 10:15:06 -0800487TEST(ImgdiffTest, image_mode_single_entry_long) {
488 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
489 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
490 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
491 '\x53', '\x58', 't', 'e', 's', 't' };
492 const std::string src(src_data.cbegin(), src_data.cend());
493 TemporaryFile src_file;
494 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
495
496 // tgt: "abcdefgxyz" + 200 bytes.
497 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
498 tgt_data.resize(tgt_data.size() + 200);
499
500 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
501 TemporaryFile tgt_file;
502 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
503
504 TemporaryFile patch_file;
505 std::vector<const char*> args = {
506 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
507 };
508 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
509
510 // Verify.
511 std::string patch;
512 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
513
514 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
515 size_t num_normal;
516 size_t num_raw;
517 size_t num_deflate;
518 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
519 ASSERT_EQ(1U, num_normal);
520 ASSERT_EQ(0U, num_deflate);
521 ASSERT_EQ(0U, num_raw);
522
523 std::string patched;
524 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
525 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
526 MemorySink, &patched));
527 ASSERT_EQ(tgt, patched);
528}