tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/image/internal/compress/flate/writer_test.go (about)

     1  // Copyright 2012 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 flate
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"math/rand"
    12  	"runtime"
    13  	"testing"
    14  )
    15  
    16  func BenchmarkEncode(b *testing.B) {
    17  	doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
    18  		b.StopTimer()
    19  		b.SetBytes(int64(n))
    20  
    21  		buf1 := make([]byte, n)
    22  		for i := 0; i < n; i += len(buf0) {
    23  			if len(buf0) > n-i {
    24  				buf0 = buf0[:n-i]
    25  			}
    26  			copy(buf1[i:], buf0)
    27  		}
    28  		buf0 = nil
    29  		w, err := NewWriter(io.Discard, level)
    30  		if err != nil {
    31  			b.Fatal(err)
    32  		}
    33  		runtime.GC()
    34  		b.StartTimer()
    35  		for i := 0; i < b.N; i++ {
    36  			w.Reset(io.Discard)
    37  			w.Write(buf1)
    38  			w.Close()
    39  		}
    40  	})
    41  }
    42  
    43  // errorWriter is a writer that fails after N writes.
    44  type errorWriter struct {
    45  	N int
    46  }
    47  
    48  func (e *errorWriter) Write(b []byte) (int, error) {
    49  	if e.N <= 0 {
    50  		return 0, io.ErrClosedPipe
    51  	}
    52  	e.N--
    53  	return len(b), nil
    54  }
    55  
    56  // Test if errors from the underlying writer is passed upwards.
    57  func TestWriteError(t *testing.T) {
    58  	t.Parallel()
    59  	buf := new(bytes.Buffer)
    60  	n := 65536
    61  	if !testing.Short() {
    62  		n *= 4
    63  	}
    64  	for i := 0; i < n; i++ {
    65  		fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
    66  	}
    67  	in := buf.Bytes()
    68  	// We create our own buffer to control number of writes.
    69  	copyBuffer := make([]byte, 128)
    70  	for l := 0; l < 10; l++ {
    71  		for fail := 1; fail <= 256; fail *= 2 {
    72  			// Fail after 'fail' writes
    73  			ew := &errorWriter{N: fail}
    74  			w, err := NewWriter(ew, l)
    75  			if err != nil {
    76  				t.Fatalf("NewWriter: level %d: %v", l, err)
    77  			}
    78  			n, err := io.CopyBuffer(w, struct{ io.Reader }{bytes.NewBuffer(in)}, copyBuffer)
    79  			if err == nil {
    80  				t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
    81  			}
    82  			n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5})
    83  			if n2 != 0 {
    84  				t.Fatal("Level", l, "Expected 0 length write, got", n)
    85  			}
    86  			if err == nil {
    87  				t.Fatal("Level", l, "Expected an error")
    88  			}
    89  			err = w.Flush()
    90  			if err == nil {
    91  				t.Fatal("Level", l, "Expected an error on flush")
    92  			}
    93  			err = w.Close()
    94  			if err == nil {
    95  				t.Fatal("Level", l, "Expected an error on close")
    96  			}
    97  
    98  			w.Reset(io.Discard)
    99  			n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6})
   100  			if err != nil {
   101  				t.Fatal("Level", l, "Got unexpected error after reset:", err)
   102  			}
   103  			if n2 == 0 {
   104  				t.Fatal("Level", l, "Got 0 length write, expected > 0")
   105  			}
   106  			if testing.Short() {
   107  				return
   108  			}
   109  		}
   110  	}
   111  }
   112  
   113  // Test if two runs produce identical results
   114  // even when writing different sizes to the Writer.
   115  func TestDeterministic(t *testing.T) {
   116  	t.Parallel()
   117  	for i := 0; i <= 9; i++ {
   118  		t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
   119  	}
   120  	t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) })
   121  }
   122  
   123  func testDeterministic(i int, t *testing.T) {
   124  	t.Parallel()
   125  	// Test so much we cross a good number of block boundaries.
   126  	var length = maxStoreBlockSize*30 + 500
   127  	if testing.Short() {
   128  		length /= 10
   129  	}
   130  
   131  	// Create a random, but compressible stream.
   132  	rng := rand.New(rand.NewSource(1))
   133  	t1 := make([]byte, length)
   134  	for i := range t1 {
   135  		t1[i] = byte(rng.Int63() & 7)
   136  	}
   137  
   138  	// Do our first encode.
   139  	var b1 bytes.Buffer
   140  	br := bytes.NewBuffer(t1)
   141  	w, err := NewWriter(&b1, i)
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	// Use a very small prime sized buffer.
   146  	cbuf := make([]byte, 787)
   147  	_, err = io.CopyBuffer(w, struct{ io.Reader }{br}, cbuf)
   148  	if err != nil {
   149  		t.Fatal(err)
   150  	}
   151  	w.Close()
   152  
   153  	// We choose a different buffer size,
   154  	// bigger than a maximum block, and also a prime.
   155  	var b2 bytes.Buffer
   156  	cbuf = make([]byte, 81761)
   157  	br2 := bytes.NewBuffer(t1)
   158  	w2, err := NewWriter(&b2, i)
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	_, err = io.CopyBuffer(w2, struct{ io.Reader }{br2}, cbuf)
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  	w2.Close()
   167  
   168  	b1b := b1.Bytes()
   169  	b2b := b2.Bytes()
   170  
   171  	if !bytes.Equal(b1b, b2b) {
   172  		t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
   173  	}
   174  }
   175  
   176  // TestDeflateFast_Reset will test that encoding is consistent
   177  // across a warparound of the table offset.
   178  // See https://github.com/golang/go/issues/34121
   179  func TestDeflateFast_Reset(t *testing.T) {
   180  	buf := new(bytes.Buffer)
   181  	n := 65536
   182  
   183  	for i := 0; i < n; i++ {
   184  		fmt.Fprintf(buf, "asdfasdfasdfasdf%d%dfghfgujyut%dyutyu\n", i, i, i)
   185  	}
   186  	// This is specific to level 1.
   187  	const level = 1
   188  	in := buf.Bytes()
   189  	offset := 1
   190  	if testing.Short() {
   191  		offset = 256
   192  	}
   193  
   194  	// We do an encode with a clean buffer to compare.
   195  	var want bytes.Buffer
   196  	w, err := NewWriter(&want, level)
   197  	if err != nil {
   198  		t.Fatalf("NewWriter: level %d: %v", level, err)
   199  	}
   200  
   201  	// Output written 3 times.
   202  	w.Write(in)
   203  	w.Write(in)
   204  	w.Write(in)
   205  	w.Close()
   206  
   207  	for ; offset <= 256; offset *= 2 {
   208  		w, err := NewWriter(io.Discard, level)
   209  		if err != nil {
   210  			t.Fatalf("NewWriter: level %d: %v", level, err)
   211  		}
   212  
   213  		// Reset until we are right before the wraparound.
   214  		// Each reset adds maxMatchOffset to the offset.
   215  		for i := 0; i < (bufferReset-len(in)-offset-maxMatchOffset)/maxMatchOffset; i++ {
   216  			// skip ahead to where we are close to wrap around...
   217  			w.d.reset(nil)
   218  		}
   219  		var got bytes.Buffer
   220  		w.Reset(&got)
   221  
   222  		// Write 3 times, close.
   223  		for i := 0; i < 3; i++ {
   224  			_, err = w.Write(in)
   225  			if err != nil {
   226  				t.Fatal(err)
   227  			}
   228  		}
   229  		err = w.Close()
   230  		if err != nil {
   231  			t.Fatal(err)
   232  		}
   233  		if !bytes.Equal(got.Bytes(), want.Bytes()) {
   234  			t.Fatalf("output did not match at wraparound, len(want)  = %d, len(got) = %d", want.Len(), got.Len())
   235  		}
   236  	}
   237  }