1// Copyright 2011 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// This file contains tests of the GobEncoder/GobDecoder support.
6
7package gob
8
9import (
10	"bytes"
11	"errors"
12	"fmt"
13	"io"
14	"net"
15	"reflect"
16	"strings"
17	"testing"
18	"time"
19)
20
21// Types that implement the GobEncoder/Decoder interfaces.
22
23type ByteStruct struct {
24	a byte // not an exported field
25}
26
27type StringStruct struct {
28	s string // not an exported field
29}
30
31type ArrayStruct struct {
32	a [8192]byte // not an exported field
33}
34
35type Gobber int
36
37type ValueGobber string // encodes with a value, decodes with a pointer.
38
39type BinaryGobber int
40
41type BinaryValueGobber string
42
43type TextGobber int
44
45type TextValueGobber string
46
47// The relevant methods
48
49func (g *ByteStruct) GobEncode() ([]byte, error) {
50	b := make([]byte, 3)
51	b[0] = g.a
52	b[1] = g.a + 1
53	b[2] = g.a + 2
54	return b, nil
55}
56
57func (g *ByteStruct) GobDecode(data []byte) error {
58	if g == nil {
59		return errors.New("NIL RECEIVER")
60	}
61	// Expect N sequential-valued bytes.
62	if len(data) == 0 {
63		return io.EOF
64	}
65	g.a = data[0]
66	for i, c := range data {
67		if c != g.a+byte(i) {
68			return errors.New("invalid data sequence")
69		}
70	}
71	return nil
72}
73
74func (g *StringStruct) GobEncode() ([]byte, error) {
75	return []byte(g.s), nil
76}
77
78func (g *StringStruct) GobDecode(data []byte) error {
79	// Expect N sequential-valued bytes.
80	if len(data) == 0 {
81		return io.EOF
82	}
83	a := data[0]
84	for i, c := range data {
85		if c != a+byte(i) {
86			return errors.New("invalid data sequence")
87		}
88	}
89	g.s = string(data)
90	return nil
91}
92
93func (a *ArrayStruct) GobEncode() ([]byte, error) {
94	return a.a[:], nil
95}
96
97func (a *ArrayStruct) GobDecode(data []byte) error {
98	if len(data) != len(a.a) {
99		return errors.New("wrong length in array decode")
100	}
101	copy(a.a[:], data)
102	return nil
103}
104
105func (g *Gobber) GobEncode() ([]byte, error) {
106	return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
107}
108
109func (g *Gobber) GobDecode(data []byte) error {
110	_, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
111	return err
112}
113
114func (g *BinaryGobber) MarshalBinary() ([]byte, error) {
115	return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
116}
117
118func (g *BinaryGobber) UnmarshalBinary(data []byte) error {
119	_, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
120	return err
121}
122
123func (g *TextGobber) MarshalText() ([]byte, error) {
124	return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
125}
126
127func (g *TextGobber) UnmarshalText(data []byte) error {
128	_, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
129	return err
130}
131
132func (v ValueGobber) GobEncode() ([]byte, error) {
133	return []byte(fmt.Sprintf("VALUE=%s", v)), nil
134}
135
136func (v *ValueGobber) GobDecode(data []byte) error {
137	_, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
138	return err
139}
140
141func (v BinaryValueGobber) MarshalBinary() ([]byte, error) {
142	return []byte(fmt.Sprintf("VALUE=%s", v)), nil
143}
144
145func (v *BinaryValueGobber) UnmarshalBinary(data []byte) error {
146	_, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
147	return err
148}
149
150func (v TextValueGobber) MarshalText() ([]byte, error) {
151	return []byte(fmt.Sprintf("VALUE=%s", v)), nil
152}
153
154func (v *TextValueGobber) UnmarshalText(data []byte) error {
155	_, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
156	return err
157}
158
159// Structs that include GobEncodable fields.
160
161type GobTest0 struct {
162	X int // guarantee we have  something in common with GobTest*
163	G *ByteStruct
164}
165
166type GobTest1 struct {
167	X int // guarantee we have  something in common with GobTest*
168	G *StringStruct
169}
170
171type GobTest2 struct {
172	X int    // guarantee we have  something in common with GobTest*
173	G string // not a GobEncoder - should give us errors
174}
175
176type GobTest3 struct {
177	X int // guarantee we have  something in common with GobTest*
178	G *Gobber
179	B *BinaryGobber
180	T *TextGobber
181}
182
183type GobTest4 struct {
184	X  int // guarantee we have  something in common with GobTest*
185	V  ValueGobber
186	BV BinaryValueGobber
187	TV TextValueGobber
188}
189
190type GobTest5 struct {
191	X  int // guarantee we have  something in common with GobTest*
192	V  *ValueGobber
193	BV *BinaryValueGobber
194	TV *TextValueGobber
195}
196
197type GobTest6 struct {
198	X  int // guarantee we have  something in common with GobTest*
199	V  ValueGobber
200	W  *ValueGobber
201	BV BinaryValueGobber
202	BW *BinaryValueGobber
203	TV TextValueGobber
204	TW *TextValueGobber
205}
206
207type GobTest7 struct {
208	X  int // guarantee we have  something in common with GobTest*
209	V  *ValueGobber
210	W  ValueGobber
211	BV *BinaryValueGobber
212	BW BinaryValueGobber
213	TV *TextValueGobber
214	TW TextValueGobber
215}
216
217type GobTestIgnoreEncoder struct {
218	X int // guarantee we have  something in common with GobTest*
219}
220
221type GobTestValueEncDec struct {
222	X int          // guarantee we have  something in common with GobTest*
223	G StringStruct // not a pointer.
224}
225
226type GobTestIndirectEncDec struct {
227	X int             // guarantee we have  something in common with GobTest*
228	G ***StringStruct // indirections to the receiver.
229}
230
231type GobTestArrayEncDec struct {
232	X int         // guarantee we have  something in common with GobTest*
233	A ArrayStruct // not a pointer.
234}
235
236type GobTestIndirectArrayEncDec struct {
237	X int            // guarantee we have  something in common with GobTest*
238	A ***ArrayStruct // indirections to a large receiver.
239}
240
241func TestGobEncoderField(t *testing.T) {
242	b := new(bytes.Buffer)
243	// First a field that's a structure.
244	enc := NewEncoder(b)
245	err := enc.Encode(GobTest0{17, &ByteStruct{'A'}})
246	if err != nil {
247		t.Fatal("encode error:", err)
248	}
249	dec := NewDecoder(b)
250	x := new(GobTest0)
251	err = dec.Decode(x)
252	if err != nil {
253		t.Fatal("decode error:", err)
254	}
255	if x.G.a != 'A' {
256		t.Errorf("expected 'A' got %c", x.G.a)
257	}
258	// Now a field that's not a structure.
259	b.Reset()
260	gobber := Gobber(23)
261	bgobber := BinaryGobber(24)
262	tgobber := TextGobber(25)
263	err = enc.Encode(GobTest3{17, &gobber, &bgobber, &tgobber})
264	if err != nil {
265		t.Fatal("encode error:", err)
266	}
267	y := new(GobTest3)
268	err = dec.Decode(y)
269	if err != nil {
270		t.Fatal("decode error:", err)
271	}
272	if *y.G != 23 || *y.B != 24 || *y.T != 25 {
273		t.Errorf("expected '23 got %d", *y.G)
274	}
275}
276
277// Even though the field is a value, we can still take its address
278// and should be able to call the methods.
279func TestGobEncoderValueField(t *testing.T) {
280	b := new(bytes.Buffer)
281	// First a field that's a structure.
282	enc := NewEncoder(b)
283	err := enc.Encode(&GobTestValueEncDec{17, StringStruct{"HIJKL"}})
284	if err != nil {
285		t.Fatal("encode error:", err)
286	}
287	dec := NewDecoder(b)
288	x := new(GobTestValueEncDec)
289	err = dec.Decode(x)
290	if err != nil {
291		t.Fatal("decode error:", err)
292	}
293	if x.G.s != "HIJKL" {
294		t.Errorf("expected `HIJKL` got %s", x.G.s)
295	}
296}
297
298// GobEncode/Decode should work even if the value is
299// more indirect than the receiver.
300func TestGobEncoderIndirectField(t *testing.T) {
301	b := new(bytes.Buffer)
302	// First a field that's a structure.
303	enc := NewEncoder(b)
304	s := &StringStruct{"HIJKL"}
305	sp := &s
306	err := enc.Encode(GobTestIndirectEncDec{17, &sp})
307	if err != nil {
308		t.Fatal("encode error:", err)
309	}
310	dec := NewDecoder(b)
311	x := new(GobTestIndirectEncDec)
312	err = dec.Decode(x)
313	if err != nil {
314		t.Fatal("decode error:", err)
315	}
316	if (***x.G).s != "HIJKL" {
317		t.Errorf("expected `HIJKL` got %s", (***x.G).s)
318	}
319}
320
321// Test with a large field with methods.
322func TestGobEncoderArrayField(t *testing.T) {
323	b := new(bytes.Buffer)
324	enc := NewEncoder(b)
325	var a GobTestArrayEncDec
326	a.X = 17
327	for i := range a.A.a {
328		a.A.a[i] = byte(i)
329	}
330	err := enc.Encode(&a)
331	if err != nil {
332		t.Fatal("encode error:", err)
333	}
334	dec := NewDecoder(b)
335	x := new(GobTestArrayEncDec)
336	err = dec.Decode(x)
337	if err != nil {
338		t.Fatal("decode error:", err)
339	}
340	for i, v := range x.A.a {
341		if v != byte(i) {
342			t.Errorf("expected %x got %x", byte(i), v)
343			break
344		}
345	}
346}
347
348// Test an indirection to a large field with methods.
349func TestGobEncoderIndirectArrayField(t *testing.T) {
350	b := new(bytes.Buffer)
351	enc := NewEncoder(b)
352	var a GobTestIndirectArrayEncDec
353	a.X = 17
354	var array ArrayStruct
355	ap := &array
356	app := &ap
357	a.A = &app
358	for i := range array.a {
359		array.a[i] = byte(i)
360	}
361	err := enc.Encode(a)
362	if err != nil {
363		t.Fatal("encode error:", err)
364	}
365	dec := NewDecoder(b)
366	x := new(GobTestIndirectArrayEncDec)
367	err = dec.Decode(x)
368	if err != nil {
369		t.Fatal("decode error:", err)
370	}
371	for i, v := range (***x.A).a {
372		if v != byte(i) {
373			t.Errorf("expected %x got %x", byte(i), v)
374			break
375		}
376	}
377}
378
379// As long as the fields have the same name and implement the
380// interface, we can cross-connect them. Not sure it's useful
381// and may even be bad but it works and it's hard to prevent
382// without exposing the contents of the object, which would
383// defeat the purpose.
384func TestGobEncoderFieldsOfDifferentType(t *testing.T) {
385	// first, string in field to byte in field
386	b := new(bytes.Buffer)
387	enc := NewEncoder(b)
388	err := enc.Encode(GobTest1{17, &StringStruct{"ABC"}})
389	if err != nil {
390		t.Fatal("encode error:", err)
391	}
392	dec := NewDecoder(b)
393	x := new(GobTest0)
394	err = dec.Decode(x)
395	if err != nil {
396		t.Fatal("decode error:", err)
397	}
398	if x.G.a != 'A' {
399		t.Errorf("expected 'A' got %c", x.G.a)
400	}
401	// now the other direction, byte in field to string in field
402	b.Reset()
403	err = enc.Encode(GobTest0{17, &ByteStruct{'X'}})
404	if err != nil {
405		t.Fatal("encode error:", err)
406	}
407	y := new(GobTest1)
408	err = dec.Decode(y)
409	if err != nil {
410		t.Fatal("decode error:", err)
411	}
412	if y.G.s != "XYZ" {
413		t.Fatalf("expected `XYZ` got %q", y.G.s)
414	}
415}
416
417// Test that we can encode a value and decode into a pointer.
418func TestGobEncoderValueEncoder(t *testing.T) {
419	// first, string in field to byte in field
420	b := new(bytes.Buffer)
421	enc := NewEncoder(b)
422	err := enc.Encode(GobTest4{17, ValueGobber("hello"), BinaryValueGobber("Καλημέρα"), TextValueGobber("こんにちは")})
423	if err != nil {
424		t.Fatal("encode error:", err)
425	}
426	dec := NewDecoder(b)
427	x := new(GobTest5)
428	err = dec.Decode(x)
429	if err != nil {
430		t.Fatal("decode error:", err)
431	}
432	if *x.V != "hello" || *x.BV != "Καλημέρα" || *x.TV != "こんにちは" {
433		t.Errorf("expected `hello` got %s", *x.V)
434	}
435}
436
437// Test that we can use a value then a pointer type of a GobEncoder
438// in the same encoded value. Bug 4647.
439func TestGobEncoderValueThenPointer(t *testing.T) {
440	v := ValueGobber("forty-two")
441	w := ValueGobber("six-by-nine")
442	bv := BinaryValueGobber("1nanocentury")
443	bw := BinaryValueGobber("πseconds")
444	tv := TextValueGobber("gravitationalacceleration")
445	tw := TextValueGobber("π²ft/s²")
446
447	// this was a bug: encoding a GobEncoder by value before a GobEncoder
448	// pointer would cause duplicate type definitions to be sent.
449
450	b := new(bytes.Buffer)
451	enc := NewEncoder(b)
452	if err := enc.Encode(GobTest6{42, v, &w, bv, &bw, tv, &tw}); err != nil {
453		t.Fatal("encode error:", err)
454	}
455	dec := NewDecoder(b)
456	x := new(GobTest6)
457	if err := dec.Decode(x); err != nil {
458		t.Fatal("decode error:", err)
459	}
460
461	if got, want := x.V, v; got != want {
462		t.Errorf("v = %q, want %q", got, want)
463	}
464	if got, want := x.W, w; got == nil {
465		t.Errorf("w = nil, want %q", want)
466	} else if *got != want {
467		t.Errorf("w = %q, want %q", *got, want)
468	}
469
470	if got, want := x.BV, bv; got != want {
471		t.Errorf("bv = %q, want %q", got, want)
472	}
473	if got, want := x.BW, bw; got == nil {
474		t.Errorf("bw = nil, want %q", want)
475	} else if *got != want {
476		t.Errorf("bw = %q, want %q", *got, want)
477	}
478
479	if got, want := x.TV, tv; got != want {
480		t.Errorf("tv = %q, want %q", got, want)
481	}
482	if got, want := x.TW, tw; got == nil {
483		t.Errorf("tw = nil, want %q", want)
484	} else if *got != want {
485		t.Errorf("tw = %q, want %q", *got, want)
486	}
487}
488
489// Test that we can use a pointer then a value type of a GobEncoder
490// in the same encoded value.
491func TestGobEncoderPointerThenValue(t *testing.T) {
492	v := ValueGobber("forty-two")
493	w := ValueGobber("six-by-nine")
494	bv := BinaryValueGobber("1nanocentury")
495	bw := BinaryValueGobber("πseconds")
496	tv := TextValueGobber("gravitationalacceleration")
497	tw := TextValueGobber("π²ft/s²")
498
499	b := new(bytes.Buffer)
500	enc := NewEncoder(b)
501	if err := enc.Encode(GobTest7{42, &v, w, &bv, bw, &tv, tw}); err != nil {
502		t.Fatal("encode error:", err)
503	}
504	dec := NewDecoder(b)
505	x := new(GobTest7)
506	if err := dec.Decode(x); err != nil {
507		t.Fatal("decode error:", err)
508	}
509
510	if got, want := x.V, v; got == nil {
511		t.Errorf("v = nil, want %q", want)
512	} else if *got != want {
513		t.Errorf("v = %q, want %q", *got, want)
514	}
515	if got, want := x.W, w; got != want {
516		t.Errorf("w = %q, want %q", got, want)
517	}
518
519	if got, want := x.BV, bv; got == nil {
520		t.Errorf("bv = nil, want %q", want)
521	} else if *got != want {
522		t.Errorf("bv = %q, want %q", *got, want)
523	}
524	if got, want := x.BW, bw; got != want {
525		t.Errorf("bw = %q, want %q", got, want)
526	}
527
528	if got, want := x.TV, tv; got == nil {
529		t.Errorf("tv = nil, want %q", want)
530	} else if *got != want {
531		t.Errorf("tv = %q, want %q", *got, want)
532	}
533	if got, want := x.TW, tw; got != want {
534		t.Errorf("tw = %q, want %q", got, want)
535	}
536}
537
538func TestGobEncoderFieldTypeError(t *testing.T) {
539	// GobEncoder to non-decoder: error
540	b := new(bytes.Buffer)
541	enc := NewEncoder(b)
542	err := enc.Encode(GobTest1{17, &StringStruct{"ABC"}})
543	if err != nil {
544		t.Fatal("encode error:", err)
545	}
546	dec := NewDecoder(b)
547	x := &GobTest2{}
548	err = dec.Decode(x)
549	if err == nil {
550		t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
551	}
552	if !strings.Contains(err.Error(), "type") {
553		t.Fatal("expected type error; got", err)
554	}
555	// Non-encoder to GobDecoder: error
556	b.Reset()
557	err = enc.Encode(GobTest2{17, "ABC"})
558	if err != nil {
559		t.Fatal("encode error:", err)
560	}
561	y := &GobTest1{}
562	err = dec.Decode(y)
563	if err == nil {
564		t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
565	}
566	if !strings.Contains(err.Error(), "type") {
567		t.Fatal("expected type error; got", err)
568	}
569}
570
571// Even though ByteStruct is a struct, it's treated as a singleton at the top level.
572func TestGobEncoderStructSingleton(t *testing.T) {
573	b := new(bytes.Buffer)
574	enc := NewEncoder(b)
575	err := enc.Encode(&ByteStruct{'A'})
576	if err != nil {
577		t.Fatal("encode error:", err)
578	}
579	dec := NewDecoder(b)
580	x := new(ByteStruct)
581	err = dec.Decode(x)
582	if err != nil {
583		t.Fatal("decode error:", err)
584	}
585	if x.a != 'A' {
586		t.Errorf("expected 'A' got %c", x.a)
587	}
588}
589
590func TestGobEncoderNonStructSingleton(t *testing.T) {
591	b := new(bytes.Buffer)
592	enc := NewEncoder(b)
593	var g Gobber = 1234
594	err := enc.Encode(&g)
595	if err != nil {
596		t.Fatal("encode error:", err)
597	}
598	dec := NewDecoder(b)
599	var x Gobber
600	err = dec.Decode(&x)
601	if err != nil {
602		t.Fatal("decode error:", err)
603	}
604	if x != 1234 {
605		t.Errorf("expected 1234 got %d", x)
606	}
607}
608
609func TestGobEncoderIgnoreStructField(t *testing.T) {
610	b := new(bytes.Buffer)
611	// First a field that's a structure.
612	enc := NewEncoder(b)
613	err := enc.Encode(GobTest0{17, &ByteStruct{'A'}})
614	if err != nil {
615		t.Fatal("encode error:", err)
616	}
617	dec := NewDecoder(b)
618	x := new(GobTestIgnoreEncoder)
619	err = dec.Decode(x)
620	if err != nil {
621		t.Fatal("decode error:", err)
622	}
623	if x.X != 17 {
624		t.Errorf("expected 17 got %c", x.X)
625	}
626}
627
628func TestGobEncoderIgnoreNonStructField(t *testing.T) {
629	b := new(bytes.Buffer)
630	// First a field that's a structure.
631	enc := NewEncoder(b)
632	gobber := Gobber(23)
633	bgobber := BinaryGobber(24)
634	tgobber := TextGobber(25)
635	err := enc.Encode(GobTest3{17, &gobber, &bgobber, &tgobber})
636	if err != nil {
637		t.Fatal("encode error:", err)
638	}
639	dec := NewDecoder(b)
640	x := new(GobTestIgnoreEncoder)
641	err = dec.Decode(x)
642	if err != nil {
643		t.Fatal("decode error:", err)
644	}
645	if x.X != 17 {
646		t.Errorf("expected 17 got %c", x.X)
647	}
648}
649
650func TestGobEncoderIgnoreNilEncoder(t *testing.T) {
651	b := new(bytes.Buffer)
652	// First a field that's a structure.
653	enc := NewEncoder(b)
654	err := enc.Encode(GobTest0{X: 18}) // G is nil
655	if err != nil {
656		t.Fatal("encode error:", err)
657	}
658	dec := NewDecoder(b)
659	x := new(GobTest0)
660	err = dec.Decode(x)
661	if err != nil {
662		t.Fatal("decode error:", err)
663	}
664	if x.X != 18 {
665		t.Errorf("expected x.X = 18, got %v", x.X)
666	}
667	if x.G != nil {
668		t.Errorf("expected x.G = nil, got %v", x.G)
669	}
670}
671
672type gobDecoderBug0 struct {
673	foo, bar string
674}
675
676func (br *gobDecoderBug0) String() string {
677	return br.foo + "-" + br.bar
678}
679
680func (br *gobDecoderBug0) GobEncode() ([]byte, error) {
681	return []byte(br.String()), nil
682}
683
684func (br *gobDecoderBug0) GobDecode(b []byte) error {
685	br.foo = "foo"
686	br.bar = "bar"
687	return nil
688}
689
690// This was a bug: the receiver has a different indirection level
691// than the variable.
692func TestGobEncoderExtraIndirect(t *testing.T) {
693	gdb := &gobDecoderBug0{"foo", "bar"}
694	buf := new(bytes.Buffer)
695	e := NewEncoder(buf)
696	if err := e.Encode(gdb); err != nil {
697		t.Fatalf("encode: %v", err)
698	}
699	d := NewDecoder(buf)
700	var got *gobDecoderBug0
701	if err := d.Decode(&got); err != nil {
702		t.Fatalf("decode: %v", err)
703	}
704	if got.foo != gdb.foo || got.bar != gdb.bar {
705		t.Errorf("got = %q, want %q", got, gdb)
706	}
707}
708
709// Another bug: this caused a crash with the new Go1 Time type.
710// We throw in a gob-encoding array, to test another case of isZero,
711// and a struct containing a nil interface, to test a third.
712type isZeroBug struct {
713	T time.Time
714	S string
715	I int
716	A isZeroBugArray
717	F isZeroBugInterface
718}
719
720type isZeroBugArray [2]uint8
721
722// Receiver is value, not pointer, to test isZero of array.
723func (a isZeroBugArray) GobEncode() (b []byte, e error) {
724	b = append(b, a[:]...)
725	return b, nil
726}
727
728func (a *isZeroBugArray) GobDecode(data []byte) error {
729	if len(data) != len(a) {
730		return io.EOF
731	}
732	a[0] = data[0]
733	a[1] = data[1]
734	return nil
735}
736
737type isZeroBugInterface struct {
738	I any
739}
740
741func (i isZeroBugInterface) GobEncode() (b []byte, e error) {
742	return []byte{}, nil
743}
744
745func (i *isZeroBugInterface) GobDecode(data []byte) error {
746	return nil
747}
748
749func TestGobEncodeIsZero(t *testing.T) {
750	x := isZeroBug{time.Unix(1e9, 0), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
751	b := new(bytes.Buffer)
752	enc := NewEncoder(b)
753	err := enc.Encode(x)
754	if err != nil {
755		t.Fatal("encode:", err)
756	}
757	var y isZeroBug
758	dec := NewDecoder(b)
759	err = dec.Decode(&y)
760	if err != nil {
761		t.Fatal("decode:", err)
762	}
763	if x != y {
764		t.Fatalf("%v != %v", x, y)
765	}
766}
767
768func TestGobEncodePtrError(t *testing.T) {
769	var err error
770	b := new(bytes.Buffer)
771	enc := NewEncoder(b)
772	err = enc.Encode(&err)
773	if err != nil {
774		t.Fatal("encode:", err)
775	}
776	dec := NewDecoder(b)
777	err2 := fmt.Errorf("foo")
778	err = dec.Decode(&err2)
779	if err != nil {
780		t.Fatal("decode:", err)
781	}
782	if err2 != nil {
783		t.Fatalf("expected nil, got %v", err2)
784	}
785}
786
787func TestNetIP(t *testing.T) {
788	// Encoding of net.IP{1,2,3,4} in Go 1.1.
789	enc := []byte{0x07, 0x0a, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}
790
791	var ip net.IP
792	err := NewDecoder(bytes.NewReader(enc)).Decode(&ip)
793	if err != nil {
794		t.Fatalf("decode: %v", err)
795	}
796	if ip.String() != "1.2.3.4" {
797		t.Errorf("decoded to %v, want 1.2.3.4", ip.String())
798	}
799}
800
801func TestIgnoreDepthLimit(t *testing.T) {
802	// We don't test the actual depth limit because it requires building an
803	// extremely large message, which takes quite a while.
804	oldNestingDepth := maxIgnoreNestingDepth
805	maxIgnoreNestingDepth = 100
806	defer func() { maxIgnoreNestingDepth = oldNestingDepth }()
807	b := new(bytes.Buffer)
808	enc := NewEncoder(b)
809
810	// Nested slice
811	typ := reflect.TypeFor[int]()
812	nested := reflect.ArrayOf(1, typ)
813	for i := 0; i < 100; i++ {
814		nested = reflect.ArrayOf(1, nested)
815	}
816	badStruct := reflect.New(reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}}))
817	enc.Encode(badStruct.Interface())
818	dec := NewDecoder(b)
819	var output struct{ Hello int }
820	expectedErr := "invalid nesting depth"
821	if err := dec.Decode(&output); err == nil || err.Error() != expectedErr {
822		t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err)
823	}
824
825	// Nested struct
826	nested = reflect.StructOf([]reflect.StructField{{Name: "F", Type: typ}})
827	for i := 0; i < 100; i++ {
828		nested = reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}})
829	}
830	badStruct = reflect.New(reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}}))
831	enc.Encode(badStruct.Interface())
832	dec = NewDecoder(b)
833	if err := dec.Decode(&output); err == nil || err.Error() != expectedErr {
834		t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err)
835	}
836}
837