mirror of
https://github.com/golang/go
synced 2024-11-20 05:04:43 -07:00
a better encoder test, with a couple of fixes for bugs it uncovered.
R=rsc DELTA=84 (65 added, 9 deleted, 10 changed) OCL=31458 CL=31458
This commit is contained in:
parent
1880b90aff
commit
f0a9840d04
@ -12,17 +12,15 @@ import (
|
|||||||
"sync";
|
"sync";
|
||||||
)
|
)
|
||||||
|
|
||||||
import "fmt" // TODO DELETE
|
|
||||||
|
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
sync.Mutex; // each item must be sent atomically
|
sync.Mutex; // each item must be sent atomically
|
||||||
sent map[reflect.Type] uint; // which types we've already sent
|
sent map[reflect.Type] TypeId; // which types we've already sent
|
||||||
state *EncState; // so we can encode integers, strings directly
|
state *EncState; // so we can encode integers, strings directly
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEncoder(w io.Writer) *Encoder {
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
enc := new(Encoder);
|
enc := new(Encoder);
|
||||||
enc.sent = make(map[reflect.Type] uint);
|
enc.sent = make(map[reflect.Type] TypeId);
|
||||||
enc.state = new(EncState);
|
enc.state = new(EncState);
|
||||||
enc.state.w = w; // the rest isn't important; all we need is buffer and writer
|
enc.state.w = w; // the rest isn't important; all we need is buffer and writer
|
||||||
return enc;
|
return enc;
|
||||||
@ -32,15 +30,9 @@ func (enc *Encoder) badType(rt reflect.Type) {
|
|||||||
enc.state.err = os.ErrorString("can't encode type " + rt.String());
|
enc.state.err = os.ErrorString("can't encode type " + rt.String());
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) sendType(rt reflect.Type) {
|
func (enc *Encoder) sendType(origt reflect.Type) {
|
||||||
// Drill down to the base type.
|
// Drill down to the base type.
|
||||||
for {
|
rt, indir_ := indirect(origt);
|
||||||
pt, ok := rt.(*reflect.PtrType);
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
rt = pt.Elem();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only send structs - everything else is basic or an error
|
// We only send structs - everything else is basic or an error
|
||||||
switch t := rt.(type) {
|
switch t := rt.(type) {
|
||||||
@ -62,9 +54,8 @@ func (enc *Encoder) sendType(rt reflect.Type) {
|
|||||||
return; // basic, array, etc; not a type to be sent.
|
return; // basic, array, etc; not a type to be sent.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we already sent this type?
|
// Have we already sent this type? This time we ask about the base type.
|
||||||
id, alreadySent := enc.sent[rt];
|
if id_, alreadySent := enc.sent[rt]; alreadySent {
|
||||||
if alreadySent {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +67,9 @@ func (enc *Encoder) sendType(rt reflect.Type) {
|
|||||||
// Type:
|
// Type:
|
||||||
Encode(enc.state.w, info.wire);
|
Encode(enc.state.w, info.wire);
|
||||||
// Remember we've sent this type.
|
// Remember we've sent this type.
|
||||||
enc.sent[rt] = id;
|
enc.sent[rt] = info.typeId;
|
||||||
|
// Remember we've sent the top-level, possibly indirect type too.
|
||||||
|
enc.sent[origt] = info.typeId;
|
||||||
// Now send the inner types
|
// Now send the inner types
|
||||||
st := rt.(*reflect.StructType);
|
st := rt.(*reflect.StructType);
|
||||||
for i := 0; i < st.NumField(); i++ {
|
for i := 0; i < st.NumField(); i++ {
|
||||||
@ -92,9 +85,13 @@ func (enc *Encoder) Encode(e interface{}) os.Error {
|
|||||||
defer enc.Unlock();
|
defer enc.Unlock();
|
||||||
|
|
||||||
// Make sure the type is known to the other side.
|
// Make sure the type is known to the other side.
|
||||||
enc.sendType(rt);
|
// First, have we already sent this type?
|
||||||
if enc.state.err != nil {
|
if id_, alreadySent := enc.sent[rt]; !alreadySent {
|
||||||
return enc.state.err
|
// No, so send it.
|
||||||
|
enc.sendType(rt);
|
||||||
|
if enc.state.err != nil {
|
||||||
|
return enc.state.err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identify the type of this top-level value.
|
// Identify the type of this top-level value.
|
||||||
|
@ -6,6 +6,7 @@ package gob
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes";
|
||||||
|
"fmt"; // DELETE
|
||||||
"gob";
|
"gob";
|
||||||
"os";
|
"os";
|
||||||
"reflect";
|
"reflect";
|
||||||
@ -34,4 +35,59 @@ func TestBasicEncoder(t *testing.T) {
|
|||||||
if enc.state.err != nil {
|
if enc.state.err != nil {
|
||||||
t.Error("encoder fail:", enc.state.err)
|
t.Error("encoder fail:", enc.state.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode the result by hand to verify;
|
||||||
|
state := new(DecState);
|
||||||
|
state.r = b;
|
||||||
|
// The output should be:
|
||||||
|
// 1) -7: the type id of ET1
|
||||||
|
id1 := DecodeInt(state);
|
||||||
|
if id1 >= 0 {
|
||||||
|
t.Fatal("expected ET1 negative id; got", id1);
|
||||||
|
}
|
||||||
|
// 2) The wireType for ET1
|
||||||
|
wire1 := new(wireType);
|
||||||
|
err := Decode(b, wire1);
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error decoding ET1 type:", err);
|
||||||
|
}
|
||||||
|
info := getTypeInfo(reflect.Typeof(ET1{}));
|
||||||
|
trueWire1 := &wireType{name:"ET1", s: info.typeId.gobType().(*structType)};
|
||||||
|
if !reflect.DeepEqual(wire1, trueWire1) {
|
||||||
|
t.Fatalf("invalid wireType for ET1: expected %+v; got %+v\n", *trueWire1, *wire1);
|
||||||
|
}
|
||||||
|
// 3) -8: the type id of ET2
|
||||||
|
id2 := DecodeInt(state);
|
||||||
|
if id2 >= 0 {
|
||||||
|
t.Fatal("expected ET2 negative id; got", id2);
|
||||||
|
}
|
||||||
|
// 4) The wireType for ET2
|
||||||
|
wire2 := new(wireType);
|
||||||
|
err = Decode(b, wire2);
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error decoding ET2 type:", err);
|
||||||
|
}
|
||||||
|
info = getTypeInfo(reflect.Typeof(ET2{}));
|
||||||
|
trueWire2 := &wireType{name:"ET2", s: info.typeId.gobType().(*structType)};
|
||||||
|
if !reflect.DeepEqual(wire2, trueWire2) {
|
||||||
|
t.Fatalf("invalid wireType for ET2: expected %+v; got %+v\n", *trueWire2, *wire2);
|
||||||
|
}
|
||||||
|
// 5) The type id for the et1 value
|
||||||
|
newId1 := DecodeInt(state);
|
||||||
|
if newId1 != -id1 {
|
||||||
|
t.Fatal("expected Et1 id", -id1, "got", newId1);
|
||||||
|
}
|
||||||
|
// 6) The value of et1
|
||||||
|
newEt1 := new(ET1);
|
||||||
|
err = Decode(b, newEt1);
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error decoding ET1 value:", err);
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(et1, newEt1) {
|
||||||
|
t.Fatalf("invalid data for et1: expected %+v; got %+v\n", *et1, *newEt1);
|
||||||
|
}
|
||||||
|
// 7) EOF
|
||||||
|
if b.Len() != 0 {
|
||||||
|
t.Error("not at eof;", b.Len(), "bytes left")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,9 @@ type structType struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *structType) safeString(seen map[TypeId] bool) string {
|
func (s *structType) safeString(seen map[TypeId] bool) string {
|
||||||
|
if s == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
if _, ok := seen[s._id]; ok {
|
if _, ok := seen[s._id]; ok {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user