github.com/arr-ai/hash@v0.8.0/hash_test.go (about)

     1  package hash
     2  
     3  import (
     4  	"math"
     5  	"math/rand"
     6  	"testing"
     7  	"unsafe"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  )
    11  
    12  func TestHash64(t *testing.T) {
    13  	if Interface(uint64(0), 0) == 0 {
    14  		t.Error()
    15  	}
    16  }
    17  
    18  func TestHash64String(t *testing.T) {
    19  	if Interface("hello", 0) == 0 {
    20  		t.Error()
    21  	}
    22  }
    23  
    24  func TestHashMatchesEquality(t *testing.T) {
    25  	t.Logf("%d unique elements", len(cornucopia))
    26  	total := 0
    27  	falsePositives := 0
    28  	for _, seeds := range [][2]uintptr{{0, 0}, {0, 1}, {0, 2}, {1, 1}, {1, 2}} {
    29  		aSeed := seeds[0]
    30  		bSeed := seeds[1]
    31  		for _, a := range cornucopia {
    32  			for _, b := range cornucopia {
    33  				if aSeed == bSeed && a == b {
    34  					assert.Equal(t, Interface(a, aSeed), Interface(b, bSeed),
    35  						"a=%v b=%v hash(a)=%v hash(b)=%v",
    36  						a, b, Interface(a, aSeed), Interface(b, aSeed))
    37  				} else if Interface(a, aSeed) == Interface(b, bSeed) {
    38  					h := Interface(a, aSeed)
    39  					_ = Interface(b, bSeed)
    40  					t.Logf("\nhash(%#v %[1]T, %v) ==\nhash(%#v %[3]T, %v) == %d",
    41  						a, aSeed, b, bSeed, h)
    42  					falsePositives++
    43  				}
    44  				total++
    45  			}
    46  		}
    47  	}
    48  	assert.LessOrEqual(t, falsePositives, total/100, total)
    49  }
    50  
    51  func BenchmarkHash(b *testing.B) {
    52  	r := rand.New(rand.NewSource(0))
    53  	for i := 0; i < b.N; i++ {
    54  		Interface(cornucopia[r.Int()%len(cornucopia)], 0)
    55  	}
    56  }
    57  
    58  var cornucopia = func() []interface{} {
    59  	x := 42
    60  	result := []interface{}{
    61  		false,
    62  		true,
    63  		&x,
    64  		&[]int{43}[0],
    65  		&[]string{"hello"}[0],
    66  		uintptr(unsafe.Pointer(&x)),
    67  		unsafe.Pointer(nil),
    68  		unsafe.Pointer(&x),
    69  		unsafe.Pointer(uintptr(unsafe.Pointer(&x))),
    70  		[...]int{},
    71  		[...]int{1, 2, 3, 4, 5},
    72  		[...]int{5, 4, 3, 2, 1},
    73  	}
    74  
    75  	// The following number lists are massive overkill, but it can't hurt.
    76  
    77  	for _, i := range []int64{
    78  		-43, -42, -10, -1, 0, 1, 10, 42,
    79  		math.MaxInt64, math.MaxInt64 - 1,
    80  		math.MinInt64, math.MinInt64 + 1,
    81  	} {
    82  		result = append(result, int(i), int8(i), int16(i), int32(i), i)
    83  	}
    84  
    85  	for _, i := range []uint64{0, 42} {
    86  		result = append(result, uint(i), uint8(i), uint16(i), uint32(i), i)
    87  	}
    88  
    89  	floats := []float64{
    90  		0, 42, math.Pi,
    91  		math.MaxFloat32, math.SmallestNonzeroFloat32,
    92  		math.MaxFloat64, math.SmallestNonzeroFloat64,
    93  	}
    94  
    95  	for _, f := range floats {
    96  		result = append(result, float32(f), f)
    97  	}
    98  
    99  	for _, re := range floats {
   100  		for _, im := range floats {
   101  			result = append(result, complex(float32(re), float32(im)))
   102  			result = append(result, complex(re, im))
   103  		}
   104  	}
   105  
   106  	for _, s := range []string{
   107  		"",
   108  		"a",
   109  		"b",
   110  		"hello",
   111  		"-------------------------------------------------------",
   112  		"--------------------------------------------------------",
   113  		"--------------------------------------------------------\000",
   114  	} {
   115  		result = append(result, s)
   116  	}
   117  
   118  	// Dedupe
   119  	m := map[interface{}]struct{}{}
   120  	for _, i := range result {
   121  		m[i] = struct{}{}
   122  	}
   123  
   124  	for i := range m {
   125  		result = append(result, i)
   126  	}
   127  
   128  	return result
   129  }()