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