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