Source file src/encoding/gob/type_test.go

     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.TypeFor[int]())
    53  	if newtyp != tInt.gobType() {
    54  		t.Errorf("reregistration of %s got new type", newtyp.string())
    55  	}
    56  	newtyp = getTypeUnlocked("uint", reflect.TypeFor[uint]())
    57  	if newtyp != tUint.gobType() {
    58  		t.Errorf("reregistration of %s got new type", newtyp.string())
    59  	}
    60  	newtyp = getTypeUnlocked("string", reflect.TypeFor[string]())
    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.TypeFor[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    any
   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.Pointer {
   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 any
   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