1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
22 // TODO(adg): a more sophisticated test suite
24 type WriteTest
struct {
31 var writeTests
= []WriteTest
{
34 Data
: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
40 Data
: nil, // large data set in the test
46 Data
: []byte("setuid file"),
48 Mode
: 0755 | fs
.ModeSetuid
,
52 Data
: []byte("setgid file"),
54 Mode
: 0755 | fs
.ModeSetgid
,
58 Data
: []byte("../link/target"),
60 Mode
: 0755 | fs
.ModeSymlink
,
64 Data
: []byte("device file"),
66 Mode
: 0755 | fs
.ModeDevice
,
70 Data
: []byte("char device file"),
72 Mode
: 0755 | fs
.ModeDevice | fs
.ModeCharDevice
,
76 func TestWriter(t
*testing
.T
) {
77 largeData
:= make([]byte, 1<<17)
78 if _
, err
:= rand
.Read(largeData
); err
!= nil {
79 t
.Fatal("rand.Read failed:", err
)
81 writeTests
[1].Data
= largeData
83 writeTests
[1].Data
= nil
87 buf
:= new(bytes
.Buffer
)
90 for _
, wt
:= range writeTests
{
94 if err
:= w
.Close(); err
!= nil {
99 r
, err
:= NewReader(bytes
.NewReader(buf
.Bytes()), int64(buf
.Len()))
103 for i
, wt
:= range writeTests
{
104 testReadFile(t
, r
.File
[i
], &wt
)
108 // TestWriterComment is test for EOCD comment read/write.
109 func TestWriterComment(t
*testing
.T
) {
110 var tests
= []struct {
116 {strings
.Repeat("a", uint16max
), true},
117 {strings
.Repeat("a", uint16max
+1), false},
120 for _
, test
:= range tests
{
122 buf
:= new(bytes
.Buffer
)
124 if err
:= w
.SetComment(test
.comment
); err
!= nil {
126 t
.Fatalf("SetComment: unexpected error %v", err
)
131 t
.Fatalf("SetComment: unexpected success, want error")
135 if err
:= w
.Close(); test
.ok
== (err
!= nil) {
139 if w
.closed != test
.ok
{
140 t
.Fatalf("Writer.closed: got %v, want %v", w
.closed, test
.ok
)
143 // skip read test in failure cases
149 r
, err
:= NewReader(bytes
.NewReader(buf
.Bytes()), int64(buf
.Len()))
153 if r
.Comment
!= test
.comment
{
154 t
.Fatalf("Reader.Comment: got %v, want %v", r
.Comment
, test
.comment
)
159 func TestWriterUTF8(t
*testing
.T
) {
160 var utf8Tests
= []struct {
168 comment
: "in the world",
173 comment
: "in the world",
178 comment
: "in the world",
184 comment
: "in the 世界",
189 comment
: "in the 世界",
193 name
: "the replacement rune is �",
194 comment
: "the replacement rune is �",
198 // Name is Japanese encoded in Shift JIS.
199 name
: "\x93\xfa\x96{\x8c\xea.txt",
200 comment
: "in the 世界",
201 flags
: 0x008, // UTF-8 must not be set
206 buf
:= new(bytes
.Buffer
)
209 for _
, test
:= range utf8Tests
{
212 Comment
: test
.comment
,
213 NonUTF8
: test
.nonUTF8
,
216 w
, err
:= w
.CreateHeader(h
)
223 if err
:= w
.Close(); err
!= nil {
228 r
, err
:= NewReader(bytes
.NewReader(buf
.Bytes()), int64(buf
.Len()))
232 for i
, test
:= range utf8Tests
{
233 flags
:= r
.File
[i
].Flags
234 if flags
!= test
.flags
{
235 t
.Errorf("CreateHeader(name=%q comment=%q nonUTF8=%v): flags=%#x, want %#x", test
.name
, test
.comment
, test
.nonUTF8
, flags
, test
.flags
)
240 func TestWriterTime(t
*testing
.T
) {
244 Modified
: time
.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time
.Hour
)),
247 if _
, err
:= w
.CreateHeader(h
); err
!= nil {
248 t
.Fatalf("unexpected CreateHeader error: %v", err
)
250 if err
:= w
.Close(); err
!= nil {
251 t
.Fatalf("unexpected Close error: %v", err
)
254 want
, err
:= os
.ReadFile("testdata/time-go.zip")
256 t
.Fatalf("unexpected ReadFile error: %v", err
)
258 if got
:= buf
.Bytes(); !bytes
.Equal(got
, want
) {
259 fmt
.Printf("%x\n%x\n", got
, want
)
260 t
.Error("contents of time-go.zip differ")
264 func TestWriterOffset(t
*testing
.T
) {
265 largeData
:= make([]byte, 1<<17)
266 if _
, err
:= rand
.Read(largeData
); err
!= nil {
267 t
.Fatal("rand.Read failed:", err
)
269 writeTests
[1].Data
= largeData
271 writeTests
[1].Data
= nil
275 buf
:= new(bytes
.Buffer
)
276 existingData
:= []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
277 n
, _
:= buf
.Write(existingData
)
279 w
.SetOffset(int64(n
))
281 for _
, wt
:= range writeTests
{
282 testCreate(t
, w
, &wt
)
285 if err
:= w
.Close(); err
!= nil {
290 r
, err
:= NewReader(bytes
.NewReader(buf
.Bytes()), int64(buf
.Len()))
294 for i
, wt
:= range writeTests
{
295 testReadFile(t
, r
.File
[i
], &wt
)
299 func TestWriterFlush(t
*testing
.T
) {
301 w
:= NewWriter(struct{ io
.Writer
}{&buf
})
302 _
, err
:= w
.Create("foo")
307 t
.Fatalf("Unexpected %d bytes already in buffer", buf
.Len())
309 if err
:= w
.Flush(); err
!= nil {
313 t
.Fatal("No bytes written after Flush")
317 func TestWriterDir(t
*testing
.T
) {
318 w
:= NewWriter(io
.Discard
)
319 dw
, err
:= w
.Create("dir/")
323 if _
, err
:= dw
.Write(nil); err
!= nil {
324 t
.Errorf("Write(nil) to directory: got %v, want nil", err
)
326 if _
, err
:= dw
.Write([]byte("hello")); err
== nil {
327 t
.Error(`Write("hello") to directory: got nil error, want non-nil`)
331 func TestWriterDirAttributes(t
*testing
.T
) {
334 if _
, err
:= w
.CreateHeader(&FileHeader
{
337 CompressedSize64
: 1234,
338 UncompressedSize64
: 5678,
342 if err
:= w
.Close(); err
!= nil {
348 binary
.LittleEndian
.PutUint32(sig
[:], uint32(fileHeaderSignature
))
350 idx
:= bytes
.Index(b
, sig
[:])
352 t
.Fatal("file header not found")
356 if !bytes
.Equal(b
[6:10], []byte{0, 0, 0, 0}) { // FileHeader.Flags: 0, FileHeader.Method: 0
357 t
.Errorf("unexpected method and flags: %v", b
[6:10])
360 if !bytes
.Equal(b
[14:26], make([]byte, 12)) { // FileHeader.{CRC32,CompressSize,UncompressedSize} all zero.
361 t
.Errorf("unexpected crc, compress and uncompressed size to be 0 was: %v", b
[14:26])
364 binary
.LittleEndian
.PutUint32(sig
[:], uint32(dataDescriptorSignature
))
365 if bytes
.Contains(b
, sig
[:]) {
366 t
.Error("there should be no data descriptor")
370 func TestWriterCopy(t
*testing
.T
) {
372 buf
:= new(bytes
.Buffer
)
374 for _
, wt
:= range writeTests
{
375 testCreate(t
, w
, &wt
)
377 if err
:= w
.Close(); err
!= nil {
382 src
, err
:= NewReader(bytes
.NewReader(buf
.Bytes()), int64(buf
.Len()))
386 for i
, wt
:= range writeTests
{
387 testReadFile(t
, src
.File
[i
], &wt
)
390 // make a new zip file copying the old compressed data.
391 buf2
:= new(bytes
.Buffer
)
392 dst
:= NewWriter(buf2
)
393 for _
, f
:= range src
.File
{
394 if err
:= dst
.Copy(f
); err
!= nil {
398 if err
:= dst
.Close(); err
!= nil {
402 // read the new one back
403 r
, err
:= NewReader(bytes
.NewReader(buf2
.Bytes()), int64(buf2
.Len()))
407 for i
, wt
:= range writeTests
{
408 testReadFile(t
, r
.File
[i
], &wt
)
412 func TestWriterCreateRaw(t
*testing
.T
) {
419 uncompressedSize
uint64
420 compressedSize
uint64
423 name
: "small store w desc",
424 content
: []byte("gophers"),
429 name
: "small deflate wo desc",
430 content
: bytes
.Repeat([]byte("abcdefg"), 2048),
436 archive
:= new(bytes
.Buffer
)
437 w
:= NewWriter(archive
)
439 for i
:= range files
{
441 f
.crc32
= crc32
.ChecksumIEEE(f
.content
)
442 size
:= uint64(len(f
.content
))
443 f
.uncompressedSize
= size
444 f
.compressedSize
= size
446 var compressedContent
[]byte
447 if f
.method
== Deflate
{
449 w
, err
:= flate
.NewWriter(&buf
, flate
.BestSpeed
)
451 t
.Fatalf("flate.NewWriter err = %v", err
)
453 _
, err
= w
.Write(f
.content
)
455 t
.Fatalf("flate Write err = %v", err
)
459 t
.Fatalf("flate Writer.Close err = %v", err
)
461 compressedContent
= buf
.Bytes()
462 f
.compressedSize
= uint64(len(compressedContent
))
470 CompressedSize64
: f
.compressedSize
,
471 UncompressedSize64
: f
.uncompressedSize
,
473 w
, err
:= w
.CreateRaw(h
)
477 if compressedContent
!= nil {
478 _
, err
= w
.Write(compressedContent
)
480 _
, err
= w
.Write(f
.content
)
483 t
.Fatalf("%s Write got %v; want nil", f
.name
, err
)
487 if err
:= w
.Close(); err
!= nil {
492 r
, err
:= NewReader(bytes
.NewReader(archive
.Bytes()), int64(archive
.Len()))
496 for i
, want
:= range files
{
498 if got
.Name
!= want
.name
{
499 t
.Errorf("got Name %s; want %s", got
.Name
, want
.name
)
501 if got
.Method
!= want
.method
{
502 t
.Errorf("%s: got Method %#x; want %#x", want
.name
, got
.Method
, want
.method
)
504 if got
.Flags
!= want
.flags
{
505 t
.Errorf("%s: got Flags %#x; want %#x", want
.name
, got
.Flags
, want
.flags
)
507 if got
.CRC32
!= want
.crc32
{
508 t
.Errorf("%s: got CRC32 %#x; want %#x", want
.name
, got
.CRC32
, want
.crc32
)
510 if got
.CompressedSize64
!= want
.compressedSize
{
511 t
.Errorf("%s: got CompressedSize64 %d; want %d", want
.name
, got
.CompressedSize64
, want
.compressedSize
)
513 if got
.UncompressedSize64
!= want
.uncompressedSize
{
514 t
.Errorf("%s: got UncompressedSize64 %d; want %d", want
.name
, got
.UncompressedSize64
, want
.uncompressedSize
)
519 t
.Errorf("%s: Open err = %v", got
.Name
, err
)
523 buf
, err
:= io
.ReadAll(r
)
525 t
.Errorf("%s: ReadAll err = %v", got
.Name
, err
)
529 if !bytes
.Equal(buf
, want
.content
) {
530 t
.Errorf("%v: ReadAll returned unexpected bytes", got
.Name
)
535 func testCreate(t
*testing
.T
, w
*Writer
, wt
*WriteTest
) {
536 header
:= &FileHeader
{
541 header
.SetMode(wt
.Mode
)
543 f
, err
:= w
.CreateHeader(header
)
547 _
, err
= f
.Write(wt
.Data
)
553 func testReadFile(t
*testing
.T
, f
*File
, wt
*WriteTest
) {
554 if f
.Name
!= wt
.Name
{
555 t
.Fatalf("File name: got %q, want %q", f
.Name
, wt
.Name
)
557 testFileMode(t
, f
, wt
.Mode
)
560 t
.Fatalf("opening %s: %v", f
.Name
, err
)
562 b
, err
:= io
.ReadAll(rc
)
564 t
.Fatalf("reading %s: %v", f
.Name
, err
)
568 t
.Fatalf("closing %s: %v", f
.Name
, err
)
570 if !bytes
.Equal(b
, wt
.Data
) {
571 t
.Errorf("File contents %q, want %q", b
, wt
.Data
)
575 func BenchmarkCompressedZipGarbage(b
*testing
.B
) {
576 bigBuf
:= bytes
.Repeat([]byte("a"), 1<<20)
578 runOnce
:= func(buf
*bytes
.Buffer
) {
581 for j
:= 0; j
< 3; j
++ {
582 w
, _
:= zw
.CreateHeader(&FileHeader
{
592 // Run once and then reset the timer.
593 // This effectively discards the very large initial flate setup cost,
594 // as well as the initialization of bigBuf.
595 runOnce(&bytes
.Buffer
{})
598 b
.RunParallel(func(pb
*testing
.PB
) {