|  | // Copyright 2011 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // This file contains tests of the GobEncoder/GobDecoder support. | 
|  |  | 
|  | package gob | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "errors" | 
|  | "fmt" | 
|  | "io" | 
|  | "net" | 
|  | "strings" | 
|  | "testing" | 
|  | "time" | 
|  | ) | 
|  |  | 
|  | // Types that implement the GobEncoder/Decoder interfaces. | 
|  |  | 
|  | type ByteStruct struct { | 
|  | a byte // not an exported field | 
|  | } | 
|  |  | 
|  | type StringStruct struct { | 
|  | s string // not an exported field | 
|  | } | 
|  |  | 
|  | type ArrayStruct struct { | 
|  | a [8192]byte // not an exported field | 
|  | } | 
|  |  | 
|  | type Gobber int | 
|  |  | 
|  | type ValueGobber string // encodes with a value, decodes with a pointer. | 
|  |  | 
|  | type BinaryGobber int | 
|  |  | 
|  | type BinaryValueGobber string | 
|  |  | 
|  | type TextGobber int | 
|  |  | 
|  | type TextValueGobber string | 
|  |  | 
|  | // The relevant methods | 
|  |  | 
|  | func (g *ByteStruct) GobEncode() ([]byte, error) { | 
|  | b := make([]byte, 3) | 
|  | b[0] = g.a | 
|  | b[1] = g.a + 1 | 
|  | b[2] = g.a + 2 | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | func (g *ByteStruct) GobDecode(data []byte) error { | 
|  | if g == nil { | 
|  | return errors.New("NIL RECEIVER") | 
|  | } | 
|  | // Expect N sequential-valued bytes. | 
|  | if len(data) == 0 { | 
|  | return io.EOF | 
|  | } | 
|  | g.a = data[0] | 
|  | for i, c := range data { | 
|  | if c != g.a+byte(i) { | 
|  | return errors.New("invalid data sequence") | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (g *StringStruct) GobEncode() ([]byte, error) { | 
|  | return []byte(g.s), nil | 
|  | } | 
|  |  | 
|  | func (g *StringStruct) GobDecode(data []byte) error { | 
|  | // Expect N sequential-valued bytes. | 
|  | if len(data) == 0 { | 
|  | return io.EOF | 
|  | } | 
|  | a := data[0] | 
|  | for i, c := range data { | 
|  | if c != a+byte(i) { | 
|  | return errors.New("invalid data sequence") | 
|  | } | 
|  | } | 
|  | g.s = string(data) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (a *ArrayStruct) GobEncode() ([]byte, error) { | 
|  | return a.a[:], nil | 
|  | } | 
|  |  | 
|  | func (a *ArrayStruct) GobDecode(data []byte) error { | 
|  | if len(data) != len(a.a) { | 
|  | return errors.New("wrong length in array decode") | 
|  | } | 
|  | copy(a.a[:], data) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (g *Gobber) GobEncode() ([]byte, error) { | 
|  | return []byte(fmt.Sprintf("VALUE=%d", *g)), nil | 
|  | } | 
|  |  | 
|  | func (g *Gobber) GobDecode(data []byte) error { | 
|  | _, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (g *BinaryGobber) MarshalBinary() ([]byte, error) { | 
|  | return []byte(fmt.Sprintf("VALUE=%d", *g)), nil | 
|  | } | 
|  |  | 
|  | func (g *BinaryGobber) UnmarshalBinary(data []byte) error { | 
|  | _, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (g *TextGobber) MarshalText() ([]byte, error) { | 
|  | return []byte(fmt.Sprintf("VALUE=%d", *g)), nil | 
|  | } | 
|  |  | 
|  | func (g *TextGobber) UnmarshalText(data []byte) error { | 
|  | _, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (v ValueGobber) GobEncode() ([]byte, error) { | 
|  | return []byte(fmt.Sprintf("VALUE=%s", v)), nil | 
|  | } | 
|  |  | 
|  | func (v *ValueGobber) GobDecode(data []byte) error { | 
|  | _, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (v BinaryValueGobber) MarshalBinary() ([]byte, error) { | 
|  | return []byte(fmt.Sprintf("VALUE=%s", v)), nil | 
|  | } | 
|  |  | 
|  | func (v *BinaryValueGobber) UnmarshalBinary(data []byte) error { | 
|  | _, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (v TextValueGobber) MarshalText() ([]byte, error) { | 
|  | return []byte(fmt.Sprintf("VALUE=%s", v)), nil | 
|  | } | 
|  |  | 
|  | func (v *TextValueGobber) UnmarshalText(data []byte) error { | 
|  | _, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Structs that include GobEncodable fields. | 
|  |  | 
|  | type GobTest0 struct { | 
|  | X int // guarantee we have  something in common with GobTest* | 
|  | G *ByteStruct | 
|  | } | 
|  |  | 
|  | type GobTest1 struct { | 
|  | X int // guarantee we have  something in common with GobTest* | 
|  | G *StringStruct | 
|  | } | 
|  |  | 
|  | type GobTest2 struct { | 
|  | X int    // guarantee we have  something in common with GobTest* | 
|  | G string // not a GobEncoder - should give us errors | 
|  | } | 
|  |  | 
|  | type GobTest3 struct { | 
|  | X int // guarantee we have  something in common with GobTest* | 
|  | G *Gobber | 
|  | B *BinaryGobber | 
|  | T *TextGobber | 
|  | } | 
|  |  | 
|  | type GobTest4 struct { | 
|  | X  int // guarantee we have  something in common with GobTest* | 
|  | V  ValueGobber | 
|  | BV BinaryValueGobber | 
|  | TV TextValueGobber | 
|  | } | 
|  |  | 
|  | type GobTest5 struct { | 
|  | X  int // guarantee we have  something in common with GobTest* | 
|  | V  *ValueGobber | 
|  | BV *BinaryValueGobber | 
|  | TV *TextValueGobber | 
|  | } | 
|  |  | 
|  | type GobTest6 struct { | 
|  | X  int // guarantee we have  something in common with GobTest* | 
|  | V  ValueGobber | 
|  | W  *ValueGobber | 
|  | BV BinaryValueGobber | 
|  | BW *BinaryValueGobber | 
|  | TV TextValueGobber | 
|  | TW *TextValueGobber | 
|  | } | 
|  |  | 
|  | type GobTest7 struct { | 
|  | X  int // guarantee we have  something in common with GobTest* | 
|  | V  *ValueGobber | 
|  | W  ValueGobber | 
|  | BV *BinaryValueGobber | 
|  | BW BinaryValueGobber | 
|  | TV *TextValueGobber | 
|  | TW TextValueGobber | 
|  | } | 
|  |  | 
|  | type GobTestIgnoreEncoder struct { | 
|  | X int // guarantee we have  something in common with GobTest* | 
|  | } | 
|  |  | 
|  | type GobTestValueEncDec struct { | 
|  | X int          // guarantee we have  something in common with GobTest* | 
|  | G StringStruct // not a pointer. | 
|  | } | 
|  |  | 
|  | type GobTestIndirectEncDec struct { | 
|  | X int             // guarantee we have  something in common with GobTest* | 
|  | G ***StringStruct // indirections to the receiver. | 
|  | } | 
|  |  | 
|  | type GobTestArrayEncDec struct { | 
|  | X int         // guarantee we have  something in common with GobTest* | 
|  | A ArrayStruct // not a pointer. | 
|  | } | 
|  |  | 
|  | type GobTestIndirectArrayEncDec struct { | 
|  | X int            // guarantee we have  something in common with GobTest* | 
|  | A ***ArrayStruct // indirections to a large receiver. | 
|  | } | 
|  |  | 
|  | func TestGobEncoderField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | // First a field that's a structure. | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(GobTest0{17, &ByteStruct{'A'}}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTest0) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.G.a != 'A' { | 
|  | t.Errorf("expected 'A' got %c", x.G.a) | 
|  | } | 
|  | // Now a field that's not a structure. | 
|  | b.Reset() | 
|  | gobber := Gobber(23) | 
|  | bgobber := BinaryGobber(24) | 
|  | tgobber := TextGobber(25) | 
|  | err = enc.Encode(GobTest3{17, &gobber, &bgobber, &tgobber}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | y := new(GobTest3) | 
|  | err = dec.Decode(y) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if *y.G != 23 || *y.B != 24 || *y.T != 25 { | 
|  | t.Errorf("expected '23 got %d", *y.G) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Even though the field is a value, we can still take its address | 
|  | // and should be able to call the methods. | 
|  | func TestGobEncoderValueField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | // First a field that's a structure. | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(&GobTestValueEncDec{17, StringStruct{"HIJKL"}}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTestValueEncDec) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.G.s != "HIJKL" { | 
|  | t.Errorf("expected `HIJKL` got %s", x.G.s) | 
|  | } | 
|  | } | 
|  |  | 
|  | // GobEncode/Decode should work even if the value is | 
|  | // more indirect than the receiver. | 
|  | func TestGobEncoderIndirectField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | // First a field that's a structure. | 
|  | enc := NewEncoder(b) | 
|  | s := &StringStruct{"HIJKL"} | 
|  | sp := &s | 
|  | err := enc.Encode(GobTestIndirectEncDec{17, &sp}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTestIndirectEncDec) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if (***x.G).s != "HIJKL" { | 
|  | t.Errorf("expected `HIJKL` got %s", (***x.G).s) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test with a large field with methods. | 
|  | func TestGobEncoderArrayField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | var a GobTestArrayEncDec | 
|  | a.X = 17 | 
|  | for i := range a.A.a { | 
|  | a.A.a[i] = byte(i) | 
|  | } | 
|  | err := enc.Encode(&a) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTestArrayEncDec) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | for i, v := range x.A.a { | 
|  | if v != byte(i) { | 
|  | t.Errorf("expected %x got %x", byte(i), v) | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test an indirection to a large field with methods. | 
|  | func TestGobEncoderIndirectArrayField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | var a GobTestIndirectArrayEncDec | 
|  | a.X = 17 | 
|  | var array ArrayStruct | 
|  | ap := &array | 
|  | app := &ap | 
|  | a.A = &app | 
|  | for i := range array.a { | 
|  | array.a[i] = byte(i) | 
|  | } | 
|  | err := enc.Encode(a) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTestIndirectArrayEncDec) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | for i, v := range (***x.A).a { | 
|  | if v != byte(i) { | 
|  | t.Errorf("expected %x got %x", byte(i), v) | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // As long as the fields have the same name and implement the | 
|  | // interface, we can cross-connect them. Not sure it's useful | 
|  | // and may even be bad but it works and it's hard to prevent | 
|  | // without exposing the contents of the object, which would | 
|  | // defeat the purpose. | 
|  | func TestGobEncoderFieldsOfDifferentType(t *testing.T) { | 
|  | // first, string in field to byte in field | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(GobTest1{17, &StringStruct{"ABC"}}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTest0) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.G.a != 'A' { | 
|  | t.Errorf("expected 'A' got %c", x.G.a) | 
|  | } | 
|  | // now the other direction, byte in field to string in field | 
|  | b.Reset() | 
|  | err = enc.Encode(GobTest0{17, &ByteStruct{'X'}}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | y := new(GobTest1) | 
|  | err = dec.Decode(y) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if y.G.s != "XYZ" { | 
|  | t.Fatalf("expected `XYZ` got %q", y.G.s) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test that we can encode a value and decode into a pointer. | 
|  | func TestGobEncoderValueEncoder(t *testing.T) { | 
|  | // first, string in field to byte in field | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(GobTest4{17, ValueGobber("hello"), BinaryValueGobber("Καλημέρα"), TextValueGobber("こんにちは")}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTest5) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if *x.V != "hello" || *x.BV != "Καλημέρα" || *x.TV != "こんにちは" { | 
|  | t.Errorf("expected `hello` got %s", *x.V) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test that we can use a value then a pointer type of a GobEncoder | 
|  | // in the same encoded value. Bug 4647. | 
|  | func TestGobEncoderValueThenPointer(t *testing.T) { | 
|  | v := ValueGobber("forty-two") | 
|  | w := ValueGobber("six-by-nine") | 
|  | bv := BinaryValueGobber("1nanocentury") | 
|  | bw := BinaryValueGobber("πseconds") | 
|  | tv := TextValueGobber("gravitationalacceleration") | 
|  | tw := TextValueGobber("π²ft/s²") | 
|  |  | 
|  | // this was a bug: encoding a GobEncoder by value before a GobEncoder | 
|  | // pointer would cause duplicate type definitions to be sent. | 
|  |  | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | if err := enc.Encode(GobTest6{42, v, &w, bv, &bw, tv, &tw}); err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTest6) | 
|  | if err := dec.Decode(x); err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  |  | 
|  | if got, want := x.V, v; got != want { | 
|  | t.Errorf("v = %q, want %q", got, want) | 
|  | } | 
|  | if got, want := x.W, w; got == nil { | 
|  | t.Errorf("w = nil, want %q", want) | 
|  | } else if *got != want { | 
|  | t.Errorf("w = %q, want %q", *got, want) | 
|  | } | 
|  |  | 
|  | if got, want := x.BV, bv; got != want { | 
|  | t.Errorf("bv = %q, want %q", got, want) | 
|  | } | 
|  | if got, want := x.BW, bw; got == nil { | 
|  | t.Errorf("bw = nil, want %q", want) | 
|  | } else if *got != want { | 
|  | t.Errorf("bw = %q, want %q", *got, want) | 
|  | } | 
|  |  | 
|  | if got, want := x.TV, tv; got != want { | 
|  | t.Errorf("tv = %q, want %q", got, want) | 
|  | } | 
|  | if got, want := x.TW, tw; got == nil { | 
|  | t.Errorf("tw = nil, want %q", want) | 
|  | } else if *got != want { | 
|  | t.Errorf("tw = %q, want %q", *got, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Test that we can use a pointer then a value type of a GobEncoder | 
|  | // in the same encoded value. | 
|  | func TestGobEncoderPointerThenValue(t *testing.T) { | 
|  | v := ValueGobber("forty-two") | 
|  | w := ValueGobber("six-by-nine") | 
|  | bv := BinaryValueGobber("1nanocentury") | 
|  | bw := BinaryValueGobber("πseconds") | 
|  | tv := TextValueGobber("gravitationalacceleration") | 
|  | tw := TextValueGobber("π²ft/s²") | 
|  |  | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | if err := enc.Encode(GobTest7{42, &v, w, &bv, bw, &tv, tw}); err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTest7) | 
|  | if err := dec.Decode(x); err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  |  | 
|  | if got, want := x.V, v; got == nil { | 
|  | t.Errorf("v = nil, want %q", want) | 
|  | } else if *got != want { | 
|  | t.Errorf("v = %q, want %q", *got, want) | 
|  | } | 
|  | if got, want := x.W, w; got != want { | 
|  | t.Errorf("w = %q, want %q", got, want) | 
|  | } | 
|  |  | 
|  | if got, want := x.BV, bv; got == nil { | 
|  | t.Errorf("bv = nil, want %q", want) | 
|  | } else if *got != want { | 
|  | t.Errorf("bv = %q, want %q", *got, want) | 
|  | } | 
|  | if got, want := x.BW, bw; got != want { | 
|  | t.Errorf("bw = %q, want %q", got, want) | 
|  | } | 
|  |  | 
|  | if got, want := x.TV, tv; got == nil { | 
|  | t.Errorf("tv = nil, want %q", want) | 
|  | } else if *got != want { | 
|  | t.Errorf("tv = %q, want %q", *got, want) | 
|  | } | 
|  | if got, want := x.TW, tw; got != want { | 
|  | t.Errorf("tw = %q, want %q", got, want) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGobEncoderFieldTypeError(t *testing.T) { | 
|  | // GobEncoder to non-decoder: error | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(GobTest1{17, &StringStruct{"ABC"}}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := &GobTest2{} | 
|  | err = dec.Decode(x) | 
|  | if err == nil { | 
|  | t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)") | 
|  | } | 
|  | if !strings.Contains(err.Error(), "type") { | 
|  | t.Fatal("expected type error; got", err) | 
|  | } | 
|  | // Non-encoder to GobDecoder: error | 
|  | b.Reset() | 
|  | err = enc.Encode(GobTest2{17, "ABC"}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | y := &GobTest1{} | 
|  | err = dec.Decode(y) | 
|  | if err == nil { | 
|  | t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)") | 
|  | } | 
|  | if !strings.Contains(err.Error(), "type") { | 
|  | t.Fatal("expected type error; got", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Even though ByteStruct is a struct, it's treated as a singleton at the top level. | 
|  | func TestGobEncoderStructSingleton(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(&ByteStruct{'A'}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(ByteStruct) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.a != 'A' { | 
|  | t.Errorf("expected 'A' got %c", x.a) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGobEncoderNonStructSingleton(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | var g Gobber = 1234 | 
|  | err := enc.Encode(&g) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | var x Gobber | 
|  | err = dec.Decode(&x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x != 1234 { | 
|  | t.Errorf("expected 1234 got %d", x) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGobEncoderIgnoreStructField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | // First a field that's a structure. | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(GobTest0{17, &ByteStruct{'A'}}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTestIgnoreEncoder) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.X != 17 { | 
|  | t.Errorf("expected 17 got %c", x.X) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGobEncoderIgnoreNonStructField(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | // First a field that's a structure. | 
|  | enc := NewEncoder(b) | 
|  | gobber := Gobber(23) | 
|  | bgobber := BinaryGobber(24) | 
|  | tgobber := TextGobber(25) | 
|  | err := enc.Encode(GobTest3{17, &gobber, &bgobber, &tgobber}) | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTestIgnoreEncoder) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.X != 17 { | 
|  | t.Errorf("expected 17 got %c", x.X) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGobEncoderIgnoreNilEncoder(t *testing.T) { | 
|  | b := new(bytes.Buffer) | 
|  | // First a field that's a structure. | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(GobTest0{X: 18}) // G is nil | 
|  | if err != nil { | 
|  | t.Fatal("encode error:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | x := new(GobTest0) | 
|  | err = dec.Decode(x) | 
|  | if err != nil { | 
|  | t.Fatal("decode error:", err) | 
|  | } | 
|  | if x.X != 18 { | 
|  | t.Errorf("expected x.X = 18, got %v", x.X) | 
|  | } | 
|  | if x.G != nil { | 
|  | t.Errorf("expected x.G = nil, got %v", x.G) | 
|  | } | 
|  | } | 
|  |  | 
|  | type gobDecoderBug0 struct { | 
|  | foo, bar string | 
|  | } | 
|  |  | 
|  | func (br *gobDecoderBug0) String() string { | 
|  | return br.foo + "-" + br.bar | 
|  | } | 
|  |  | 
|  | func (br *gobDecoderBug0) GobEncode() ([]byte, error) { | 
|  | return []byte(br.String()), nil | 
|  | } | 
|  |  | 
|  | func (br *gobDecoderBug0) GobDecode(b []byte) error { | 
|  | br.foo = "foo" | 
|  | br.bar = "bar" | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // This was a bug: the receiver has a different indirection level | 
|  | // than the variable. | 
|  | func TestGobEncoderExtraIndirect(t *testing.T) { | 
|  | gdb := &gobDecoderBug0{"foo", "bar"} | 
|  | buf := new(bytes.Buffer) | 
|  | e := NewEncoder(buf) | 
|  | if err := e.Encode(gdb); err != nil { | 
|  | t.Fatalf("encode: %v", err) | 
|  | } | 
|  | d := NewDecoder(buf) | 
|  | var got *gobDecoderBug0 | 
|  | if err := d.Decode(&got); err != nil { | 
|  | t.Fatalf("decode: %v", err) | 
|  | } | 
|  | if got.foo != gdb.foo || got.bar != gdb.bar { | 
|  | t.Errorf("got = %q, want %q", got, gdb) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Another bug: this caused a crash with the new Go1 Time type. | 
|  | // We throw in a gob-encoding array, to test another case of isZero, | 
|  | // and a struct containing an nil interface, to test a third. | 
|  | type isZeroBug struct { | 
|  | T time.Time | 
|  | S string | 
|  | I int | 
|  | A isZeroBugArray | 
|  | F isZeroBugInterface | 
|  | } | 
|  |  | 
|  | type isZeroBugArray [2]uint8 | 
|  |  | 
|  | // Receiver is value, not pointer, to test isZero of array. | 
|  | func (a isZeroBugArray) GobEncode() (b []byte, e error) { | 
|  | b = append(b, a[:]...) | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | func (a *isZeroBugArray) GobDecode(data []byte) error { | 
|  | if len(data) != len(a) { | 
|  | return io.EOF | 
|  | } | 
|  | a[0] = data[0] | 
|  | a[1] = data[1] | 
|  | return nil | 
|  | } | 
|  |  | 
|  | type isZeroBugInterface struct { | 
|  | I interface{} | 
|  | } | 
|  |  | 
|  | func (i isZeroBugInterface) GobEncode() (b []byte, e error) { | 
|  | return []byte{}, nil | 
|  | } | 
|  |  | 
|  | func (i *isZeroBugInterface) GobDecode(data []byte) error { | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func TestGobEncodeIsZero(t *testing.T) { | 
|  | x := isZeroBug{time.Unix(1e9, 0), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}} | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | err := enc.Encode(x) | 
|  | if err != nil { | 
|  | t.Fatal("encode:", err) | 
|  | } | 
|  | var y isZeroBug | 
|  | dec := NewDecoder(b) | 
|  | err = dec.Decode(&y) | 
|  | if err != nil { | 
|  | t.Fatal("decode:", err) | 
|  | } | 
|  | if x != y { | 
|  | t.Fatalf("%v != %v", x, y) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestGobEncodePtrError(t *testing.T) { | 
|  | var err error | 
|  | b := new(bytes.Buffer) | 
|  | enc := NewEncoder(b) | 
|  | err = enc.Encode(&err) | 
|  | if err != nil { | 
|  | t.Fatal("encode:", err) | 
|  | } | 
|  | dec := NewDecoder(b) | 
|  | err2 := fmt.Errorf("foo") | 
|  | err = dec.Decode(&err2) | 
|  | if err != nil { | 
|  | t.Fatal("decode:", err) | 
|  | } | 
|  | if err2 != nil { | 
|  | t.Fatalf("expected nil, got %v", err2) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestNetIP(t *testing.T) { | 
|  | // Encoding of net.IP{1,2,3,4} in Go 1.1. | 
|  | enc := []byte{0x07, 0x0a, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04} | 
|  |  | 
|  | var ip net.IP | 
|  | err := NewDecoder(bytes.NewReader(enc)).Decode(&ip) | 
|  | if err != nil { | 
|  | t.Fatalf("decode: %v", err) | 
|  | } | 
|  | if ip.String() != "1.2.3.4" { | 
|  | t.Errorf("decoded to %v, want 1.2.3.4", ip.String()) | 
|  | } | 
|  | } |