Home | History | Annotate | Download | only in gob
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package gob
      6 
      7 import (
      8 	"bytes"
      9 	"reflect"
     10 	"testing"
     11 )
     12 
     13 type typeT struct {
     14 	id  typeId
     15 	str string
     16 }
     17 
     18 var basicTypes = []typeT{
     19 	{tBool, "bool"},
     20 	{tInt, "int"},
     21 	{tUint, "uint"},
     22 	{tFloat, "float"},
     23 	{tBytes, "bytes"},
     24 	{tString, "string"},
     25 }
     26 
     27 func getTypeUnlocked(name string, rt reflect.Type) gobType {
     28 	typeLock.Lock()
     29 	defer typeLock.Unlock()
     30 	t, err := getBaseType(name, rt)
     31 	if err != nil {
     32 		panic("getTypeUnlocked: " + err.Error())
     33 	}
     34 	return t
     35 }
     36 
     37 // Sanity checks
     38 func TestBasic(t *testing.T) {
     39 	for _, tt := range basicTypes {
     40 		if tt.id.string() != tt.str {
     41 			t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
     42 		}
     43 		if tt.id == 0 {
     44 			t.Errorf("id for %q is zero", tt.str)
     45 		}
     46 	}
     47 }
     48 
     49 // Reregister some basic types to check registration is idempotent.
     50 func TestReregistration(t *testing.T) {
     51 	newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0)))
     52 	if newtyp != tInt.gobType() {
     53 		t.Errorf("reregistration of %s got new type", newtyp.string())
     54 	}
     55 	newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0)))
     56 	if newtyp != tUint.gobType() {
     57 		t.Errorf("reregistration of %s got new type", newtyp.string())
     58 	}
     59 	newtyp = getTypeUnlocked("string", reflect.TypeOf("hello"))
     60 	if newtyp != tString.gobType() {
     61 		t.Errorf("reregistration of %s got new type", newtyp.string())
     62 	}
     63 }
     64 
     65 func TestArrayType(t *testing.T) {
     66 	var a3 [3]int
     67 	a3int := getTypeUnlocked("foo", reflect.TypeOf(a3))
     68 	newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3))
     69 	if a3int != newa3int {
     70 		t.Errorf("second registration of [3]int creates new type")
     71 	}
     72 	var a4 [4]int
     73 	a4int := getTypeUnlocked("goo", reflect.TypeOf(a4))
     74 	if a3int == a4int {
     75 		t.Errorf("registration of [3]int creates same type as [4]int")
     76 	}
     77 	var b3 [3]bool
     78 	a3bool := getTypeUnlocked("", reflect.TypeOf(b3))
     79 	if a3int == a3bool {
     80 		t.Errorf("registration of [3]bool creates same type as [3]int")
     81 	}
     82 	str := a3bool.string()
     83 	expected := "[3]bool"
     84 	if str != expected {
     85 		t.Errorf("array printed as %q; expected %q", str, expected)
     86 	}
     87 }
     88 
     89 func TestSliceType(t *testing.T) {
     90 	var s []int
     91 	sint := getTypeUnlocked("slice", reflect.TypeOf(s))
     92 	var news []int
     93 	newsint := getTypeUnlocked("slice1", reflect.TypeOf(news))
     94 	if sint != newsint {
     95 		t.Errorf("second registration of []int creates new type")
     96 	}
     97 	var b []bool
     98 	sbool := getTypeUnlocked("", reflect.TypeOf(b))
     99 	if sbool == sint {
    100 		t.Errorf("registration of []bool creates same type as []int")
    101 	}
    102 	str := sbool.string()
    103 	expected := "[]bool"
    104 	if str != expected {
    105 		t.Errorf("slice printed as %q; expected %q", str, expected)
    106 	}
    107 }
    108 
    109 func TestMapType(t *testing.T) {
    110 	var m map[string]int
    111 	mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m))
    112 	var newm map[string]int
    113 	newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm))
    114 	if mapStringInt != newMapStringInt {
    115 		t.Errorf("second registration of map[string]int creates new type")
    116 	}
    117 	var b map[string]bool
    118 	mapStringBool := getTypeUnlocked("", reflect.TypeOf(b))
    119 	if mapStringBool == mapStringInt {
    120 		t.Errorf("registration of map[string]bool creates same type as map[string]int")
    121 	}
    122 	str := mapStringBool.string()
    123 	expected := "map[string]bool"
    124 	if str != expected {
    125 		t.Errorf("map printed as %q; expected %q", str, expected)
    126 	}
    127 }
    128 
    129 type Bar struct {
    130 	X string
    131 }
    132 
    133 // This structure has pointers and refers to itself, making it a good test case.
    134 type Foo struct {
    135 	A int
    136 	B int32 // will become int
    137 	C string
    138 	D []byte
    139 	E *float64    // will become float64
    140 	F ****float64 // will become float64
    141 	G *Bar
    142 	H *Bar // should not interpolate the definition of Bar again
    143 	I *Foo // will not explode
    144 }
    145 
    146 func TestStructType(t *testing.T) {
    147 	sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{}))
    148 	str := sstruct.string()
    149 	// If we can print it correctly, we built it correctly.
    150 	expected := "Foo = struct { A int; B int; C string; D bytes; E float; F float; G Bar = struct { X string; }; H Bar; I Foo; }"
    151 	if str != expected {
    152 		t.Errorf("struct printed as %q; expected %q", str, expected)
    153 	}
    154 }
    155 
    156 // Should be OK to register the same type multiple times, as long as they're
    157 // at the same level of indirection.
    158 func TestRegistration(t *testing.T) {
    159 	type T struct{ a int }
    160 	Register(new(T))
    161 	Register(new(T))
    162 }
    163 
    164 type N1 struct{}
    165 type N2 struct{}
    166 
    167 // See comment in type.go/Register.
    168 func TestRegistrationNaming(t *testing.T) {
    169 	testCases := []struct {
    170 		t    interface{}
    171 		name string
    172 	}{
    173 		{&N1{}, "*gob.N1"},
    174 		{N2{}, "encoding/gob.N2"},
    175 	}
    176 
    177 	for _, tc := range testCases {
    178 		Register(tc.t)
    179 
    180 		tct := reflect.TypeOf(tc.t)
    181 		registerLock.RLock()
    182 		ct := nameToConcreteType[tc.name]
    183 		registerLock.RUnlock()
    184 		if ct != tct {
    185 			t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct)
    186 		}
    187 		// concreteTypeToName is keyed off the base type.
    188 		if tct.Kind() == reflect.Ptr {
    189 			tct = tct.Elem()
    190 		}
    191 		if n := concreteTypeToName[tct]; n != tc.name {
    192 			t.Errorf("concreteTypeToName[%v] got %v, want %v", tct, n, tc.name)
    193 		}
    194 	}
    195 }
    196 
    197 func TestStressParallel(t *testing.T) {
    198 	type T2 struct{ A int }
    199 	c := make(chan bool)
    200 	const N = 10
    201 	for i := 0; i < N; i++ {
    202 		go func() {
    203 			p := new(T2)
    204 			Register(p)
    205 			b := new(bytes.Buffer)
    206 			enc := NewEncoder(b)
    207 			err := enc.Encode(p)
    208 			if err != nil {
    209 				t.Error("encoder fail:", err)
    210 			}
    211 			dec := NewDecoder(b)
    212 			err = dec.Decode(p)
    213 			if err != nil {
    214 				t.Error("decoder fail:", err)
    215 			}
    216 			c <- true
    217 		}()
    218 	}
    219 	for i := 0; i < N; i++ {
    220 		<-c
    221 	}
    222 }
    223