...

Source file src/compress/flate/deflate_test.go

Documentation: compress/flate

		 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 flate
		 6  
		 7  import (
		 8  	"bytes"
		 9  	"errors"
		10  	"fmt"
		11  	"internal/testenv"
		12  	"io"
		13  	"math/rand"
		14  	"os"
		15  	"reflect"
		16  	"runtime/debug"
		17  	"sync"
		18  	"testing"
		19  )
		20  
		21  type deflateTest struct {
		22  	in		[]byte
		23  	level int
		24  	out	 []byte
		25  }
		26  
		27  type deflateInflateTest struct {
		28  	in []byte
		29  }
		30  
		31  type reverseBitsTest struct {
		32  	in			 uint16
		33  	bitCount uint8
		34  	out			uint16
		35  }
		36  
		37  var deflateTests = []*deflateTest{
		38  	{[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
		39  	{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
		40  	{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
		41  	{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
		42  
		43  	{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
		44  	{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
		45  	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
		46  		[]byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
		47  	},
		48  	{[]byte{}, 2, []byte{1, 0, 0, 255, 255}},
		49  	{[]byte{0x11}, 2, []byte{18, 4, 4, 0, 0, 255, 255}},
		50  	{[]byte{0x11, 0x12}, 2, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
		51  	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 2, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
		52  	{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
		53  	{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
		54  	{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
		55  	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
		56  }
		57  
		58  var deflateInflateTests = []*deflateInflateTest{
		59  	{[]byte{}},
		60  	{[]byte{0x11}},
		61  	{[]byte{0x11, 0x12}},
		62  	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
		63  	{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
		64  	{largeDataChunk()},
		65  }
		66  
		67  var reverseBitsTests = []*reverseBitsTest{
		68  	{1, 1, 1},
		69  	{1, 2, 2},
		70  	{1, 3, 4},
		71  	{1, 4, 8},
		72  	{1, 5, 16},
		73  	{17, 5, 17},
		74  	{257, 9, 257},
		75  	{29, 5, 23},
		76  }
		77  
		78  func largeDataChunk() []byte {
		79  	result := make([]byte, 100000)
		80  	for i := range result {
		81  		result[i] = byte(i * i & 0xFF)
		82  	}
		83  	return result
		84  }
		85  
		86  func TestBulkHash4(t *testing.T) {
		87  	for _, x := range deflateTests {
		88  		y := x.out
		89  		if len(y) < minMatchLength {
		90  			continue
		91  		}
		92  		y = append(y, y...)
		93  		for j := 4; j < len(y); j++ {
		94  			y := y[:j]
		95  			dst := make([]uint32, len(y)-minMatchLength+1)
		96  			for i := range dst {
		97  				dst[i] = uint32(i + 100)
		98  			}
		99  			bulkHash4(y, dst)
	 100  			for i, got := range dst {
	 101  				want := hash4(y[i:])
	 102  				if got != want && got == uint32(i)+100 {
	 103  					t.Errorf("Len:%d Index:%d, want 0x%08x but not modified", len(y), i, want)
	 104  				} else if got != want {
	 105  					t.Errorf("Len:%d Index:%d, got 0x%08x want:0x%08x", len(y), i, got, want)
	 106  				}
	 107  			}
	 108  		}
	 109  	}
	 110  }
	 111  
	 112  func TestDeflate(t *testing.T) {
	 113  	for _, h := range deflateTests {
	 114  		var buf bytes.Buffer
	 115  		w, err := NewWriter(&buf, h.level)
	 116  		if err != nil {
	 117  			t.Errorf("NewWriter: %v", err)
	 118  			continue
	 119  		}
	 120  		w.Write(h.in)
	 121  		w.Close()
	 122  		if !bytes.Equal(buf.Bytes(), h.out) {
	 123  			t.Errorf("Deflate(%d, %x) = \n%#v, want \n%#v", h.level, h.in, buf.Bytes(), h.out)
	 124  		}
	 125  	}
	 126  }
	 127  
	 128  // A sparseReader returns a stream consisting of 0s followed by 1<<16 1s.
	 129  // This tests missing hash references in a very large input.
	 130  type sparseReader struct {
	 131  	l	 int64
	 132  	cur int64
	 133  }
	 134  
	 135  func (r *sparseReader) Read(b []byte) (n int, err error) {
	 136  	if r.cur >= r.l {
	 137  		return 0, io.EOF
	 138  	}
	 139  	n = len(b)
	 140  	cur := r.cur + int64(n)
	 141  	if cur > r.l {
	 142  		n -= int(cur - r.l)
	 143  		cur = r.l
	 144  	}
	 145  	for i := range b[0:n] {
	 146  		if r.cur+int64(i) >= r.l-1<<16 {
	 147  			b[i] = 1
	 148  		} else {
	 149  			b[i] = 0
	 150  		}
	 151  	}
	 152  	r.cur = cur
	 153  	return
	 154  }
	 155  
	 156  func TestVeryLongSparseChunk(t *testing.T) {
	 157  	if testing.Short() {
	 158  		t.Skip("skipping sparse chunk during short test")
	 159  	}
	 160  	w, err := NewWriter(io.Discard, 1)
	 161  	if err != nil {
	 162  		t.Errorf("NewWriter: %v", err)
	 163  		return
	 164  	}
	 165  	if _, err = io.Copy(w, &sparseReader{l: 23e8}); err != nil {
	 166  		t.Errorf("Compress failed: %v", err)
	 167  		return
	 168  	}
	 169  }
	 170  
	 171  type syncBuffer struct {
	 172  	buf		bytes.Buffer
	 173  	mu		 sync.RWMutex
	 174  	closed bool
	 175  	ready	chan bool
	 176  }
	 177  
	 178  func newSyncBuffer() *syncBuffer {
	 179  	return &syncBuffer{ready: make(chan bool, 1)}
	 180  }
	 181  
	 182  func (b *syncBuffer) Read(p []byte) (n int, err error) {
	 183  	for {
	 184  		b.mu.RLock()
	 185  		n, err = b.buf.Read(p)
	 186  		b.mu.RUnlock()
	 187  		if n > 0 || b.closed {
	 188  			return
	 189  		}
	 190  		<-b.ready
	 191  	}
	 192  }
	 193  
	 194  func (b *syncBuffer) signal() {
	 195  	select {
	 196  	case b.ready <- true:
	 197  	default:
	 198  	}
	 199  }
	 200  
	 201  func (b *syncBuffer) Write(p []byte) (n int, err error) {
	 202  	n, err = b.buf.Write(p)
	 203  	b.signal()
	 204  	return
	 205  }
	 206  
	 207  func (b *syncBuffer) WriteMode() {
	 208  	b.mu.Lock()
	 209  }
	 210  
	 211  func (b *syncBuffer) ReadMode() {
	 212  	b.mu.Unlock()
	 213  	b.signal()
	 214  }
	 215  
	 216  func (b *syncBuffer) Close() error {
	 217  	b.closed = true
	 218  	b.signal()
	 219  	return nil
	 220  }
	 221  
	 222  func testSync(t *testing.T, level int, input []byte, name string) {
	 223  	if len(input) == 0 {
	 224  		return
	 225  	}
	 226  
	 227  	t.Logf("--testSync %d, %d, %s", level, len(input), name)
	 228  	buf := newSyncBuffer()
	 229  	buf1 := new(bytes.Buffer)
	 230  	buf.WriteMode()
	 231  	w, err := NewWriter(io.MultiWriter(buf, buf1), level)
	 232  	if err != nil {
	 233  		t.Errorf("NewWriter: %v", err)
	 234  		return
	 235  	}
	 236  	r := NewReader(buf)
	 237  
	 238  	// Write half the input and read back.
	 239  	for i := 0; i < 2; i++ {
	 240  		var lo, hi int
	 241  		if i == 0 {
	 242  			lo, hi = 0, (len(input)+1)/2
	 243  		} else {
	 244  			lo, hi = (len(input)+1)/2, len(input)
	 245  		}
	 246  		t.Logf("#%d: write %d-%d", i, lo, hi)
	 247  		if _, err := w.Write(input[lo:hi]); err != nil {
	 248  			t.Errorf("testSync: write: %v", err)
	 249  			return
	 250  		}
	 251  		if i == 0 {
	 252  			if err := w.Flush(); err != nil {
	 253  				t.Errorf("testSync: flush: %v", err)
	 254  				return
	 255  			}
	 256  		} else {
	 257  			if err := w.Close(); err != nil {
	 258  				t.Errorf("testSync: close: %v", err)
	 259  			}
	 260  		}
	 261  		buf.ReadMode()
	 262  		out := make([]byte, hi-lo+1)
	 263  		m, err := io.ReadAtLeast(r, out, hi-lo)
	 264  		t.Logf("#%d: read %d", i, m)
	 265  		if m != hi-lo || err != nil {
	 266  			t.Errorf("testSync/%d (%d, %d, %s): read %d: %d, %v (%d left)", i, level, len(input), name, hi-lo, m, err, buf.buf.Len())
	 267  			return
	 268  		}
	 269  		if !bytes.Equal(input[lo:hi], out[:hi-lo]) {
	 270  			t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo])
	 271  			return
	 272  		}
	 273  		// This test originally checked that after reading
	 274  		// the first half of the input, there was nothing left
	 275  		// in the read buffer (buf.buf.Len() != 0) but that is
	 276  		// not necessarily the case: the write Flush may emit
	 277  		// some extra framing bits that are not necessary
	 278  		// to process to obtain the first half of the uncompressed
	 279  		// data. The test ran correctly most of the time, because
	 280  		// the background goroutine had usually read even
	 281  		// those extra bits by now, but it's not a useful thing to
	 282  		// check.
	 283  		buf.WriteMode()
	 284  	}
	 285  	buf.ReadMode()
	 286  	out := make([]byte, 10)
	 287  	if n, err := r.Read(out); n > 0 || err != io.EOF {
	 288  		t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n])
	 289  	}
	 290  	if buf.buf.Len() != 0 {
	 291  		t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name)
	 292  	}
	 293  	r.Close()
	 294  
	 295  	// stream should work for ordinary reader too
	 296  	r = NewReader(buf1)
	 297  	out, err = io.ReadAll(r)
	 298  	if err != nil {
	 299  		t.Errorf("testSync: read: %s", err)
	 300  		return
	 301  	}
	 302  	r.Close()
	 303  	if !bytes.Equal(input, out) {
	 304  		t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name)
	 305  	}
	 306  }
	 307  
	 308  func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) {
	 309  	var buffer bytes.Buffer
	 310  	w, err := NewWriter(&buffer, level)
	 311  	if err != nil {
	 312  		t.Errorf("NewWriter: %v", err)
	 313  		return
	 314  	}
	 315  	w.Write(input)
	 316  	w.Close()
	 317  	if limit > 0 && buffer.Len() > limit {
	 318  		t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
	 319  		return
	 320  	}
	 321  	if limit > 0 {
	 322  		t.Logf("level: %d, size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len())
	 323  	}
	 324  	r := NewReader(&buffer)
	 325  	out, err := io.ReadAll(r)
	 326  	if err != nil {
	 327  		t.Errorf("read: %s", err)
	 328  		return
	 329  	}
	 330  	r.Close()
	 331  	if !bytes.Equal(input, out) {
	 332  		t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
	 333  		return
	 334  	}
	 335  	testSync(t, level, input, name)
	 336  }
	 337  
	 338  func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) {
	 339  	for i := 0; i < 10; i++ {
	 340  		testToFromWithLevelAndLimit(t, i, input, name, limit[i])
	 341  	}
	 342  	// Test HuffmanCompression
	 343  	testToFromWithLevelAndLimit(t, -2, input, name, limit[10])
	 344  }
	 345  
	 346  func TestDeflateInflate(t *testing.T) {
	 347  	t.Parallel()
	 348  	for i, h := range deflateInflateTests {
	 349  		if testing.Short() && len(h.in) > 10000 {
	 350  			continue
	 351  		}
	 352  		testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{})
	 353  	}
	 354  }
	 355  
	 356  func TestReverseBits(t *testing.T) {
	 357  	for _, h := range reverseBitsTests {
	 358  		if v := reverseBits(h.in, h.bitCount); v != h.out {
	 359  			t.Errorf("reverseBits(%v,%v) = %v, want %v",
	 360  				h.in, h.bitCount, v, h.out)
	 361  		}
	 362  	}
	 363  }
	 364  
	 365  type deflateInflateStringTest struct {
	 366  	filename string
	 367  	label		string
	 368  	limit		[11]int
	 369  }
	 370  
	 371  var deflateInflateStringTests = []deflateInflateStringTest{
	 372  	{
	 373  		"../testdata/e.txt",
	 374  		"2.718281828...",
	 375  		[...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683},
	 376  	},
	 377  	{
	 378  		"../../testdata/Isaac.Newton-Opticks.txt",
	 379  		"Isaac.Newton-Opticks",
	 380  		[...]int{567248, 218338, 198211, 193152, 181100, 175427, 175427, 173597, 173422, 173422, 325240},
	 381  	},
	 382  }
	 383  
	 384  func TestDeflateInflateString(t *testing.T) {
	 385  	t.Parallel()
	 386  	if testing.Short() && testenv.Builder() == "" {
	 387  		t.Skip("skipping in short mode")
	 388  	}
	 389  	for _, test := range deflateInflateStringTests {
	 390  		gold, err := os.ReadFile(test.filename)
	 391  		if err != nil {
	 392  			t.Error(err)
	 393  		}
	 394  		testToFromWithLimit(t, gold, test.label, test.limit)
	 395  		if testing.Short() {
	 396  			break
	 397  		}
	 398  	}
	 399  }
	 400  
	 401  func TestReaderDict(t *testing.T) {
	 402  	const (
	 403  		dict = "hello world"
	 404  		text = "hello again world"
	 405  	)
	 406  	var b bytes.Buffer
	 407  	w, err := NewWriter(&b, 5)
	 408  	if err != nil {
	 409  		t.Fatalf("NewWriter: %v", err)
	 410  	}
	 411  	w.Write([]byte(dict))
	 412  	w.Flush()
	 413  	b.Reset()
	 414  	w.Write([]byte(text))
	 415  	w.Close()
	 416  
	 417  	r := NewReaderDict(&b, []byte(dict))
	 418  	data, err := io.ReadAll(r)
	 419  	if err != nil {
	 420  		t.Fatal(err)
	 421  	}
	 422  	if string(data) != "hello again world" {
	 423  		t.Fatalf("read returned %q want %q", string(data), text)
	 424  	}
	 425  }
	 426  
	 427  func TestWriterDict(t *testing.T) {
	 428  	const (
	 429  		dict = "hello world"
	 430  		text = "hello again world"
	 431  	)
	 432  	var b bytes.Buffer
	 433  	w, err := NewWriter(&b, 5)
	 434  	if err != nil {
	 435  		t.Fatalf("NewWriter: %v", err)
	 436  	}
	 437  	w.Write([]byte(dict))
	 438  	w.Flush()
	 439  	b.Reset()
	 440  	w.Write([]byte(text))
	 441  	w.Close()
	 442  
	 443  	var b1 bytes.Buffer
	 444  	w, _ = NewWriterDict(&b1, 5, []byte(dict))
	 445  	w.Write([]byte(text))
	 446  	w.Close()
	 447  
	 448  	if !bytes.Equal(b1.Bytes(), b.Bytes()) {
	 449  		t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes())
	 450  	}
	 451  }
	 452  
	 453  // See https://golang.org/issue/2508
	 454  func TestRegression2508(t *testing.T) {
	 455  	if testing.Short() {
	 456  		t.Logf("test disabled with -short")
	 457  		return
	 458  	}
	 459  	w, err := NewWriter(io.Discard, 1)
	 460  	if err != nil {
	 461  		t.Fatalf("NewWriter: %v", err)
	 462  	}
	 463  	buf := make([]byte, 1024)
	 464  	for i := 0; i < 131072; i++ {
	 465  		if _, err := w.Write(buf); err != nil {
	 466  			t.Fatalf("writer failed: %v", err)
	 467  		}
	 468  	}
	 469  	w.Close()
	 470  }
	 471  
	 472  func TestWriterReset(t *testing.T) {
	 473  	t.Parallel()
	 474  	for level := 0; level <= 9; level++ {
	 475  		if testing.Short() && level > 1 {
	 476  			break
	 477  		}
	 478  		w, err := NewWriter(io.Discard, level)
	 479  		if err != nil {
	 480  			t.Fatalf("NewWriter: %v", err)
	 481  		}
	 482  		buf := []byte("hello world")
	 483  		n := 1024
	 484  		if testing.Short() {
	 485  			n = 10
	 486  		}
	 487  		for i := 0; i < n; i++ {
	 488  			w.Write(buf)
	 489  		}
	 490  		w.Reset(io.Discard)
	 491  
	 492  		wref, err := NewWriter(io.Discard, level)
	 493  		if err != nil {
	 494  			t.Fatalf("NewWriter: %v", err)
	 495  		}
	 496  
	 497  		// DeepEqual doesn't compare functions.
	 498  		w.d.fill, wref.d.fill = nil, nil
	 499  		w.d.step, wref.d.step = nil, nil
	 500  		w.d.bulkHasher, wref.d.bulkHasher = nil, nil
	 501  		w.d.bestSpeed, wref.d.bestSpeed = nil, nil
	 502  		// hashMatch is always overwritten when used.
	 503  		copy(w.d.hashMatch[:], wref.d.hashMatch[:])
	 504  		if len(w.d.tokens) != 0 {
	 505  			t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, len(w.d.tokens))
	 506  		}
	 507  		// As long as the length is 0, we don't care about the content.
	 508  		w.d.tokens = wref.d.tokens
	 509  
	 510  		// We don't care if there are values in the window, as long as it is at d.index is 0
	 511  		w.d.window = wref.d.window
	 512  		if !reflect.DeepEqual(w, wref) {
	 513  			t.Errorf("level %d Writer not reset after Reset", level)
	 514  		}
	 515  	}
	 516  
	 517  	levels := []int{0, 1, 2, 5, 9}
	 518  	for _, level := range levels {
	 519  		t.Run(fmt.Sprint(level), func(t *testing.T) {
	 520  			testResetOutput(t, level, nil)
	 521  		})
	 522  	}
	 523  
	 524  	t.Run("dict", func(t *testing.T) {
	 525  		for _, level := range levels {
	 526  			t.Run(fmt.Sprint(level), func(t *testing.T) {
	 527  				testResetOutput(t, level, nil)
	 528  			})
	 529  		}
	 530  	})
	 531  }
	 532  
	 533  func testResetOutput(t *testing.T, level int, dict []byte) {
	 534  	writeData := func(w *Writer) {
	 535  		msg := []byte("now is the time for all good gophers")
	 536  		w.Write(msg)
	 537  		w.Flush()
	 538  
	 539  		hello := []byte("hello world")
	 540  		for i := 0; i < 1024; i++ {
	 541  			w.Write(hello)
	 542  		}
	 543  
	 544  		fill := bytes.Repeat([]byte("x"), 65000)
	 545  		w.Write(fill)
	 546  	}
	 547  
	 548  	buf := new(bytes.Buffer)
	 549  	var w *Writer
	 550  	var err error
	 551  	if dict == nil {
	 552  		w, err = NewWriter(buf, level)
	 553  	} else {
	 554  		w, err = NewWriterDict(buf, level, dict)
	 555  	}
	 556  	if err != nil {
	 557  		t.Fatalf("NewWriter: %v", err)
	 558  	}
	 559  
	 560  	writeData(w)
	 561  	w.Close()
	 562  	out1 := buf.Bytes()
	 563  
	 564  	buf2 := new(bytes.Buffer)
	 565  	w.Reset(buf2)
	 566  	writeData(w)
	 567  	w.Close()
	 568  	out2 := buf2.Bytes()
	 569  
	 570  	if len(out1) != len(out2) {
	 571  		t.Errorf("got %d, expected %d bytes", len(out2), len(out1))
	 572  		return
	 573  	}
	 574  	if !bytes.Equal(out1, out2) {
	 575  		mm := 0
	 576  		for i, b := range out1[:len(out2)] {
	 577  			if b != out2[i] {
	 578  				t.Errorf("mismatch index %d: %#02x, expected %#02x", i, out2[i], b)
	 579  			}
	 580  			mm++
	 581  			if mm == 10 {
	 582  				t.Fatal("Stopping")
	 583  			}
	 584  		}
	 585  	}
	 586  	t.Logf("got %d bytes", len(out1))
	 587  }
	 588  
	 589  // TestBestSpeed tests that round-tripping through deflate and then inflate
	 590  // recovers the original input. The Write sizes are near the thresholds in the
	 591  // compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize
	 592  // (65535).
	 593  func TestBestSpeed(t *testing.T) {
	 594  	t.Parallel()
	 595  	abc := make([]byte, 128)
	 596  	for i := range abc {
	 597  		abc[i] = byte(i)
	 598  	}
	 599  	abcabc := bytes.Repeat(abc, 131072/len(abc))
	 600  	var want []byte
	 601  
	 602  	testCases := [][]int{
	 603  		{65536, 0},
	 604  		{65536, 1},
	 605  		{65536, 1, 256},
	 606  		{65536, 1, 65536},
	 607  		{65536, 14},
	 608  		{65536, 15},
	 609  		{65536, 16},
	 610  		{65536, 16, 256},
	 611  		{65536, 16, 65536},
	 612  		{65536, 127},
	 613  		{65536, 128},
	 614  		{65536, 128, 256},
	 615  		{65536, 128, 65536},
	 616  		{65536, 129},
	 617  		{65536, 65536, 256},
	 618  		{65536, 65536, 65536},
	 619  	}
	 620  
	 621  	for i, tc := range testCases {
	 622  		if i >= 3 && testing.Short() {
	 623  			break
	 624  		}
	 625  		for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} {
	 626  			tc[0] = firstN
	 627  		outer:
	 628  			for _, flush := range []bool{false, true} {
	 629  				buf := new(bytes.Buffer)
	 630  				want = want[:0]
	 631  
	 632  				w, err := NewWriter(buf, BestSpeed)
	 633  				if err != nil {
	 634  					t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err)
	 635  					continue
	 636  				}
	 637  				for _, n := range tc {
	 638  					want = append(want, abcabc[:n]...)
	 639  					if _, err := w.Write(abcabc[:n]); err != nil {
	 640  						t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err)
	 641  						continue outer
	 642  					}
	 643  					if !flush {
	 644  						continue
	 645  					}
	 646  					if err := w.Flush(); err != nil {
	 647  						t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err)
	 648  						continue outer
	 649  					}
	 650  				}
	 651  				if err := w.Close(); err != nil {
	 652  					t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err)
	 653  					continue
	 654  				}
	 655  
	 656  				r := NewReader(buf)
	 657  				got, err := io.ReadAll(r)
	 658  				if err != nil {
	 659  					t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err)
	 660  					continue
	 661  				}
	 662  				r.Close()
	 663  
	 664  				if !bytes.Equal(got, want) {
	 665  					t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush)
	 666  					continue
	 667  				}
	 668  			}
	 669  		}
	 670  	}
	 671  }
	 672  
	 673  var errIO = errors.New("IO error")
	 674  
	 675  // failWriter fails with errIO exactly at the nth call to Write.
	 676  type failWriter struct{ n int }
	 677  
	 678  func (w *failWriter) Write(b []byte) (int, error) {
	 679  	w.n--
	 680  	if w.n == -1 {
	 681  		return 0, errIO
	 682  	}
	 683  	return len(b), nil
	 684  }
	 685  
	 686  func TestWriterPersistentError(t *testing.T) {
	 687  	t.Parallel()
	 688  	d, err := os.ReadFile("../../testdata/Isaac.Newton-Opticks.txt")
	 689  	if err != nil {
	 690  		t.Fatalf("ReadFile: %v", err)
	 691  	}
	 692  	d = d[:10000] // Keep this test short
	 693  
	 694  	zw, err := NewWriter(nil, DefaultCompression)
	 695  	if err != nil {
	 696  		t.Fatalf("NewWriter: %v", err)
	 697  	}
	 698  
	 699  	// Sweep over the threshold at which an error is returned.
	 700  	// The variable i makes it such that the ith call to failWriter.Write will
	 701  	// return errIO. Since failWriter errors are not persistent, we must ensure
	 702  	// that flate.Writer errors are persistent.
	 703  	for i := 0; i < 1000; i++ {
	 704  		fw := &failWriter{i}
	 705  		zw.Reset(fw)
	 706  
	 707  		_, werr := zw.Write(d)
	 708  		cerr := zw.Close()
	 709  		if werr != errIO && werr != nil {
	 710  			t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO)
	 711  		}
	 712  		if cerr != errIO && fw.n < 0 {
	 713  			t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO)
	 714  		}
	 715  		if fw.n >= 0 {
	 716  			// At this point, the failure threshold was sufficiently high enough
	 717  			// that we wrote the whole stream without any errors.
	 718  			return
	 719  		}
	 720  	}
	 721  }
	 722  
	 723  func TestBestSpeedMatch(t *testing.T) {
	 724  	t.Parallel()
	 725  	cases := []struct {
	 726  		previous, current []byte
	 727  		t, s, want				int32
	 728  	}{{
	 729  		previous: []byte{0, 0, 0, 1, 2},
	 730  		current:	[]byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
	 731  		t:				-3,
	 732  		s:				3,
	 733  		want:		 6,
	 734  	}, {
	 735  		previous: []byte{0, 0, 0, 1, 2},
	 736  		current:	[]byte{2, 4, 5, 0, 1, 2, 3, 4, 5},
	 737  		t:				-3,
	 738  		s:				3,
	 739  		want:		 3,
	 740  	}, {
	 741  		previous: []byte{0, 0, 0, 1, 1},
	 742  		current:	[]byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
	 743  		t:				-3,
	 744  		s:				3,
	 745  		want:		 2,
	 746  	}, {
	 747  		previous: []byte{0, 0, 0, 1, 2},
	 748  		current:	[]byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
	 749  		t:				-1,
	 750  		s:				0,
	 751  		want:		 4,
	 752  	}, {
	 753  		previous: []byte{0, 0, 0, 1, 2, 3, 4, 5, 2, 2},
	 754  		current:	[]byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
	 755  		t:				-7,
	 756  		s:				4,
	 757  		want:		 5,
	 758  	}, {
	 759  		previous: []byte{9, 9, 9, 9, 9},
	 760  		current:	[]byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
	 761  		t:				-1,
	 762  		s:				0,
	 763  		want:		 0,
	 764  	}, {
	 765  		previous: []byte{9, 9, 9, 9, 9},
	 766  		current:	[]byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
	 767  		t:				0,
	 768  		s:				1,
	 769  		want:		 0,
	 770  	}, {
	 771  		previous: []byte{},
	 772  		current:	[]byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
	 773  		t:				-5,
	 774  		s:				1,
	 775  		want:		 0,
	 776  	}, {
	 777  		previous: []byte{},
	 778  		current:	[]byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
	 779  		t:				-1,
	 780  		s:				1,
	 781  		want:		 0,
	 782  	}, {
	 783  		previous: []byte{},
	 784  		current:	[]byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
	 785  		t:				0,
	 786  		s:				1,
	 787  		want:		 3,
	 788  	}, {
	 789  		previous: []byte{3, 4, 5},
	 790  		current:	[]byte{3, 4, 5},
	 791  		t:				-3,
	 792  		s:				0,
	 793  		want:		 3,
	 794  	}, {
	 795  		previous: make([]byte, 1000),
	 796  		current:	make([]byte, 1000),
	 797  		t:				-1000,
	 798  		s:				0,
	 799  		want:		 maxMatchLength - 4,
	 800  	}, {
	 801  		previous: make([]byte, 200),
	 802  		current:	make([]byte, 500),
	 803  		t:				-200,
	 804  		s:				0,
	 805  		want:		 maxMatchLength - 4,
	 806  	}, {
	 807  		previous: make([]byte, 200),
	 808  		current:	make([]byte, 500),
	 809  		t:				0,
	 810  		s:				1,
	 811  		want:		 maxMatchLength - 4,
	 812  	}, {
	 813  		previous: make([]byte, maxMatchLength-4),
	 814  		current:	make([]byte, 500),
	 815  		t:				-(maxMatchLength - 4),
	 816  		s:				0,
	 817  		want:		 maxMatchLength - 4,
	 818  	}, {
	 819  		previous: make([]byte, 200),
	 820  		current:	make([]byte, 500),
	 821  		t:				-200,
	 822  		s:				400,
	 823  		want:		 100,
	 824  	}, {
	 825  		previous: make([]byte, 10),
	 826  		current:	make([]byte, 500),
	 827  		t:				200,
	 828  		s:				400,
	 829  		want:		 100,
	 830  	}}
	 831  	for i, c := range cases {
	 832  		e := deflateFast{prev: c.previous}
	 833  		got := e.matchLen(c.s, c.t, c.current)
	 834  		if got != c.want {
	 835  			t.Errorf("Test %d: match length, want %d, got %d", i, c.want, got)
	 836  		}
	 837  	}
	 838  }
	 839  
	 840  func TestBestSpeedMaxMatchOffset(t *testing.T) {
	 841  	t.Parallel()
	 842  	const abc, xyz = "abcdefgh", "stuvwxyz"
	 843  	for _, matchBefore := range []bool{false, true} {
	 844  		for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} {
	 845  			for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ {
	 846  				report := func(desc string, err error) {
	 847  					t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v",
	 848  						matchBefore, extra, offsetAdj, desc, err)
	 849  				}
	 850  
	 851  				offset := maxMatchOffset + offsetAdj
	 852  
	 853  				// Make src to be a []byte of the form
	 854  				//	"%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1)
	 855  				// where:
	 856  				//	zeros0 is approximately maxMatchOffset zeros.
	 857  				//	xyzMaybe is either xyz or the empty string.
	 858  				//	zeros1 is between 0 and 30 zeros.
	 859  				// The difference between the two abc's will be offset, which
	 860  				// is maxMatchOffset plus or minus a small adjustment.
	 861  				src := make([]byte, offset+len(abc)+extra)
	 862  				copy(src, abc)
	 863  				if !matchBefore {
	 864  					copy(src[offset-len(xyz):], xyz)
	 865  				}
	 866  				copy(src[offset:], abc)
	 867  
	 868  				buf := new(bytes.Buffer)
	 869  				w, err := NewWriter(buf, BestSpeed)
	 870  				if err != nil {
	 871  					report("NewWriter: ", err)
	 872  					continue
	 873  				}
	 874  				if _, err := w.Write(src); err != nil {
	 875  					report("Write: ", err)
	 876  					continue
	 877  				}
	 878  				if err := w.Close(); err != nil {
	 879  					report("Writer.Close: ", err)
	 880  					continue
	 881  				}
	 882  
	 883  				r := NewReader(buf)
	 884  				dst, err := io.ReadAll(r)
	 885  				r.Close()
	 886  				if err != nil {
	 887  					report("ReadAll: ", err)
	 888  					continue
	 889  				}
	 890  
	 891  				if !bytes.Equal(dst, src) {
	 892  					report("", fmt.Errorf("bytes differ after round-tripping"))
	 893  					continue
	 894  				}
	 895  			}
	 896  		}
	 897  	}
	 898  }
	 899  
	 900  func TestBestSpeedShiftOffsets(t *testing.T) {
	 901  	// Test if shiftoffsets properly preserves matches and resets out-of-range matches
	 902  	// seen in https://github.com/golang/go/issues/4142
	 903  	enc := newDeflateFast()
	 904  
	 905  	// testData may not generate internal matches.
	 906  	testData := make([]byte, 32)
	 907  	rng := rand.New(rand.NewSource(0))
	 908  	for i := range testData {
	 909  		testData[i] = byte(rng.Uint32())
	 910  	}
	 911  
	 912  	// Encode the testdata with clean state.
	 913  	// Second part should pick up matches from the first block.
	 914  	wantFirstTokens := len(enc.encode(nil, testData))
	 915  	wantSecondTokens := len(enc.encode(nil, testData))
	 916  
	 917  	if wantFirstTokens <= wantSecondTokens {
	 918  		t.Fatalf("test needs matches between inputs to be generated")
	 919  	}
	 920  	// Forward the current indicator to before wraparound.
	 921  	enc.cur = bufferReset - int32(len(testData))
	 922  
	 923  	// Part 1 before wrap, should match clean state.
	 924  	got := len(enc.encode(nil, testData))
	 925  	if wantFirstTokens != got {
	 926  		t.Errorf("got %d, want %d tokens", got, wantFirstTokens)
	 927  	}
	 928  
	 929  	// Verify we are about to wrap.
	 930  	if enc.cur != bufferReset {
	 931  		t.Errorf("got %d, want e.cur to be at bufferReset (%d)", enc.cur, bufferReset)
	 932  	}
	 933  
	 934  	// Part 2 should match clean state as well even if wrapped.
	 935  	got = len(enc.encode(nil, testData))
	 936  	if wantSecondTokens != got {
	 937  		t.Errorf("got %d, want %d token", got, wantSecondTokens)
	 938  	}
	 939  
	 940  	// Verify that we wrapped.
	 941  	if enc.cur >= bufferReset {
	 942  		t.Errorf("want e.cur to be < bufferReset (%d), got %d", bufferReset, enc.cur)
	 943  	}
	 944  
	 945  	// Forward the current buffer, leaving the matches at the bottom.
	 946  	enc.cur = bufferReset
	 947  	enc.shiftOffsets()
	 948  
	 949  	// Ensure that no matches were picked up.
	 950  	got = len(enc.encode(nil, testData))
	 951  	if wantFirstTokens != got {
	 952  		t.Errorf("got %d, want %d tokens", got, wantFirstTokens)
	 953  	}
	 954  }
	 955  
	 956  func TestMaxStackSize(t *testing.T) {
	 957  	// This test must not run in parallel with other tests as debug.SetMaxStack
	 958  	// affects all goroutines.
	 959  	n := debug.SetMaxStack(1 << 16)
	 960  	defer debug.SetMaxStack(n)
	 961  
	 962  	var wg sync.WaitGroup
	 963  	defer wg.Wait()
	 964  
	 965  	b := make([]byte, 1<<20)
	 966  	for level := HuffmanOnly; level <= BestCompression; level++ {
	 967  		// Run in separate goroutine to increase probability of stack regrowth.
	 968  		wg.Add(1)
	 969  		go func(level int) {
	 970  			defer wg.Done()
	 971  			zw, err := NewWriter(io.Discard, level)
	 972  			if err != nil {
	 973  				t.Errorf("level %d, NewWriter() = %v, want nil", level, err)
	 974  			}
	 975  			if n, err := zw.Write(b); n != len(b) || err != nil {
	 976  				t.Errorf("level %d, Write() = (%d, %v), want (%d, nil)", level, n, err, len(b))
	 977  			}
	 978  			if err := zw.Close(); err != nil {
	 979  				t.Errorf("level %d, Close() = %v, want nil", level, err)
	 980  			}
	 981  			zw.Reset(io.Discard)
	 982  		}(level)
	 983  	}
	 984  }
	 985  

View as plain text