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