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