blob: 3163a57cf84c2556182ce705101e178dce7a727f [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
Tianjie Xu2903cdd2017-08-18 18:15:47 -070019#include <algorithm>
Tao Bao97555da2016-12-15 10:15:06 -080020#include <string>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070021#include <tuple>
Tao Bao97555da2016-12-15 10:15:06 -080022#include <vector>
23
24#include <android-base/file.h>
Tianjie Xu12b90552017-03-07 14:44:14 -080025#include <android-base/memory.h>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070026#include <android-base/stringprintf.h>
Tao Bao97555da2016-12-15 10:15:06 -080027#include <android-base/test_utils.h>
28#include <applypatch/imgdiff.h>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070029#include <applypatch/imgdiff_image.h>
Tao Bao97555da2016-12-15 10:15:06 -080030#include <applypatch/imgpatch.h>
31#include <gtest/gtest.h>
32#include <ziparchive/zip_writer.h>
33
Tianjie Xu12b90552017-03-07 14:44:14 -080034using android::base::get_unaligned;
Tao Bao97555da2016-12-15 10:15:06 -080035
Tao Bao97555da2016-12-15 10:15:06 -080036// Sanity check for the given imgdiff patch header.
37static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
38 size_t* num_deflate) {
39 const size_t size = patch.size();
40 const char* data = patch.data();
41
42 ASSERT_GE(size, 12U);
43 ASSERT_EQ("IMGDIFF2", std::string(data, 8));
44
Tianjie Xu12b90552017-03-07 14:44:14 -080045 const int num_chunks = get_unaligned<int32_t>(data + 8);
Tao Bao97555da2016-12-15 10:15:06 -080046 ASSERT_GE(num_chunks, 0);
47
48 size_t normal = 0;
49 size_t raw = 0;
50 size_t deflate = 0;
51
52 size_t pos = 12;
53 for (int i = 0; i < num_chunks; ++i) {
54 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080055 int type = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080056 pos += 4;
57 if (type == CHUNK_NORMAL) {
58 pos += 24;
59 ASSERT_LE(pos, size);
60 normal++;
61 } else if (type == CHUNK_RAW) {
62 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080063 ssize_t data_len = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080064 ASSERT_GT(data_len, 0);
65 pos += 4 + data_len;
66 ASSERT_LE(pos, size);
67 raw++;
68 } else if (type == CHUNK_DEFLATE) {
69 pos += 60;
70 ASSERT_LE(pos, size);
71 deflate++;
72 } else {
73 FAIL() << "Invalid patch type: " << type;
74 }
75 }
76
77 if (num_normal != nullptr) *num_normal = normal;
78 if (num_raw != nullptr) *num_raw = raw;
79 if (num_deflate != nullptr) *num_deflate = deflate;
80}
81
Tianjie Xu2903cdd2017-08-18 18:15:47 -070082static void GenerateTarget(const std::string& src, const std::string& patch, std::string* patched) {
83 patched->clear();
84 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
85 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
86 [&](const unsigned char* data, size_t len) {
87 patched->append(reinterpret_cast<const char*>(data), len);
88 return len;
89 }));
90}
91
Tao Baoc0e1c462017-02-01 10:20:10 -080092static void verify_patched_image(const std::string& src, const std::string& patch,
93 const std::string& tgt) {
94 std::string patched;
Tianjie Xu2903cdd2017-08-18 18:15:47 -070095 GenerateTarget(src, patch, &patched);
Tao Baoc0e1c462017-02-01 10:20:10 -080096 ASSERT_EQ(tgt, patched);
97}
98
Tao Bao97555da2016-12-15 10:15:06 -080099TEST(ImgdiffTest, invalid_args) {
100 // Insufficient inputs.
101 ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
102 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" }));
103 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" }));
104 ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" }));
105
106 // Failed to read bonus file.
107 ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" }));
108
109 // Failed to read input files.
110 ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" }));
111 ASSERT_EQ(
112 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" }));
113}
114
115TEST(ImgdiffTest, image_mode_smoke) {
116 // Random bytes.
117 const std::string src("abcdefg");
118 TemporaryFile src_file;
119 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
120
121 const std::string tgt("abcdefgxyz");
122 TemporaryFile tgt_file;
123 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
124
125 TemporaryFile patch_file;
126 std::vector<const char*> args = {
127 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
128 };
129 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
130
131 // Verify.
132 std::string patch;
133 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
134
135 // Expect one CHUNK_RAW entry.
136 size_t num_normal;
137 size_t num_raw;
138 size_t num_deflate;
139 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
140 ASSERT_EQ(0U, num_normal);
141 ASSERT_EQ(0U, num_deflate);
142 ASSERT_EQ(1U, num_raw);
143
Tao Baoc0e1c462017-02-01 10:20:10 -0800144 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800145}
146
147TEST(ImgdiffTest, zip_mode_smoke_store) {
148 // Construct src and tgt zip files.
149 TemporaryFile src_file;
150 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
151 ZipWriter src_writer(src_file_ptr);
152 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode.
153 const std::string src_content("abcdefg");
154 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
155 ASSERT_EQ(0, src_writer.FinishEntry());
156 ASSERT_EQ(0, src_writer.Finish());
157 ASSERT_EQ(0, fclose(src_file_ptr));
158
159 TemporaryFile tgt_file;
160 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
161 ZipWriter tgt_writer(tgt_file_ptr);
162 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode.
163 const std::string tgt_content("abcdefgxyz");
164 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
165 ASSERT_EQ(0, tgt_writer.FinishEntry());
166 ASSERT_EQ(0, tgt_writer.Finish());
167 ASSERT_EQ(0, fclose(tgt_file_ptr));
168
169 // Compute patch.
170 TemporaryFile patch_file;
171 std::vector<const char*> args = {
172 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
173 };
174 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
175
176 // Verify.
177 std::string tgt;
178 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
179 std::string src;
180 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
181 std::string patch;
182 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
183
184 // Expect one CHUNK_RAW entry.
185 size_t num_normal;
186 size_t num_raw;
187 size_t num_deflate;
188 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
189 ASSERT_EQ(0U, num_normal);
190 ASSERT_EQ(0U, num_deflate);
191 ASSERT_EQ(1U, num_raw);
192
Tao Baoc0e1c462017-02-01 10:20:10 -0800193 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800194}
195
196TEST(ImgdiffTest, zip_mode_smoke_compressed) {
197 // Construct src and tgt zip files.
198 TemporaryFile src_file;
199 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
200 ZipWriter src_writer(src_file_ptr);
201 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
202 const std::string src_content("abcdefg");
203 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
204 ASSERT_EQ(0, src_writer.FinishEntry());
205 ASSERT_EQ(0, src_writer.Finish());
206 ASSERT_EQ(0, fclose(src_file_ptr));
207
208 TemporaryFile tgt_file;
209 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
210 ZipWriter tgt_writer(tgt_file_ptr);
211 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
212 const std::string tgt_content("abcdefgxyz");
213 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
214 ASSERT_EQ(0, tgt_writer.FinishEntry());
215 ASSERT_EQ(0, tgt_writer.Finish());
216 ASSERT_EQ(0, fclose(tgt_file_ptr));
217
218 // Compute patch.
219 TemporaryFile patch_file;
220 std::vector<const char*> args = {
221 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
222 };
223 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
224
225 // Verify.
226 std::string tgt;
227 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
228 std::string src;
229 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
230 std::string patch;
231 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
232
233 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
234 size_t num_normal;
235 size_t num_raw;
236 size_t num_deflate;
237 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
238 ASSERT_EQ(0U, num_normal);
239 ASSERT_EQ(1U, num_deflate);
240 ASSERT_EQ(2U, num_raw);
241
Tao Baoc0e1c462017-02-01 10:20:10 -0800242 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800243}
244
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800245TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
246 // Construct src and tgt zip files.
247 TemporaryFile src_file;
248 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
249 ZipWriter src_writer(src_file_ptr);
250 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
251 const std::string src_content("abcdefg");
252 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
253 ASSERT_EQ(0, src_writer.FinishEntry());
254 ASSERT_EQ(0, src_writer.Finish());
255 ASSERT_EQ(0, fclose(src_file_ptr));
256
257 TemporaryFile tgt_file;
258 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
259 ZipWriter tgt_writer(tgt_file_ptr);
260 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
261 const std::string tgt_content("abcdefgxyz");
262 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
263 ASSERT_EQ(0, tgt_writer.FinishEntry());
264 ASSERT_EQ(0, tgt_writer.Finish());
265 // Add trailing zeros to the target zip file.
266 std::vector<uint8_t> zeros(10);
267 ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr));
268 ASSERT_EQ(0, fclose(tgt_file_ptr));
269
270 // Compute patch.
271 TemporaryFile patch_file;
272 std::vector<const char*> args = {
273 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
274 };
275 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
276
277 // Verify.
278 std::string tgt;
279 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
280 std::string src;
281 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
282 std::string patch;
283 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
284
285 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
286 size_t num_normal;
287 size_t num_raw;
288 size_t num_deflate;
289 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
290 ASSERT_EQ(0U, num_normal);
291 ASSERT_EQ(1U, num_deflate);
292 ASSERT_EQ(2U, num_raw);
293
Tao Baoc0e1c462017-02-01 10:20:10 -0800294 verify_patched_image(src, patch, tgt);
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800295}
296
Tao Bao97555da2016-12-15 10:15:06 -0800297TEST(ImgdiffTest, image_mode_simple) {
298 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
299 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
300 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
301 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
302 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
303 '\x00', '\x00', '\x00' };
304 const std::string src(src_data.cbegin(), src_data.cend());
305 TemporaryFile src_file;
306 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
307
308 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
309 const std::vector<char> tgt_data = {
310 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
311 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
312 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
313 };
314 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
315 TemporaryFile tgt_file;
316 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
317
318 TemporaryFile patch_file;
319 std::vector<const char*> args = {
320 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
321 };
322 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
323
324 // Verify.
325 std::string patch;
326 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
327
328 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
329 size_t num_normal;
330 size_t num_raw;
331 size_t num_deflate;
332 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
333 ASSERT_EQ(0U, num_normal);
334 ASSERT_EQ(1U, num_deflate);
335 ASSERT_EQ(2U, num_raw);
336
Tao Baoc0e1c462017-02-01 10:20:10 -0800337 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800338}
339
Tianjie Xu14ebc1e2017-07-05 12:04:07 -0700340TEST(ImgdiffTest, image_mode_bad_gzip) {
341 // Modify the uncompressed length in the gzip footer.
342 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
343 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
344 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
345 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
346 '\xff', '\xff', '\xff' };
347 const std::string src(src_data.cbegin(), src_data.cend());
348 TemporaryFile src_file;
349 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
350
351 // Modify the uncompressed length in the gzip footer.
352 const std::vector<char> tgt_data = {
353 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
354 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
355 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff'
356 };
357 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
358 TemporaryFile tgt_file;
359 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
360
361 TemporaryFile patch_file;
362 std::vector<const char*> args = {
363 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
364 };
365 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
366
367 // Verify.
368 std::string patch;
369 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
370 verify_patched_image(src, patch, tgt);
371}
372
Tao Bao97555da2016-12-15 10:15:06 -0800373TEST(ImgdiffTest, image_mode_different_num_chunks) {
374 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
375 const std::vector<char> src_data = {
376 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08',
377 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
378 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
379 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
380 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
381 };
382 const std::string src(src_data.cbegin(), src_data.cend());
383 TemporaryFile src_file;
384 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
385
386 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
387 const std::vector<char> tgt_data = {
388 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
389 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
390 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
391 };
392 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
393 TemporaryFile tgt_file;
394 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
395
396 TemporaryFile patch_file;
397 std::vector<const char*> args = {
398 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
399 };
400 ASSERT_EQ(1, imgdiff(args.size(), args.data()));
401}
402
403TEST(ImgdiffTest, image_mode_merge_chunks) {
404 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
405 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
406 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
407 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
408 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
409 '\x00', '\x00', '\x00' };
410 const std::string src(src_data.cbegin(), src_data.cend());
411 TemporaryFile src_file;
412 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
413
414 // tgt: gzipped "xyz" + "abcdefgh".
415 const std::vector<char> tgt_data = {
416 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
417 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
418 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'
419 };
420 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
421 TemporaryFile tgt_file;
422 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
423
424 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
425 // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
426
427 TemporaryFile patch_file;
428 std::vector<const char*> args = {
429 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
430 };
431 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
432
433 // Verify.
434 std::string patch;
435 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
436
437 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
438 size_t num_normal;
439 size_t num_raw;
440 size_t num_deflate;
441 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
442 ASSERT_EQ(0U, num_normal);
443 ASSERT_EQ(1U, num_deflate);
444 ASSERT_EQ(2U, num_raw);
445
Tao Baoc0e1c462017-02-01 10:20:10 -0800446 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800447}
448
449TEST(ImgdiffTest, image_mode_spurious_magic) {
450 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
451 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
452 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
453 '\x53', '\x58', 't', 'e', 's', 't' };
454 const std::string src(src_data.cbegin(), src_data.cend());
455 TemporaryFile src_file;
456 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
457
458 // tgt: "abcdefgxyz".
459 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
460 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
461 TemporaryFile tgt_file;
462 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
463
464 TemporaryFile patch_file;
465 std::vector<const char*> args = {
466 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
467 };
468 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
469
470 // Verify.
471 std::string patch;
472 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
473
474 // Expect one CHUNK_RAW (header) entry.
475 size_t num_normal;
476 size_t num_raw;
477 size_t num_deflate;
478 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
479 ASSERT_EQ(0U, num_normal);
480 ASSERT_EQ(0U, num_deflate);
481 ASSERT_EQ(1U, num_raw);
482
Tao Baoc0e1c462017-02-01 10:20:10 -0800483 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800484}
485
Tao Baod37ce8f2016-12-17 17:10:04 -0800486TEST(ImgdiffTest, image_mode_short_input1) {
487 // src: "abcdefgh" + '0x1f8b0b'.
488 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
489 'g', 'h', '\x1f', '\x8b', '\x08' };
490 const std::string src(src_data.cbegin(), src_data.cend());
491 TemporaryFile src_file;
492 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
493
494 // tgt: "abcdefgxyz".
495 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
496 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
497 TemporaryFile tgt_file;
498 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
499
500 TemporaryFile patch_file;
501 std::vector<const char*> args = {
502 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
503 };
504 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
505
506 // Verify.
507 std::string patch;
508 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
509
510 // Expect one CHUNK_RAW (header) entry.
511 size_t num_normal;
512 size_t num_raw;
513 size_t num_deflate;
514 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
515 ASSERT_EQ(0U, num_normal);
516 ASSERT_EQ(0U, num_deflate);
517 ASSERT_EQ(1U, num_raw);
518
Tao Baoc0e1c462017-02-01 10:20:10 -0800519 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800520}
521
522TEST(ImgdiffTest, image_mode_short_input2) {
523 // src: "abcdefgh" + '0x1f8b0b00'.
524 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
525 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
526 const std::string src(src_data.cbegin(), src_data.cend());
527 TemporaryFile src_file;
528 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
529
530 // tgt: "abcdefgxyz".
531 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
532 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
533 TemporaryFile tgt_file;
534 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
535
536 TemporaryFile patch_file;
537 std::vector<const char*> args = {
538 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
539 };
540 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
541
542 // Verify.
543 std::string patch;
544 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
545
546 // Expect one CHUNK_RAW (header) entry.
547 size_t num_normal;
548 size_t num_raw;
549 size_t num_deflate;
550 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
551 ASSERT_EQ(0U, num_normal);
552 ASSERT_EQ(0U, num_deflate);
553 ASSERT_EQ(1U, num_raw);
554
Tao Baoc0e1c462017-02-01 10:20:10 -0800555 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800556}
557
Tao Bao97555da2016-12-15 10:15:06 -0800558TEST(ImgdiffTest, image_mode_single_entry_long) {
559 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
560 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
561 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
562 '\x53', '\x58', 't', 'e', 's', 't' };
563 const std::string src(src_data.cbegin(), src_data.cend());
564 TemporaryFile src_file;
565 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
566
567 // tgt: "abcdefgxyz" + 200 bytes.
568 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
569 tgt_data.resize(tgt_data.size() + 200);
570
571 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
572 TemporaryFile tgt_file;
573 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
574
575 TemporaryFile patch_file;
576 std::vector<const char*> args = {
577 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
578 };
579 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
580
581 // Verify.
582 std::string patch;
583 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
584
585 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
586 size_t num_normal;
587 size_t num_raw;
588 size_t num_deflate;
589 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
590 ASSERT_EQ(1U, num_normal);
591 ASSERT_EQ(0U, num_deflate);
592 ASSERT_EQ(0U, num_raw);
593
Tao Baoc0e1c462017-02-01 10:20:10 -0800594 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800595}
Tianjie Xuce5fa5e2017-05-15 12:32:33 -0700596
597TEST(ImgpatchTest, image_mode_patch_corruption) {
598 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
599 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
600 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
601 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
602 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
603 '\x00', '\x00', '\x00' };
604 const std::string src(src_data.cbegin(), src_data.cend());
605 TemporaryFile src_file;
606 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
607
608 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
609 const std::vector<char> tgt_data = {
610 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
611 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
612 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
613 };
614 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
615 TemporaryFile tgt_file;
616 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
617
618 TemporaryFile patch_file;
619 std::vector<const char*> args = {
620 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
621 };
622 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
623
624 // Verify.
625 std::string patch;
626 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
627 verify_patched_image(src, patch, tgt);
628
629 // Corrupt the end of the patch and expect the ApplyImagePatch to fail.
630 patch.insert(patch.end() - 10, 10, '0');
631 ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
632 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
633 [](const unsigned char* /*data*/, size_t len) { return len; }));
634}
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700635
636static void construct_store_entry(const std::vector<std::tuple<std::string, size_t, char>>& info,
637 ZipWriter* writer) {
638 for (auto& t : info) {
639 // Create t(1) blocks of t(2), and write the data to t(0)
640 ASSERT_EQ(0, writer->StartEntry(std::get<0>(t).c_str(), 0));
641 const std::string content(std::get<1>(t) * 4096, std::get<2>(t));
642 ASSERT_EQ(0, writer->WriteBytes(content.data(), content.size()));
643 ASSERT_EQ(0, writer->FinishEntry());
644 }
645}
646
647static void construct_deflate_entry(const std::vector<std::tuple<std::string, size_t, size_t>>& info,
648 ZipWriter* writer, const std::string& data) {
649 for (auto& t : info) {
650 // t(0): entry_name; t(1): block offset; t(2) length in blocks.
651 ASSERT_EQ(0, writer->StartEntry(std::get<0>(t).c_str(), ZipWriter::kCompress));
652 ASSERT_EQ(0, writer->WriteBytes(data.data() + std::get<1>(t) * 4096, std::get<2>(t) * 4096));
653 ASSERT_EQ(0, writer->FinishEntry());
654 }
655}
656
657// Look for the generated source and patch pieces in the debug_dir and generate the target on
658// each pair. Concatenate the split target and match against the orignal one.
659static void GenerateAndCheckSplitTarget(const std::string& debug_dir, size_t count,
660 const std::string& tgt) {
661 std::string patched;
662 for (size_t i = 0; i < count; i++) {
663 std::string split_src_path = android::base::StringPrintf("%s/src-%zu", debug_dir.c_str(), i);
664 std::string split_patch_path = android::base::StringPrintf("%s/patch-%zu", debug_dir.c_str(), i);
665
666 std::string split_src;
667 std::string split_patch;
668 ASSERT_TRUE(android::base::ReadFileToString(split_src_path, &split_src));
669 ASSERT_TRUE(android::base::ReadFileToString(split_patch_path, &split_patch));
670
671 std::string split_tgt;
672 GenerateTarget(split_src, split_patch, &split_tgt);
673 patched += split_tgt;
674 }
675
676 // Verify we can get back the original target image.
677 ASSERT_EQ(tgt, patched);
678}
679
680std::vector<ImageChunk> ConstructImageChunks(
681 const std::vector<uint8_t>& content, const std::vector<std::tuple<std::string, size_t>>& info) {
682 std::vector<ImageChunk> chunks;
683 size_t start = 0;
684 for (const auto& t : info) {
685 size_t length = std::get<1>(t);
686 chunks.emplace_back(CHUNK_NORMAL, start, &content, length, std::get<0>(t));
687 start += length;
688 }
689
690 return chunks;
691}
692
693TEST(ImgdiffTest, zip_mode_split_image_smoke) {
694 std::vector<uint8_t> content;
695 content.reserve(4096 * 50);
696 uint8_t n = 0;
697 generate_n(back_inserter(content), 4096 * 50, [&n]() { return n++ / 4096; });
698
699 ZipModeImage tgt_image(false, 4096 * 10);
700 std::vector<ImageChunk> tgt_chunks = ConstructImageChunks(content, { { "a", 100 },
701 { "b", 4096 * 2 },
702 { "c", 4096 * 3 },
703 { "d", 300 },
704 { "e-0", 4096 * 10 },
705 { "e-1", 4096 * 5 },
706 { "CD", 200 } });
707 tgt_image.Initialize(std::move(tgt_chunks),
708 std::vector<uint8_t>(content.begin(), content.begin() + 82520));
709
710 tgt_image.DumpChunks();
711
712 ZipModeImage src_image(true, 4096 * 10);
713 std::vector<ImageChunk> src_chunks = ConstructImageChunks(content, { { "b", 4096 * 3 },
714 { "c-0", 4096 * 10 },
715 { "c-1", 4096 * 2 },
716 { "a", 4096 * 5 },
717 { "e-0", 4096 * 10 },
718 { "e-1", 10000 },
719 { "CD", 5000 } });
720 src_image.Initialize(std::move(src_chunks),
721 std::vector<uint8_t>(content.begin(), content.begin() + 137880));
722
723 std::vector<ZipModeImage> split_tgt_images;
724 std::vector<ZipModeImage> split_src_images;
725 std::vector<SortedRangeSet> split_src_ranges;
726
727 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
728 &split_src_images, &split_src_ranges);
729
730 // src_piece 1: a 5 blocks, b 3 blocks
731 // src_piece 2: c-0 10 blocks
732 // src_piece 3: d 0 block, e-0 10 blocks
733 // src_piece 4: e-1 2 blocks; CD 2 blocks
734 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
735 ASSERT_EQ(static_cast<size_t>(4), split_tgt_images.size());
736
737 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[0].NumOfChunks());
738 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[0][0].DataLengthForPatch());
739 ASSERT_EQ("4,0,3,15,20", split_src_ranges[0].ToString());
740
741 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[1].NumOfChunks());
742 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[1][0].DataLengthForPatch());
743 ASSERT_EQ("2,3,13", split_src_ranges[1].ToString());
744
745 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[2].NumOfChunks());
746 ASSERT_EQ(static_cast<size_t>(40960), split_tgt_images[2][0].DataLengthForPatch());
747 ASSERT_EQ("2,20,30", split_src_ranges[2].ToString());
748
749 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[3].NumOfChunks());
750 ASSERT_EQ(static_cast<size_t>(16984), split_tgt_images[3][0].DataLengthForPatch());
751 ASSERT_EQ("2,30,34", split_src_ranges[3].ToString());
752}
753
754TEST(ImgdiffTest, zip_mode_store_large_apk) {
755 // Construct src and tgt zip files with limit = 10 blocks.
756 // src tgt
757 // 12 blocks 'd' 3 blocks 'a'
758 // 8 blocks 'c' 3 blocks 'b'
759 // 3 blocks 'b' 8 blocks 'c' (exceeds limit)
760 // 3 blocks 'a' 12 blocks 'd' (exceeds limit)
761 // 3 blocks 'e'
762 TemporaryFile tgt_file;
763 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
764 ZipWriter tgt_writer(tgt_file_ptr);
765 construct_store_entry(
766 { { "a", 3, 'a' }, { "b", 3, 'b' }, { "c", 8, 'c' }, { "d", 12, 'd' }, { "e", 3, 'e' } },
767 &tgt_writer);
768 ASSERT_EQ(0, tgt_writer.Finish());
769 ASSERT_EQ(0, fclose(tgt_file_ptr));
770
771 TemporaryFile src_file;
772 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
773 ZipWriter src_writer(src_file_ptr);
774 construct_store_entry({ { "d", 12, 'd' }, { "c", 8, 'c' }, { "b", 3, 'b' }, { "a", 3, 'a' } },
775 &src_writer);
776 ASSERT_EQ(0, src_writer.Finish());
777 ASSERT_EQ(0, fclose(src_file_ptr));
778
779 // Compute patch.
780 TemporaryFile patch_file;
781 TemporaryDir debug_dir;
782 std::vector<const char*> args = {
783 "imgdiff", "-z", "--block-limit=10", android::base::StringPrintf(
784 "--debug-dir=%s", debug_dir.path).c_str(), src_file.path, tgt_file.path, patch_file.path,
785 };
786 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
787
788 std::string tgt;
789 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
790
791 // Expect 4 pieces of patch.(Rougly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e')
792 GenerateAndCheckSplitTarget(debug_dir.path, 4, tgt);
793}
794
795TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
796 // Generate 50 blocks of random data.
797 std::string random_data;
798 random_data.reserve(4096 * 50);
799 generate_n(back_inserter(random_data), 4096 * 50, []() { return rand() % 256; });
800
801 // Construct src and tgt zip files with limit = 10 blocks.
802 // src tgt
803 // 22 blocks, "d" 4 blocks, "a"
804 // 5 blocks, "b" 4 blocks, "b"
805 // 3 blocks, "a" 7 blocks, "c" (exceeds limit)
806 // 8 blocks, "c" 20 blocks, "d" (exceeds limit)
807 // 1 block, "f" 2 blocks, "e"
808 TemporaryFile tgt_file;
809 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
810 ZipWriter tgt_writer(tgt_file_ptr);
811
812 construct_deflate_entry(
813 { { "a", 0, 4 }, { "b", 5, 4 }, { "c", 12, 8 }, { "d", 21, 20 }, { "e", 45, 2 },
814 { "f", 48, 1 } }, &tgt_writer, random_data);
815
816 ASSERT_EQ(0, tgt_writer.Finish());
817 ASSERT_EQ(0, fclose(tgt_file_ptr));
818
819 TemporaryFile src_file;
820 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
821 ZipWriter src_writer(src_file_ptr);
822
823 construct_deflate_entry(
824 { { "d", 21, 22 }, { "b", 5, 5 }, { "a", 0, 3 }, { "g", 9, 1 }, { "c", 11, 8 },
825 { "f", 45, 1 } }, &src_writer, random_data);
826
827 ASSERT_EQ(0, src_writer.Finish());
828 ASSERT_EQ(0, fclose(src_file_ptr));
829
830 ZipModeImage src_image(true, 10 * 4096);
831 ZipModeImage tgt_image(false, 10 * 4096);
832 ASSERT_TRUE(src_image.Initialize(src_file.path));
833 ASSERT_TRUE(tgt_image.Initialize(tgt_file.path));
834 ASSERT_TRUE(ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image));
835
836 src_image.DumpChunks();
837 tgt_image.DumpChunks();
838
839 std::vector<ZipModeImage> split_tgt_images;
840 std::vector<ZipModeImage> split_src_images;
841 std::vector<SortedRangeSet> split_src_ranges;
842 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
843 &split_src_images, &split_src_ranges);
844
845 // src_piece 1: a 3 blocks, b 5 blocks
846 // src_piece 2: c 8 blocks
847 // src_piece 3: d-0 10 block
848 // src_piece 4: d-1 10 blocks
849 // src_piece 5: e 1 block, CD
850 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
851 ASSERT_EQ(static_cast<size_t>(5), split_tgt_images.size());
852
853 ASSERT_EQ(static_cast<size_t>(2), split_src_images[0].NumOfChunks());
854 ASSERT_EQ("a", split_src_images[0][0].GetEntryName());
855 ASSERT_EQ("b", split_src_images[0][1].GetEntryName());
856
857 ASSERT_EQ(static_cast<size_t>(1), split_src_images[1].NumOfChunks());
858 ASSERT_EQ("c", split_src_images[1][0].GetEntryName());
859
860 ASSERT_EQ(static_cast<size_t>(0), split_src_images[2].NumOfChunks());
861 ASSERT_EQ(static_cast<size_t>(0), split_src_images[3].NumOfChunks());
862 ASSERT_EQ(static_cast<size_t>(0), split_src_images[4].NumOfChunks());
863
864 // Compute patch.
865 TemporaryFile patch_file;
866 TemporaryDir debug_dir;
867 ASSERT_TRUE(ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
868 patch_file.path, debug_dir.path));
869
870 std::string tgt;
871 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
872
873 // Expect 5 pieces of patch. ["a","b"; "c"; "d-0"; "d-1"; "e"]
874 GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt);
875}
876
877TEST(ImgdiffTest, zip_mode_no_match_source) {
878 // Generate 20 blocks of random data.
879 std::string random_data;
880 random_data.reserve(4096 * 20);
881 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
882
883 TemporaryFile tgt_file;
884 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
885 ZipWriter tgt_writer(tgt_file_ptr);
886
887 construct_deflate_entry({ { "a", 0, 4 }, { "b", 5, 5 }, { "c", 11, 5 } }, &tgt_writer,
888 random_data);
889
890 ASSERT_EQ(0, tgt_writer.Finish());
891 ASSERT_EQ(0, fclose(tgt_file_ptr));
892
893 // We don't have a matching source entry.
894 TemporaryFile src_file;
895 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
896 ZipWriter src_writer(src_file_ptr);
897 construct_store_entry({ { "d", 1, 'd' } }, &src_writer);
898 ASSERT_EQ(0, src_writer.Finish());
899 ASSERT_EQ(0, fclose(src_file_ptr));
900
901 // Compute patch.
902 TemporaryFile patch_file;
903 TemporaryDir debug_dir;
904 std::vector<const char*> args = {
905 "imgdiff", "-z", "--block-limit=10", android::base::StringPrintf(
906 "--debug-dir=%s", debug_dir.path).c_str(), src_file.path, tgt_file.path, patch_file.path,
907 };
908 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
909
910 std::string tgt;
911 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
912
913 // Expect 1 pieces of patch due to no matching source entry.
914 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
915}
916
917TEST(ImgdiffTest, zip_mode_large_enough_limit) {
918 // Generate 20 blocks of random data.
919 std::string random_data;
920 random_data.reserve(4096 * 20);
921 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
922
923 TemporaryFile tgt_file;
924 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
925 ZipWriter tgt_writer(tgt_file_ptr);
926
927 construct_deflate_entry({ { "a", 0, 10 }, { "b", 10, 5 } }, &tgt_writer, random_data);
928
929 ASSERT_EQ(0, tgt_writer.Finish());
930 ASSERT_EQ(0, fclose(tgt_file_ptr));
931
932 // Construct 10 blocks of source.
933 TemporaryFile src_file;
934 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
935 ZipWriter src_writer(src_file_ptr);
936 construct_deflate_entry({ { "a", 1, 10 } }, &src_writer, random_data);
937 ASSERT_EQ(0, src_writer.Finish());
938 ASSERT_EQ(0, fclose(src_file_ptr));
939
940 // Compute patch with a limit of 20 blocks.
941 TemporaryFile patch_file;
942 TemporaryDir debug_dir;
943 std::vector<const char*> args = {
944 "imgdiff", "-z", "--block-limit=20", android::base::StringPrintf(
945 "--debug-dir=%s", debug_dir.path).c_str(), src_file.path, tgt_file.path, patch_file.path,
946 };
947 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
948
949 std::string tgt;
950 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
951
952 // Expect 1 pieces of patch since limit is larger than the zip file size.
953 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
954}