blob: 6f5960bbdb4df60ced3df591f0bc5ec07eaf25ef [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
331TEST(ImgdiffTest, image_mode_different_num_chunks) {
332 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
333 const std::vector<char> src_data = {
334 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08',
335 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
336 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
337 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
338 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
339 };
340 const std::string src(src_data.cbegin(), src_data.cend());
341 TemporaryFile src_file;
342 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
343
344 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
345 const std::vector<char> tgt_data = {
346 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
347 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
348 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
349 };
350 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
351 TemporaryFile tgt_file;
352 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
353
354 TemporaryFile patch_file;
355 std::vector<const char*> args = {
356 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
357 };
358 ASSERT_EQ(1, imgdiff(args.size(), args.data()));
359}
360
361TEST(ImgdiffTest, image_mode_merge_chunks) {
362 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
363 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
364 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
365 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
366 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
367 '\x00', '\x00', '\x00' };
368 const std::string src(src_data.cbegin(), src_data.cend());
369 TemporaryFile src_file;
370 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
371
372 // tgt: gzipped "xyz" + "abcdefgh".
373 const std::vector<char> tgt_data = {
374 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
375 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
376 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'
377 };
378 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
379 TemporaryFile tgt_file;
380 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
381
382 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
383 // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
384
385 TemporaryFile patch_file;
386 std::vector<const char*> args = {
387 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
388 };
389 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
390
391 // Verify.
392 std::string patch;
393 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
394
395 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
396 size_t num_normal;
397 size_t num_raw;
398 size_t num_deflate;
399 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
400 ASSERT_EQ(0U, num_normal);
401 ASSERT_EQ(1U, num_deflate);
402 ASSERT_EQ(2U, num_raw);
403
Tao Baoc0e1c462017-02-01 10:20:10 -0800404 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800405}
406
407TEST(ImgdiffTest, image_mode_spurious_magic) {
408 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
409 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
410 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
411 '\x53', '\x58', 't', 'e', 's', 't' };
412 const std::string src(src_data.cbegin(), src_data.cend());
413 TemporaryFile src_file;
414 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
415
416 // tgt: "abcdefgxyz".
417 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
418 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
419 TemporaryFile tgt_file;
420 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
421
422 TemporaryFile patch_file;
423 std::vector<const char*> args = {
424 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
425 };
426 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
427
428 // Verify.
429 std::string patch;
430 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
431
432 // Expect one CHUNK_RAW (header) entry.
433 size_t num_normal;
434 size_t num_raw;
435 size_t num_deflate;
436 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
437 ASSERT_EQ(0U, num_normal);
438 ASSERT_EQ(0U, num_deflate);
439 ASSERT_EQ(1U, num_raw);
440
Tao Baoc0e1c462017-02-01 10:20:10 -0800441 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800442}
443
Tao Baod37ce8f2016-12-17 17:10:04 -0800444TEST(ImgdiffTest, image_mode_short_input1) {
445 // src: "abcdefgh" + '0x1f8b0b'.
446 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
447 'g', 'h', '\x1f', '\x8b', '\x08' };
448 const std::string src(src_data.cbegin(), src_data.cend());
449 TemporaryFile src_file;
450 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
451
452 // tgt: "abcdefgxyz".
453 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
454 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
455 TemporaryFile tgt_file;
456 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
457
458 TemporaryFile patch_file;
459 std::vector<const char*> args = {
460 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
461 };
462 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
463
464 // Verify.
465 std::string patch;
466 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
467
468 // Expect one CHUNK_RAW (header) entry.
469 size_t num_normal;
470 size_t num_raw;
471 size_t num_deflate;
472 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
473 ASSERT_EQ(0U, num_normal);
474 ASSERT_EQ(0U, num_deflate);
475 ASSERT_EQ(1U, num_raw);
476
Tao Baoc0e1c462017-02-01 10:20:10 -0800477 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800478}
479
480TEST(ImgdiffTest, image_mode_short_input2) {
481 // src: "abcdefgh" + '0x1f8b0b00'.
482 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
483 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
484 const std::string src(src_data.cbegin(), src_data.cend());
485 TemporaryFile src_file;
486 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
487
488 // tgt: "abcdefgxyz".
489 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
490 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
491 TemporaryFile tgt_file;
492 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
493
494 TemporaryFile patch_file;
495 std::vector<const char*> args = {
496 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
497 };
498 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
499
500 // Verify.
501 std::string patch;
502 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
503
504 // Expect one CHUNK_RAW (header) entry.
505 size_t num_normal;
506 size_t num_raw;
507 size_t num_deflate;
508 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
509 ASSERT_EQ(0U, num_normal);
510 ASSERT_EQ(0U, num_deflate);
511 ASSERT_EQ(1U, num_raw);
512
Tao Baoc0e1c462017-02-01 10:20:10 -0800513 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800514}
515
Tao Bao97555da2016-12-15 10:15:06 -0800516TEST(ImgdiffTest, image_mode_single_entry_long) {
517 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
518 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
519 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
520 '\x53', '\x58', 't', 'e', 's', 't' };
521 const std::string src(src_data.cbegin(), src_data.cend());
522 TemporaryFile src_file;
523 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
524
525 // tgt: "abcdefgxyz" + 200 bytes.
526 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
527 tgt_data.resize(tgt_data.size() + 200);
528
529 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
530 TemporaryFile tgt_file;
531 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
532
533 TemporaryFile patch_file;
534 std::vector<const char*> args = {
535 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
536 };
537 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
538
539 // Verify.
540 std::string patch;
541 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
542
543 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
544 size_t num_normal;
545 size_t num_raw;
546 size_t num_deflate;
547 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
548 ASSERT_EQ(1U, num_normal);
549 ASSERT_EQ(0U, num_deflate);
550 ASSERT_EQ(0U, num_raw);
551
Tao Baoc0e1c462017-02-01 10:20:10 -0800552 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800553}
Tianjie Xuce5fa5e2017-05-15 12:32:33 -0700554
555TEST(ImgpatchTest, image_mode_patch_corruption) {
556 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
557 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
558 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
559 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
560 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
561 '\x00', '\x00', '\x00' };
562 const std::string src(src_data.cbegin(), src_data.cend());
563 TemporaryFile src_file;
564 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
565
566 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
567 const std::vector<char> tgt_data = {
568 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
569 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
570 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
571 };
572 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
573 TemporaryFile tgt_file;
574 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
575
576 TemporaryFile patch_file;
577 std::vector<const char*> args = {
578 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
579 };
580 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
581
582 // Verify.
583 std::string patch;
584 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
585 verify_patched_image(src, patch, tgt);
586
587 // Corrupt the end of the patch and expect the ApplyImagePatch to fail.
588 patch.insert(patch.end() - 10, 10, '0');
589 ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
590 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
591 [](const unsigned char* /*data*/, size_t len) { return len; }));
592}