blob: e230d22d4315584702e5f89ace19f6ee8088b547 [file] [log] [blame]
// Copyright 2009 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 gob
import (
"bytes"
"reflect"
"testing"
)
type typeT struct {
id typeId
str string
}
var basicTypes = []typeT{
{tBool, "bool"},
{tInt, "int"},
{tUint, "uint"},
{tFloat, "float"},
{tBytes, "bytes"},
{tString, "string"},
}
func getTypeUnlocked(name string, rt reflect.Type) gobType {
typeLock.Lock()
defer typeLock.Unlock()
t, err := getBaseType(name, rt)
if err != nil {
panic("getTypeUnlocked: " + err.Error())
}
return t
}
// Sanity checks
func TestBasic(t *testing.T) {
for _, tt := range basicTypes {
if tt.id.string() != tt.str {
t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
}
if tt.id == 0 {
t.Errorf("id for %q is zero", tt.str)
}
}
}
// Reregister some basic types to check registration is idempotent.
func TestReregistration(t *testing.T) {
newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0)))
if newtyp != tInt.gobType() {
t.Errorf("reregistration of %s got new type", newtyp.string())
}
newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0)))
if newtyp != tUint.gobType() {
t.Errorf("reregistration of %s got new type", newtyp.string())
}
newtyp = getTypeUnlocked("string", reflect.TypeOf("hello"))
if newtyp != tString.gobType() {
t.Errorf("reregistration of %s got new type", newtyp.string())
}
}
func TestArrayType(t *testing.T) {
var a3 [3]int
a3int := getTypeUnlocked("foo", reflect.TypeOf(a3))
newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3))
if a3int != newa3int {
t.Errorf("second registration of [3]int creates new type")
}
var a4 [4]int
a4int := getTypeUnlocked("goo", reflect.TypeOf(a4))
if a3int == a4int {
t.Errorf("registration of [3]int creates same type as [4]int")
}
var b3 [3]bool
a3bool := getTypeUnlocked("", reflect.TypeOf(b3))
if a3int == a3bool {
t.Errorf("registration of [3]bool creates same type as [3]int")
}
str := a3bool.string()
expected := "[3]bool"
if str != expected {
t.Errorf("array printed as %q; expected %q", str, expected)
}
}
func TestSliceType(t *testing.T) {
var s []int
sint := getTypeUnlocked("slice", reflect.TypeOf(s))
var news []int
newsint := getTypeUnlocked("slice1", reflect.TypeOf(news))
if sint != newsint {
t.Errorf("second registration of []int creates new type")
}
var b []bool
sbool := getTypeUnlocked("", reflect.TypeOf(b))
if sbool == sint {
t.Errorf("registration of []bool creates same type as []int")
}
str := sbool.string()
expected := "[]bool"
if str != expected {
t.Errorf("slice printed as %q; expected %q", str, expected)
}
}
func TestMapType(t *testing.T) {
var m map[string]int
mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m))
var newm map[string]int
newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm))
if mapStringInt != newMapStringInt {
t.Errorf("second registration of map[string]int creates new type")
}
var b map[string]bool
mapStringBool := getTypeUnlocked("", reflect.TypeOf(b))
if mapStringBool == mapStringInt {
t.Errorf("registration of map[string]bool creates same type as map[string]int")
}
str := mapStringBool.string()
expected := "map[string]bool"
if str != expected {
t.Errorf("map printed as %q; expected %q", str, expected)
}
}
type Bar struct {
X string
}
// This structure has pointers and refers to itself, making it a good test case.
type Foo struct {
A int
B int32 // will become int
C string
D []byte
E *float64 // will become float64
F ****float64 // will become float64
G *Bar
H *Bar // should not interpolate the definition of Bar again
I *Foo // will not explode
}
func TestStructType(t *testing.T) {
sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{}))
str := sstruct.string()
// If we can print it correctly, we built it correctly.
expected := "Foo = struct { A int; B int; C string; D bytes; E float; F float; G Bar = struct { X string; }; H Bar; I Foo; }"
if str != expected {
t.Errorf("struct printed as %q; expected %q", str, expected)
}
}
// Should be OK to register the same type multiple times, as long as they're
// at the same level of indirection.
func TestRegistration(t *testing.T) {
type T struct{ a int }
Register(new(T))
Register(new(T))
}
type N1 struct{}
type N2 struct{}
// See comment in type.go/Register.
func TestRegistrationNaming(t *testing.T) {
testCases := []struct {
t interface{}
name string
}{
{&N1{}, "*gob.N1"},
{N2{}, "encoding/gob.N2"},
}
for _, tc := range testCases {
Register(tc.t)
tct := reflect.TypeOf(tc.t)
registerLock.RLock()
ct := nameToConcreteType[tc.name]
registerLock.RUnlock()
if ct != tct {
t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct)
}
// concreteTypeToName is keyed off the base type.
if tct.Kind() == reflect.Ptr {
tct = tct.Elem()
}
if n := concreteTypeToName[tct]; n != tc.name {
t.Errorf("concreteTypeToName[%v] got %v, want %v", tct, n, tc.name)
}
}
}
func TestStressParallel(t *testing.T) {
type T2 struct{ A int }
c := make(chan bool)
const N = 10
for i := 0; i < N; i++ {
go func() {
p := new(T2)
Register(p)
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(p)
if err != nil {
t.Error("encoder fail:", err)
}
dec := NewDecoder(b)
err = dec.Decode(p)
if err != nil {
t.Error("decoder fail:", err)
}
c <- true
}()
}
for i := 0; i < N; i++ {
<-c
}
}