blob: bf25aebb0d7c9f839c265a79a0c875865bf10237 [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
Tao Baoc0e1c462017-02-01 10:20:10 -080017#include <stdio.h>
18
Tao Bao97555da2016-12-15 10:15:06 -080019#include <string>
20#include <vector>
21
22#include <android-base/file.h>
Tianjie Xu12b90552017-03-07 14:44:14 -080023#include <android-base/memory.h>
Tao Bao97555da2016-12-15 10:15:06 -080024#include <android-base/test_utils.h>
25#include <applypatch/imgdiff.h>
26#include <applypatch/imgpatch.h>
27#include <gtest/gtest.h>
28#include <ziparchive/zip_writer.h>
29
Tianjie Xu12b90552017-03-07 14:44:14 -080030using android::base::get_unaligned;
Tao Bao97555da2016-12-15 10:15:06 -080031
Tao Bao97555da2016-12-15 10:15:06 -080032// Sanity check for the given imgdiff patch header.
33static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
34 size_t* num_deflate) {
35 const size_t size = patch.size();
36 const char* data = patch.data();
37
38 ASSERT_GE(size, 12U);
39 ASSERT_EQ("IMGDIFF2", std::string(data, 8));
40
Tianjie Xu12b90552017-03-07 14:44:14 -080041 const int num_chunks = get_unaligned<int32_t>(data + 8);
Tao Bao97555da2016-12-15 10:15:06 -080042 ASSERT_GE(num_chunks, 0);
43
44 size_t normal = 0;
45 size_t raw = 0;
46 size_t deflate = 0;
47
48 size_t pos = 12;
49 for (int i = 0; i < num_chunks; ++i) {
50 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080051 int type = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080052 pos += 4;
53 if (type == CHUNK_NORMAL) {
54 pos += 24;
55 ASSERT_LE(pos, size);
56 normal++;
57 } else if (type == CHUNK_RAW) {
58 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080059 ssize_t data_len = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080060 ASSERT_GT(data_len, 0);
61 pos += 4 + data_len;
62 ASSERT_LE(pos, size);
63 raw++;
64 } else if (type == CHUNK_DEFLATE) {
65 pos += 60;
66 ASSERT_LE(pos, size);
67 deflate++;
68 } else {
69 FAIL() << "Invalid patch type: " << type;
70 }
71 }
72
73 if (num_normal != nullptr) *num_normal = normal;
74 if (num_raw != nullptr) *num_raw = raw;
75 if (num_deflate != nullptr) *num_deflate = deflate;
76}
77
Tao Baoc0e1c462017-02-01 10:20:10 -080078static void verify_patched_image(const std::string& src, const std::string& patch,
79 const std::string& tgt) {
80 std::string patched;
81 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
82 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
83 [&patched](const unsigned char* data, size_t len) {
84 patched.append(reinterpret_cast<const char*>(data), len);
85 return len;
86 }));
87 ASSERT_EQ(tgt, patched);
88}
89
Tao Bao97555da2016-12-15 10:15:06 -080090TEST(ImgdiffTest, invalid_args) {
91 // Insufficient inputs.
92 ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
93 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" }));
94 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" }));
95 ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" }));
96
97 // Failed to read bonus file.
98 ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" }));
99
100 // Failed to read input files.
101 ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" }));
102 ASSERT_EQ(
103 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" }));
104}
105
106TEST(ImgdiffTest, image_mode_smoke) {
107 // Random bytes.
108 const std::string src("abcdefg");
109 TemporaryFile src_file;
110 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
111
112 const std::string tgt("abcdefgxyz");
113 TemporaryFile tgt_file;
114 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
115
116 TemporaryFile patch_file;
117 std::vector<const char*> args = {
118 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
119 };
120 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
121
122 // Verify.
123 std::string patch;
124 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
125
126 // Expect one CHUNK_RAW entry.
127 size_t num_normal;
128 size_t num_raw;
129 size_t num_deflate;
130 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
131 ASSERT_EQ(0U, num_normal);
132 ASSERT_EQ(0U, num_deflate);
133 ASSERT_EQ(1U, num_raw);
134
Tao Baoc0e1c462017-02-01 10:20:10 -0800135 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800136}
137
138TEST(ImgdiffTest, zip_mode_smoke_store) {
139 // Construct src and tgt zip files.
140 TemporaryFile src_file;
141 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
142 ZipWriter src_writer(src_file_ptr);
143 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode.
144 const std::string src_content("abcdefg");
145 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
146 ASSERT_EQ(0, src_writer.FinishEntry());
147 ASSERT_EQ(0, src_writer.Finish());
148 ASSERT_EQ(0, fclose(src_file_ptr));
149
150 TemporaryFile tgt_file;
151 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
152 ZipWriter tgt_writer(tgt_file_ptr);
153 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode.
154 const std::string tgt_content("abcdefgxyz");
155 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
156 ASSERT_EQ(0, tgt_writer.FinishEntry());
157 ASSERT_EQ(0, tgt_writer.Finish());
158 ASSERT_EQ(0, fclose(tgt_file_ptr));
159
160 // Compute patch.
161 TemporaryFile patch_file;
162 std::vector<const char*> args = {
163 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
164 };
165 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
166
167 // Verify.
168 std::string tgt;
169 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
170 std::string src;
171 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
172 std::string patch;
173 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
174
175 // Expect one CHUNK_RAW entry.
176 size_t num_normal;
177 size_t num_raw;
178 size_t num_deflate;
179 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
180 ASSERT_EQ(0U, num_normal);
181 ASSERT_EQ(0U, num_deflate);
182 ASSERT_EQ(1U, num_raw);
183
Tao Baoc0e1c462017-02-01 10:20:10 -0800184 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800185}
186
187TEST(ImgdiffTest, zip_mode_smoke_compressed) {
188 // Construct src and tgt zip files.
189 TemporaryFile src_file;
190 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
191 ZipWriter src_writer(src_file_ptr);
192 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
193 const std::string src_content("abcdefg");
194 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
195 ASSERT_EQ(0, src_writer.FinishEntry());
196 ASSERT_EQ(0, src_writer.Finish());
197 ASSERT_EQ(0, fclose(src_file_ptr));
198
199 TemporaryFile tgt_file;
200 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
201 ZipWriter tgt_writer(tgt_file_ptr);
202 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
203 const std::string tgt_content("abcdefgxyz");
204 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
205 ASSERT_EQ(0, tgt_writer.FinishEntry());
206 ASSERT_EQ(0, tgt_writer.Finish());
207 ASSERT_EQ(0, fclose(tgt_file_ptr));
208
209 // Compute patch.
210 TemporaryFile patch_file;
211 std::vector<const char*> args = {
212 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
213 };
214 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
215
216 // Verify.
217 std::string tgt;
218 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
219 std::string src;
220 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
221 std::string patch;
222 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
223
224 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
225 size_t num_normal;
226 size_t num_raw;
227 size_t num_deflate;
228 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
229 ASSERT_EQ(0U, num_normal);
230 ASSERT_EQ(1U, num_deflate);
231 ASSERT_EQ(2U, num_raw);
232
Tao Baoc0e1c462017-02-01 10:20:10 -0800233 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800234}
235
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800236TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
237 // Construct src and tgt zip files.
238 TemporaryFile src_file;
239 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
240 ZipWriter src_writer(src_file_ptr);
241 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
242 const std::string src_content("abcdefg");
243 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
244 ASSERT_EQ(0, src_writer.FinishEntry());
245 ASSERT_EQ(0, src_writer.Finish());
246 ASSERT_EQ(0, fclose(src_file_ptr));
247
248 TemporaryFile tgt_file;
249 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
250 ZipWriter tgt_writer(tgt_file_ptr);
251 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
252 const std::string tgt_content("abcdefgxyz");
253 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
254 ASSERT_EQ(0, tgt_writer.FinishEntry());
255 ASSERT_EQ(0, tgt_writer.Finish());
256 // Add trailing zeros to the target zip file.
257 std::vector<uint8_t> zeros(10);
258 ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr));
259 ASSERT_EQ(0, fclose(tgt_file_ptr));
260
261 // Compute patch.
262 TemporaryFile patch_file;
263 std::vector<const char*> args = {
264 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
265 };
266 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
267
268 // Verify.
269 std::string tgt;
270 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
271 std::string src;
272 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
273 std::string patch;
274 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
275
276 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
277 size_t num_normal;
278 size_t num_raw;
279 size_t num_deflate;
280 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
281 ASSERT_EQ(0U, num_normal);
282 ASSERT_EQ(1U, num_deflate);
283 ASSERT_EQ(2U, num_raw);
284
Tao Baoc0e1c462017-02-01 10:20:10 -0800285 verify_patched_image(src, patch, tgt);
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800286}
287
Tao Bao97555da2016-12-15 10:15:06 -0800288TEST(ImgdiffTest, image_mode_simple) {
289 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
290 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
291 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
292 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
293 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
294 '\x00', '\x00', '\x00' };
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(0, imgdiff(args.size(), args.data()));
314
315 // Verify.
316 std::string patch;
317 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
318
319 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
320 size_t num_normal;
321 size_t num_raw;
322 size_t num_deflate;
323 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
324 ASSERT_EQ(0U, num_normal);
325 ASSERT_EQ(1U, num_deflate);
326 ASSERT_EQ(2U, num_raw);
327
Tao Baoc0e1c462017-02-01 10:20:10 -0800328 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800329}
330
Tianjie Xu14ebc1e2017-07-05 12:04:07 -0700331TEST(ImgdiffTest, image_mode_bad_gzip) {
332 // Modify the uncompressed length in the gzip footer.
333 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
334 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
335 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
336 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
337 '\xff', '\xff', '\xff' };
338 const std::string src(src_data.cbegin(), src_data.cend());
339 TemporaryFile src_file;
340 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
341
342 // Modify the uncompressed length in the gzip footer.
343 const std::vector<char> tgt_data = {
344 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
345 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
346 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff'
347 };
348 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
349 TemporaryFile tgt_file;
350 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
351
352 TemporaryFile patch_file;
353 std::vector<const char*> args = {
354 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
355 };
356 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
357
358 // Verify.
359 std::string patch;
360 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
361 verify_patched_image(src, patch, tgt);
362}
363
Tao Bao97555da2016-12-15 10:15:06 -0800364TEST(ImgdiffTest, image_mode_different_num_chunks) {
365 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
366 const std::vector<char> src_data = {
367 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08',
368 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
369 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
370 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
371 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
372 };
373 const std::string src(src_data.cbegin(), src_data.cend());
374 TemporaryFile src_file;
375 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
376
377 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
378 const std::vector<char> tgt_data = {
379 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
380 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
381 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
382 };
383 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
384 TemporaryFile tgt_file;
385 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
386
387 TemporaryFile patch_file;
388 std::vector<const char*> args = {
389 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
390 };
391 ASSERT_EQ(1, imgdiff(args.size(), args.data()));
392}
393
394TEST(ImgdiffTest, image_mode_merge_chunks) {
395 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
396 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
397 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
398 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
399 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
400 '\x00', '\x00', '\x00' };
401 const std::string src(src_data.cbegin(), src_data.cend());
402 TemporaryFile src_file;
403 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
404
405 // tgt: gzipped "xyz" + "abcdefgh".
406 const std::vector<char> tgt_data = {
407 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
408 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
409 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'
410 };
411 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
412 TemporaryFile tgt_file;
413 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
414
415 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
416 // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
417
418 TemporaryFile patch_file;
419 std::vector<const char*> args = {
420 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
421 };
422 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
423
424 // Verify.
425 std::string patch;
426 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
427
428 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
429 size_t num_normal;
430 size_t num_raw;
431 size_t num_deflate;
432 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
433 ASSERT_EQ(0U, num_normal);
434 ASSERT_EQ(1U, num_deflate);
435 ASSERT_EQ(2U, num_raw);
436
Tao Baoc0e1c462017-02-01 10:20:10 -0800437 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800438}
439
440TEST(ImgdiffTest, image_mode_spurious_magic) {
441 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
442 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
443 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
444 '\x53', '\x58', 't', 'e', 's', 't' };
445 const std::string src(src_data.cbegin(), src_data.cend());
446 TemporaryFile src_file;
447 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
448
449 // tgt: "abcdefgxyz".
450 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
451 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
452 TemporaryFile tgt_file;
453 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
454
455 TemporaryFile patch_file;
456 std::vector<const char*> args = {
457 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
458 };
459 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
460
461 // Verify.
462 std::string patch;
463 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
464
465 // Expect one CHUNK_RAW (header) entry.
466 size_t num_normal;
467 size_t num_raw;
468 size_t num_deflate;
469 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
470 ASSERT_EQ(0U, num_normal);
471 ASSERT_EQ(0U, num_deflate);
472 ASSERT_EQ(1U, num_raw);
473
Tao Baoc0e1c462017-02-01 10:20:10 -0800474 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800475}
476
Tao Baod37ce8f2016-12-17 17:10:04 -0800477TEST(ImgdiffTest, image_mode_short_input1) {
478 // src: "abcdefgh" + '0x1f8b0b'.
479 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
480 'g', 'h', '\x1f', '\x8b', '\x08' };
481 const std::string src(src_data.cbegin(), src_data.cend());
482 TemporaryFile src_file;
483 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
484
485 // tgt: "abcdefgxyz".
486 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
487 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
488 TemporaryFile tgt_file;
489 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
490
491 TemporaryFile patch_file;
492 std::vector<const char*> args = {
493 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
494 };
495 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
496
497 // Verify.
498 std::string patch;
499 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
500
501 // Expect one CHUNK_RAW (header) entry.
502 size_t num_normal;
503 size_t num_raw;
504 size_t num_deflate;
505 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
506 ASSERT_EQ(0U, num_normal);
507 ASSERT_EQ(0U, num_deflate);
508 ASSERT_EQ(1U, num_raw);
509
Tao Baoc0e1c462017-02-01 10:20:10 -0800510 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800511}
512
513TEST(ImgdiffTest, image_mode_short_input2) {
514 // src: "abcdefgh" + '0x1f8b0b00'.
515 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
516 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
517 const std::string src(src_data.cbegin(), src_data.cend());
518 TemporaryFile src_file;
519 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
520
521 // tgt: "abcdefgxyz".
522 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
523 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
524 TemporaryFile tgt_file;
525 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
526
527 TemporaryFile patch_file;
528 std::vector<const char*> args = {
529 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
530 };
531 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
532
533 // Verify.
534 std::string patch;
535 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
536
537 // Expect one CHUNK_RAW (header) entry.
538 size_t num_normal;
539 size_t num_raw;
540 size_t num_deflate;
541 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
542 ASSERT_EQ(0U, num_normal);
543 ASSERT_EQ(0U, num_deflate);
544 ASSERT_EQ(1U, num_raw);
545
Tao Baoc0e1c462017-02-01 10:20:10 -0800546 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800547}
548
Tao Bao97555da2016-12-15 10:15:06 -0800549TEST(ImgdiffTest, image_mode_single_entry_long) {
550 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
551 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
552 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
553 '\x53', '\x58', 't', 'e', 's', 't' };
554 const std::string src(src_data.cbegin(), src_data.cend());
555 TemporaryFile src_file;
556 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
557
558 // tgt: "abcdefgxyz" + 200 bytes.
559 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
560 tgt_data.resize(tgt_data.size() + 200);
561
562 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
563 TemporaryFile tgt_file;
564 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
565
566 TemporaryFile patch_file;
567 std::vector<const char*> args = {
568 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
569 };
570 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
571
572 // Verify.
573 std::string patch;
574 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
575
576 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
577 size_t num_normal;
578 size_t num_raw;
579 size_t num_deflate;
580 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
581 ASSERT_EQ(1U, num_normal);
582 ASSERT_EQ(0U, num_deflate);
583 ASSERT_EQ(0U, num_raw);
584
Tao Baoc0e1c462017-02-01 10:20:10 -0800585 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800586}
Tianjie Xuce5fa5e2017-05-15 12:32:33 -0700587
588TEST(ImgpatchTest, image_mode_patch_corruption) {
589 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
590 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
591 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
592 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
593 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
594 '\x00', '\x00', '\x00' };
595 const std::string src(src_data.cbegin(), src_data.cend());
596 TemporaryFile src_file;
597 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
598
599 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
600 const std::vector<char> tgt_data = {
601 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
602 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
603 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
604 };
605 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
606 TemporaryFile tgt_file;
607 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
608
609 TemporaryFile patch_file;
610 std::vector<const char*> args = {
611 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
612 };
613 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
614
615 // Verify.
616 std::string patch;
617 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
618 verify_patched_image(src, patch, tgt);
619
620 // Corrupt the end of the patch and expect the ApplyImagePatch to fail.
621 patch.insert(patch.end() - 10, 10, '0');
622 ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
623 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
624 [](const unsigned char* /*data*/, size_t len) { return len; }));
625}