From afdb8cff3ef267ecddb5ce807b850b8664ca9387 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Fri, 11 Mar 2016 12:23:11 +0100 Subject: [PATCH] compress/flate: test if results are deterministic This will test if deflate output is deterministic between two runs of the deflater, when write sizes differ. The deflater makes no official promises that results are deterministic between runs, but this is a good test to determine unintentional randomness. Note that this does not guarantee that results are deterministic across platforms nor that results will be deterministic between Go versions. This is also not guarantees we should imply. Change-Id: Id7dd89fe276060fd83a43d0b34ac35d50fcd32d9 Reviewed-on: https://go-review.googlesource.com/20573 Reviewed-by: Brad Fitzpatrick --- src/compress/flate/writer_test.go | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/compress/flate/writer_test.go b/src/compress/flate/writer_test.go index 5c18ba346c..428152f304 100644 --- a/src/compress/flate/writer_test.go +++ b/src/compress/flate/writer_test.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "io/ioutil" + "math/rand" "runtime" "testing" ) @@ -127,3 +128,68 @@ func TestWriteError(t *testing.T) { } } } + +// Test if two runs produce identical results +// even when writing different sizes to the Writer. +func TestDeterministicL0(t *testing.T) { testDeterministic(0, t) } +func TestDeterministicL1(t *testing.T) { testDeterministic(1, t) } +func TestDeterministicL2(t *testing.T) { testDeterministic(2, t) } +func TestDeterministicL3(t *testing.T) { testDeterministic(3, t) } +func TestDeterministicL4(t *testing.T) { testDeterministic(4, t) } +func TestDeterministicL5(t *testing.T) { testDeterministic(5, t) } +func TestDeterministicL6(t *testing.T) { testDeterministic(6, t) } +func TestDeterministicL7(t *testing.T) { testDeterministic(7, t) } +func TestDeterministicL8(t *testing.T) { testDeterministic(8, t) } +func TestDeterministicL9(t *testing.T) { testDeterministic(9, t) } + +func testDeterministic(i int, t *testing.T) { + // Test so much we cross a good number of block boundaries. + var length = maxStoreBlockSize*30 + 500 + if testing.Short() { + length /= 10 + } + + // Create a random, but compressible stream. + rng := rand.New(rand.NewSource(1)) + t1 := make([]byte, length) + for i := range t1 { + t1[i] = byte(rng.Int63() & 7) + } + + // Do our first encode. + var b1 bytes.Buffer + br := bytes.NewBuffer(t1) + w, err := NewWriter(&b1, i) + if err != nil { + t.Fatal(err) + } + // Use a very small prime sized buffer. + cbuf := make([]byte, 787) + _, err = io.CopyBuffer(w, br, cbuf) + if err != nil { + t.Fatal(err) + } + w.Close() + + // We choose a different buffer size, + // bigger than a maximum block, and also a prime. + var b2 bytes.Buffer + cbuf = make([]byte, 81761) + br2 := bytes.NewBuffer(t1) + w2, err := NewWriter(&b2, i) + if err != nil { + t.Fatal(err) + } + _, err = io.CopyBuffer(w2, br2, cbuf) + if err != nil { + t.Fatal(err) + } + w2.Close() + + b1b := b1.Bytes() + b2b := b2.Bytes() + + if bytes.Compare(b1b, b2b) != 0 { + t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b)) + } +}