github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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  	"strings"
    14  	"testing"
    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  }
    25  
    26  var writeTests = []WriteTest{
    27  	{
    28  		Name:   "foo",
    29  		Data:   []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
    30  		Method: Store,
    31  		Mode:   0666,
    32  	},
    33  	{
    34  		Name:   "bar",
    35  		Data:   nil, // large data set in the test
    36  		Method: Deflate,
    37  		Mode:   0644,
    38  	},
    39  	{
    40  		Name:   "setuid",
    41  		Data:   []byte("setuid file"),
    42  		Method: Deflate,
    43  		Mode:   0755 | os.ModeSetuid,
    44  	},
    45  	{
    46  		Name:   "setgid",
    47  		Data:   []byte("setgid file"),
    48  		Method: Deflate,
    49  		Mode:   0755 | os.ModeSetgid,
    50  	},
    51  	{
    52  		Name:   "symlink",
    53  		Data:   []byte("../link/target"),
    54  		Method: Deflate,
    55  		Mode:   0755 | os.ModeSymlink,
    56  	},
    57  }
    58  
    59  func TestWriter(t *testing.T) {
    60  	largeData := make([]byte, 1<<17)
    61  	for i := range largeData {
    62  		largeData[i] = byte(rand.Int())
    63  	}
    64  	writeTests[1].Data = largeData
    65  	defer func() {
    66  		writeTests[1].Data = nil
    67  	}()
    68  
    69  	// write a zip file
    70  	buf := new(bytes.Buffer)
    71  	w := NewWriter(buf)
    72  
    73  	for _, wt := range writeTests {
    74  		testCreate(t, w, &wt)
    75  	}
    76  
    77  	if err := w.Close(); err != nil {
    78  		t.Fatal(err)
    79  	}
    80  
    81  	// read it back
    82  	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	for i, wt := range writeTests {
    87  		testReadFile(t, r.File[i], &wt)
    88  	}
    89  }
    90  
    91  // TestWriterComment is test for EOCD comment read/write.
    92  func TestWriterComment(t *testing.T) {
    93  	var tests = []struct {
    94  		comment string
    95  		ok      bool
    96  	}{
    97  		{"hi, hello", true},
    98  		{"hi, こんにちわ", true},
    99  		{strings.Repeat("a", uint16max), true},
   100  		{strings.Repeat("a", uint16max+1), false},
   101  	}
   102  
   103  	for _, test := range tests {
   104  		// write a zip file
   105  		buf := new(bytes.Buffer)
   106  		w := NewWriter(buf)
   107  		w.Comment = test.comment
   108  
   109  		if err := w.Close(); test.ok == (err != nil) {
   110  			t.Fatal(err)
   111  		}
   112  
   113  		if w.closed != test.ok {
   114  			t.Fatalf("Writer.closed: got %v, want %v", w.closed, test.ok)
   115  		}
   116  
   117  		// skip read test in failure cases
   118  		if !test.ok {
   119  			continue
   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  		if r.Comment != test.comment {
   128  			t.Fatalf("Reader.Comment: got %v, want %v", r.Comment, test.comment)
   129  		}
   130  	}
   131  }
   132  
   133  func TestWriterUTF8(t *testing.T) {
   134  	var utf8Tests = []struct {
   135  		name    string
   136  		comment string
   137  		expect  uint16
   138  	}{
   139  		{
   140  			name:    "hi, hello",
   141  			comment: "in the world",
   142  			expect:  0x8,
   143  		},
   144  		{
   145  			name:    "hi, こんにちわ",
   146  			comment: "in the world",
   147  			expect:  0x808,
   148  		},
   149  		{
   150  			name:    "hi, hello",
   151  			comment: "in the 世界",
   152  			expect:  0x808,
   153  		},
   154  		{
   155  			name:    "hi, こんにちわ",
   156  			comment: "in the 世界",
   157  			expect:  0x808,
   158  		},
   159  	}
   160  
   161  	// write a zip file
   162  	buf := new(bytes.Buffer)
   163  	w := NewWriter(buf)
   164  
   165  	for _, test := range utf8Tests {
   166  		h := &FileHeader{
   167  			Name:    test.name,
   168  			Comment: test.comment,
   169  			Method:  Deflate,
   170  		}
   171  		w, err := w.CreateHeader(h)
   172  		if err != nil {
   173  			t.Fatal(err)
   174  		}
   175  		w.Write([]byte{})
   176  	}
   177  
   178  	if err := w.Close(); err != nil {
   179  		t.Fatal(err)
   180  	}
   181  
   182  	// read it back
   183  	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	for i, test := range utf8Tests {
   188  		got := r.File[i].Flags
   189  		t.Logf("name %v, comment %v", test.name, test.comment)
   190  		if got != test.expect {
   191  			t.Fatalf("Flags: got %v, want %v", got, test.expect)
   192  		}
   193  	}
   194  }
   195  
   196  func TestWriterOffset(t *testing.T) {
   197  	largeData := make([]byte, 1<<17)
   198  	for i := range largeData {
   199  		largeData[i] = byte(rand.Int())
   200  	}
   201  	writeTests[1].Data = largeData
   202  	defer func() {
   203  		writeTests[1].Data = nil
   204  	}()
   205  
   206  	// write a zip file
   207  	buf := new(bytes.Buffer)
   208  	existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
   209  	n, _ := buf.Write(existingData)
   210  	w := NewWriter(buf)
   211  	w.SetOffset(int64(n))
   212  
   213  	for _, wt := range writeTests {
   214  		testCreate(t, w, &wt)
   215  	}
   216  
   217  	if err := w.Close(); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  
   221  	// read it back
   222  	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  	for i, wt := range writeTests {
   227  		testReadFile(t, r.File[i], &wt)
   228  	}
   229  }
   230  
   231  func TestWriterFlush(t *testing.T) {
   232  	var buf bytes.Buffer
   233  	w := NewWriter(struct{ io.Writer }{&buf})
   234  	_, err := w.Create("foo")
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	if buf.Len() > 0 {
   239  		t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
   240  	}
   241  	if err := w.Flush(); err != nil {
   242  		t.Fatal(err)
   243  	}
   244  	if buf.Len() == 0 {
   245  		t.Fatal("No bytes written after Flush")
   246  	}
   247  }
   248  
   249  func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
   250  	header := &FileHeader{
   251  		Name:   wt.Name,
   252  		Method: wt.Method,
   253  	}
   254  	if wt.Mode != 0 {
   255  		header.SetMode(wt.Mode)
   256  	}
   257  	f, err := w.CreateHeader(header)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  	_, err = f.Write(wt.Data)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  }
   266  
   267  func testReadFile(t *testing.T, f *File, wt *WriteTest) {
   268  	if f.Name != wt.Name {
   269  		t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
   270  	}
   271  	testFileMode(t, wt.Name, f, wt.Mode)
   272  	rc, err := f.Open()
   273  	if err != nil {
   274  		t.Fatal("opening:", err)
   275  	}
   276  	b, err := ioutil.ReadAll(rc)
   277  	if err != nil {
   278  		t.Fatal("reading:", err)
   279  	}
   280  	err = rc.Close()
   281  	if err != nil {
   282  		t.Fatal("closing:", err)
   283  	}
   284  	if !bytes.Equal(b, wt.Data) {
   285  		t.Errorf("File contents %q, want %q", b, wt.Data)
   286  	}
   287  }
   288  
   289  func BenchmarkCompressedZipGarbage(b *testing.B) {
   290  	bigBuf := bytes.Repeat([]byte("a"), 1<<20)
   291  
   292  	runOnce := func(buf *bytes.Buffer) {
   293  		buf.Reset()
   294  		zw := NewWriter(buf)
   295  		for j := 0; j < 3; j++ {
   296  			w, _ := zw.CreateHeader(&FileHeader{
   297  				Name:   "foo",
   298  				Method: Deflate,
   299  			})
   300  			w.Write(bigBuf)
   301  		}
   302  		zw.Close()
   303  	}
   304  
   305  	b.ReportAllocs()
   306  	// Run once and then reset the timer.
   307  	// This effectively discards the very large initial flate setup cost,
   308  	// as well as the initialization of bigBuf.
   309  	runOnce(&bytes.Buffer{})
   310  	b.ResetTimer()
   311  
   312  	b.RunParallel(func(pb *testing.PB) {
   313  		var buf bytes.Buffer
   314  		for pb.Next() {
   315  			runOnce(&buf)
   316  		}
   317  	})
   318  }