github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/klauspost/compress/snappy/snappy_test.go (about)

     1  // Copyright 2011 The Snappy-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  //+build go1.4
     6  
     7  package snappy
     8  
     9  import (
    10  	"bytes"
    11  	"flag"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"math/rand"
    16  	"net/http"
    17  	"os"
    18  	"path/filepath"
    19  	"strings"
    20  	"testing"
    21  
    22  	old "github.com/insionng/yougam/libraries/golang/snappy"
    23  )
    24  
    25  var (
    26  	download = flag.Bool("download", false, "If true, download any missing files before running benchmarks")
    27  	testdata = flag.String("testdata", "testdata", "Directory containing the test data")
    28  )
    29  
    30  func TestMaxEncodedLenOfMaxUncompressedChunkLen(t *testing.T) {
    31  	got := maxEncodedLenOfMaxUncompressedChunkLen
    32  	want := MaxEncodedLen(maxUncompressedChunkLen)
    33  	if got != want {
    34  		t.Fatalf("got %d, want %d", got, want)
    35  	}
    36  }
    37  
    38  func roundtrip(b, ebuf, dbuf []byte) error {
    39  	d, err := Decode(dbuf, Encode(ebuf, b))
    40  	if err != nil {
    41  		return fmt.Errorf("decoding error: %v", err)
    42  	}
    43  	if !bytes.Equal(b, d) {
    44  		return fmt.Errorf("roundtrip mismatch:\n\twant %v\n\tgot  %v", b, d)
    45  	}
    46  	return nil
    47  }
    48  
    49  func TestEmpty(t *testing.T) {
    50  	if err := roundtrip(nil, nil, nil); err != nil {
    51  		t.Fatal(err)
    52  	}
    53  }
    54  
    55  func TestSmallCopy(t *testing.T) {
    56  	for _, ebuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} {
    57  		for _, dbuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} {
    58  			for i := 0; i < 32; i++ {
    59  				s := "aaaa" + strings.Repeat("b", i) + "aaaabbbb"
    60  				if err := roundtrip([]byte(s), ebuf, dbuf); err != nil {
    61  					t.Errorf("len(ebuf)=%d, len(dbuf)=%d, i=%d: %v", len(ebuf), len(dbuf), i, err)
    62  				}
    63  			}
    64  		}
    65  	}
    66  }
    67  
    68  func TestSmallRand(t *testing.T) {
    69  	rng := rand.New(rand.NewSource(1))
    70  	for n := 1; n < 20000; n += 23 {
    71  		b := make([]byte, n)
    72  		for i := range b {
    73  			b[i] = uint8(rng.Uint32())
    74  		}
    75  		if err := roundtrip(b, nil, nil); err != nil {
    76  			t.Fatal(err)
    77  		}
    78  	}
    79  }
    80  
    81  func TestSmallRegular(t *testing.T) {
    82  	for n := 1; n < 20000; n += 23 {
    83  		b := make([]byte, n)
    84  		for i := range b {
    85  			b[i] = uint8(i%10 + 'a')
    86  		}
    87  		if err := roundtrip(b, nil, nil); err != nil {
    88  			t.Fatal(err)
    89  		}
    90  	}
    91  }
    92  
    93  func TestInvalidVarint(t *testing.T) {
    94  	data := []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00")
    95  	if _, err := DecodedLen(data); err != ErrCorrupt {
    96  		t.Errorf("DecodedLen: got %v, want ErrCorrupt", err)
    97  	}
    98  	if _, err := Decode(nil, data); err != ErrCorrupt {
    99  		t.Errorf("Decode: got %v, want ErrCorrupt", err)
   100  	}
   101  
   102  	// The encoded varint overflows 32 bits
   103  	data = []byte("\xff\xff\xff\xff\xff\x00")
   104  
   105  	if _, err := DecodedLen(data); err != ErrCorrupt {
   106  		t.Errorf("DecodedLen: got %v, want ErrCorrupt", err)
   107  	}
   108  	if _, err := Decode(nil, data); err != ErrCorrupt {
   109  		t.Errorf("Decode: got %v, want ErrCorrupt", err)
   110  	}
   111  }
   112  
   113  func TestDecode(t *testing.T) {
   114  	testCases := []struct {
   115  		desc    string
   116  		input   string
   117  		want    string
   118  		wantErr error
   119  	}{{
   120  		`decodedLen=0x100000000 is too long`,
   121  		"\x80\x80\x80\x80\x10" + "\x00\x41",
   122  		"",
   123  		ErrCorrupt,
   124  	}, {
   125  		`decodedLen=3; tagLiteral, 0-byte length; length=3; valid input`,
   126  		"\x03" + "\x08\xff\xff\xff",
   127  		"\xff\xff\xff",
   128  		nil,
   129  	}, {
   130  		`decodedLen=1; tagLiteral, 1-byte length; not enough length bytes`,
   131  		"\x01" + "\xf0",
   132  		"",
   133  		ErrCorrupt,
   134  	}, {
   135  		`decodedLen=3; tagLiteral, 1-byte length; length=3; valid input`,
   136  		"\x03" + "\xf0\x02\xff\xff\xff",
   137  		"\xff\xff\xff",
   138  		nil,
   139  	}, {
   140  		`decodedLen=1; tagLiteral, 2-byte length; not enough length bytes`,
   141  		"\x01" + "\xf4\x00",
   142  		"",
   143  		ErrCorrupt,
   144  	}, {
   145  		`decodedLen=3; tagLiteral, 2-byte length; length=3; valid input`,
   146  		"\x03" + "\xf4\x02\x00\xff\xff\xff",
   147  		"\xff\xff\xff",
   148  		nil,
   149  	}, {
   150  		`decodedLen=1; tagLiteral, 3-byte length; not enough length bytes`,
   151  		"\x01" + "\xf8\x00\x00",
   152  		"",
   153  		ErrCorrupt,
   154  	}, {
   155  		`decodedLen=3; tagLiteral, 3-byte length; length=3; valid input`,
   156  		"\x03" + "\xf8\x02\x00\x00\xff\xff\xff",
   157  		"\xff\xff\xff",
   158  		nil,
   159  	}, {
   160  		`decodedLen=1; tagLiteral, 4-byte length; not enough length bytes`,
   161  		"\x01" + "\xfc\x00\x00\x00",
   162  		"",
   163  		ErrCorrupt,
   164  	}, {
   165  		`decodedLen=1; tagLiteral, 4-byte length; length=3; not enough dst bytes`,
   166  		"\x01" + "\xfc\x02\x00\x00\x00\xff\xff\xff",
   167  		"",
   168  		ErrCorrupt,
   169  	}, {
   170  		`decodedLen=4; tagLiteral, 4-byte length; length=3; not enough src bytes`,
   171  		"\x04" + "\xfc\x02\x00\x00\x00\xff",
   172  		"",
   173  		ErrCorrupt,
   174  	}, {
   175  		`decodedLen=3; tagLiteral, 4-byte length; length=3; valid input`,
   176  		"\x03" + "\xfc\x02\x00\x00\x00\xff\xff\xff",
   177  		"\xff\xff\xff",
   178  		nil,
   179  	}, {
   180  		`decodedLen=4; tagCopy1, 1 extra length|offset byte; not enough extra bytes`,
   181  		"\x04" + "\x01",
   182  		"",
   183  		ErrCorrupt,
   184  	}, {
   185  		`decodedLen=4; tagCopy2, 2 extra length|offset bytes; not enough extra bytes`,
   186  		"\x04" + "\x02\x00",
   187  		"",
   188  		ErrCorrupt,
   189  	}, {
   190  		`decodedLen=4; tagCopy4; unsupported COPY_4 tag`,
   191  		"\x04" + "\x03\x00\x00\x00\x00",
   192  		"",
   193  		errUnsupportedCopy4Tag,
   194  	}, {
   195  		`decodedLen=4; tagLiteral (4 bytes "abcd"); valid input`,
   196  		"\x04" + "\x0cabcd",
   197  		"abcd",
   198  		nil,
   199  	}, {
   200  		`decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=4; valid input`,
   201  		"\x08" + "\x0cabcd" + "\x01\x04",
   202  		"abcdabcd",
   203  		nil,
   204  	}, {
   205  		`decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=2; valid input`,
   206  		"\x08" + "\x0cabcd" + "\x01\x02",
   207  		"abcdcdcd",
   208  		nil,
   209  	}, {
   210  		`decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=1; valid input`,
   211  		"\x08" + "\x0cabcd" + "\x01\x01",
   212  		"abcddddd",
   213  		nil,
   214  	}, {
   215  		`decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=0; zero offset`,
   216  		"\x08" + "\x0cabcd" + "\x01\x00",
   217  		"",
   218  		ErrCorrupt,
   219  	}, {
   220  		`decodedLen=9; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=4; inconsistent dLen`,
   221  		"\x09" + "\x0cabcd" + "\x01\x04",
   222  		"",
   223  		ErrCorrupt,
   224  	}, {
   225  		`decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=5; offset too large`,
   226  		"\x08" + "\x0cabcd" + "\x01\x05",
   227  		"",
   228  		ErrCorrupt,
   229  	}, {
   230  		`decodedLen=7; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=4; length too large`,
   231  		"\x07" + "\x0cabcd" + "\x01\x04",
   232  		"",
   233  		ErrCorrupt,
   234  	}}
   235  
   236  	for _, tc := range testCases {
   237  		g, gotErr := Decode(nil, []byte(tc.input))
   238  		if got := string(g); got != tc.want || gotErr != tc.wantErr {
   239  			t.Errorf("%s:\ngot  %q, %v\nwant %q, %v", tc.desc, got, gotErr, tc.want, tc.wantErr)
   240  		}
   241  	}
   242  }
   243  
   244  // TestEncodeNoiseThenRepeats encodes a 32K block for which the first half is
   245  // very incompressible and the second half is very compressible. The encoded
   246  // form's length should be closer to 50% of the original length than 100%.
   247  func TestEncodeNoiseThenRepeats(t *testing.T) {
   248  	const origLen = 32768
   249  	src := make([]byte, origLen)
   250  	rng := rand.New(rand.NewSource(1))
   251  	firstHalf, secondHalf := src[:origLen/2], src[origLen/2:]
   252  	for i := range firstHalf {
   253  		firstHalf[i] = uint8(rng.Intn(256))
   254  	}
   255  	for i := range secondHalf {
   256  		secondHalf[i] = uint8(i >> 8)
   257  	}
   258  	dst := Encode(nil, src)
   259  	if got, want := len(dst), origLen*3/4; got >= want {
   260  		t.Fatalf("got %d encoded bytes, want less than %d", got, want)
   261  	}
   262  }
   263  
   264  // TestEncodeNoiseThenRepeats encodes a 8GB block for which the first half is
   265  // very incompressible and the second half is very compressible. The encoded
   266  // form's length should be closer to 50% of the original length than 100%.
   267  func TestEncodeNoiseThenRepeatsBig(t *testing.T) {
   268  	const origLen = 8 << 20
   269  	src := make([]byte, origLen)
   270  	rng := rand.New(rand.NewSource(1))
   271  	firstHalf, secondHalf := src[:origLen/2], src[origLen/2:]
   272  	for i := range firstHalf {
   273  		firstHalf[i] = uint8(rng.Intn(256))
   274  	}
   275  	for i := range secondHalf {
   276  		secondHalf[i] = uint8(i >> 8)
   277  	}
   278  	dst := Encode(nil, src)
   279  	if got, want := len(dst), origLen*3/4; got >= want {
   280  		t.Fatalf("got %d encoded bytes, want less than %d", got, want)
   281  	}
   282  }
   283  
   284  func cmp(a, b []byte) error {
   285  	if len(a) != len(b) {
   286  		return fmt.Errorf("got %d bytes, want %d", len(a), len(b))
   287  	}
   288  	for i := range a {
   289  		if a[i] != b[i] {
   290  			return fmt.Errorf("byte #%d: got 0x%02x, want 0x%02x", i, a[i], b[i])
   291  		}
   292  	}
   293  	return nil
   294  }
   295  
   296  func TestFramingFormat(t *testing.T) {
   297  	// src is comprised of alternating 1e5-sized sequences of random
   298  	// (incompressible) bytes and repeated (compressible) bytes. 1e5 was chosen
   299  	// because it is larger than maxUncompressedChunkLen (64k).
   300  	src := make([]byte, 1e6)
   301  	rng := rand.New(rand.NewSource(1))
   302  	for i := 0; i < 10; i++ {
   303  		if i%2 == 0 {
   304  			for j := 0; j < 1e5; j++ {
   305  				src[1e5*i+j] = uint8(rng.Intn(256))
   306  			}
   307  		} else {
   308  			for j := 0; j < 1e5; j++ {
   309  				src[1e5*i+j] = uint8(i)
   310  			}
   311  		}
   312  	}
   313  
   314  	buf := new(bytes.Buffer)
   315  	if _, err := NewWriter(buf).Write(src); err != nil {
   316  		t.Fatalf("Write: encoding: %v", err)
   317  	}
   318  	dst, err := ioutil.ReadAll(NewReader(buf))
   319  	if err != nil {
   320  		t.Fatalf("ReadAll: decoding: %v", err)
   321  	}
   322  	if err := cmp(dst, src); err != nil {
   323  		t.Fatal(err)
   324  	}
   325  }
   326  
   327  func TestWriterGoldenOutput(t *testing.T) {
   328  	buf := new(bytes.Buffer)
   329  	w := NewBufferedWriter(buf)
   330  	defer w.Close()
   331  	w.Write([]byte("abcd")) // Not compressible.
   332  	w.Flush()
   333  	w.Write(bytes.Repeat([]byte{'A'}, 100)) // Compressible.
   334  	w.Flush()
   335  	got := buf.String()
   336  	want := strings.Join([]string{
   337  		magicChunk,
   338  		"\x01\x08\x00\x00", // Uncompressed chunk, 8 bytes long (including 4 byte checksum).
   339  		"\x68\x10\xe6\xb6", // Checksum.
   340  		"\x61\x62\x63\x64", // Uncompressed payload: "abcd".
   341  		"\x00\x0d\x00\x00", // Compressed chunk, 13 bytes long (including 4 byte checksum).
   342  		"\x37\xcb\xbc\x9d", // Checksum.
   343  		"\x64",             // Compressed payload: Uncompressed length (varint encoded): 100.
   344  		"\x00\x41",         // Compressed payload: tagLiteral, length=1, "A".
   345  		"\xfe\x01\x00",     // Compressed payload: tagCopy2,   length=64, offset=1.
   346  		"\x8a\x01\x00",     // Compressed payload: tagCopy2,   length=35, offset=1.
   347  	}, "")
   348  	if got != want {
   349  		t.Fatalf("\ngot:  % x\nwant: % x", got, want)
   350  	}
   351  }
   352  
   353  func TestNewBufferedWriter(t *testing.T) {
   354  	// Test all 32 possible sub-sequences of these 5 input slices.
   355  	//
   356  	// Their lengths sum to 400,000, which is over 6 times the Writer ibuf
   357  	// capacity: 6 * maxUncompressedChunkLen is 393,216.
   358  	inputs := [][]byte{
   359  		bytes.Repeat([]byte{'a'}, 40000),
   360  		bytes.Repeat([]byte{'b'}, 150000),
   361  		bytes.Repeat([]byte{'c'}, 60000),
   362  		bytes.Repeat([]byte{'d'}, 120000),
   363  		bytes.Repeat([]byte{'e'}, 30000),
   364  	}
   365  loop:
   366  	for i := 0; i < 1<<uint(len(inputs)); i++ {
   367  		var want []byte
   368  		buf := new(bytes.Buffer)
   369  		w := NewBufferedWriter(buf)
   370  		for j, input := range inputs {
   371  			if i&(1<<uint(j)) == 0 {
   372  				continue
   373  			}
   374  			if _, err := w.Write(input); err != nil {
   375  				t.Errorf("i=%#02x: j=%d: Write: %v", i, j, err)
   376  				continue loop
   377  			}
   378  			want = append(want, input...)
   379  		}
   380  		if err := w.Close(); err != nil {
   381  			t.Errorf("i=%#02x: Close: %v", i, err)
   382  			continue
   383  		}
   384  		got, err := ioutil.ReadAll(NewReader(buf))
   385  		if err != nil {
   386  			t.Errorf("i=%#02x: ReadAll: %v", i, err)
   387  			continue
   388  		}
   389  		if err := cmp(got, want); err != nil {
   390  			t.Errorf("i=%#02x: %v", i, err)
   391  			continue
   392  		}
   393  	}
   394  }
   395  
   396  func TestFlush(t *testing.T) {
   397  	buf := new(bytes.Buffer)
   398  	w := NewBufferedWriter(buf)
   399  	defer w.Close()
   400  	if _, err := w.Write(bytes.Repeat([]byte{'x'}, 20)); err != nil {
   401  		t.Fatalf("Write: %v", err)
   402  	}
   403  	if n := buf.Len(); n != 0 {
   404  		t.Fatalf("before Flush: %d bytes were written to the underlying io.Writer, want 0", n)
   405  	}
   406  	if err := w.Flush(); err != nil {
   407  		t.Fatalf("Flush: %v", err)
   408  	}
   409  	if n := buf.Len(); n == 0 {
   410  		t.Fatalf("after Flush: %d bytes were written to the underlying io.Writer, want non-0", n)
   411  	}
   412  }
   413  
   414  func TestReaderReset(t *testing.T) {
   415  	gold := bytes.Repeat([]byte("All that is gold does not glitter,\n"), 10000)
   416  	buf := new(bytes.Buffer)
   417  	if _, err := NewWriter(buf).Write(gold); err != nil {
   418  		t.Fatalf("Write: %v", err)
   419  	}
   420  	encoded, invalid, partial := buf.String(), "invalid", "partial"
   421  	r := NewReader(nil)
   422  	for i, s := range []string{encoded, invalid, partial, encoded, partial, invalid, encoded, encoded} {
   423  		if s == partial {
   424  			r.Reset(strings.NewReader(encoded))
   425  			if _, err := r.Read(make([]byte, 101)); err != nil {
   426  				t.Errorf("#%d: %v", i, err)
   427  				continue
   428  			}
   429  			continue
   430  		}
   431  		r.Reset(strings.NewReader(s))
   432  		got, err := ioutil.ReadAll(r)
   433  		switch s {
   434  		case encoded:
   435  			if err != nil {
   436  				t.Errorf("#%d: %v", i, err)
   437  				continue
   438  			}
   439  			if err := cmp(got, gold); err != nil {
   440  				t.Errorf("#%d: %v", i, err)
   441  				continue
   442  			}
   443  		case invalid:
   444  			if err == nil {
   445  				t.Errorf("#%d: got nil error, want non-nil", i)
   446  				continue
   447  			}
   448  		}
   449  	}
   450  }
   451  
   452  func TestWriterReset(t *testing.T) {
   453  	gold := bytes.Repeat([]byte("Not all those who wander are lost;\n"), 10000)
   454  	const n = 20
   455  	for _, buffered := range []bool{false, true} {
   456  		var w *Writer
   457  		if buffered {
   458  			w = NewBufferedWriter(nil)
   459  			defer w.Close()
   460  		} else {
   461  			w = NewWriter(nil)
   462  		}
   463  
   464  		var gots, wants [][]byte
   465  		failed := false
   466  		for i := 0; i <= n; i++ {
   467  			buf := new(bytes.Buffer)
   468  			w.Reset(buf)
   469  			want := gold[:len(gold)*i/n]
   470  			if _, err := w.Write(want); err != nil {
   471  				t.Errorf("#%d: Write: %v", i, err)
   472  				failed = true
   473  				continue
   474  			}
   475  			if buffered {
   476  				if err := w.Flush(); err != nil {
   477  					t.Errorf("#%d: Flush: %v", i, err)
   478  					failed = true
   479  					continue
   480  				}
   481  			}
   482  			got, err := ioutil.ReadAll(NewReader(buf))
   483  			if err != nil {
   484  				t.Errorf("#%d: ReadAll: %v", i, err)
   485  				failed = true
   486  				continue
   487  			}
   488  			gots = append(gots, got)
   489  			wants = append(wants, want)
   490  		}
   491  		if failed {
   492  			continue
   493  		}
   494  		for i := range gots {
   495  			if err := cmp(gots[i], wants[i]); err != nil {
   496  				t.Errorf("#%d: %v", i, err)
   497  			}
   498  		}
   499  	}
   500  }
   501  
   502  func TestWriterResetWithoutFlush(t *testing.T) {
   503  	buf0 := new(bytes.Buffer)
   504  	buf1 := new(bytes.Buffer)
   505  	w := NewBufferedWriter(buf0)
   506  	if _, err := w.Write([]byte("xxx")); err != nil {
   507  		t.Fatalf("Write #0: %v", err)
   508  	}
   509  	// Note that we don't Flush the Writer before calling Reset.
   510  	w.Reset(buf1)
   511  	if _, err := w.Write([]byte("yyy")); err != nil {
   512  		t.Fatalf("Write #1: %v", err)
   513  	}
   514  	if err := w.Flush(); err != nil {
   515  		t.Fatalf("Flush: %v", err)
   516  	}
   517  	got, err := ioutil.ReadAll(NewReader(buf1))
   518  	if err != nil {
   519  		t.Fatalf("ReadAll: %v", err)
   520  	}
   521  	if err := cmp(got, []byte("yyy")); err != nil {
   522  		t.Fatal(err)
   523  	}
   524  }
   525  
   526  type writeCounter int
   527  
   528  func (c *writeCounter) Write(p []byte) (int, error) {
   529  	*c++
   530  	return len(p), nil
   531  }
   532  
   533  // TestNumUnderlyingWrites tests that each Writer flush only makes one or two
   534  // Write calls on its underlying io.Writer, depending on whether or not the
   535  // flushed buffer was compressible.
   536  func TestNumUnderlyingWrites(t *testing.T) {
   537  	testCases := []struct {
   538  		input []byte
   539  		want  int
   540  	}{
   541  		{bytes.Repeat([]byte{'x'}, 100), 1},
   542  		{bytes.Repeat([]byte{'y'}, 100), 1},
   543  		{[]byte("ABCDEFGHIJKLMNOPQRST"), 2},
   544  	}
   545  
   546  	var c writeCounter
   547  	w := NewBufferedWriter(&c)
   548  	defer w.Close()
   549  	for i, tc := range testCases {
   550  		c = 0
   551  		if _, err := w.Write(tc.input); err != nil {
   552  			t.Errorf("#%d: Write: %v", i, err)
   553  			continue
   554  		}
   555  		if err := w.Flush(); err != nil {
   556  			t.Errorf("#%d: Flush: %v", i, err)
   557  			continue
   558  		}
   559  		if int(c) != tc.want {
   560  			t.Errorf("#%d: got %d underlying writes, want %d", i, c, tc.want)
   561  			continue
   562  		}
   563  	}
   564  }
   565  
   566  func benchDecode(b *testing.B, src []byte) {
   567  	encoded := Encode(nil, src)
   568  	// Bandwidth is in amount of uncompressed data.
   569  	b.SetBytes(int64(len(src)))
   570  	b.ResetTimer()
   571  	for i := 0; i < b.N; i++ {
   572  		Decode(src, encoded)
   573  	}
   574  }
   575  
   576  func benchEncode(b *testing.B, src []byte) {
   577  	// Bandwidth is in amount of uncompressed data.
   578  	b.SetBytes(int64(len(src)))
   579  	dst := make([]byte, MaxEncodedLen(len(src)))
   580  	b.ResetTimer()
   581  	for i := 0; i < b.N; i++ {
   582  		Encode(dst, src)
   583  	}
   584  }
   585  
   586  func readFile(b testing.TB, filename string) []byte {
   587  	src, err := ioutil.ReadFile(filename)
   588  	if err != nil {
   589  		b.Skipf("skipping benchmark: %v", err)
   590  	}
   591  	if len(src) == 0 {
   592  		b.Fatalf("%s has zero length", filename)
   593  	}
   594  	return src
   595  }
   596  
   597  // expand returns a slice of length n containing repeated copies of src.
   598  func expand(src []byte, n int) []byte {
   599  	dst := make([]byte, n)
   600  	for x := dst; len(x) > 0; {
   601  		i := copy(x, src)
   602  		x = x[i:]
   603  	}
   604  	return dst
   605  }
   606  
   607  func benchWords(b *testing.B, n int, decode bool) {
   608  	// Note: the file is OS-language dependent so the resulting values are not
   609  	// directly comparable for non-US-English OS installations.
   610  	data := expand(readFile(b, "/usr/share/dict/words"), n)
   611  	if decode {
   612  		benchDecode(b, data)
   613  	} else {
   614  		benchEncode(b, data)
   615  	}
   616  }
   617  
   618  func BenchmarkWordsDecode1e1(b *testing.B) { benchWords(b, 1e1, true) }
   619  func BenchmarkWordsDecode1e2(b *testing.B) { benchWords(b, 1e2, true) }
   620  func BenchmarkWordsDecode1e3(b *testing.B) { benchWords(b, 1e3, true) }
   621  func BenchmarkWordsDecode1e4(b *testing.B) { benchWords(b, 1e4, true) }
   622  func BenchmarkWordsDecode1e5(b *testing.B) { benchWords(b, 1e5, true) }
   623  func BenchmarkWordsDecode1e6(b *testing.B) { benchWords(b, 1e6, true) }
   624  func BenchmarkWordsEncode1e1(b *testing.B) { benchWords(b, 1e1, false) }
   625  func BenchmarkWordsEncode1e2(b *testing.B) { benchWords(b, 1e2, false) }
   626  func BenchmarkWordsEncode1e3(b *testing.B) { benchWords(b, 1e3, false) }
   627  func BenchmarkWordsEncode1e4(b *testing.B) { benchWords(b, 1e4, false) }
   628  func BenchmarkWordsEncode1e5(b *testing.B) { benchWords(b, 1e5, false) }
   629  func BenchmarkWordsEncode1e6(b *testing.B) { benchWords(b, 1e6, false) }
   630  
   631  func BenchmarkRandomEncode(b *testing.B) {
   632  	rng := rand.New(rand.NewSource(1))
   633  	data := make([]byte, 1<<20)
   634  	for i := range data {
   635  		data[i] = uint8(rng.Intn(256))
   636  	}
   637  	benchEncode(b, data)
   638  }
   639  
   640  // testFiles' values are copied directly from
   641  // https://raw.githubusercontent.com/google/snappy/master/snappy_unittest.cc
   642  // The label field is unused in snappy-go.
   643  //
   644  // If this list changes (due to the upstream C++ list changing), remember to
   645  // update the .gitignore file in this repository.
   646  var testFiles = []struct {
   647  	label     string
   648  	filename  string
   649  	sizeLimit int
   650  }{
   651  	{"html", "html", 0},
   652  	{"urls", "urls.10K", 0},
   653  	{"jpg", "fireworks.jpeg", 0},
   654  	{"jpg_200", "fireworks.jpeg", 200},
   655  	{"pdf", "paper-100k.pdf", 0},
   656  	{"html4", "html_x_4", 0},
   657  	{"txt1", "alice29.txt", 0},
   658  	{"txt2", "asyoulik.txt", 0},
   659  	{"txt3", "lcet10.txt", 0},
   660  	{"txt4", "plrabn12.txt", 0},
   661  	{"pb", "geo.protodata", 0},
   662  	{"gaviota", "kppkn.gtb", 0},
   663  }
   664  
   665  // The test data files are present at this canonical URL.
   666  const baseURL = "https://raw.githubusercontent.com/google/snappy/master/testdata/"
   667  
   668  func downloadTestdata(b *testing.B, basename string) (errRet error) {
   669  	filename := filepath.Join(*testdata, basename)
   670  	if stat, err := os.Stat(filename); err == nil && stat.Size() != 0 {
   671  		return nil
   672  	}
   673  
   674  	if !*download {
   675  		b.Skipf("test data not found; skipping benchmark without the -download flag")
   676  	}
   677  	// Download the official snappy C++ implementation reference test data
   678  	// files for benchmarking.
   679  	if err := os.Mkdir(*testdata, 0777); err != nil && !os.IsExist(err) {
   680  		return fmt.Errorf("failed to create testdata: %s", err)
   681  	}
   682  
   683  	f, err := os.Create(filename)
   684  	if err != nil {
   685  		return fmt.Errorf("failed to create %s: %s", filename, err)
   686  	}
   687  	defer f.Close()
   688  	defer func() {
   689  		if errRet != nil {
   690  			os.Remove(filename)
   691  		}
   692  	}()
   693  	url := baseURL + basename
   694  	resp, err := http.Get(url)
   695  	if err != nil {
   696  		return fmt.Errorf("failed to download %s: %s", url, err)
   697  	}
   698  	defer resp.Body.Close()
   699  	if s := resp.StatusCode; s != http.StatusOK {
   700  		return fmt.Errorf("downloading %s: HTTP status code %d (%s)", url, s, http.StatusText(s))
   701  	}
   702  	_, err = io.Copy(f, resp.Body)
   703  	if err != nil {
   704  		return fmt.Errorf("failed to download %s to %s: %s", url, filename, err)
   705  	}
   706  	return nil
   707  }
   708  
   709  func benchFile(b *testing.B, n int, decode bool) {
   710  	if err := downloadTestdata(b, testFiles[n].filename); err != nil {
   711  		b.Fatalf("failed to download testdata: %s", err)
   712  	}
   713  	data := readFile(b, filepath.Join(*testdata, testFiles[n].filename))
   714  	if n := testFiles[n].sizeLimit; 0 < n && n < len(data) {
   715  		data = data[:n]
   716  	}
   717  	if decode {
   718  		benchDecode(b, data)
   719  	} else {
   720  		benchEncode(b, data)
   721  	}
   722  }
   723  
   724  // Naming convention is kept similar to what snappy's C++ implementation uses.
   725  func Benchmark_UFlat0(b *testing.B)  { benchFile(b, 0, true) }
   726  func Benchmark_UFlat1(b *testing.B)  { benchFile(b, 1, true) }
   727  func Benchmark_UFlat2(b *testing.B)  { benchFile(b, 2, true) }
   728  func Benchmark_UFlat3(b *testing.B)  { benchFile(b, 3, true) }
   729  func Benchmark_UFlat4(b *testing.B)  { benchFile(b, 4, true) }
   730  func Benchmark_UFlat5(b *testing.B)  { benchFile(b, 5, true) }
   731  func Benchmark_UFlat6(b *testing.B)  { benchFile(b, 6, true) }
   732  func Benchmark_UFlat7(b *testing.B)  { benchFile(b, 7, true) }
   733  func Benchmark_UFlat8(b *testing.B)  { benchFile(b, 8, true) }
   734  func Benchmark_UFlat9(b *testing.B)  { benchFile(b, 9, true) }
   735  func Benchmark_UFlat10(b *testing.B) { benchFile(b, 10, true) }
   736  func Benchmark_UFlat11(b *testing.B) { benchFile(b, 11, true) }
   737  func Benchmark_ZFlat0(b *testing.B)  { benchFile(b, 0, false) }
   738  func Benchmark_ZFlat1(b *testing.B)  { benchFile(b, 1, false) }
   739  func Benchmark_ZFlat2(b *testing.B)  { benchFile(b, 2, false) }
   740  func Benchmark_ZFlat3(b *testing.B)  { benchFile(b, 3, false) }
   741  func Benchmark_ZFlat4(b *testing.B)  { benchFile(b, 4, false) }
   742  func Benchmark_ZFlat5(b *testing.B)  { benchFile(b, 5, false) }
   743  func Benchmark_ZFlat6(b *testing.B)  { benchFile(b, 6, false) }
   744  func Benchmark_ZFlat7(b *testing.B)  { benchFile(b, 7, false) }
   745  func Benchmark_ZFlat8(b *testing.B)  { benchFile(b, 8, false) }
   746  func Benchmark_ZFlat9(b *testing.B)  { benchFile(b, 9, false) }
   747  func Benchmark_ZFlat10(b *testing.B) { benchFile(b, 10, false) }
   748  func Benchmark_ZFlat11(b *testing.B) { benchFile(b, 11, false) }
   749  
   750  // Prints compression size and ratio.
   751  func BenchmarkCompressionSize(b *testing.B) {
   752  	fmt.Println("\ndata\tinsize\toutsize\treference\treduction\tref-red\tr-delta")
   753  	for i, tf := range testFiles {
   754  		if err := downloadTestdata(b, tf.filename); err != nil {
   755  			b.Fatalf("failed to download testdata: %s", err)
   756  		}
   757  		src := readFile(b, filepath.Join(*testdata, tf.filename))
   758  		dst := Encode(nil, src)
   759  		odst := old.Encode(nil, src)
   760  
   761  		rthis := 100 - float64(len(dst))/float64(len(src))*100
   762  		rold := 100 - float64(len(odst))/float64(len(src))*100
   763  		fmt.Printf("Flat%d:\t%s\t%d\t%d\t%d\t%.2f%%\t%.2f%%\t%.2f%%\n", i, tf.label, len(src), len(dst), len(odst), rthis, rthis, rthis-rold)
   764  	}
   765  	// BenchmarkCompressionSize isn't really a benchmark, in the sense of "I
   766  	// want to run some code b.N times and see how long it takes". Instead, it
   767  	// prints out compressed sizes for the set of testFiles. Like the ns/op or
   768  	// MB/s metrics that the Benchmark_Z* benchmarks above give, this
   769  	// compression metric is also useful to know when tweaking the encoding
   770  	// algorithm, so this function is also run as a 'benchmark'.
   771  	b.Skip("ok")
   772  }
   773  
   774  func benchFileStream(b *testing.B, n int, decode bool) {
   775  	if err := downloadTestdata(b, testFiles[n].filename); err != nil {
   776  		b.Fatalf("failed to download testdata: %s", err)
   777  	}
   778  	data := readFile(b, filepath.Join(*testdata, testFiles[n].filename))
   779  	if decode {
   780  		benchDecodeStream(b, data)
   781  	} else {
   782  		benchEncodeStream(b, data)
   783  	}
   784  }
   785  
   786  func benchDecodeStream(b *testing.B, src []byte) {
   787  	in := bytes.NewBuffer(nil)
   788  	_, _ = NewWriter(in).Write(src)
   789  	encoded := in.Bytes()
   790  	r := NewReader(in)
   791  
   792  	// Bandwidth is in amount of uncompressed data.
   793  	b.SetBytes(int64(len(src)))
   794  	b.ResetTimer()
   795  	for i := 0; i < b.N; i++ {
   796  		r.Reset(bytes.NewBuffer(encoded))
   797  		io.Copy(ioutil.Discard, r)
   798  	}
   799  }
   800  
   801  func benchEncodeStream(b *testing.B, src []byte) {
   802  	r := NewWriter(ioutil.Discard)
   803  	// Bandwidth is in amount of uncompressed data.
   804  	b.SetBytes(int64(len(src)))
   805  	b.ResetTimer()
   806  	for i := 0; i < b.N; i++ {
   807  		_, err := r.Write(src)
   808  		if err != nil {
   809  			b.Fatal(err)
   810  		}
   811  	}
   812  }
   813  
   814  /*
   815  func Benchmark_Stream_UFlat0(b *testing.B)  { benchFileStream(b, 0, true) }
   816  func Benchmark_Stream_UFlat1(b *testing.B)  { benchFileStream(b, 1, true) }
   817  func Benchmark_Stream_UFlat2(b *testing.B)  { benchFileStream(b, 2, true) }
   818  func Benchmark_Stream_UFlat3(b *testing.B)  { benchFileStream(b, 3, true) }
   819  func Benchmark_Stream_UFlat4(b *testing.B)  { benchFileStream(b, 4, true) }
   820  func Benchmark_Stream_UFlat5(b *testing.B)  { benchFileStream(b, 5, true) }
   821  func Benchmark_Stream_UFlat6(b *testing.B)  { benchFileStream(b, 6, true) }
   822  func Benchmark_Stream_UFlat7(b *testing.B)  { benchFileStream(b, 7, true) }
   823  func Benchmark_Stream_UFlat8(b *testing.B)  { benchFileStream(b, 8, true) }
   824  func Benchmark_Stream_UFlat9(b *testing.B)  { benchFileStream(b, 9, true) }
   825  func Benchmark_Stream_UFlat10(b *testing.B) { benchFileStream(b, 10, true) }
   826  func Benchmark_Stream_UFlat11(b *testing.B) { benchFileStream(b, 11, true) }
   827  func Benchmark_Stream_ZFlat0(b *testing.B)  { benchFileStream(b, 0, false) }
   828  func Benchmark_Stream_ZFlat1(b *testing.B)  { benchFileStream(b, 1, false) }
   829  func Benchmark_Stream_ZFlat2(b *testing.B)  { benchFileStream(b, 2, false) }
   830  func Benchmark_Stream_ZFlat3(b *testing.B)  { benchFileStream(b, 3, false) }
   831  func Benchmark_Stream_ZFlat4(b *testing.B)  { benchFileStream(b, 4, false) }
   832  func Benchmark_Stream_ZFlat5(b *testing.B)  { benchFileStream(b, 5, false) }
   833  func Benchmark_Stream_ZFlat6(b *testing.B)  { benchFileStream(b, 6, false) }
   834  func Benchmark_Stream_ZFlat7(b *testing.B)  { benchFileStream(b, 7, false) }
   835  func Benchmark_Stream_ZFlat8(b *testing.B)  { benchFileStream(b, 8, false) }
   836  func Benchmark_Stream_ZFlat9(b *testing.B)  { benchFileStream(b, 9, false) }
   837  func Benchmark_Stream_ZFlat10(b *testing.B) { benchFileStream(b, 10, false) }
   838  func Benchmark_Stream_ZFlat11(b *testing.B) { benchFileStream(b, 11, false) }
   839  */