...

Source file src/github.com/cespare/xxhash/v2/xxhash_test.go

Documentation: github.com/cespare/xxhash/v2

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

View as plain text