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