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