libstdc++: Qualify calls in <bits/stl_uninitialized.h> to prevent ADL
[official-gcc.git] / libgo / go / archive / zip / writer_test.go
blob2b73eca814f621a9a0289f24cf0b6bbe8df35c6c
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.
5 package zip
7 import (
8 "bytes"
9 "compress/flate"
10 "encoding/binary"
11 "fmt"
12 "hash/crc32"
13 "io"
14 "io/fs"
15 "math/rand"
16 "os"
17 "strings"
18 "testing"
19 "time"
22 // TODO(adg): a more sophisticated test suite
24 type WriteTest struct {
25 Name string
26 Data []byte
27 Method uint16
28 Mode fs.FileMode
31 var writeTests = []WriteTest{
33 Name: "foo",
34 Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
35 Method: Store,
36 Mode: 0666,
39 Name: "bar",
40 Data: nil, // large data set in the test
41 Method: Deflate,
42 Mode: 0644,
45 Name: "setuid",
46 Data: []byte("setuid file"),
47 Method: Deflate,
48 Mode: 0755 | fs.ModeSetuid,
51 Name: "setgid",
52 Data: []byte("setgid file"),
53 Method: Deflate,
54 Mode: 0755 | fs.ModeSetgid,
57 Name: "symlink",
58 Data: []byte("../link/target"),
59 Method: Deflate,
60 Mode: 0755 | fs.ModeSymlink,
63 Name: "device",
64 Data: []byte("device file"),
65 Method: Deflate,
66 Mode: 0755 | fs.ModeDevice,
69 Name: "chardevice",
70 Data: []byte("char device file"),
71 Method: Deflate,
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
82 defer func() {
83 writeTests[1].Data = nil
84 }()
86 // write a zip file
87 buf := new(bytes.Buffer)
88 w := NewWriter(buf)
90 for _, wt := range writeTests {
91 testCreate(t, w, &wt)
94 if err := w.Close(); err != nil {
95 t.Fatal(err)
98 // read it back
99 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
100 if err != nil {
101 t.Fatal(err)
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 {
111 comment string
112 ok bool
114 {"hi, hello", true},
115 {"hi, こんにちわ", true},
116 {strings.Repeat("a", uint16max), true},
117 {strings.Repeat("a", uint16max+1), false},
120 for _, test := range tests {
121 // write a zip file
122 buf := new(bytes.Buffer)
123 w := NewWriter(buf)
124 if err := w.SetComment(test.comment); err != nil {
125 if test.ok {
126 t.Fatalf("SetComment: unexpected error %v", err)
128 continue
129 } else {
130 if !test.ok {
131 t.Fatalf("SetComment: unexpected success, want error")
135 if err := w.Close(); test.ok == (err != nil) {
136 t.Fatal(err)
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
144 if !test.ok {
145 continue
148 // read it back
149 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
150 if err != nil {
151 t.Fatal(err)
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 {
161 name string
162 comment string
163 nonUTF8 bool
164 flags uint16
167 name: "hi, hello",
168 comment: "in the world",
169 flags: 0x8,
172 name: "hi, こんにちわ",
173 comment: "in the world",
174 flags: 0x808,
177 name: "hi, こんにちわ",
178 comment: "in the world",
179 nonUTF8: true,
180 flags: 0x8,
183 name: "hi, hello",
184 comment: "in the 世界",
185 flags: 0x808,
188 name: "hi, こんにちわ",
189 comment: "in the 世界",
190 flags: 0x808,
193 name: "the replacement rune is �",
194 comment: "the replacement rune is �",
195 flags: 0x808,
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
205 // write a zip file
206 buf := new(bytes.Buffer)
207 w := NewWriter(buf)
209 for _, test := range utf8Tests {
210 h := &FileHeader{
211 Name: test.name,
212 Comment: test.comment,
213 NonUTF8: test.nonUTF8,
214 Method: Deflate,
216 w, err := w.CreateHeader(h)
217 if err != nil {
218 t.Fatal(err)
220 w.Write([]byte{})
223 if err := w.Close(); err != nil {
224 t.Fatal(err)
227 // read it back
228 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
229 if err != nil {
230 t.Fatal(err)
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) {
241 var buf bytes.Buffer
242 h := &FileHeader{
243 Name: "test.txt",
244 Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
246 w := NewWriter(&buf)
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")
255 if err != nil {
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
270 defer func() {
271 writeTests[1].Data = nil
274 // write a zip file
275 buf := new(bytes.Buffer)
276 existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
277 n, _ := buf.Write(existingData)
278 w := NewWriter(buf)
279 w.SetOffset(int64(n))
281 for _, wt := range writeTests {
282 testCreate(t, w, &wt)
285 if err := w.Close(); err != nil {
286 t.Fatal(err)
289 // read it back
290 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
291 if err != nil {
292 t.Fatal(err)
294 for i, wt := range writeTests {
295 testReadFile(t, r.File[i], &wt)
299 func TestWriterFlush(t *testing.T) {
300 var buf bytes.Buffer
301 w := NewWriter(struct{ io.Writer }{&buf})
302 _, err := w.Create("foo")
303 if err != nil {
304 t.Fatal(err)
306 if buf.Len() > 0 {
307 t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
309 if err := w.Flush(); err != nil {
310 t.Fatal(err)
312 if buf.Len() == 0 {
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/")
320 if err != nil {
321 t.Fatal(err)
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) {
332 var buf bytes.Buffer
333 w := NewWriter(&buf)
334 if _, err := w.CreateHeader(&FileHeader{
335 Name: "dir/",
336 Method: Deflate,
337 CompressedSize64: 1234,
338 UncompressedSize64: 5678,
339 }); err != nil {
340 t.Fatal(err)
342 if err := w.Close(); err != nil {
343 t.Fatal(err)
345 b := buf.Bytes()
347 var sig [4]byte
348 binary.LittleEndian.PutUint32(sig[:], uint32(fileHeaderSignature))
350 idx := bytes.Index(b, sig[:])
351 if idx == -1 {
352 t.Fatal("file header not found")
354 b = b[idx:]
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) {
371 // make a zip file
372 buf := new(bytes.Buffer)
373 w := NewWriter(buf)
374 for _, wt := range writeTests {
375 testCreate(t, w, &wt)
377 if err := w.Close(); err != nil {
378 t.Fatal(err)
381 // read it back
382 src, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
383 if err != nil {
384 t.Fatal(err)
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 {
395 t.Fatal(err)
398 if err := dst.Close(); err != nil {
399 t.Fatal(err)
402 // read the new one back
403 r, err := NewReader(bytes.NewReader(buf2.Bytes()), int64(buf2.Len()))
404 if err != nil {
405 t.Fatal(err)
407 for i, wt := range writeTests {
408 testReadFile(t, r.File[i], &wt)
412 func TestWriterCreateRaw(t *testing.T) {
413 files := []struct {
414 name string
415 content []byte
416 method uint16
417 flags uint16
418 crc32 uint32
419 uncompressedSize uint64
420 compressedSize uint64
423 name: "small store w desc",
424 content: []byte("gophers"),
425 method: Store,
426 flags: 0x8,
429 name: "small deflate wo desc",
430 content: bytes.Repeat([]byte("abcdefg"), 2048),
431 method: Deflate,
435 // write a zip file
436 archive := new(bytes.Buffer)
437 w := NewWriter(archive)
439 for i := range files {
440 f := &files[i]
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 {
448 var buf bytes.Buffer
449 w, err := flate.NewWriter(&buf, flate.BestSpeed)
450 if err != nil {
451 t.Fatalf("flate.NewWriter err = %v", err)
453 _, err = w.Write(f.content)
454 if err != nil {
455 t.Fatalf("flate Write err = %v", err)
457 err = w.Close()
458 if err != nil {
459 t.Fatalf("flate Writer.Close err = %v", err)
461 compressedContent = buf.Bytes()
462 f.compressedSize = uint64(len(compressedContent))
465 h := &FileHeader{
466 Name: f.name,
467 Method: f.method,
468 Flags: f.flags,
469 CRC32: f.crc32,
470 CompressedSize64: f.compressedSize,
471 UncompressedSize64: f.uncompressedSize,
473 w, err := w.CreateRaw(h)
474 if err != nil {
475 t.Fatal(err)
477 if compressedContent != nil {
478 _, err = w.Write(compressedContent)
479 } else {
480 _, err = w.Write(f.content)
482 if err != nil {
483 t.Fatalf("%s Write got %v; want nil", f.name, err)
487 if err := w.Close(); err != nil {
488 t.Fatal(err)
491 // read it back
492 r, err := NewReader(bytes.NewReader(archive.Bytes()), int64(archive.Len()))
493 if err != nil {
494 t.Fatal(err)
496 for i, want := range files {
497 got := r.File[i]
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)
517 r, err := got.Open()
518 if err != nil {
519 t.Errorf("%s: Open err = %v", got.Name, err)
520 continue
523 buf, err := io.ReadAll(r)
524 if err != nil {
525 t.Errorf("%s: ReadAll err = %v", got.Name, err)
526 continue
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{
537 Name: wt.Name,
538 Method: wt.Method,
540 if wt.Mode != 0 {
541 header.SetMode(wt.Mode)
543 f, err := w.CreateHeader(header)
544 if err != nil {
545 t.Fatal(err)
547 _, err = f.Write(wt.Data)
548 if err != nil {
549 t.Fatal(err)
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)
558 rc, err := f.Open()
559 if err != nil {
560 t.Fatalf("opening %s: %v", f.Name, err)
562 b, err := io.ReadAll(rc)
563 if err != nil {
564 t.Fatalf("reading %s: %v", f.Name, err)
566 err = rc.Close()
567 if err != nil {
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) {
579 buf.Reset()
580 zw := NewWriter(buf)
581 for j := 0; j < 3; j++ {
582 w, _ := zw.CreateHeader(&FileHeader{
583 Name: "foo",
584 Method: Deflate,
586 w.Write(bigBuf)
588 zw.Close()
591 b.ReportAllocs()
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{})
596 b.ResetTimer()
598 b.RunParallel(func(pb *testing.PB) {
599 var buf bytes.Buffer
600 for pb.Next() {
601 runOnce(&buf)