1
9
10 package xz_test
11
12 import (
13 "bytes"
14 "crypto/md5"
15 "fmt"
16 "io"
17 "io/ioutil"
18 "os"
19 "path/filepath"
20 "testing"
21 "testing/iotest"
22
23 "github.com/xi2/xz"
24 )
25
26 type testFile struct {
27 file string
28 md5sum string
29 err error
30 }
31
32
33
34
35 var badFiles = []testFile{
36 {
37 file: "bad-0-backward_size.xz",
38 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
39 err: xz.ErrData,
40 },
41 {
42 file: "bad-0cat-alone.xz",
43 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
44 err: xz.ErrFormat,
45 },
46 {
47 file: "bad-0cat-header_magic.xz",
48 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
49 err: xz.ErrFormat,
50 },
51 {
52 file: "bad-0catpad-empty.xz",
53 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
54 err: xz.ErrData,
55 },
56 {
57 file: "bad-0-empty-truncated.xz",
58 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
59 err: xz.ErrBuf,
60 },
61 {
62 file: "bad-0-footer_magic.xz",
63 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
64 err: xz.ErrData,
65 },
66 {
67 file: "bad-0-header_magic.xz",
68 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
69 err: xz.ErrFormat,
70 },
71 {
72 file: "bad-0-nonempty_index.xz",
73 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
74 err: xz.ErrData,
75 },
76 {
77 file: "bad-0pad-empty.xz",
78 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
79 err: xz.ErrData,
80 },
81 {
82 file: "bad-1-block_header-1.xz",
83 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
84 err: xz.ErrData,
85 },
86 {
87 file: "bad-1-block_header-2.xz",
88 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
89 err: xz.ErrData,
90 },
91 {
92 file: "bad-1-block_header-3.xz",
93 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
94 err: xz.ErrData,
95 },
96 {
97 file: "bad-1-block_header-4.xz",
98 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
99 err: xz.ErrData,
100 },
101 {
102 file: "bad-1-block_header-5.xz",
103 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
104 err: xz.ErrData,
105 },
106 {
107 file: "bad-1-block_header-6.xz",
108 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
109 err: xz.ErrData,
110 },
111 {
112 file: "bad-1-check-crc32.xz",
113 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
114 err: xz.ErrData,
115 },
116 {
117 file: "bad-1-check-crc64.xz",
118 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
119 err: xz.ErrData,
120 },
121 {
122 file: "bad-1-check-sha256.xz",
123 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
124 err: xz.ErrData,
125 },
126 {
127 file: "bad-1-lzma2-1.xz",
128 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
129 err: xz.ErrData,
130 },
131 {
132 file: "bad-1-lzma2-2.xz",
133 md5sum: "211dbb3d39f3c244585397f6d3c09be3",
134 err: xz.ErrData,
135 },
136 {
137 file: "bad-1-lzma2-3.xz",
138 md5sum: "211dbb3d39f3c244585397f6d3c09be3",
139 err: xz.ErrData,
140 },
141 {
142 file: "bad-1-lzma2-4.xz",
143 md5sum: "6492b8d167aee3ca222d07a49d24015a",
144 err: xz.ErrData,
145 },
146 {
147 file: "bad-1-lzma2-5.xz",
148 md5sum: "6492b8d167aee3ca222d07a49d24015a",
149 err: xz.ErrData,
150 },
151 {
152 file: "bad-1-lzma2-6.xz",
153 md5sum: "09f7e02f1290be211da707a266f153b3",
154 err: xz.ErrData,
155 },
156 {
157 file: "bad-1-lzma2-7.xz",
158 md5sum: "c214a5e586cb3f0673cc6138f7de25ab",
159 err: xz.ErrData,
160 },
161 {
162 file: "bad-1-lzma2-8.xz",
163 md5sum: "211dbb3d39f3c244585397f6d3c09be3",
164 err: xz.ErrData,
165 },
166 {
167 file: "bad-1-stream_flags-1.xz",
168 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
169 err: xz.ErrData,
170 },
171 {
172 file: "bad-1-stream_flags-2.xz",
173 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
174 err: xz.ErrData,
175 },
176 {
177 file: "bad-1-stream_flags-3.xz",
178 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
179 err: xz.ErrData,
180 },
181 {
182 file: "bad-1-vli-1.xz",
183 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
184 err: xz.ErrData,
185 },
186 {
187 file: "bad-1-vli-2.xz",
188 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
189 err: xz.ErrData,
190 },
191 {
192 file: "bad-2-compressed_data_padding.xz",
193 md5sum: "09f7e02f1290be211da707a266f153b3",
194 err: xz.ErrData,
195 },
196 {
197 file: "bad-2-index-1.xz",
198 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
199 err: xz.ErrData,
200 },
201 {
202 file: "bad-2-index-2.xz",
203 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
204 err: xz.ErrData,
205 },
206 {
207 file: "bad-2-index-3.xz",
208 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
209 err: xz.ErrData,
210 },
211 {
212 file: "bad-2-index-4.xz",
213 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
214 err: xz.ErrData,
215 },
216 {
217 file: "bad-2-index-5.xz",
218 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
219 err: xz.ErrData,
220 },
221 }
222
223 var goodFiles = []testFile{
224 {
225 file: "good-0cat-empty.xz",
226 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
227 err: nil,
228 },
229 {
230 file: "good-0catpad-empty.xz",
231 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
232 err: nil,
233 },
234 {
235 file: "good-0-empty.xz",
236 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
237 err: nil,
238 },
239 {
240 file: "good-0pad-empty.xz",
241 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
242 err: nil,
243 },
244 {
245 file: "good-1-3delta-lzma2.xz",
246 md5sum: "c214a5e586cb3f0673cc6138f7de25ab",
247 err: nil,
248 },
249 {
250 file: "good-1-block_header-1.xz",
251 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
252 err: nil,
253 },
254 {
255 file: "good-1-block_header-2.xz",
256 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
257 err: nil,
258 },
259 {
260 file: "good-1-block_header-3.xz",
261 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
262 err: nil,
263 },
264 {
265 file: "good-1-check-crc32.xz",
266 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
267 err: nil,
268 },
269 {
270 file: "good-1-check-crc64.xz",
271 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
272 err: nil,
273 },
274 {
275 file: "good-1-check-none.xz",
276 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
277 err: nil,
278 },
279 {
280 file: "good-1-check-sha256.xz",
281 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
282 err: nil,
283 },
284 {
285 file: "good-1-delta-lzma2.tiff.xz",
286 md5sum: "c692be6d1987989af5eeafc329085ad2",
287 err: nil,
288 },
289 {
290 file: "good-1-lzma2-1.xz",
291 md5sum: "c214a5e586cb3f0673cc6138f7de25ab",
292 err: nil,
293 },
294 {
295 file: "good-1-lzma2-2.xz",
296 md5sum: "c214a5e586cb3f0673cc6138f7de25ab",
297 err: nil,
298 },
299 {
300 file: "good-1-lzma2-3.xz",
301 md5sum: "c214a5e586cb3f0673cc6138f7de25ab",
302 err: nil,
303 },
304 {
305 file: "good-1-lzma2-4.xz",
306 md5sum: "c214a5e586cb3f0673cc6138f7de25ab",
307 err: nil,
308 },
309 {
310 file: "good-1-lzma2-5.xz",
311 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
312 err: nil,
313 },
314 {
315 file: "good-1-sparc-lzma2.xz",
316 md5sum: "835f2865f1d7c7ad2c7de0d5fd07faef",
317 err: nil,
318 },
319 {
320 file: "good-1-x86-lzma2.xz",
321 md5sum: "ce212d6a1cfe73d8395a2b42f94c2419",
322 err: nil,
323 },
324 {
325 file: "good-2-lzma2.xz",
326 md5sum: "fbf68a8e34b2ded53bba54e68794b4fe",
327 err: nil,
328 },
329 }
330
331 var unsupportedFiles = []testFile{
332 {
333 file: "unsupported-block_header.xz",
334 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
335 err: xz.ErrOptions,
336 },
337 {
338 file: "unsupported-check.xz",
339 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
340 err: xz.ErrUnsupportedCheck,
341 },
342 {
343 file: "unsupported-filter_flags-1.xz",
344 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
345 err: xz.ErrOptions,
346 },
347 {
348 file: "unsupported-filter_flags-2.xz",
349 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
350 err: xz.ErrOptions,
351 },
352 {
353 file: "unsupported-filter_flags-3.xz",
354 md5sum: "d41d8cd98f00b204e9800998ecf8427e",
355 err: xz.ErrOptions,
356 },
357 }
358
359 var otherFiles = []testFile{
360 {
361 file: "good-1-x86-lzma2-offset-2048.xz",
362 md5sum: "ce212d6a1cfe73d8395a2b42f94c2419",
363 err: nil,
364 },
365 {
366 file: "good-2-lzma2-corrupt.xz",
367 md5sum: "d9c5223e7e6e305e6c1c6ed73789df88",
368 err: xz.ErrData,
369 },
370 {
371 file: "words.xz",
372 md5sum: "00e28a90cb4a975fdaa3b375d3124a66",
373 err: nil,
374 },
375 {
376 file: "random-1mb.xz",
377 md5sum: "3f04b090e5d26a1cbeea53c21ebcad03",
378 err: nil,
379 },
380 {
381 file: "zeros-100mb.xz",
382 md5sum: "0f86d7c5a6180cf9584c1d21144d85b0",
383 err: nil,
384 },
385 }
386
387 func openTestFile(file string) (*os.File, error) {
388 f, err := os.Open(filepath.Join("testdata", "xz-utils", file))
389 if err == nil {
390 return f, nil
391 }
392 if err != nil && !os.IsNotExist(err) {
393 return nil, err
394 }
395 f, err = os.Open(filepath.Join("testdata", "other", file))
396 if err == nil {
397 return f, nil
398 }
399 return nil, err
400 }
401
402 func readTestFile(file string) ([]byte, error) {
403 b, err := ioutil.ReadFile(filepath.Join("testdata", "xz-utils", file))
404 if err == nil {
405 return b, nil
406 }
407 if err != nil && !os.IsNotExist(err) {
408 return nil, err
409 }
410 b, err = ioutil.ReadFile(filepath.Join("testdata", "other", file))
411 if err == nil {
412 return b, nil
413 }
414 return nil, err
415 }
416
417
418
419 func testFileData(file string) (md5sum string, err error) {
420 fileList := badFiles
421 fileList = append(fileList, goodFiles...)
422 fileList = append(fileList, unsupportedFiles...)
423 fileList = append(fileList, otherFiles...)
424 for _, f := range fileList {
425 if f.file == file {
426 return f.md5sum, f.err
427 }
428 }
429 return "", nil
430 }
431
432
433
434 func testFileList(t *testing.T, files []testFile, reuseReader bool) {
435 var r *xz.Reader
436 var err error
437 if reuseReader {
438 r, err = xz.NewReader(nil, 0)
439 }
440 for _, f := range files {
441 func() {
442 var fr *os.File
443 fr, err = openTestFile(f.file)
444 if err != nil {
445 t.Fatal(err)
446 }
447 defer fr.Close()
448 hash := md5.New()
449 switch reuseReader {
450 case true:
451 err = r.Reset(fr)
452 case false:
453 r, err = xz.NewReader(fr, 0)
454 }
455 if err == nil {
456 _, err = io.Copy(hash, r)
457 }
458 if err != f.err {
459 t.Fatalf("%s: wanted error: %v, got: %v\n", f.file, f.err, err)
460 }
461 md5sum := fmt.Sprintf("%x", hash.Sum(nil))
462 if f.md5sum != md5sum {
463 t.Fatalf(
464 "%s: wanted md5: %v, got: %v\n", f.file, f.md5sum, md5sum)
465 }
466 }()
467 }
468 }
469
470
471
472
473 func testFileListByteReads(t *testing.T, files []testFile) {
474 for _, f := range files {
475 func() {
476 fr, err := openTestFile(f.file)
477 if err != nil {
478 t.Fatal(err)
479 }
480 defer fr.Close()
481 hash := md5.New()
482 obr := iotest.OneByteReader(fr)
483 r, err := xz.NewReader(obr, 0)
484 if err == nil {
485 b := make([]byte, 1)
486 var n int
487 for err == nil {
488 n, err = r.Read(b)
489 if n == 1 {
490 _, _ = hash.Write(b)
491 }
492 }
493 if err == io.EOF {
494 err = nil
495 }
496 }
497 if err != f.err {
498 t.Fatalf("%s: wanted error: %v, got: %v\n", f.file, f.err, err)
499 }
500 md5sum := fmt.Sprintf("%x", hash.Sum(nil))
501 if f.md5sum != md5sum {
502 t.Fatalf(
503 "%s: wanted md5: %v, got: %v\n", f.file, f.md5sum, md5sum)
504 }
505 }()
506 }
507 }
508
509 func TestBadFiles(t *testing.T) {
510 testFileList(t, badFiles, false)
511 }
512
513 func TestGoodFiles(t *testing.T) {
514 testFileList(t, goodFiles, false)
515 }
516
517 func TestUnsupportedFiles(t *testing.T) {
518 testFileList(t, unsupportedFiles, false)
519 }
520
521 func TestOtherFiles(t *testing.T) {
522 testFileList(t, otherFiles, false)
523 }
524
525 func TestMemlimit(t *testing.T) {
526 data, err := readTestFile("words.xz")
527 if err != nil {
528 t.Fatal(err)
529 }
530 r, err := xz.NewReader(bytes.NewReader(data), 1<<25)
531 if err == nil {
532 b := new(bytes.Buffer)
533 _, err = io.Copy(b, r)
534 }
535 if err != xz.ErrMemlimit {
536 t.Fatalf("wanted error: %v, got: %v\n", xz.ErrMemlimit, err)
537 }
538 }
539
540
541
542 func TestPrematureError(t *testing.T) {
543 data, err := readTestFile("good-2-lzma2-corrupt.xz")
544 if err != nil {
545 t.Fatal(err)
546 }
547 r, err := xz.NewReader(bytes.NewReader(data), 0)
548 if err != nil {
549 t.Fatal(err)
550 }
551 b := make([]byte, 2)
552 n, err := r.Read(b)
553 if n != 2 || err != nil {
554 t.Fatalf("Read returned: (%d,%v), expected: (2,%v)\n", n, err, nil)
555 }
556 n, err = r.Read(b)
557 if n != 2 || err != nil {
558 t.Fatalf("Read returned: (%d,%v), expected: (2,%v)\n", n, err, nil)
559 }
560 n, err = r.Read(b)
561 if n != 2 || err != xz.ErrData {
562 t.Fatalf("Read returned: (%d,%v), expected: (2,%v)\n",
563 n, err, xz.ErrData)
564 }
565 }
566
567 func TestMultipleBadReads(t *testing.T) {
568 data, err := readTestFile("good-2-lzma2-corrupt.xz")
569 if err != nil {
570 t.Fatal(err)
571 }
572 r, err := xz.NewReader(bytes.NewReader(data), 0)
573 if err != nil {
574 t.Fatal(err)
575 }
576 b := make([]byte, 100)
577 n, err := r.Read(b)
578 if n != 6 || err != xz.ErrData {
579 t.Fatalf("Read returned: (%d,%v), expected: (6,%v)\n",
580 n, err, xz.ErrData)
581 }
582 n, err = r.Read(b)
583 if n != 0 || err != xz.ErrData {
584 t.Fatalf("Read returned: (%d,%v), expected: (0,%v)\n",
585 n, err, xz.ErrData)
586 }
587 n, err = r.Read(b)
588 if n != 0 || err != xz.ErrData {
589 t.Fatalf("Read returned: (%d,%v), expected: (0,%v)\n",
590 n, err, xz.ErrData)
591 }
592 }
593
594
595
596
597 func TestByteReads(t *testing.T) {
598 fileList := badFiles
599 fileList = append(fileList, goodFiles...)
600 fileList = append(fileList, unsupportedFiles...)
601 fileList = append(fileList, otherFiles...)
602 fileListSmall := []testFile{}
603 for _, f := range fileList {
604 if f.file != "zeros-100mb.xz" {
605 fileListSmall = append(fileListSmall, f)
606 }
607 }
608 testFileListByteReads(t, fileListSmall)
609 }
610
611 func TestMultistream(t *testing.T) {
612 files := []string{
613 "good-1-x86-lzma2-offset-2048.xz",
614 "random-1mb.xz",
615 "words.xz",
616 "good-1-x86-lzma2-offset-2048.xz",
617 "random-1mb.xz",
618 "words.xz",
619 }
620 var readers []io.Reader
621 for _, f := range files {
622 data, err := readTestFile(f)
623 if err != nil {
624 t.Fatal(err)
625 }
626 readers = append(readers, bytes.NewReader(data))
627 }
628 mr := io.MultiReader(readers...)
629 r, err := xz.NewReader(mr, 0)
630 if err != nil {
631 t.Fatal(err)
632 }
633 for i, f := range files {
634 r.Multistream(false)
635 hash := md5.New()
636 _, err = io.Copy(hash, r)
637 if err != nil {
638 t.Fatalf("%s: wanted copy error: %v, got: %v\n", f, nil, err)
639 }
640 md5sum := fmt.Sprintf("%x", hash.Sum(nil))
641 wantedMD5, _ := testFileData(f)
642 if wantedMD5 != md5sum {
643 t.Fatalf(
644 "%s: wanted md5: %v, got: %v\n", f, wantedMD5, md5sum)
645 }
646 err = r.Reset(nil)
647 var wantedErr error
648 switch {
649 case i < len(files)-1:
650 wantedErr = nil
651 case i == len(files)-1:
652 wantedErr = io.EOF
653 }
654 if wantedErr != err {
655 t.Fatalf("%s: wanted reset error: %v, got: %v\n",
656 f, wantedErr, err)
657 }
658 }
659 }
660
661
662
663 func TestReuseReader(t *testing.T) {
664 fileList := badFiles
665 fileList = append(fileList, goodFiles...)
666 fileList = append(fileList, unsupportedFiles...)
667 fileList = append(fileList, otherFiles...)
668 testFileList(t, fileList, true)
669 }
670
671
672
673
674
675 func TestReuseReaderPartialReads(t *testing.T) {
676 data, err := readTestFile("words.xz")
677 if err != nil {
678 t.Fatal(err)
679 }
680 z, err := xz.NewReader(nil, 0)
681 if err != nil {
682 t.Fatal(err)
683 }
684 for i := 0; i <= 80000; i += 10000 {
685 err = z.Reset(bytes.NewReader(data))
686 if err != nil {
687 t.Fatal(err)
688 }
689 b := make([]byte, i)
690 _, err = io.ReadFull(z, b)
691 if err != nil {
692 t.Fatalf("io.ReadFull: wanted error: %v, got: %v\n", nil, err)
693 }
694 err = z.Reset(bytes.NewReader(data))
695 if err != nil {
696 t.Fatal(err)
697 }
698 hash := md5.New()
699 _, err = io.Copy(hash, z)
700 if err != nil {
701 t.Fatalf("io.Copy: wanted error: %v, got: %v\n", nil, err)
702 }
703 md5sum := fmt.Sprintf("%x", hash.Sum(nil))
704 wantedMD5, _ := testFileData("words.xz")
705 if wantedMD5 != md5sum {
706 t.Fatalf(
707 "hash.Sum: wanted md5: %v, got: %v\n", wantedMD5, md5sum)
708 }
709 }
710 }
711
View as plain text