github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/src/archive/zip/writer_test.go (about)

     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.
     4  
     5  package zip
     6  
     7  import (
     8  	"bytes"
     9  	"io"
    10  	"io/ioutil"
    11  	"math/rand"
    12  	"os"
    13  	"testing"
    14  	"time"
    15  )
    16  
    17  // TODO(adg): a more sophisticated test suite
    18  
    19  type WriteTest struct {
    20  	Name   string
    21  	Data   []byte
    22  	Method uint16
    23  	Mode   os.FileMode
    24  	Mtime  string
    25  }
    26  
    27  var writeTests = []WriteTest{
    28  	{
    29  		Name:   "foo",
    30  		Data:   []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
    31  		Method: Store,
    32  		Mode:   0666,
    33  		Mtime:  "02-01-08 00:01:02",
    34  	},
    35  	{
    36  		Name:   "bar",
    37  		Data:   nil, // large data set in the test
    38  		Method: Deflate,
    39  		Mode:   0644,
    40  		Mtime:  "03-02-08 01:02:03",
    41  	},
    42  	{
    43  		Name:   "setuid",
    44  		Data:   []byte("setuid file"),
    45  		Method: Deflate,
    46  		Mode:   0755 | os.ModeSetuid,
    47  		Mtime:  "04-03-08 02:03:04",
    48  	},
    49  	{
    50  		Name:   "setgid",
    51  		Data:   []byte("setgid file"),
    52  		Method: Deflate,
    53  		Mode:   0755 | os.ModeSetgid,
    54  		Mtime:  "05-04-08 03:04:04",
    55  	},
    56  	{
    57  		Name:   "symlink",
    58  		Data:   []byte("../link/target"),
    59  		Method: Deflate,
    60  		Mode:   0755 | os.ModeSymlink,
    61  		Mtime:  "03-02-08 11:22:33",
    62  	},
    63  }
    64  
    65  func TestWriter(t *testing.T) {
    66  	largeData := make([]byte, 1<<17)
    67  	for i := range largeData {
    68  		largeData[i] = byte(rand.Int())
    69  	}
    70  	writeTests[1].Data = largeData
    71  	defer func() {
    72  		writeTests[1].Data = nil
    73  	}()
    74  
    75  	// write a zip file
    76  	buf := new(bytes.Buffer)
    77  	w := NewWriter(buf)
    78  
    79  	for _, wt := range writeTests {
    80  		testCreate(t, w, &wt)
    81  	}
    82  
    83  	if err := w.Close(); err != nil {
    84  		t.Fatal(err)
    85  	}
    86  
    87  	// read it back
    88  	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
    89  	if err != nil {
    90  		t.Fatal(err)
    91  	}
    92  	for i, wt := range writeTests {
    93  		testReadFile(t, r.File[i], &wt)
    94  	}
    95  }
    96  
    97  func TestWriterOffset(t *testing.T) {
    98  	largeData := make([]byte, 1<<17)
    99  	for i := range largeData {
   100  		largeData[i] = byte(rand.Int())
   101  	}
   102  	writeTests[1].Data = largeData
   103  	defer func() {
   104  		writeTests[1].Data = nil
   105  	}()
   106  
   107  	// write a zip file
   108  	buf := new(bytes.Buffer)
   109  	existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
   110  	n, _ := buf.Write(existingData)
   111  	w := NewWriter(buf)
   112  	w.SetOffset(int64(n))
   113  
   114  	for _, wt := range writeTests {
   115  		testCreate(t, w, &wt)
   116  	}
   117  
   118  	if err := w.Close(); err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	// read it back
   123  	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  	for i, wt := range writeTests {
   128  		testReadFile(t, r.File[i], &wt)
   129  	}
   130  }
   131  
   132  func TestWriterFlush(t *testing.T) {
   133  	var buf bytes.Buffer
   134  	w := NewWriter(struct{ io.Writer }{&buf})
   135  	_, err := w.Create("foo")
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  	if buf.Len() > 0 {
   140  		t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
   141  	}
   142  	if err := w.Flush(); err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	if buf.Len() == 0 {
   146  		t.Fatal("No bytes written after Flush")
   147  	}
   148  }
   149  
   150  func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
   151  	header := &FileHeader{
   152  		Name:   wt.Name,
   153  		Method: wt.Method,
   154  	}
   155  	if wt.Mode != 0 {
   156  		header.SetMode(wt.Mode)
   157  	}
   158  	mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
   159  	if err != nil {
   160  		t.Fatal("time.Parse:", err)
   161  	}
   162  	header.SetModTime(mtime)
   163  	f, err := w.CreateHeader(header)
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	_, err = f.Write(wt.Data)
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  }
   172  
   173  func testReadFile(t *testing.T, f *File, wt *WriteTest) {
   174  	if f.Name != wt.Name {
   175  		t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
   176  	}
   177  	testFileMode(t, wt.Name, f, wt.Mode)
   178  	rc, err := f.Open()
   179  	if err != nil {
   180  		t.Fatal("opening:", err)
   181  	}
   182  	b, err := ioutil.ReadAll(rc)
   183  	if err != nil {
   184  		t.Fatal("reading:", err)
   185  	}
   186  	err = rc.Close()
   187  	if err != nil {
   188  		t.Fatal("closing:", err)
   189  	}
   190  	if !bytes.Equal(b, wt.Data) {
   191  		t.Errorf("File contents %q, want %q", b, wt.Data)
   192  	}
   193  
   194  	mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
   195  	if err != nil {
   196  		t.Fatal("time.Parse:", err)
   197  	}
   198  
   199  	diff := mtime.Sub(f.ModTime())
   200  	if diff < 0 {
   201  		diff = -diff
   202  	}
   203  
   204  	// allow several time span
   205  	if diff > 5*time.Second {
   206  		t.Errorf("File modtime %v, want %v", mtime, f.ModTime())
   207  	}
   208  }
   209  
   210  func BenchmarkCompressedZipGarbage(b *testing.B) {
   211  	b.ReportAllocs()
   212  	var buf bytes.Buffer
   213  	bigBuf := bytes.Repeat([]byte("a"), 1<<20)
   214  	for i := 0; i <= b.N; i++ {
   215  		buf.Reset()
   216  		zw := NewWriter(&buf)
   217  		for j := 0; j < 3; j++ {
   218  			w, _ := zw.CreateHeader(&FileHeader{
   219  				Name:   "foo",
   220  				Method: Deflate,
   221  			})
   222  			w.Write(bigBuf)
   223  		}
   224  		zw.Close()
   225  		if i == 0 {
   226  			// Reset the timer after the first time through.
   227  			// This effectively discards the very large initial flate setup cost,
   228  			// as well as the initialization of bigBuf.
   229  			b.ResetTimer()
   230  		}
   231  	}
   232  }