...
Run Format

Source file src/archive/zip/writer_test.go

Documentation: archive/zip

  // 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 TestWriterUTF8(t *testing.T) {
  	var utf8Tests = []struct {
  		name    string
  		comment string
  		expect  uint16
  	}{
  		{
  			name:    "hi, hello",
  			comment: "in the world",
  			expect:  0x8,
  		},
  		{
  			name:    "hi, こんにちわ",
  			comment: "in the world",
  			expect:  0x808,
  		},
  		{
  			name:    "hi, hello",
  			comment: "in the 世界",
  			expect:  0x808,
  		},
  		{
  			name:    "hi, こんにちわ",
  			comment: "in the 世界",
  			expect:  0x808,
  		},
  	}
  
  	// write a zip file
  	buf := new(bytes.Buffer)
  	w := NewWriter(buf)
  
  	for _, test := range utf8Tests {
  		h := &FileHeader{
  			Name:    test.name,
  			Comment: test.comment,
  			Method:  Deflate,
  		}
  		w, err := w.CreateHeader(h)
  		if err != nil {
  			t.Fatal(err)
  		}
  		w.Write([]byte{})
  	}
  
  	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, test := range utf8Tests {
  		got := r.File[i].Flags
  		t.Logf("name %v, comment %v", test.name, test.comment)
  		if got != test.expect {
  			t.Fatalf("Flags: got %v, want %v", got, test.expect)
  		}
  	}
  }
  
  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) {
  	bigBuf := bytes.Repeat([]byte("a"), 1<<20)
  
  	runOnce := func(buf *bytes.Buffer) {
  		buf.Reset()
  		zw := NewWriter(buf)
  		for j := 0; j < 3; j++ {
  			w, _ := zw.CreateHeader(&FileHeader{
  				Name:   "foo",
  				Method: Deflate,
  			})
  			w.Write(bigBuf)
  		}
  		zw.Close()
  	}
  
  	b.ReportAllocs()
  	// Run once and then reset the timer.
  	// This effectively discards the very large initial flate setup cost,
  	// as well as the initialization of bigBuf.
  	runOnce(&bytes.Buffer{})
  	b.ResetTimer()
  
  	b.RunParallel(func(pb *testing.PB) {
  		var buf bytes.Buffer
  		for pb.Next() {
  			runOnce(&buf)
  		}
  	})
  }
  

View as plain text