blob: c64c3f499fd6ecf1973c4e41b97fdc79aebbe674 [file] [log] [blame]
Nan Zhang674dd932018-01-26 18:30:36 -08001// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package zip
16
17import (
Colin Cross05518bc2018-09-27 15:06:19 -070018 "bytes"
Zhenhuang Wangb8451b82023-01-06 20:58:01 +080019 "encoding/hex"
Colin Cross05518bc2018-09-27 15:06:19 -070020 "hash/crc32"
21 "io"
22 "os"
Nan Zhang674dd932018-01-26 18:30:36 -080023 "reflect"
Colin Cross05518bc2018-09-27 15:06:19 -070024 "syscall"
Nan Zhang674dd932018-01-26 18:30:36 -080025 "testing"
Colin Cross05518bc2018-09-27 15:06:19 -070026
27 "android/soong/third_party/zip"
28
29 "github.com/google/blueprint/pathtools"
Nan Zhang674dd932018-01-26 18:30:36 -080030)
31
Colin Cross05518bc2018-09-27 15:06:19 -070032var (
33 fileA = []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
34 fileB = []byte("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB")
35 fileC = []byte("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC")
36 fileEmpty = []byte("")
37 fileManifest = []byte("Manifest-Version: 1.0\nCreated-By: soong_zip\n\n")
38
Zhenhuang Wangb8451b82023-01-06 20:58:01 +080039 sha256FileA = "d53eda7a637c99cc7fb566d96e9fa109bf15c478410a3f5eb4d4c4e26cd081f6"
40 sha256FileB = "430c56c5818e62bcb6d478901ef86284e97714c138f3c86aa14fd6a84b7ce5d3"
41 sha256FileC = "31c5ab6111f1d6aa13c2c4e92bb3c0f7c76b61b42d141af1e846eb7f6586a51c"
42
Colin Cross05518bc2018-09-27 15:06:19 -070043 fileCustomManifest = []byte("Custom manifest: true\n")
44 customManifestAfter = []byte("Manifest-Version: 1.0\nCreated-By: soong_zip\nCustom manifest: true\n\n")
45)
46
47var mockFs = pathtools.MockFs(map[string][]byte{
Colin Cross9cb51db2019-06-17 14:12:41 -070048 "a/a/a": fileA,
49 "a/a/b": fileB,
50 "a/a/c -> ../../c": nil,
51 "dangling -> missing": nil,
52 "a/a/d -> b": nil,
53 "c": fileC,
Colin Cross7ddd08a2022-08-15 15:47:41 -070054 "d/a/a": nil,
Colin Crosscaf4d4c2021-02-03 15:15:14 -080055 "l_nl": []byte("a/a/a\na/a/b\nc\n\\[\n"),
56 "l_sp": []byte("a/a/a a/a/b c \\["),
Colin Cross9cb51db2019-06-17 14:12:41 -070057 "l2": []byte("missing\n"),
Colin Crosscaf4d4c2021-02-03 15:15:14 -080058 "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'\n'['"),
Colin Cross053fca12020-08-19 13:51:47 -070059 "@ -> c": nil,
60 "foo'bar -> c": nil,
Colin Cross9cb51db2019-06-17 14:12:41 -070061 "manifest.txt": fileCustomManifest,
Colin Crosscaf4d4c2021-02-03 15:15:14 -080062 "[": fileEmpty,
Colin Cross05518bc2018-09-27 15:06:19 -070063})
64
65func fh(name string, contents []byte, method uint16) zip.FileHeader {
66 return zip.FileHeader{
67 Name: name,
68 Method: method,
69 CRC32: crc32.ChecksumIEEE(contents),
70 UncompressedSize64: uint64(len(contents)),
Chris Grossfa5b4e92021-06-02 12:56:08 -070071 ExternalAttrs: (syscall.S_IFREG | 0644) << 16,
Colin Cross05518bc2018-09-27 15:06:19 -070072 }
73}
74
Zhenhuang Wangb8451b82023-01-06 20:58:01 +080075func fhWithSHA256(name string, contents []byte, method uint16, sha256 string) zip.FileHeader {
76 h := fh(name, contents, method)
77 // The extra field contains 38 bytes, including 2 bytes of header ID, 2 bytes
78 // of size, 2 bytes of signature, and 32 bytes of checksum data block.
79 var extra [38]byte
80 // The first 6 bytes contains Sha256HeaderID (0x4967), size (unit(34)) and
81 // Sha256HeaderSignature (0x9514)
82 copy(extra[0:], []byte{103, 73, 34, 0, 20, 149})
83 sha256Bytes, _ := hex.DecodeString(sha256)
84 copy(extra[6:], sha256Bytes)
85 h.Extra = append(h.Extra, extra[:]...)
86 return h
87}
88
Colin Cross05518bc2018-09-27 15:06:19 -070089func fhManifest(contents []byte) zip.FileHeader {
90 return zip.FileHeader{
91 Name: "META-INF/MANIFEST.MF",
92 Method: zip.Store,
93 CRC32: crc32.ChecksumIEEE(contents),
94 UncompressedSize64: uint64(len(contents)),
Chris Grossfa5b4e92021-06-02 12:56:08 -070095 ExternalAttrs: (syscall.S_IFREG | 0644) << 16,
Colin Cross05518bc2018-09-27 15:06:19 -070096 }
97}
98
99func fhLink(name string, to string) zip.FileHeader {
100 return zip.FileHeader{
101 Name: name,
102 Method: zip.Store,
103 CRC32: crc32.ChecksumIEEE([]byte(to)),
104 UncompressedSize64: uint64(len(to)),
105 ExternalAttrs: (syscall.S_IFLNK | 0777) << 16,
106 }
107}
108
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800109type fhDirOptions struct {
110 extra []byte
111}
112
113func fhDir(name string, opts fhDirOptions) zip.FileHeader {
Colin Cross05518bc2018-09-27 15:06:19 -0700114 return zip.FileHeader{
115 Name: name,
116 Method: zip.Store,
117 CRC32: crc32.ChecksumIEEE(nil),
118 UncompressedSize64: 0,
Chris Grossfa5b4e92021-06-02 12:56:08 -0700119 ExternalAttrs: (syscall.S_IFDIR|0755)<<16 | 0x10,
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800120 Extra: opts.extra,
Colin Cross05518bc2018-09-27 15:06:19 -0700121 }
122}
123
124func fileArgsBuilder() *FileArgsBuilder {
125 return &FileArgsBuilder{
126 fs: mockFs,
127 }
128}
129
130func TestZip(t *testing.T) {
131 testCases := []struct {
Colin Cross4be8f9e2018-09-28 15:16:48 -0700132 name string
133 args *FileArgsBuilder
134 compressionLevel int
135 emulateJar bool
136 nonDeflatedFiles map[string]bool
137 dirEntries bool
138 manifest string
139 storeSymlinks bool
140 ignoreMissingFiles bool
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800141 sha256Checksum bool
Colin Cross05518bc2018-09-27 15:06:19 -0700142
143 files []zip.FileHeader
144 err error
145 }{
146 {
147 name: "empty args",
148 args: fileArgsBuilder(),
149
150 files: []zip.FileHeader{},
151 },
152 {
153 name: "files",
154 args: fileArgsBuilder().
155 File("a/a/a").
156 File("a/a/b").
Colin Crosscaf4d4c2021-02-03 15:15:14 -0800157 File("c").
158 File(`\[`),
Colin Cross05518bc2018-09-27 15:06:19 -0700159 compressionLevel: 9,
160
161 files: []zip.FileHeader{
162 fh("a/a/a", fileA, zip.Deflate),
163 fh("a/a/b", fileB, zip.Deflate),
164 fh("c", fileC, zip.Deflate),
Colin Crosscaf4d4c2021-02-03 15:15:14 -0800165 fh("[", fileEmpty, zip.Store),
Colin Cross05518bc2018-09-27 15:06:19 -0700166 },
167 },
168 {
Colin Cross1d98ee22018-09-18 17:05:15 -0700169 name: "files glob",
170 args: fileArgsBuilder().
171 SourcePrefixToStrip("a").
172 File("a/**/*"),
173 compressionLevel: 9,
Colin Cross09f11052018-09-21 15:12:39 -0700174 storeSymlinks: true,
Colin Cross1d98ee22018-09-18 17:05:15 -0700175
176 files: []zip.FileHeader{
177 fh("a/a", fileA, zip.Deflate),
178 fh("a/b", fileB, zip.Deflate),
179 fhLink("a/c", "../../c"),
180 fhLink("a/d", "b"),
181 },
182 },
183 {
184 name: "dir",
185 args: fileArgsBuilder().
186 SourcePrefixToStrip("a").
187 Dir("a"),
188 compressionLevel: 9,
Colin Cross09f11052018-09-21 15:12:39 -0700189 storeSymlinks: true,
Colin Cross1d98ee22018-09-18 17:05:15 -0700190
191 files: []zip.FileHeader{
192 fh("a/a", fileA, zip.Deflate),
193 fh("a/b", fileB, zip.Deflate),
194 fhLink("a/c", "../../c"),
195 fhLink("a/d", "b"),
196 },
197 },
198 {
Colin Cross05518bc2018-09-27 15:06:19 -0700199 name: "stored files",
200 args: fileArgsBuilder().
201 File("a/a/a").
202 File("a/a/b").
203 File("c"),
204 compressionLevel: 0,
205
206 files: []zip.FileHeader{
207 fh("a/a/a", fileA, zip.Store),
208 fh("a/a/b", fileB, zip.Store),
209 fh("c", fileC, zip.Store),
210 },
211 },
212 {
213 name: "symlinks in zip",
214 args: fileArgsBuilder().
215 File("a/a/a").
216 File("a/a/b").
217 File("a/a/c").
218 File("a/a/d"),
219 compressionLevel: 9,
Colin Cross09f11052018-09-21 15:12:39 -0700220 storeSymlinks: true,
Colin Cross05518bc2018-09-27 15:06:19 -0700221
222 files: []zip.FileHeader{
223 fh("a/a/a", fileA, zip.Deflate),
224 fh("a/a/b", fileB, zip.Deflate),
225 fhLink("a/a/c", "../../c"),
226 fhLink("a/a/d", "b"),
227 },
228 },
229 {
Colin Cross09f11052018-09-21 15:12:39 -0700230 name: "follow symlinks",
231 args: fileArgsBuilder().
232 File("a/a/a").
233 File("a/a/b").
234 File("a/a/c").
235 File("a/a/d"),
236 compressionLevel: 9,
237 storeSymlinks: false,
238
239 files: []zip.FileHeader{
240 fh("a/a/a", fileA, zip.Deflate),
241 fh("a/a/b", fileB, zip.Deflate),
242 fh("a/a/c", fileC, zip.Deflate),
243 fh("a/a/d", fileB, zip.Deflate),
244 },
245 },
246 {
Colin Cross9cb51db2019-06-17 14:12:41 -0700247 name: "dangling symlinks",
248 args: fileArgsBuilder().
249 File("dangling"),
250 compressionLevel: 9,
251 storeSymlinks: true,
252
253 files: []zip.FileHeader{
254 fhLink("dangling", "missing"),
255 },
256 },
257 {
Colin Cross05518bc2018-09-27 15:06:19 -0700258 name: "list",
259 args: fileArgsBuilder().
Jiyong Park04bbf982019-11-04 13:18:41 +0900260 List("l_nl"),
261 compressionLevel: 9,
262
263 files: []zip.FileHeader{
264 fh("a/a/a", fileA, zip.Deflate),
265 fh("a/a/b", fileB, zip.Deflate),
266 fh("c", fileC, zip.Deflate),
Colin Crosscaf4d4c2021-02-03 15:15:14 -0800267 fh("[", fileEmpty, zip.Store),
Jiyong Park04bbf982019-11-04 13:18:41 +0900268 },
269 },
270 {
271 name: "list",
272 args: fileArgsBuilder().
273 List("l_sp"),
Colin Cross05518bc2018-09-27 15:06:19 -0700274 compressionLevel: 9,
275
276 files: []zip.FileHeader{
277 fh("a/a/a", fileA, zip.Deflate),
278 fh("a/a/b", fileB, zip.Deflate),
279 fh("c", fileC, zip.Deflate),
Colin Crosscaf4d4c2021-02-03 15:15:14 -0800280 fh("[", fileEmpty, zip.Store),
Colin Cross05518bc2018-09-27 15:06:19 -0700281 },
282 },
283 {
Colin Cross053fca12020-08-19 13:51:47 -0700284 name: "rsp",
285 args: fileArgsBuilder().
286 RspFile("rsp"),
287 compressionLevel: 9,
288
289 files: []zip.FileHeader{
290 fh("a/a/a", fileA, zip.Deflate),
291 fh("a/a/b", fileB, zip.Deflate),
292 fh("@", fileC, zip.Deflate),
293 fh("foo'bar", fileC, zip.Deflate),
Colin Crosscaf4d4c2021-02-03 15:15:14 -0800294 fh("[", fileEmpty, zip.Store),
Colin Cross053fca12020-08-19 13:51:47 -0700295 },
296 },
297 {
Colin Cross05518bc2018-09-27 15:06:19 -0700298 name: "prefix in zip",
299 args: fileArgsBuilder().
300 PathPrefixInZip("foo").
301 File("a/a/a").
302 File("a/a/b").
303 File("c"),
304 compressionLevel: 9,
305
306 files: []zip.FileHeader{
307 fh("foo/a/a/a", fileA, zip.Deflate),
308 fh("foo/a/a/b", fileB, zip.Deflate),
309 fh("foo/c", fileC, zip.Deflate),
310 },
311 },
312 {
313 name: "relative root",
314 args: fileArgsBuilder().
315 SourcePrefixToStrip("a").
316 File("a/a/a").
317 File("a/a/b"),
318 compressionLevel: 9,
319
320 files: []zip.FileHeader{
321 fh("a/a", fileA, zip.Deflate),
322 fh("a/b", fileB, zip.Deflate),
323 },
324 },
325 {
326 name: "multiple relative root",
327 args: fileArgsBuilder().
328 SourcePrefixToStrip("a").
329 File("a/a/a").
330 SourcePrefixToStrip("a/a").
331 File("a/a/b"),
332 compressionLevel: 9,
333
334 files: []zip.FileHeader{
335 fh("a/a", fileA, zip.Deflate),
336 fh("b", fileB, zip.Deflate),
337 },
338 },
339 {
340 name: "emulate jar",
341 args: fileArgsBuilder().
342 File("a/a/a").
343 File("a/a/b"),
344 compressionLevel: 9,
345 emulateJar: true,
346
347 files: []zip.FileHeader{
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800348 fhDir("META-INF/", fhDirOptions{extra: []byte{254, 202, 0, 0}}),
Colin Cross05518bc2018-09-27 15:06:19 -0700349 fhManifest(fileManifest),
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800350 fhDir("a/", fhDirOptions{}),
351 fhDir("a/a/", fhDirOptions{}),
Colin Cross05518bc2018-09-27 15:06:19 -0700352 fh("a/a/a", fileA, zip.Deflate),
353 fh("a/a/b", fileB, zip.Deflate),
354 },
355 },
356 {
357 name: "emulate jar with manifest",
358 args: fileArgsBuilder().
359 File("a/a/a").
360 File("a/a/b"),
361 compressionLevel: 9,
362 emulateJar: true,
363 manifest: "manifest.txt",
364
365 files: []zip.FileHeader{
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800366 fhDir("META-INF/", fhDirOptions{extra: []byte{254, 202, 0, 0}}),
Colin Cross05518bc2018-09-27 15:06:19 -0700367 fhManifest(customManifestAfter),
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800368 fhDir("a/", fhDirOptions{}),
369 fhDir("a/a/", fhDirOptions{}),
Colin Cross05518bc2018-09-27 15:06:19 -0700370 fh("a/a/a", fileA, zip.Deflate),
371 fh("a/a/b", fileB, zip.Deflate),
372 },
373 },
374 {
375 name: "dir entries",
376 args: fileArgsBuilder().
377 File("a/a/a").
378 File("a/a/b"),
379 compressionLevel: 9,
380 dirEntries: true,
381
382 files: []zip.FileHeader{
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800383 fhDir("a/", fhDirOptions{}),
384 fhDir("a/a/", fhDirOptions{}),
Colin Cross05518bc2018-09-27 15:06:19 -0700385 fh("a/a/a", fileA, zip.Deflate),
386 fh("a/a/b", fileB, zip.Deflate),
387 },
388 },
389 {
390 name: "junk paths",
391 args: fileArgsBuilder().
392 JunkPaths(true).
393 File("a/a/a").
394 File("a/a/b"),
395 compressionLevel: 9,
396
397 files: []zip.FileHeader{
398 fh("a", fileA, zip.Deflate),
399 fh("b", fileB, zip.Deflate),
400 },
401 },
402 {
403 name: "non deflated files",
404 args: fileArgsBuilder().
405 File("a/a/a").
406 File("a/a/b"),
407 compressionLevel: 9,
408 nonDeflatedFiles: map[string]bool{"a/a/a": true},
409
410 files: []zip.FileHeader{
411 fh("a/a/a", fileA, zip.Store),
412 fh("a/a/b", fileB, zip.Deflate),
413 },
414 },
Colin Cross4be8f9e2018-09-28 15:16:48 -0700415 {
416 name: "ignore missing files",
417 args: fileArgsBuilder().
418 File("a/a/a").
419 File("a/a/b").
420 File("missing"),
421 compressionLevel: 9,
422 ignoreMissingFiles: true,
423
424 files: []zip.FileHeader{
425 fh("a/a/a", fileA, zip.Deflate),
426 fh("a/a/b", fileB, zip.Deflate),
427 },
428 },
Colin Cross7ddd08a2022-08-15 15:47:41 -0700429 {
430 name: "duplicate sources",
431 args: fileArgsBuilder().
432 File("a/a/a").
433 File("a/a/a"),
434 compressionLevel: 9,
435
436 files: []zip.FileHeader{
437 fh("a/a/a", fileA, zip.Deflate),
438 },
439 },
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800440 {
441 name: "generate SHA256 checksum",
442 args: fileArgsBuilder().
443 File("a/a/a").
444 File("a/a/b").
445 File("a/a/c").
446 File("c"),
447 compressionLevel: 9,
448 sha256Checksum: true,
449
450 files: []zip.FileHeader{
451 fhWithSHA256("a/a/a", fileA, zip.Deflate, sha256FileA),
452 fhWithSHA256("a/a/b", fileB, zip.Deflate, sha256FileB),
453 fhWithSHA256("a/a/c", fileC, zip.Deflate, sha256FileC),
454 fhWithSHA256("c", fileC, zip.Deflate, sha256FileC),
455 },
456 },
Colin Cross25ff3052023-05-08 15:05:29 -0700457 {
458 name: "explicit path",
459 args: fileArgsBuilder().
460 ExplicitPathInZip("foo").
461 File("a/a/a").
462 File("a/a/b"),
463 compressionLevel: 9,
464
465 files: []zip.FileHeader{
466 fh("foo", fileA, zip.Deflate),
467 fh("a/a/b", fileB, zip.Deflate),
468 },
469 },
470 {
471 name: "explicit path with prefix",
472 args: fileArgsBuilder().
473 PathPrefixInZip("prefix").
474 ExplicitPathInZip("foo").
475 File("a/a/a").
476 File("a/a/b"),
477 compressionLevel: 9,
478
479 files: []zip.FileHeader{
480 fh("prefix/foo", fileA, zip.Deflate),
481 fh("prefix/a/a/b", fileB, zip.Deflate),
482 },
483 },
484 {
485 name: "explicit path with glob",
486 args: fileArgsBuilder().
487 ExplicitPathInZip("foo").
488 File("a/a/a*").
489 File("a/a/b"),
490 compressionLevel: 9,
491
492 files: []zip.FileHeader{
493 fh("foo", fileA, zip.Deflate),
494 fh("a/a/b", fileB, zip.Deflate),
495 },
496 },
497 {
498 name: "explicit path with junk paths",
499 args: fileArgsBuilder().
500 JunkPaths(true).
501 ExplicitPathInZip("foo/bar").
502 File("a/a/a*").
503 File("a/a/b"),
504 compressionLevel: 9,
505
506 files: []zip.FileHeader{
507 fh("foo/bar", fileA, zip.Deflate),
508 fh("b", fileB, zip.Deflate),
509 },
510 },
Colin Cross05518bc2018-09-27 15:06:19 -0700511
512 // errors
513 {
514 name: "error missing file",
515 args: fileArgsBuilder().
516 File("missing"),
517 err: os.ErrNotExist,
518 },
519 {
Colin Cross1d98ee22018-09-18 17:05:15 -0700520 name: "error missing dir",
521 args: fileArgsBuilder().
522 Dir("missing"),
523 err: os.ErrNotExist,
524 },
525 {
Colin Cross05518bc2018-09-27 15:06:19 -0700526 name: "error missing file in list",
527 args: fileArgsBuilder().
528 List("l2"),
529 err: os.ErrNotExist,
530 },
Colin Cross1d98ee22018-09-18 17:05:15 -0700531 {
532 name: "error incorrect relative root",
533 args: fileArgsBuilder().
534 SourcePrefixToStrip("b").
535 File("a/a/a"),
536 err: IncorrectRelativeRootError{},
537 },
Colin Cross7ddd08a2022-08-15 15:47:41 -0700538 {
539 name: "error conflicting file",
540 args: fileArgsBuilder().
541 SourcePrefixToStrip("a").
542 File("a/a/a").
543 SourcePrefixToStrip("d").
544 File("d/a/a"),
545 err: ConflictingFileError{},
546 },
Colin Cross25ff3052023-05-08 15:05:29 -0700547 {
548 name: "error explicit path conflicting",
549 args: fileArgsBuilder().
550 ExplicitPathInZip("foo").
551 File("a/a/a").
552 ExplicitPathInZip("foo").
553 File("a/a/b"),
554 err: ConflictingFileError{},
555 },
556 {
557 name: "error explicit path conflicting glob",
558 args: fileArgsBuilder().
559 ExplicitPathInZip("foo").
560 File("a/a/*"),
561 err: ConflictingFileError{},
562 },
Colin Cross05518bc2018-09-27 15:06:19 -0700563 }
564
565 for _, test := range testCases {
566 t.Run(test.name, func(t *testing.T) {
567 if test.args.Error() != nil {
568 t.Fatal(test.args.Error())
569 }
570
571 args := ZipArgs{}
572 args.FileArgs = test.args.FileArgs()
573 args.CompressionLevel = test.compressionLevel
574 args.EmulateJar = test.emulateJar
575 args.AddDirectoryEntriesToZip = test.dirEntries
576 args.NonDeflatedFiles = test.nonDeflatedFiles
577 args.ManifestSourcePath = test.manifest
Colin Cross09f11052018-09-21 15:12:39 -0700578 args.StoreSymlinks = test.storeSymlinks
Colin Cross4be8f9e2018-09-28 15:16:48 -0700579 args.IgnoreMissingFiles = test.ignoreMissingFiles
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800580 args.Sha256Checksum = test.sha256Checksum
Colin Cross05518bc2018-09-27 15:06:19 -0700581 args.Filesystem = mockFs
Colin Cross4be8f9e2018-09-28 15:16:48 -0700582 args.Stderr = &bytes.Buffer{}
Colin Cross05518bc2018-09-27 15:06:19 -0700583
584 buf := &bytes.Buffer{}
Sasha Smundak8eedba62020-11-16 19:00:27 -0800585 err := zipTo(args, buf)
Colin Cross05518bc2018-09-27 15:06:19 -0700586
587 if (err != nil) != (test.err != nil) {
588 t.Fatalf("want error %v, got %v", test.err, err)
589 } else if test.err != nil {
590 if os.IsNotExist(test.err) {
Colin Cross7ddd08a2022-08-15 15:47:41 -0700591 if !os.IsNotExist(err) {
Colin Cross05518bc2018-09-27 15:06:19 -0700592 t.Fatalf("want error %v, got %v", test.err, err)
593 }
Colin Cross1d98ee22018-09-18 17:05:15 -0700594 } else if _, wantRelativeRootErr := test.err.(IncorrectRelativeRootError); wantRelativeRootErr {
595 if _, gotRelativeRootErr := err.(IncorrectRelativeRootError); !gotRelativeRootErr {
596 t.Fatalf("want error %v, got %v", test.err, err)
597 }
Colin Cross7ddd08a2022-08-15 15:47:41 -0700598 } else if _, wantConflictingFileError := test.err.(ConflictingFileError); wantConflictingFileError {
599 if _, gotConflictingFileError := err.(ConflictingFileError); !gotConflictingFileError {
600 t.Fatalf("want error %v, got %v", test.err, err)
601 }
Colin Cross05518bc2018-09-27 15:06:19 -0700602 } else {
603 t.Fatalf("want error %v, got %v", test.err, err)
604 }
605 return
606 }
607
608 br := bytes.NewReader(buf.Bytes())
609 zr, err := zip.NewReader(br, int64(br.Len()))
610 if err != nil {
611 t.Fatal(err)
612 }
613
614 var files []zip.FileHeader
615 for _, f := range zr.File {
616 r, err := f.Open()
617 if err != nil {
618 t.Fatalf("error when opening %s: %s", f.Name, err)
619 }
620
621 crc := crc32.NewIEEE()
622 len, err := io.Copy(crc, r)
623 r.Close()
624 if err != nil {
625 t.Fatalf("error when reading %s: %s", f.Name, err)
626 }
627
628 if uint64(len) != f.UncompressedSize64 {
629 t.Errorf("incorrect length for %s, want %d got %d", f.Name, f.UncompressedSize64, len)
630 }
631
632 if crc.Sum32() != f.CRC32 {
633 t.Errorf("incorrect crc for %s, want %x got %x", f.Name, f.CRC32, crc)
634 }
635
636 files = append(files, f.FileHeader)
637 }
638
639 if len(files) != len(test.files) {
640 t.Fatalf("want %d files, got %d", len(test.files), len(files))
641 }
642
643 for i := range files {
644 want := test.files[i]
645 got := files[i]
646
647 if want.Name != got.Name {
648 t.Errorf("incorrect file %d want %q got %q", i, want.Name, got.Name)
649 continue
650 }
651
652 if want.UncompressedSize64 != got.UncompressedSize64 {
653 t.Errorf("incorrect file %s length want %v got %v", want.Name,
654 want.UncompressedSize64, got.UncompressedSize64)
655 }
656
657 if want.ExternalAttrs != got.ExternalAttrs {
658 t.Errorf("incorrect file %s attrs want %x got %x", want.Name,
659 want.ExternalAttrs, got.ExternalAttrs)
660 }
661
662 if want.CRC32 != got.CRC32 {
663 t.Errorf("incorrect file %s crc want %v got %v", want.Name,
664 want.CRC32, got.CRC32)
665 }
666
667 if want.Method != got.Method {
668 t.Errorf("incorrect file %s method want %v got %v", want.Name,
669 want.Method, got.Method)
670 }
Zhenhuang Wangb8451b82023-01-06 20:58:01 +0800671
672 if !bytes.Equal(want.Extra, got.Extra) {
673 t.Errorf("incorrect file %s extra want %v got %v", want.Name,
674 want.Extra, got.Extra)
675 }
Colin Cross05518bc2018-09-27 15:06:19 -0700676 }
677 })
678 }
679}
680
Colin Cross9cb51db2019-06-17 14:12:41 -0700681func TestSrcJar(t *testing.T) {
682 mockFs := pathtools.MockFs(map[string][]byte{
683 "wrong_package.java": []byte("package foo;"),
684 "foo/correct_package.java": []byte("package foo;"),
685 "src/no_package.java": nil,
686 "src2/parse_error.java": []byte("error"),
687 })
688
689 want := []string{
690 "foo/",
691 "foo/wrong_package.java",
692 "foo/correct_package.java",
693 "no_package.java",
694 "src2/",
695 "src2/parse_error.java",
696 }
697
698 args := ZipArgs{}
699 args.FileArgs = NewFileArgsBuilder().File("**/*.java").FileArgs()
700
701 args.SrcJar = true
702 args.AddDirectoryEntriesToZip = true
703 args.Filesystem = mockFs
704 args.Stderr = &bytes.Buffer{}
705
706 buf := &bytes.Buffer{}
Sasha Smundak8eedba62020-11-16 19:00:27 -0800707 err := zipTo(args, buf)
Colin Cross9cb51db2019-06-17 14:12:41 -0700708 if err != nil {
709 t.Fatalf("got error %v", err)
710 }
711
712 br := bytes.NewReader(buf.Bytes())
713 zr, err := zip.NewReader(br, int64(br.Len()))
714 if err != nil {
715 t.Fatal(err)
716 }
717
718 var got []string
719 for _, f := range zr.File {
720 r, err := f.Open()
721 if err != nil {
722 t.Fatalf("error when opening %s: %s", f.Name, err)
723 }
724
725 crc := crc32.NewIEEE()
726 len, err := io.Copy(crc, r)
727 r.Close()
728 if err != nil {
729 t.Fatalf("error when reading %s: %s", f.Name, err)
730 }
731
732 if uint64(len) != f.UncompressedSize64 {
733 t.Errorf("incorrect length for %s, want %d got %d", f.Name, f.UncompressedSize64, len)
734 }
735
736 if crc.Sum32() != f.CRC32 {
737 t.Errorf("incorrect crc for %s, want %x got %x", f.Name, f.CRC32, crc)
738 }
739
740 got = append(got, f.Name)
741 }
742
743 if !reflect.DeepEqual(want, got) {
744 t.Errorf("want files %q, got %q", want, got)
745 }
746}