f8d9fa9e80
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
799 lines
18 KiB
Go
799 lines
18 KiB
Go
// 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.Index(err.Error(), "type") < 0 {
|
|
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.Index(err.Error(), "type") < 0 {
|
|
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.Now(), "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())
|
|
}
|
|
}
|