util/deephash: include type as part of hash for interfaces (#2476)

A Go interface may hold any number of different concrete types.
Just because two underlying values hash to the same thing
does not mean the two values are identical if they have different
concrete types. As such, include the type in the hash.
This commit is contained in:
Joe Tsai
2021-07-21 10:26:04 -07:00
committed by GitHub
parent 3a4201e773
commit 23ad028414
2 changed files with 48 additions and 1 deletions
+28
View File
@@ -5,6 +5,7 @@
package deephash
import (
"archive/tar"
"bufio"
"bytes"
"fmt"
@@ -21,6 +22,33 @@ import (
"tailscale.com/wgengine/wgcfg"
)
func TestHash(t *testing.T) {
type tuple [2]interface{}
type iface struct{ X interface{} }
type MyBool bool
type MyHeader tar.Header
tests := []struct {
in tuple
wantEq bool
}{
{in: tuple{iface{MyBool(true)}, iface{MyBool(true)}}, wantEq: true},
{in: tuple{iface{true}, iface{MyBool(true)}}, wantEq: false},
{in: tuple{iface{MyHeader{}}, iface{MyHeader{}}}, wantEq: true},
{in: tuple{iface{MyHeader{}}, iface{tar.Header{}}}, wantEq: false},
{in: tuple{iface{&MyHeader{}}, iface{&MyHeader{}}}, wantEq: true},
{in: tuple{iface{&MyHeader{}}, iface{&tar.Header{}}}, wantEq: false},
{in: tuple{iface{[]map[string]MyBool{}}, iface{[]map[string]MyBool{}}}, wantEq: true},
{in: tuple{iface{[]map[string]bool{}}, iface{[]map[string]MyBool{}}}, wantEq: false},
}
for _, tt := range tests {
gotEq := Hash(tt.in[0]) == Hash(tt.in[1])
if gotEq != tt.wantEq {
t.Errorf("(Hash(%v) == Hash(%v)) = %v, want %v", tt.in[0], tt.in[1], gotEq, tt.wantEq)
}
}
}
func TestDeepHash(t *testing.T) {
// v contains the types of values we care about for our current callers.
// Mostly we're just testing that we don't panic on handled types.