]>
Commit | Line | Data |
---|---|---|
7a938933 ILT |
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 ( | |
4ccad563 | 8 | "bytes" |
7a938933 ILT |
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() | |
8039ca76 | 30 | t, err := getBaseType(name, rt) |
7a938933 | 31 | if err != nil { |
2fd401c8 | 32 | panic("getTypeUnlocked: " + err.Error()) |
7a938933 ILT |
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) { | |
9ff56c95 | 51 | newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0))) |
7a938933 ILT |
52 | if newtyp != tInt.gobType() { |
53 | t.Errorf("reregistration of %s got new type", newtyp.string()) | |
54 | } | |
9ff56c95 | 55 | newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0))) |
7a938933 ILT |
56 | if newtyp != tUint.gobType() { |
57 | t.Errorf("reregistration of %s got new type", newtyp.string()) | |
58 | } | |
9ff56c95 | 59 | newtyp = getTypeUnlocked("string", reflect.TypeOf("hello")) |
7a938933 ILT |
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 | |
9ff56c95 ILT |
67 | a3int := getTypeUnlocked("foo", reflect.TypeOf(a3)) |
68 | newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3)) | |
7a938933 ILT |
69 | if a3int != newa3int { |
70 | t.Errorf("second registration of [3]int creates new type") | |
71 | } | |
72 | var a4 [4]int | |
9ff56c95 | 73 | a4int := getTypeUnlocked("goo", reflect.TypeOf(a4)) |
7a938933 ILT |
74 | if a3int == a4int { |
75 | t.Errorf("registration of [3]int creates same type as [4]int") | |
76 | } | |
77 | var b3 [3]bool | |
9ff56c95 | 78 | a3bool := getTypeUnlocked("", reflect.TypeOf(b3)) |
7a938933 ILT |
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 | |
9ff56c95 | 91 | sint := getTypeUnlocked("slice", reflect.TypeOf(s)) |
7a938933 | 92 | var news []int |
9ff56c95 | 93 | newsint := getTypeUnlocked("slice1", reflect.TypeOf(news)) |
7a938933 ILT |
94 | if sint != newsint { |
95 | t.Errorf("second registration of []int creates new type") | |
96 | } | |
97 | var b []bool | |
9ff56c95 | 98 | sbool := getTypeUnlocked("", reflect.TypeOf(b)) |
7a938933 ILT |
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 | |
9ff56c95 | 111 | mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m)) |
7a938933 | 112 | var newm map[string]int |
9ff56c95 | 113 | newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm)) |
7a938933 ILT |
114 | if mapStringInt != newMapStringInt { |
115 | t.Errorf("second registration of map[string]int creates new type") | |
116 | } | |
117 | var b map[string]bool | |
9ff56c95 | 118 | mapStringBool := getTypeUnlocked("", reflect.TypeOf(b)) |
7a938933 ILT |
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 { | |
8039ca76 | 130 | X string |
7a938933 ILT |
131 | } |
132 | ||
133 | // This structure has pointers and refers to itself, making it a good test case. | |
134 | type Foo struct { | |
8039ca76 ILT |
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 | |
7a938933 ILT |
144 | } |
145 | ||
146 | func TestStructType(t *testing.T) { | |
9ff56c95 | 147 | sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{})) |
7a938933 ILT |
148 | str := sstruct.string() |
149 | // If we can print it correctly, we built it correctly. | |
8039ca76 | 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; }" |
7a938933 ILT |
151 | if str != expected { |
152 | t.Errorf("struct printed as %q; expected %q", str, expected) | |
153 | } | |
154 | } | |
9c63abc9 ILT |
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 | } | |
4ccad563 ILT |
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 | } |