go/src/archive/zip/writer_test.go

206 lines
3.9 KiB
Go
Raw Normal View History

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package zip
import (
"bytes"
"io"
"io/ioutil"
"math/rand"
"os"
"testing"
)
// TODO(adg): a more sophisticated test suite
type WriteTest struct {
Name string
Data []byte
Method uint16
Mode os.FileMode
}
var writeTests = []WriteTest{
{
Name: "foo",
Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
Method: Store,
Mode: 0666,
},
{
Name: "bar",
Data: nil, // large data set in the test
Method: Deflate,
Mode: 0644,
},
{
Name: "setuid",
Data: []byte("setuid file"),
Method: Deflate,
Mode: 0755 | os.ModeSetuid,
},
{
Name: "setgid",
Data: []byte("setgid file"),
Method: Deflate,
Mode: 0755 | os.ModeSetgid,
},
{
Name: "symlink",
Data: []byte("../link/target"),
Method: Deflate,
Mode: 0755 | os.ModeSymlink,
},
}
func TestWriter(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {
largeData[i] = byte(rand.Int())
}
writeTests[1].Data = largeData
defer func() {
writeTests[1].Data = nil
}()
// write a zip file
buf := new(bytes.Buffer)
w := NewWriter(buf)
for _, wt := range writeTests {
testCreate(t, w, &wt)
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
// read it back
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
if err != nil {
t.Fatal(err)
}
for i, wt := range writeTests {
testReadFile(t, r.File[i], &wt)
}
}
func TestWriterOffset(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {
largeData[i] = byte(rand.Int())
}
writeTests[1].Data = largeData
defer func() {
writeTests[1].Data = nil
}()
// write a zip file
buf := new(bytes.Buffer)
existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
n, _ := buf.Write(existingData)
w := NewWriter(buf)
w.SetOffset(int64(n))
for _, wt := range writeTests {
testCreate(t, w, &wt)
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
// read it back
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
if err != nil {
t.Fatal(err)
}
for i, wt := range writeTests {
testReadFile(t, r.File[i], &wt)
}
}
func TestWriterFlush(t *testing.T) {
var buf bytes.Buffer
w := NewWriter(struct{ io.Writer }{&buf})
_, err := w.Create("foo")
if err != nil {
t.Fatal(err)
}
if buf.Len() > 0 {
t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
if buf.Len() == 0 {
t.Fatal("No bytes written after Flush")
}
}
func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
header := &FileHeader{
Name: wt.Name,
Method: wt.Method,
}
if wt.Mode != 0 {
header.SetMode(wt.Mode)
}
f, err := w.CreateHeader(header)
if err != nil {
t.Fatal(err)
}
_, err = f.Write(wt.Data)
if err != nil {
t.Fatal(err)
}
}
func testReadFile(t *testing.T, f *File, wt *WriteTest) {
if f.Name != wt.Name {
t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
}
testFileMode(t, wt.Name, f, wt.Mode)
rc, err := f.Open()
if err != nil {
t.Fatal("opening:", err)
}
b, err := ioutil.ReadAll(rc)
if err != nil {
t.Fatal("reading:", err)
}
err = rc.Close()
if err != nil {
t.Fatal("closing:", err)
}
if !bytes.Equal(b, wt.Data) {
t.Errorf("File contents %q, want %q", b, wt.Data)
}
}
func BenchmarkCompressedZipGarbage(b *testing.B) {
b.ReportAllocs()
var buf bytes.Buffer
bigBuf := bytes.Repeat([]byte("a"), 1<<20)
archive/zip: improve BenchmarkCompressedZipGarbage Before this CL: $ go test -bench=CompressedZipGarbage -count=5 -run=NONE archive/zip BenchmarkCompressedZipGarbage-8 50 20677087 ns/op 42973 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20584764 ns/op 24294 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 20859221 ns/op 42973 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20901176 ns/op 24294 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 21282409 ns/op 42973 B/op 47 allocs/op The B/op number is effectively meaningless. There is a surprisingly large one-time cost that gets divided by the number of iterations that your machine can get through in a second. This CL discards the first run, which helps. It is not a panacea. Running with -benchtime=10s will allow the sync.Pool to be emptied, which brings the problem back. However, since there are more iterations to divide the cost through, it’s not quite as bad, and running with a high benchtime is rare. This CL changes the meaning of the B/op number, which is unfortunate, since it won’t have the same order of magnitude as previous Go versions. But it wasn’t really comparable before anyway, since it didn’t have any reliable meaning at all. After this CL: $ go test -bench=CompressedZipGarbage -count=5 -run=NONE archive/zip BenchmarkCompressedZipGarbage-8 100 20881890 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 20622757 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 20628193 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20756612 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20639774 ns/op 5616 B/op 47 allocs/op Change-Id: Iedee04f39328974c7fa272a6113d423e7ffce50f Reviewed-on: https://go-review.googlesource.com/22585 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-04-28 15:01:41 -07:00
for i := 0; i <= b.N; i++ {
buf.Reset()
zw := NewWriter(&buf)
for j := 0; j < 3; j++ {
w, _ := zw.CreateHeader(&FileHeader{
Name: "foo",
Method: Deflate,
})
w.Write(bigBuf)
}
zw.Close()
archive/zip: improve BenchmarkCompressedZipGarbage Before this CL: $ go test -bench=CompressedZipGarbage -count=5 -run=NONE archive/zip BenchmarkCompressedZipGarbage-8 50 20677087 ns/op 42973 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20584764 ns/op 24294 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 20859221 ns/op 42973 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20901176 ns/op 24294 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 21282409 ns/op 42973 B/op 47 allocs/op The B/op number is effectively meaningless. There is a surprisingly large one-time cost that gets divided by the number of iterations that your machine can get through in a second. This CL discards the first run, which helps. It is not a panacea. Running with -benchtime=10s will allow the sync.Pool to be emptied, which brings the problem back. However, since there are more iterations to divide the cost through, it’s not quite as bad, and running with a high benchtime is rare. This CL changes the meaning of the B/op number, which is unfortunate, since it won’t have the same order of magnitude as previous Go versions. But it wasn’t really comparable before anyway, since it didn’t have any reliable meaning at all. After this CL: $ go test -bench=CompressedZipGarbage -count=5 -run=NONE archive/zip BenchmarkCompressedZipGarbage-8 100 20881890 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 20622757 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 50 20628193 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20756612 ns/op 5616 B/op 47 allocs/op BenchmarkCompressedZipGarbage-8 100 20639774 ns/op 5616 B/op 47 allocs/op Change-Id: Iedee04f39328974c7fa272a6113d423e7ffce50f Reviewed-on: https://go-review.googlesource.com/22585 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-04-28 15:01:41 -07:00
if i == 0 {
// Reset the timer after the first time through.
// This effectively discards the very large initial flate setup cost,
// as well as the initialization of bigBuf.
b.ResetTimer()
}
}
}