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

     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  // This test tests some internals of the flate package.
     6  // The tests in package compress/gzip serve as the
     7  // end-to-end test of the decompressor.
     8  
     9  package flate
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/hex"
    14  	"io"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  // The following test should not panic.
    20  func TestIssue5915(t *testing.T) {
    21  	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6,
    22  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    23  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8}
    24  	var h huffmanDecoder
    25  	if h.init(bits) {
    26  		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
    27  	}
    28  }
    29  
    30  // The following test should not panic.
    31  func TestIssue5962(t *testing.T) {
    32  	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0,
    33  		5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11}
    34  	var h huffmanDecoder
    35  	if h.init(bits) {
    36  		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
    37  	}
    38  }
    39  
    40  // The following test should not panic.
    41  func TestIssue6255(t *testing.T) {
    42  	bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11}
    43  	bits2 := []int{11, 13}
    44  	var h huffmanDecoder
    45  	if !h.init(bits1) {
    46  		t.Fatalf("Given sequence of bits is good and should succeed.")
    47  	}
    48  	if h.init(bits2) {
    49  		t.Fatalf("Given sequence of bits is bad and should not succeed.")
    50  	}
    51  }
    52  
    53  func TestInvalidEncoding(t *testing.T) {
    54  	// Initialize Huffman decoder to recognize "0".
    55  	var h huffmanDecoder
    56  	if !h.init([]int{1}) {
    57  		t.Fatal("Failed to initialize Huffman decoder")
    58  	}
    59  
    60  	// Initialize decompressor with invalid Huffman coding.
    61  	var f decompressor
    62  	f.r = bytes.NewReader([]byte{0xff})
    63  
    64  	_, err := f.huffSym(&h)
    65  	if err == nil {
    66  		t.Fatal("Should have rejected invalid bit sequence")
    67  	}
    68  }
    69  
    70  func TestInvalidBits(t *testing.T) {
    71  	oversubscribed := []int{1, 2, 3, 4, 4, 5}
    72  	incomplete := []int{1, 2, 4, 4}
    73  	var h huffmanDecoder
    74  	if h.init(oversubscribed) {
    75  		t.Fatal("Should reject oversubscribed bit-length set")
    76  	}
    77  	if h.init(incomplete) {
    78  		t.Fatal("Should reject incomplete bit-length set")
    79  	}
    80  }
    81  
    82  func TestStreams(t *testing.T) {
    83  	// To verify any of these hexstrings as valid or invalid flate streams
    84  	// according to the C zlib library, you can use the Python wrapper library:
    85  	// >>> hex_string = "010100feff11"
    86  	// >>> import zlib
    87  	// >>> zlib.decompress(hex_string.decode("hex"), -15) # Negative means raw DEFLATE
    88  	// '\x11'
    89  
    90  	testCases := []struct {
    91  		desc   string // Description of the stream
    92  		stream string // Hexstring of the input DEFLATE stream
    93  		want   string // Expected result. Use "fail" to expect failure
    94  	}{{
    95  		"degenerate HCLenTree",
    96  		"05e0010000000000100000000000000000000000000000000000000000000000" +
    97  			"00000000000000000004",
    98  		"fail",
    99  	}, {
   100  		"complete HCLenTree, empty HLitTree, empty HDistTree",
   101  		"05e0010400000000000000000000000000000000000000000000000000000000" +
   102  			"00000000000000000010",
   103  		"fail",
   104  	}, {
   105  		"empty HCLenTree",
   106  		"05e0010000000000000000000000000000000000000000000000000000000000" +
   107  			"00000000000000000010",
   108  		"fail",
   109  	}, {
   110  		"complete HCLenTree, complete HLitTree, empty HDistTree, use missing HDist symbol",
   111  		"000100feff000de0010400000000100000000000000000000000000000000000" +
   112  			"0000000000000000000000000000002c",
   113  		"fail",
   114  	}, {
   115  		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use missing HDist symbol",
   116  		"000100feff000de0010000000000000000000000000000000000000000000000" +
   117  			"00000000000000000610000000004070",
   118  		"fail",
   119  	}, {
   120  		"complete HCLenTree, empty HLitTree, empty HDistTree",
   121  		"05e0010400000000100400000000000000000000000000000000000000000000" +
   122  			"0000000000000000000000000008",
   123  		"fail",
   124  	}, {
   125  		"complete HCLenTree, empty HLitTree, degenerate HDistTree",
   126  		"05e0010400000000100400000000000000000000000000000000000000000000" +
   127  			"0000000000000000000800000008",
   128  		"fail",
   129  	}, {
   130  		"complete HCLenTree, degenerate HLitTree, degenerate HDistTree, use missing HLit symbol",
   131  		"05e0010400000000100000000000000000000000000000000000000000000000" +
   132  			"0000000000000000001c",
   133  		"fail",
   134  	}, {
   135  		"complete HCLenTree, complete HLitTree, too large HDistTree",
   136  		"edff870500000000200400000000000000000000000000000000000000000000" +
   137  			"000000000000000000080000000000000004",
   138  		"fail",
   139  	}, {
   140  		"complete HCLenTree, complete HLitTree, empty HDistTree, excessive repeater code",
   141  		"edfd870500000000200400000000000000000000000000000000000000000000" +
   142  			"000000000000000000e8b100",
   143  		"fail",
   144  	}, {
   145  		"complete HCLenTree, complete HLitTree, empty HDistTree of normal length 30",
   146  		"05fd01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
   147  			"ffffffffffffffffff07000000fe01",
   148  		"",
   149  	}, {
   150  		"complete HCLenTree, complete HLitTree, empty HDistTree of excessive length 31",
   151  		"05fe01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
   152  			"ffffffffffffffffff07000000fc03",
   153  		"fail",
   154  	}, {
   155  		"complete HCLenTree, over-subscribed HLitTree, empty HDistTree",
   156  		"05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" +
   157  			"ffffffffffffffffff07f00f",
   158  		"fail",
   159  	}, {
   160  		"complete HCLenTree, under-subscribed HLitTree, empty HDistTree",
   161  		"05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" +
   162  			"fffffffffcffffffff07f00f",
   163  		"fail",
   164  	}, {
   165  		"complete HCLenTree, complete HLitTree with single code, empty HDistTree",
   166  		"05e001240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
   167  			"ffffffffffffffffff07f00f",
   168  		"01",
   169  	}, {
   170  		"complete HCLenTree, complete HLitTree with multiple codes, empty HDistTree",
   171  		"05e301240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
   172  			"ffffffffffffffffff07807f",
   173  		"01",
   174  	}, {
   175  		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HDist symbol",
   176  		"000100feff000de0010400000000100000000000000000000000000000000000" +
   177  			"0000000000000000000000000000003c",
   178  		"00000000",
   179  	}, {
   180  		"complete HCLenTree, degenerate HLitTree, degenerate HDistTree",
   181  		"05e0010400000000100000000000000000000000000000000000000000000000" +
   182  			"0000000000000000000c",
   183  		"",
   184  	}, {
   185  		"complete HCLenTree, degenerate HLitTree, empty HDistTree",
   186  		"05e0010400000000100000000000000000000000000000000000000000000000" +
   187  			"00000000000000000004",
   188  		"",
   189  	}, {
   190  		"complete HCLenTree, complete HLitTree, empty HDistTree, spanning repeater code",
   191  		"edfd870500000000200400000000000000000000000000000000000000000000" +
   192  			"000000000000000000e8b000",
   193  		"",
   194  	}, {
   195  		"complete HCLenTree with length codes, complete HLitTree, empty HDistTree",
   196  		"ede0010400000000100000000000000000000000000000000000000000000000" +
   197  			"0000000000000000000400004000",
   198  		"",
   199  	}, {
   200  		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit symbol 284 with count 31",
   201  		"000100feff00ede0010400000000100000000000000000000000000000000000" +
   202  			"000000000000000000000000000000040000407f00",
   203  		"0000000000000000000000000000000000000000000000000000000000000000" +
   204  			"0000000000000000000000000000000000000000000000000000000000000000" +
   205  			"0000000000000000000000000000000000000000000000000000000000000000" +
   206  			"0000000000000000000000000000000000000000000000000000000000000000" +
   207  			"0000000000000000000000000000000000000000000000000000000000000000" +
   208  			"0000000000000000000000000000000000000000000000000000000000000000" +
   209  			"0000000000000000000000000000000000000000000000000000000000000000" +
   210  			"0000000000000000000000000000000000000000000000000000000000000000" +
   211  			"000000",
   212  	}, {
   213  		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit and HDist symbols",
   214  		"0cc2010d00000082b0ac4aff0eb07d27060000ffff",
   215  		"616263616263",
   216  	}, {
   217  		"fixed block, use reserved symbol 287",
   218  		"33180700",
   219  		"fail",
   220  	}, {
   221  		"raw block",
   222  		"010100feff11",
   223  		"11",
   224  	}, {
   225  		"issue 10426 - over-subscribed HCLenTree causes a hang",
   226  		"344c4a4e494d4b070000ff2e2eff2e2e2e2e2eff",
   227  		"fail",
   228  	}, {
   229  		"issue 11030 - empty HDistTree unexpectedly leads to error",
   230  		"05c0070600000080400fff37a0ca",
   231  		"",
   232  	}, {
   233  		"issue 11033 - empty HDistTree unexpectedly leads to error",
   234  		"050fb109c020cca5d017dcbca044881ee1034ec149c8980bbc413c2ab35be9dc" +
   235  			"b1473449922449922411202306ee97b0383a521b4ffdcf3217f9f7d3adb701",
   236  		"3130303634342068652e706870005d05355f7ed957ff084a90925d19e3ebc6d0" +
   237  			"c6d7",
   238  	}}
   239  
   240  	for i, tc := range testCases {
   241  		data, err := hex.DecodeString(tc.stream)
   242  		if err != nil {
   243  			t.Fatal(err)
   244  		}
   245  		data, err = io.ReadAll(NewReader(bytes.NewReader(data)))
   246  		if tc.want == "fail" {
   247  			if err == nil {
   248  				t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc)
   249  			}
   250  		} else {
   251  			if err != nil {
   252  				t.Errorf("#%d (%s): %v", i, tc.desc, err)
   253  				continue
   254  			}
   255  			if got := hex.EncodeToString(data); got != tc.want {
   256  				t.Errorf("#%d (%s):\ngot  %q\nwant %q", i, tc.desc, got, tc.want)
   257  			}
   258  
   259  		}
   260  	}
   261  }
   262  
   263  func TestTruncatedStreams(t *testing.T) {
   264  	const data = "\x00\f\x00\xf3\xffhello, world\x01\x00\x00\xff\xff"
   265  
   266  	for i := 0; i < len(data)-1; i++ {
   267  		r := NewReader(strings.NewReader(data[:i]))
   268  		_, err := io.Copy(io.Discard, r)
   269  		if err != io.ErrUnexpectedEOF {
   270  			t.Errorf("io.Copy(%d) on truncated stream: got %v, want %v", i, err, io.ErrUnexpectedEOF)
   271  		}
   272  	}
   273  }
   274  
   275  // Verify that flate.Reader.Read returns (n, io.EOF) instead
   276  // of (n, nil) + (0, io.EOF) when possible.
   277  //
   278  // This helps net/http.Transport reuse HTTP/1 connections more
   279  // aggressively.
   280  //
   281  // See https://github.com/google/go-github/pull/317 for background.
   282  func TestReaderEarlyEOF(t *testing.T) {
   283  	t.Parallel()
   284  	testSizes := []int{
   285  		1, 2, 3, 4, 5, 6, 7, 8,
   286  		100, 1000, 10000, 100000,
   287  		128, 1024, 16384, 131072,
   288  
   289  		// Testing multiples of windowSize triggers the case
   290  		// where Read will fail to return an early io.EOF.
   291  		windowSize * 1, windowSize * 2, windowSize * 3,
   292  	}
   293  
   294  	var maxSize int
   295  	for _, n := range testSizes {
   296  		if maxSize < n {
   297  			maxSize = n
   298  		}
   299  	}
   300  
   301  	readBuf := make([]byte, 40)
   302  	data := make([]byte, maxSize)
   303  	for i := range data {
   304  		data[i] = byte(i)
   305  	}
   306  
   307  	for _, sz := range testSizes {
   308  		if testing.Short() && sz > windowSize {
   309  			continue
   310  		}
   311  		for _, flush := range []bool{true, false} {
   312  			earlyEOF := true // Do we expect early io.EOF?
   313  
   314  			var buf bytes.Buffer
   315  			w, _ := NewWriter(&buf, 5)
   316  			w.Write(data[:sz])
   317  			if flush {
   318  				// If a Flush occurs after all the actual data, the flushing
   319  				// semantics dictate that we will observe a (0, io.EOF) since
   320  				// Read must return data before it knows that the stream ended.
   321  				w.Flush()
   322  				earlyEOF = false
   323  			}
   324  			w.Close()
   325  
   326  			r := NewReader(&buf)
   327  			for {
   328  				n, err := r.Read(readBuf)
   329  				if err == io.EOF {
   330  					// If the availWrite == windowSize, then that means that the
   331  					// previous Read returned because the write buffer was full
   332  					// and it just so happened that the stream had no more data.
   333  					// This situation is rare, but unavoidable.
   334  					if r.(*decompressor).dict.availWrite() == windowSize {
   335  						earlyEOF = false
   336  					}
   337  
   338  					if n == 0 && earlyEOF {
   339  						t.Errorf("On size:%d flush:%v, Read() = (0, io.EOF), want (n, io.EOF)", sz, flush)
   340  					}
   341  					if n != 0 && !earlyEOF {
   342  						t.Errorf("On size:%d flush:%v, Read() = (%d, io.EOF), want (0, io.EOF)", sz, flush, n)
   343  					}
   344  					break
   345  				}
   346  				if err != nil {
   347  					t.Fatal(err)
   348  				}
   349  			}
   350  		}
   351  	}
   352  }