blob: d4b0f63b1a6b6aae667f2edaf440ace80ccef92a [file] [log] [blame]
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package typeutil_test
// TODO(adonovan):
// - test use of explicit hasher across two maps.
// - test hashcodes are consistent with equals for a range of types
// (e.g. all types generated by type-checking some body of real code).
import (
"go/types"
"testing"
"golang.org/x/tools/go/types/typeutil"
)
var (
tStr = types.Typ[types.String] // string
tPStr1 = types.NewPointer(tStr) // *string
tPStr2 = types.NewPointer(tStr) // *string, again
tInt = types.Typ[types.Int] // int
tChanInt1 = types.NewChan(types.RecvOnly, tInt) // <-chan int
tChanInt2 = types.NewChan(types.RecvOnly, tInt) // <-chan int, again
)
func checkEqualButNotIdentical(t *testing.T, x, y types.Type, comment string) {
if !types.Identical(x, y) {
t.Errorf("%s: not equal: %s, %s", comment, x, y)
}
if x == y {
t.Errorf("%s: identical: %v, %v", comment, x, y)
}
}
func TestAxioms(t *testing.T) {
checkEqualButNotIdentical(t, tPStr1, tPStr2, "tPstr{1,2}")
checkEqualButNotIdentical(t, tChanInt1, tChanInt2, "tChanInt{1,2}")
}
func TestMap(t *testing.T) {
var tmap *typeutil.Map
// All methods but Set are safe on on (*T)(nil).
tmap.Len()
tmap.At(tPStr1)
tmap.Delete(tPStr1)
tmap.KeysString()
_ = tmap.String()
tmap = new(typeutil.Map)
// Length of empty map.
if l := tmap.Len(); l != 0 {
t.Errorf("Len() on empty Map: got %d, want 0", l)
}
// At of missing key.
if v := tmap.At(tPStr1); v != nil {
t.Errorf("At() on empty Map: got %v, want nil", v)
}
// Deletion of missing key.
if tmap.Delete(tPStr1) {
t.Errorf("Delete() on empty Map: got true, want false")
}
// Set of new key.
if prev := tmap.Set(tPStr1, "*string"); prev != nil {
t.Errorf("Set() on empty Map returned non-nil previous value %s", prev)
}
// Now: {*string: "*string"}
// Length of non-empty map.
if l := tmap.Len(); l != 1 {
t.Errorf("Len(): got %d, want 1", l)
}
// At via insertion key.
if v := tmap.At(tPStr1); v != "*string" {
t.Errorf("At(): got %q, want \"*string\"", v)
}
// At via equal key.
if v := tmap.At(tPStr2); v != "*string" {
t.Errorf("At(): got %q, want \"*string\"", v)
}
// Iteration over sole entry.
tmap.Iterate(func(key types.Type, value interface{}) {
if key != tPStr1 {
t.Errorf("Iterate: key: got %s, want %s", key, tPStr1)
}
if want := "*string"; value != want {
t.Errorf("Iterate: value: got %s, want %s", value, want)
}
})
// Setion with key equal to present one.
if prev := tmap.Set(tPStr2, "*string again"); prev != "*string" {
t.Errorf("Set() previous value: got %s, want \"*string\"", prev)
}
// Setion of another association.
if prev := tmap.Set(tChanInt1, "<-chan int"); prev != nil {
t.Errorf("Set() previous value: got %s, want nil", prev)
}
// Now: {*string: "*string again", <-chan int: "<-chan int"}
want1 := "{*string: \"*string again\", <-chan int: \"<-chan int\"}"
want2 := "{<-chan int: \"<-chan int\", *string: \"*string again\"}"
if s := tmap.String(); s != want1 && s != want2 {
t.Errorf("String(): got %s, want %s", s, want1)
}
want1 = "{*string, <-chan int}"
want2 = "{<-chan int, *string}"
if s := tmap.KeysString(); s != want1 && s != want2 {
t.Errorf("KeysString(): got %s, want %s", s, want1)
}
// Keys().
I := types.Identical
switch k := tmap.Keys(); {
case I(k[0], tChanInt1) && I(k[1], tPStr1): // ok
case I(k[1], tChanInt1) && I(k[0], tPStr1): // ok
default:
t.Errorf("Keys(): got %v, want %s", k, want2)
}
if l := tmap.Len(); l != 2 {
t.Errorf("Len(): got %d, want 1", l)
}
// At via original key.
if v := tmap.At(tPStr1); v != "*string again" {
t.Errorf("At(): got %q, want \"*string again\"", v)
}
hamming := 1
tmap.Iterate(func(key types.Type, value interface{}) {
switch {
case I(key, tChanInt1):
hamming *= 2 // ok
case I(key, tPStr1):
hamming *= 3 // ok
}
})
if hamming != 6 {
t.Errorf("Iterate: hamming: got %d, want %d", hamming, 6)
}
if v := tmap.At(tChanInt2); v != "<-chan int" {
t.Errorf("At(): got %q, want \"<-chan int\"", v)
}
// Deletion with key equal to present one.
if !tmap.Delete(tChanInt2) {
t.Errorf("Delete() of existing key: got false, want true")
}
// Now: {*string: "*string again"}
if l := tmap.Len(); l != 1 {
t.Errorf("Len(): got %d, want 1", l)
}
// Deletion again.
if !tmap.Delete(tPStr2) {
t.Errorf("Delete() of existing key: got false, want true")
}
// Now: {}
if l := tmap.Len(); l != 0 {
t.Errorf("Len(): got %d, want %d", l, 0)
}
if s := tmap.String(); s != "{}" {
t.Errorf("Len(): got %q, want %q", s, "")
}
}