github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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 if err := w.SetComment(test.comment); err != nil { 110 if test.ok { 111 t.Fatalf("SetComment: unexpected error %v", err) 112 } 113 continue 114 } else { 115 if !test.ok { 116 t.Fatalf("SetComment: unexpected success, want error") 117 } 118 } 119 120 if err := w.Close(); test.ok == (err != nil) { 121 t.Fatal(err) 122 } 123 124 if w.closed != test.ok { 125 t.Fatalf("Writer.closed: got %v, want %v", w.closed, test.ok) 126 } 127 128 // skip read test in failure cases 129 if !test.ok { 130 continue 131 } 132 133 // read it back 134 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) 135 if err != nil { 136 t.Fatal(err) 137 } 138 if r.Comment != test.comment { 139 t.Fatalf("Reader.Comment: got %v, want %v", r.Comment, test.comment) 140 } 141 } 142 } 143 144 func TestWriterUTF8(t *testing.T) { 145 var utf8Tests = []struct { 146 name string 147 comment string 148 nonUTF8 bool 149 flags uint16 150 }{ 151 { 152 name: "hi, hello", 153 comment: "in the world", 154 flags: 0x8, 155 }, 156 { 157 name: "hi, こんにちわ", 158 comment: "in the world", 159 flags: 0x808, 160 }, 161 { 162 name: "hi, こんにちわ", 163 comment: "in the world", 164 nonUTF8: true, 165 flags: 0x8, 166 }, 167 { 168 name: "hi, hello", 169 comment: "in the 世界", 170 flags: 0x808, 171 }, 172 { 173 name: "hi, こんにちわ", 174 comment: "in the 世界", 175 flags: 0x808, 176 }, 177 { 178 name: "the replacement rune is �", 179 comment: "the replacement rune is �", 180 flags: 0x808, 181 }, 182 { 183 // Name is Japanese encoded in Shift JIS. 184 name: "\x93\xfa\x96{\x8c\xea.txt", 185 comment: "in the 世界", 186 flags: 0x008, // UTF-8 must not be set 187 }, 188 } 189 190 // write a zip file 191 buf := new(bytes.Buffer) 192 w := NewWriter(buf) 193 194 for _, test := range utf8Tests { 195 h := &FileHeader{ 196 Name: test.name, 197 Comment: test.comment, 198 NonUTF8: test.nonUTF8, 199 Method: Deflate, 200 } 201 w, err := w.CreateHeader(h) 202 if err != nil { 203 t.Fatal(err) 204 } 205 w.Write([]byte{}) 206 } 207 208 if err := w.Close(); err != nil { 209 t.Fatal(err) 210 } 211 212 // read it back 213 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) 214 if err != nil { 215 t.Fatal(err) 216 } 217 for i, test := range utf8Tests { 218 flags := r.File[i].Flags 219 if flags != test.flags { 220 t.Errorf("CreateHeader(name=%q comment=%q nonUTF8=%v): flags=%#x, want %#x", test.name, test.comment, test.nonUTF8, flags, test.flags) 221 } 222 } 223 } 224 225 func TestWriterTime(t *testing.T) { 226 var buf bytes.Buffer 227 h := &FileHeader{ 228 Name: "test.txt", 229 Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), 230 } 231 w := NewWriter(&buf) 232 if _, err := w.CreateHeader(h); err != nil { 233 t.Fatalf("unexpected CreateHeader error: %v", err) 234 } 235 if err := w.Close(); err != nil { 236 t.Fatalf("unexpected Close error: %v", err) 237 } 238 239 want, err := ioutil.ReadFile("testdata/time-go.zip") 240 if err != nil { 241 t.Fatalf("unexpected ReadFile error: %v", err) 242 } 243 if got := buf.Bytes(); !bytes.Equal(got, want) { 244 fmt.Printf("%x\n%x\n", got, want) 245 t.Error("contents of time-go.zip differ") 246 } 247 } 248 249 func TestWriterOffset(t *testing.T) { 250 largeData := make([]byte, 1<<17) 251 if _, err := rand.Read(largeData); err != nil { 252 t.Fatal("rand.Read failed:", err) 253 } 254 writeTests[1].Data = largeData 255 defer func() { 256 writeTests[1].Data = nil 257 }() 258 259 // write a zip file 260 buf := new(bytes.Buffer) 261 existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3} 262 n, _ := buf.Write(existingData) 263 w := NewWriter(buf) 264 w.SetOffset(int64(n)) 265 266 for _, wt := range writeTests { 267 testCreate(t, w, &wt) 268 } 269 270 if err := w.Close(); err != nil { 271 t.Fatal(err) 272 } 273 274 // read it back 275 r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) 276 if err != nil { 277 t.Fatal(err) 278 } 279 for i, wt := range writeTests { 280 testReadFile(t, r.File[i], &wt) 281 } 282 } 283 284 func TestWriterFlush(t *testing.T) { 285 var buf bytes.Buffer 286 w := NewWriter(struct{ io.Writer }{&buf}) 287 _, err := w.Create("foo") 288 if err != nil { 289 t.Fatal(err) 290 } 291 if buf.Len() > 0 { 292 t.Fatalf("Unexpected %d bytes already in buffer", buf.Len()) 293 } 294 if err := w.Flush(); err != nil { 295 t.Fatal(err) 296 } 297 if buf.Len() == 0 { 298 t.Fatal("No bytes written after Flush") 299 } 300 } 301 302 func testCreate(t *testing.T, w *Writer, wt *WriteTest) { 303 header := &FileHeader{ 304 Name: wt.Name, 305 Method: wt.Method, 306 } 307 if wt.Mode != 0 { 308 header.SetMode(wt.Mode) 309 } 310 f, err := w.CreateHeader(header) 311 if err != nil { 312 t.Fatal(err) 313 } 314 _, err = f.Write(wt.Data) 315 if err != nil { 316 t.Fatal(err) 317 } 318 } 319 320 func testReadFile(t *testing.T, f *File, wt *WriteTest) { 321 if f.Name != wt.Name { 322 t.Fatalf("File name: got %q, want %q", f.Name, wt.Name) 323 } 324 testFileMode(t, f, wt.Mode) 325 rc, err := f.Open() 326 if err != nil { 327 t.Fatal("opening:", err) 328 } 329 b, err := ioutil.ReadAll(rc) 330 if err != nil { 331 t.Fatal("reading:", err) 332 } 333 err = rc.Close() 334 if err != nil { 335 t.Fatal("closing:", err) 336 } 337 if !bytes.Equal(b, wt.Data) { 338 t.Errorf("File contents %q, want %q", b, wt.Data) 339 } 340 } 341 342 func BenchmarkCompressedZipGarbage(b *testing.B) { 343 bigBuf := bytes.Repeat([]byte("a"), 1<<20) 344 345 runOnce := func(buf *bytes.Buffer) { 346 buf.Reset() 347 zw := NewWriter(buf) 348 for j := 0; j < 3; j++ { 349 w, _ := zw.CreateHeader(&FileHeader{ 350 Name: "foo", 351 Method: Deflate, 352 }) 353 w.Write(bigBuf) 354 } 355 zw.Close() 356 } 357 358 b.ReportAllocs() 359 // Run once and then reset the timer. 360 // This effectively discards the very large initial flate setup cost, 361 // as well as the initialization of bigBuf. 362 runOnce(&bytes.Buffer{}) 363 b.ResetTimer() 364 365 b.RunParallel(func(pb *testing.PB) { 366 var buf bytes.Buffer 367 for pb.Next() { 368 runOnce(&buf) 369 } 370 }) 371 }