Source file src/compress/zlib/writer_test.go

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

View as plain text