| // 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 a 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()) | |
| } | |
| } |