...

Source file src/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_test.go

Documentation: github.com/klauspost/compress/zstd/internal/xxhash

     1  package xxhash
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  func TestAll(t *testing.T) {
    12  	for _, tt := range []struct {
    13  		name  string
    14  		input string
    15  		want  uint64
    16  	}{
    17  		{"empty", "", 0xef46db3751d8e999},
    18  		{"a", "a", 0xd24ec4f1a98c6e5b},
    19  		{"as", "as", 0x1c330fb2d66be179},
    20  		{"asd", "asd", 0x631c37ce72a97393},
    21  		{"asdf", "asdf", 0x415872f599cea71e},
    22  		{
    23  			"len=63",
    24  			// Exactly 63 characters, which exercises all code paths.
    25  			"Call me Ishmael. Some years ago--never mind how long precisely-",
    26  			0x02a2e85470d6fd96,
    27  		},
    28  	} {
    29  		lastChunkSize := len(tt.input)
    30  		if lastChunkSize == 0 {
    31  			lastChunkSize = 1
    32  		}
    33  		for chunkSize := 1; chunkSize <= lastChunkSize; chunkSize++ {
    34  			name := fmt.Sprintf("%s,chunkSize=%d", tt.name, chunkSize)
    35  			t.Run(name, func(t *testing.T) {
    36  				testDigest(t, tt.input, chunkSize, tt.want)
    37  			})
    38  		}
    39  		t.Run(tt.name, func(t *testing.T) { testSum(t, tt.input, tt.want) })
    40  	}
    41  }
    42  
    43  func testDigest(t *testing.T, input string, chunkSize int, want uint64) {
    44  	d := New()
    45  	ds := New() // uses WriteString
    46  	for i := 0; i < len(input); i += chunkSize {
    47  		chunk := input[i:]
    48  		if len(chunk) > chunkSize {
    49  			chunk = chunk[:chunkSize]
    50  		}
    51  		n, err := d.Write([]byte(chunk))
    52  		if err != nil || n != len(chunk) {
    53  			t.Fatalf("Digest.Write: got (%d, %v); want (%d, nil)", n, err, len(chunk))
    54  		}
    55  		n, err = ds.WriteString(chunk)
    56  		if err != nil || n != len(chunk) {
    57  			t.Fatalf("Digest.WriteString: got (%d, %v); want (%d, nil)", n, err, len(chunk))
    58  		}
    59  	}
    60  	if got := d.Sum64(); got != want {
    61  		t.Fatalf("Digest.Sum64: got 0x%x; want 0x%x", got, want)
    62  	}
    63  	if got := ds.Sum64(); got != want {
    64  		t.Fatalf("Digest.Sum64 (WriteString): got 0x%x; want 0x%x", got, want)
    65  	}
    66  	var b [8]byte
    67  	binary.BigEndian.PutUint64(b[:], want)
    68  	if got := d.Sum(nil); !bytes.Equal(got, b[:]) {
    69  		t.Fatalf("Sum: got %v; want %v", got, b[:])
    70  	}
    71  }
    72  
    73  func testSum(t *testing.T, input string, want uint64) {
    74  	if got := Sum64([]byte(input)); got != want {
    75  		t.Fatalf("Sum64: got 0x%x; want 0x%x", got, want)
    76  	}
    77  	if got := Sum64String(input); got != want {
    78  		t.Fatalf("Sum64String: got 0x%x; want 0x%x", got, want)
    79  	}
    80  }
    81  
    82  func TestReset(t *testing.T) {
    83  	parts := []string{"The quic", "k br", "o", "wn fox jumps", " ov", "er the lazy ", "dog."}
    84  	d := New()
    85  	for _, part := range parts {
    86  		d.Write([]byte(part))
    87  	}
    88  	h0 := d.Sum64()
    89  
    90  	d.Reset()
    91  	d.Write([]byte(strings.Join(parts, "")))
    92  	h1 := d.Sum64()
    93  
    94  	if h0 != h1 {
    95  		t.Errorf("0x%x != 0x%x", h0, h1)
    96  	}
    97  }
    98  
    99  func TestBinaryMarshaling(t *testing.T) {
   100  	d := New()
   101  	d.WriteString("abc")
   102  	b, err := d.MarshalBinary()
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	d = New()
   107  	d.WriteString("junk")
   108  	if err := d.UnmarshalBinary(b); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	d.WriteString("def")
   112  	if got, want := d.Sum64(), Sum64String("abcdef"); got != want {
   113  		t.Fatalf("after MarshalBinary+UnmarshalBinary, got 0x%x; want 0x%x", got, want)
   114  	}
   115  
   116  	d0 := New()
   117  	d1 := New()
   118  	for i := 0; i < 64; i++ {
   119  		b, err := d0.MarshalBinary()
   120  		if err != nil {
   121  			t.Fatal(err)
   122  		}
   123  		d0 = new(Digest)
   124  		if err := d0.UnmarshalBinary(b); err != nil {
   125  			t.Fatal(err)
   126  		}
   127  		if got, want := d0.Sum64(), d1.Sum64(); got != want {
   128  			t.Fatalf("after %d Writes, unmarshaled Digest gave sum 0x%x; want 0x%x", i, got, want)
   129  		}
   130  
   131  		d0.Write([]byte{'a'})
   132  		d1.Write([]byte{'a'})
   133  	}
   134  }
   135  
   136  var sink uint64
   137  
   138  func TestAllocs(t *testing.T) {
   139  	const shortStr = "abcdefghijklmnop"
   140  	// Sum64([]byte(shortString)) shouldn't allocate because the
   141  	// intermediate []byte ought not to escape.
   142  	// (See https://github.com/cespare/xxhash/pull/2.)
   143  	t.Run("Sum64", func(t *testing.T) {
   144  		testAllocs(t, func() {
   145  			sink = Sum64([]byte(shortStr))
   146  		})
   147  	})
   148  	// Creating and using a Digest shouldn't allocate because its methods
   149  	// shouldn't make it escape. (A previous version of New returned a
   150  	// hash.Hash64 which forces an allocation.)
   151  	t.Run("Digest", func(t *testing.T) {
   152  		b := []byte("asdf")
   153  		testAllocs(t, func() {
   154  			d := New()
   155  			d.Write(b)
   156  			sink = d.Sum64()
   157  		})
   158  	})
   159  }
   160  
   161  func testAllocs(t *testing.T, fn func()) {
   162  	t.Helper()
   163  	if allocs := int(testing.AllocsPerRun(10, fn)); allocs > 0 {
   164  		t.Fatalf("got %d allocation(s) (want zero)", allocs)
   165  	}
   166  }
   167  

View as plain text