Home | History | Annotate | Download | only in zlib
      1 // Copyright 2009 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 zlib
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"internal/testenv"
     11 	"io"
     12 	"io/ioutil"
     13 	"os"
     14 	"testing"
     15 )
     16 
     17 var filenames = []string{
     18 	"../testdata/gettysburg.txt",
     19 	"../testdata/e.txt",
     20 	"../testdata/pi.txt",
     21 }
     22 
     23 var data = []string{
     24 	"test a reasonable sized string that can be compressed",
     25 }
     26 
     27 // Tests that compressing and then decompressing the given file at the given compression level and dictionary
     28 // yields equivalent bytes to the original file.
     29 func testFileLevelDict(t *testing.T, fn string, level int, d string) {
     30 	// Read the file, as golden output.
     31 	golden, err := os.Open(fn)
     32 	if err != nil {
     33 		t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
     34 		return
     35 	}
     36 	defer golden.Close()
     37 	b0, err0 := ioutil.ReadAll(golden)
     38 	if err0 != nil {
     39 		t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0)
     40 		return
     41 	}
     42 	testLevelDict(t, fn, b0, level, d)
     43 }
     44 
     45 func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) {
     46 	// Make dictionary, if given.
     47 	var dict []byte
     48 	if d != "" {
     49 		dict = []byte(d)
     50 	}
     51 
     52 	// Push data through a pipe that compresses at the write end, and decompresses at the read end.
     53 	piper, pipew := io.Pipe()
     54 	defer piper.Close()
     55 	go func() {
     56 		defer pipew.Close()
     57 		zlibw, err := NewWriterLevelDict(pipew, level, dict)
     58 		if err != nil {
     59 			t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
     60 			return
     61 		}
     62 		defer zlibw.Close()
     63 		_, err = zlibw.Write(b0)
     64 		if err != nil {
     65 			t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
     66 			return
     67 		}
     68 	}()
     69 	zlibr, err := NewReaderDict(piper, dict)
     70 	if err != nil {
     71 		t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
     72 		return
     73 	}
     74 	defer zlibr.Close()
     75 
     76 	// Compare the decompressed data.
     77 	b1, err1 := ioutil.ReadAll(zlibr)
     78 	if err1 != nil {
     79 		t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err1)
     80 		return
     81 	}
     82 	if len(b0) != len(b1) {
     83 		t.Errorf("%s (level=%d, dict=%q): length mismatch %d versus %d", fn, level, d, len(b0), len(b1))
     84 		return
     85 	}
     86 	for i := 0; i < len(b0); i++ {
     87 		if b0[i] != b1[i] {
     88 			t.Errorf("%s (level=%d, dict=%q): mismatch at %d, 0x%02x versus 0x%02x\n", fn, level, d, i, b0[i], b1[i])
     89 			return
     90 		}
     91 	}
     92 }
     93 
     94 func testFileLevelDictReset(t *testing.T, fn string, level int, dict []byte) {
     95 	var b0 []byte
     96 	var err error
     97 	if fn != "" {
     98 		b0, err = ioutil.ReadFile(fn)
     99 		if err != nil {
    100 			t.Errorf("%s (level=%d): %v", fn, level, err)
    101 			return
    102 		}
    103 	}
    104 
    105 	// Compress once.
    106 	buf := new(bytes.Buffer)
    107 	var zlibw *Writer
    108 	if dict == nil {
    109 		zlibw, err = NewWriterLevel(buf, level)
    110 	} else {
    111 		zlibw, err = NewWriterLevelDict(buf, level, dict)
    112 	}
    113 	if err == nil {
    114 		_, err = zlibw.Write(b0)
    115 	}
    116 	if err == nil {
    117 		err = zlibw.Close()
    118 	}
    119 	if err != nil {
    120 		t.Errorf("%s (level=%d): %v", fn, level, err)
    121 		return
    122 	}
    123 	out := buf.String()
    124 
    125 	// Reset and compress again.
    126 	buf2 := new(bytes.Buffer)
    127 	zlibw.Reset(buf2)
    128 	_, err = zlibw.Write(b0)
    129 	if err == nil {
    130 		err = zlibw.Close()
    131 	}
    132 	if err != nil {
    133 		t.Errorf("%s (level=%d): %v", fn, level, err)
    134 		return
    135 	}
    136 	out2 := buf2.String()
    137 
    138 	if out2 != out {
    139 		t.Errorf("%s (level=%d): different output after reset (got %d bytes, expected %d",
    140 			fn, level, len(out2), len(out))
    141 	}
    142 }
    143 
    144 func TestWriter(t *testing.T) {
    145 	for i, s := range data {
    146 		b := []byte(s)
    147 		tag := fmt.Sprintf("#%d", i)
    148 		testLevelDict(t, tag, b, DefaultCompression, "")
    149 		testLevelDict(t, tag, b, NoCompression, "")
    150 		testLevelDict(t, tag, b, HuffmanOnly, "")
    151 		for level := BestSpeed; level <= BestCompression; level++ {
    152 			testLevelDict(t, tag, b, level, "")
    153 		}
    154 	}
    155 }
    156 
    157 func TestWriterBig(t *testing.T) {
    158 	for i, fn := range filenames {
    159 		testFileLevelDict(t, fn, DefaultCompression, "")
    160 		testFileLevelDict(t, fn, NoCompression, "")
    161 		testFileLevelDict(t, fn, HuffmanOnly, "")
    162 		for level := BestSpeed; level <= BestCompression; level++ {
    163 			testFileLevelDict(t, fn, level, "")
    164 			if level >= 1 && testing.Short() && testenv.Builder() == "" {
    165 				break
    166 			}
    167 		}
    168 		if i == 0 && testing.Short() && testenv.Builder() == "" {
    169 			break
    170 		}
    171 	}
    172 }
    173 
    174 func TestWriterDict(t *testing.T) {
    175 	const dictionary = "0123456789."
    176 	for i, fn := range filenames {
    177 		testFileLevelDict(t, fn, DefaultCompression, dictionary)
    178 		testFileLevelDict(t, fn, NoCompression, dictionary)
    179 		testFileLevelDict(t, fn, HuffmanOnly, dictionary)
    180 		for level := BestSpeed; level <= BestCompression; level++ {
    181 			testFileLevelDict(t, fn, level, dictionary)
    182 			if level >= 1 && testing.Short() && testenv.Builder() == "" {
    183 				break
    184 			}
    185 		}
    186 		if i == 0 && testing.Short() && testenv.Builder() == "" {
    187 			break
    188 		}
    189 	}
    190 }
    191 
    192 func TestWriterReset(t *testing.T) {
    193 	const dictionary = "0123456789."
    194 	for _, fn := range filenames {
    195 		testFileLevelDictReset(t, fn, NoCompression, nil)
    196 		testFileLevelDictReset(t, fn, DefaultCompression, nil)
    197 		testFileLevelDictReset(t, fn, HuffmanOnly, nil)
    198 		testFileLevelDictReset(t, fn, NoCompression, []byte(dictionary))
    199 		testFileLevelDictReset(t, fn, DefaultCompression, []byte(dictionary))
    200 		testFileLevelDictReset(t, fn, HuffmanOnly, []byte(dictionary))
    201 		if testing.Short() {
    202 			break
    203 		}
    204 		for level := BestSpeed; level <= BestCompression; level++ {
    205 			testFileLevelDictReset(t, fn, level, nil)
    206 		}
    207 	}
    208 }
    209 
    210 func TestWriterDictIsUsed(t *testing.T) {
    211 	var input = []byte("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
    212 	var buf bytes.Buffer
    213 	compressor, err := NewWriterLevelDict(&buf, BestCompression, input)
    214 	if err != nil {
    215 		t.Errorf("error in NewWriterLevelDict: %s", err)
    216 		return
    217 	}
    218 	compressor.Write(input)
    219 	compressor.Close()
    220 	const expectedMaxSize = 25
    221 	output := buf.Bytes()
    222 	if len(output) > expectedMaxSize {
    223 		t.Errorf("result too large (got %d, want <= %d bytes). Is the dictionary being used?", len(output), expectedMaxSize)
    224 	}
    225 }
    226