...

Source file src/encoding/gob/type_test.go

Documentation: encoding/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  	"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  }
	 263  

View as plain text