| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package deephash
- import (
- "io"
- "reflect"
- "testing"
- "time"
- "unsafe"
- "tailscale.com/tailcfg"
- "tailscale.com/types/structs"
- )
- func TestTypeIsMemHashable(t *testing.T) {
- tests := []struct {
- val any
- want bool
- }{
- {true, true},
- {uint(1), true},
- {uint8(1), true},
- {uint16(1), true},
- {uint32(1), true},
- {uint64(1), true},
- {uintptr(1), true},
- {int(1), true},
- {int8(1), true},
- {int16(1), true},
- {int32(1), true},
- {int64(1), true},
- {float32(1), true},
- {float64(1), true},
- {complex64(1), true},
- {complex128(1), true},
- {[32]byte{}, true},
- {func() {}, false},
- {make(chan int), false},
- {struct{ io.Writer }{nil}, false},
- {unsafe.Pointer(nil), false},
- {new(int), false},
- {TwoInts{}, true},
- {[4]TwoInts{}, true},
- {IntThenByte{}, false},
- {[4]IntThenByte{}, false},
- {tailcfg.PortRange{}, true},
- {int16(0), true},
- {struct {
- _ int
- _ int
- }{}, true},
- {struct {
- _ int
- _ uint8
- _ int
- }{}, false}, // gap
- {struct {
- _ structs.Incomparable // if not last, zero-width
- x int
- }{}, true},
- {struct {
- x int
- _ structs.Incomparable // zero-width last: has space, can't memhash
- }{},
- false},
- {[0]chan bool{}, true},
- {struct{ f [0]func() }{}, true},
- {&selfHasherPointerRecv{}, false},
- }
- for _, tt := range tests {
- got := typeIsMemHashable(reflect.TypeOf(tt.val))
- if got != tt.want {
- t.Errorf("for type %T: got %v, want %v", tt.val, got, tt.want)
- }
- }
- }
- func TestTypeIsRecursive(t *testing.T) {
- type RecursiveStruct struct {
- _ *RecursiveStruct
- }
- type RecursiveChan chan *RecursiveChan
- tests := []struct {
- val any
- want bool
- }{
- {val: 42, want: false},
- {val: "string", want: false},
- {val: 1 + 2i, want: false},
- {val: struct{}{}, want: false},
- {val: (*RecursiveStruct)(nil), want: true},
- {val: RecursiveStruct{}, want: true},
- {val: time.Unix(0, 0), want: false},
- {val: structs.Incomparable{}, want: false}, // ignore its [0]func()
- {val: tailcfg.NetPortRange{}, want: false}, // uses structs.Incomparable
- {val: (*tailcfg.Node)(nil), want: false},
- {val: map[string]bool{}, want: false},
- {val: func() {}, want: false},
- {val: make(chan int), want: false},
- {val: unsafe.Pointer(nil), want: false},
- {val: make(RecursiveChan), want: true},
- {val: make(chan int), want: false},
- {val: (*selfHasherPointerRecv)(nil), want: false},
- }
- for _, tt := range tests {
- got := typeIsRecursive(reflect.TypeOf(tt.val))
- if got != tt.want {
- t.Errorf("for type %T: got %v, want %v", tt.val, got, tt.want)
- }
- }
- }
|