func TestEnumWithDuplicateValuesWire(t *testing.T) { tests := []struct { e te.EnumWithDuplicateValues v wire.Value }{ {te.EnumWithDuplicateValuesP, wire.NewValueI32(0)}, {te.EnumWithDuplicateValuesQ, wire.NewValueI32(-1)}, {te.EnumWithDuplicateValuesR, wire.NewValueI32(0)}, } for _, tt := range tests { assertRoundTrip(t, &tt.e, tt.v, "EnumWithDuplicateValues") } }
func TestEnumDefaultWire(t *testing.T) { tests := []struct { e te.EnumDefault v wire.Value }{ {te.EnumDefaultFoo, wire.NewValueI32(0)}, {te.EnumDefaultBar, wire.NewValueI32(1)}, {te.EnumDefaultBaz, wire.NewValueI32(2)}, } for _, tt := range tests { assertRoundTrip(t, &tt.e, tt.v, "EnumDefault") } }
func (v *PrimitiveRequiredStruct) ToWire() (wire.Value, error) { var ( fields [8]wire.Field i int = 0 w wire.Value err error ) w, err = wire.NewValueBool(v.BoolField), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ w, err = wire.NewValueI8(v.ByteField), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 2, Value: w} i++ w, err = wire.NewValueI16(v.Int16Field), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 3, Value: w} i++ w, err = wire.NewValueI32(v.Int32Field), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 4, Value: w} i++ w, err = wire.NewValueI64(v.Int64Field), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 5, Value: w} i++ w, err = wire.NewValueDouble(v.DoubleField), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 6, Value: w} i++ w, err = wire.NewValueString(v.StringField), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 7, Value: w} i++ if v.BinaryField == nil { return w, errors.New("field BinaryField of PrimitiveRequiredStruct is required") } w, err = wire.NewValueBinary(v.BinaryField), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 8, Value: w} i++ return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func TestUnionFromWireInconsistencies(t *testing.T) { tests := []struct { desc string input wire.Value success *tu.Document failure string }{ { desc: "multiple recognized fields", input: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBinary([]byte{1, 2, 3})}, {ID: 2, Value: wire.NewValueString("hello")}, }}), failure: "should have exactly one field: got 2 fields", }, { desc: "recognized and unrecognized fields", input: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBinary([]byte{1, 2, 3})}, {ID: 3, Value: wire.NewValueString("hello")}, }}), success: &tu.Document{Pdf: []byte{1, 2, 3}}, }, { desc: "recognized field duplicates", input: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBinary([]byte{1, 2, 3})}, {ID: 1, Value: wire.NewValueBinary([]byte{4, 5, 6})}, }}), success: &tu.Document{Pdf: []byte{4, 5, 6}}, }, { desc: "only unrecognized fields", input: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueI32(42)}, // also a type mismatch {ID: 3, Value: wire.NewValueString("hello")}, }}), failure: "should have exactly one field: got 0 fields", }, { desc: "no fields", input: wire.NewValueStruct(wire.Struct{}), failure: "should have exactly one field: got 0 fields", }, } for _, tt := range tests { var o tu.Document err := o.FromWire(tt.input) if tt.success != nil { if assert.NoError(t, err, tt.desc) { assert.Equal(t, tt.success, &o, tt.desc) } } else { if assert.Error(t, err, tt.desc) { assert.Contains(t, err.Error(), tt.failure, tt.desc) } } } }
func TestStructFromWireUnrecognizedField(t *testing.T) { tests := []struct { desc string give wire.Value want ts.ContactInfo wantError string }{ { desc: "unknown field", give: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("foo")}, {ID: 2, Value: wire.NewValueI32(42)}, }}), want: ts.ContactInfo{EmailAddress: "foo"}, }, { desc: "only unknown field", give: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueString("bar")}, }}), wantError: "field EmailAddress of ContactInfo is required", }, { desc: "wrong type for recognized field", give: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(42)}, {ID: 1, Value: wire.NewValueString("foo")}, }}), want: ts.ContactInfo{EmailAddress: "foo"}, }, } for _, tt := range tests { var o ts.ContactInfo err := o.FromWire(tt.give) if tt.wantError != "" { if assert.Error(t, err, tt.desc) { assert.Contains(t, err.Error(), tt.wantError) } } else { if assert.NoError(t, err, tt.desc) { assert.Equal(t, tt.want, o) } } } }
func (m _Map_I32_I32_MapItemList) ForEach(f func(wire.MapItem) error) error { for k, v := range m { kw, err := wire.NewValueI32(k), error(nil) if err != nil { return err } vw, err := wire.NewValueI32(v), error(nil) if err != nil { return err } err = f(wire.MapItem{Key: kw, Value: vw}) if err != nil { return err } } return nil }
func (v *ThriftTest_TestMulti_Args) ToWire() (wire.Value, error) { var ( fields [6]wire.Field i int = 0 w wire.Value err error ) if v.Arg0 != nil { w, err = wire.NewValueI8(*(v.Arg0)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ } if v.Arg1 != nil { w, err = wire.NewValueI32(*(v.Arg1)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 2, Value: w} i++ } if v.Arg2 != nil { w, err = wire.NewValueI64(*(v.Arg2)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 3, Value: w} i++ } if v.Arg3 != nil { w, err = wire.NewValueMap(_Map_I16_String_MapItemList(v.Arg3)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 4, Value: w} i++ } if v.Arg4 != nil { w, err = v.Arg4.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 5, Value: w} i++ } if v.Arg5 != nil { w, err = v.Arg5.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 6, Value: w} i++ } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func (v _Set_I32_ValueList) ForEach(f func(wire.Value) error) error { for x := range v { w, err := wire.NewValueI32(x), error(nil) if err != nil { return err } err = f(w) if err != nil { return err } } return nil }
func (m _Map_EnumWithDuplicateValues_I32_MapItemList) ForEach(f func(wire.MapItem) error) error { for k, v := range m { kw, err := k.ToWire() if err != nil { return err } vw, err := wire.NewValueI32(v), error(nil) if err != nil { return err } err = f(wire.MapItem{Key: kw, Value: vw}) if err != nil { return err } } return nil }
func (v *ThriftTest_TestI32_Args) ToWire() (wire.Value, error) { var ( fields [1]wire.Field i int = 0 w wire.Value err error ) if v.Thing != nil { w, err = wire.NewValueI32(*(v.Thing)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func TestDisableEnveloperEncode(t *testing.T) { rand := rand.New(rand.NewSource(time.Now().Unix())) tests := []struct { value wire.Value want []byte }{ { wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), []byte{0x00}, }, { wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(42)}, }}), []byte{ 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, }, }, } for _, tt := range tests { e := wire.Envelope{Value: tt.value, Type: wire.Call} generate(&e.Name, rand) generate(&e.SeqID, rand) var buffer bytes.Buffer proto := disableEnvelopingProtocol{protocol.Binary, wire.Reply} if !assert.NoError(t, proto.EncodeEnveloped(e, &buffer)) { continue } assert.Equal(t, tt.want, buffer.Bytes()) gotE, err := proto.DecodeEnveloped(bytes.NewReader(tt.want)) if !assert.NoError(t, err) { continue } assert.Equal(t, wire.Reply, gotE.Type) assert.True(t, wire.ValuesAreEqual(tt.value, gotE.Value)) } }
func (m _Map_I32_Map_I32_I32_MapItemList) ForEach(f func(wire.MapItem) error) error { for k, v := range m { if v == nil { return fmt.Errorf("invalid [%v]: value is nil", k) } kw, err := wire.NewValueI32(k), error(nil) if err != nil { return err } vw, err := wire.NewValueMap(_Map_I32_I32_MapItemList(v)), error(nil) if err != nil { return err } err = f(wire.MapItem{Key: kw, Value: vw}) if err != nil { return err } } return nil }
func (v *ThriftTest_TestI32_Result) ToWire() (wire.Value, error) { var ( fields [1]wire.Field i int = 0 w wire.Value err error ) if v.Success != nil { w, err = wire.NewValueI32(*(v.Success)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 0, Value: w} i++ } if i != 1 { return wire.Value{}, fmt.Errorf("ThriftTest_TestI32_Result should have exactly one field: got %v fields", i) } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func (v *HandshakeResponse) ToWire() (wire.Value, error) { var ( fields [4]wire.Field i int = 0 w wire.Value err error ) w, err = wire.NewValueString(v.Name), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ w, err = wire.NewValueI32(v.APIVersion), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 2, Value: w} i++ if v.Features == nil { return w, errors.New("field Features of HandshakeResponse is required") } w, err = wire.NewValueList(_List_Feature_ValueList(v.Features)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 3, Value: w} i++ if v.LibraryVersion != nil { w, err = wire.NewValueString(*(v.LibraryVersion)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 4, Value: w} i++ } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func (v *Node) ToWire() (wire.Value, error) { var ( fields [2]wire.Field i int = 0 w wire.Value err error ) w, err = wire.NewValueI32(v.Value), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ if v.Tail != nil { w, err = v.Tail.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 2, Value: w} i++ } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func TestOptionalEnum(t *testing.T) { foo := te.EnumDefaultFoo tests := []struct { s te.StructWithOptionalEnum v wire.Value }{ { te.StructWithOptionalEnum{E: &foo}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(0)}, }}), }, { te.StructWithOptionalEnum{}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), }, } for _, tt := range tests { assertRoundTrip(t, &tt.s, tt.v, "StructWithOptionalEnum") } }
func TestClient(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() internalError := exception.ExceptionTypeInternalError unknownMethod := exception.ExceptionTypeUnknownMethod tests := []struct { desc string // Either transportError or decode* can be set. transportError error decodeEnvelope wire.Envelope decodeError error wantError error // expected error if any }{ { desc: "nothing went wrong", decodeEnvelope: wire.Envelope{ Name: "hello", Type: wire.Reply, SeqID: 1, Value: wire.NewValueStruct(wire.Struct{}), }, }, { desc: "decode error", decodeError: errors.New("great sadness"), wantError: errors.New("great sadness"), }, { desc: "internal error", decodeEnvelope: wire.Envelope{ Name: "hello", Type: wire.Exception, SeqID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("great sadness")}, {ID: 2, Value: wire.NewValueI32(6)}, // Internal error }}), }, wantError: &exception.TApplicationException{ Message: ptr.String("great sadness"), Type: &internalError, }, }, { desc: "unknown method", decodeEnvelope: wire.Envelope{ Name: "hello", Type: wire.Exception, SeqID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString(`unknown method "hello"`)}, {ID: 2, Value: wire.NewValueI32(1)}, // Internal error }}), }, wantError: &exception.TApplicationException{ Message: ptr.String(`unknown method "hello"`), Type: &unknownMethod, }, }, { desc: "unknown envelope type", decodeEnvelope: wire.Envelope{ Name: "hello", Type: wire.EnvelopeType(12), SeqID: 1, Value: wire.NewValueStruct(wire.Struct{}), }, wantError: errUnknownEnvelopeType(12), }, { desc: "transport error", transportError: errors.New("great sadness"), wantError: errors.New("great sadness"), }, } for _, tt := range tests { proto := NewMockProtocol(mockCtrl) proto.EXPECT().EncodeEnveloped( wire.Envelope{ Name: "hello", Type: wire.Call, SeqID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("world")}, }}), }, gomock.Any(), ).Do(func(_ wire.Envelope, w io.Writer) { _, err := w.Write([]byte{1, 2, 3}) assert.NoError(t, err, tt.desc) }).Return(nil) transport := envelopetest.NewMockTransport(mockCtrl) if tt.transportError != nil { transport.EXPECT().Send([]byte{1, 2, 3}).Return(nil, tt.transportError) } else { transport.EXPECT().Send([]byte{1, 2, 3}).Return([]byte{4, 5, 6}, nil) proto.EXPECT().DecodeEnveloped(gomock.Any()). Return(tt.decodeEnvelope, tt.decodeError) } client := NewClient(proto, transport) _, err := client.Send("hello", wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("world")}, }})) assert.Equal(t, tt.wantError, err) } }
func vi32(i int32) wire.Value { return wire.NewValueI32(i) }
func (v ExceptionType) ToWire() (wire.Value, error) { return wire.NewValueI32(int32(v)), nil }
func TestStructValidation(t *testing.T) { tests := []struct { desc string serialize thriftType deserialize wire.Value typ reflect.Type // must be set if serialize is not wantError string }{ { desc: "Point: missing X", deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(42)}, }}), typ: reflect.TypeOf(ts.Point{}), wantError: "field Y of Point is required", }, { desc: "Point: missing Y", deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueDouble(42)}, }}), typ: reflect.TypeOf(ts.Point{}), wantError: "field X of Point is required", }, { desc: "Size: missing width", deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(42)}, }}), typ: reflect.TypeOf(ts.Size{}), wantError: "field Height of Size is required", }, { desc: "Size: missing height", deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueDouble(42)}, }}), typ: reflect.TypeOf(ts.Size{}), wantError: "field Width of Size is required", }, { desc: "Frame: missing topLeft", serialize: &ts.Frame{Size: &ts.Size{Width: 1, Height: 2}}, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, {ID: 2, Value: wire.NewValueDouble(2)}, }}), }, }}), wantError: "field TopLeft of Frame is required", }, { desc: "Frame: missing Size", serialize: &ts.Frame{TopLeft: &ts.Point{X: 1, Y: 2}}, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, {ID: 2, Value: wire.NewValueDouble(2)}, }}), }, }}), wantError: "field Size of Frame is required", }, { desc: "Frame: topLeft: missing y", deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, {ID: 2, Value: wire.NewValueDouble(2)}, }}), }, }}), typ: reflect.TypeOf(ts.Frame{}), wantError: "field Y of Point is required", }, { desc: "Graph: missing edges", serialize: &ts.Graph{Edges: nil}, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), wantError: "field Edges of Graph is required", }, { desc: "Graph: edges: misssing end", serialize: &ts.Graph{ Edges: []*ts.Edge{ {StartPoint: &ts.Point{X: 1, Y: 2}, EndPoint: &ts.Point{X: 3, Y: 4}}, {StartPoint: &ts.Point{X: 5, Y: 6}}, }, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TStruct, []wire.Value{ wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, {ID: 2, Value: wire.NewValueDouble(2)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(3)}, {ID: 2, Value: wire.NewValueDouble(4)}, }}), }, }}), wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, {ID: 2, Value: wire.NewValueDouble(2)}, }}), }, }}), }), ), }, }}), wantError: "field EndPoint of Edge is required", }, { desc: "User: contact: missing emailAddress", deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("hello")}, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), }, }}), typ: reflect.TypeOf(ts.User{}), wantError: "field EmailAddress of ContactInfo is required", }, { desc: "PrimitiveContainersRequired: missing list", serialize: &tc.PrimitiveContainersRequired{ SetOfInts: map[int32]struct{}{ 1: {}, 2: {}, 3: {}, }, MapOfIntsToDoubles: map[int64]float64{1: 2.3, 4: 5.6}, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 2, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(1), wire.NewValueI32(2), wire.NewValueI32(3), }), ), }, { ID: 3, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TI64, wire.TDouble, []wire.MapItem{ { Key: wire.NewValueI64(1), Value: wire.NewValueDouble(2.3), }, { Key: wire.NewValueI64(4), Value: wire.NewValueDouble(5.6), }, }), ), }, }}), wantError: "field ListOfStrings of PrimitiveContainersRequired is required", }, { desc: "PrimitiveContainersRequired: missing set", serialize: &tc.PrimitiveContainersRequired{ ListOfStrings: []string{"hello", "world"}, MapOfIntsToDoubles: map[int64]float64{1: 2.3, 4: 5.6}, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("hello"), wire.NewValueString("world"), }), ), }, { ID: 3, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TI64, wire.TDouble, []wire.MapItem{ { Key: wire.NewValueI64(1), Value: wire.NewValueDouble(2.3), }, { Key: wire.NewValueI64(4), Value: wire.NewValueDouble(5.6), }, }), ), }, }}), wantError: "field SetOfInts of PrimitiveContainersRequired is required", }, { desc: "PrimitiveContainersRequired: missing map", serialize: &tc.PrimitiveContainersRequired{ ListOfStrings: []string{"hello", "world"}, SetOfInts: map[int32]struct{}{ 1: {}, 2: {}, 3: {}, }, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("hello"), wire.NewValueString("world"), }), ), }, { ID: 2, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(1), wire.NewValueI32(2), wire.NewValueI32(3), }), ), }, }}), wantError: "field MapOfIntsToDoubles of PrimitiveContainersRequired is required", }, { desc: "Document: empty", serialize: &tu.Document{}, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), wantError: "Document should have exactly one field: got 0 fields", }, { desc: "Document: multiple", serialize: &tu.Document{ Pdf: td.PDF{}, PlainText: stringp("hello"), }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueBinary([]byte{}), }, { ID: 2, Value: wire.NewValueString("hello"), }, }}), wantError: "Document should have exactly one field: got 2 fields", }, { desc: "ArbitraryValue: empty", serialize: &tu.ArbitraryValue{}, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), wantError: "ArbitraryValue should have exactly one field: got 0 fields", }, { desc: "ArbitraryValue: primitives", serialize: &tu.ArbitraryValue{ BoolValue: boolp(true), Int64Value: int64p(42), StringValue: stringp(""), }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBool(true)}, {ID: 2, Value: wire.NewValueI64(42)}, {ID: 3, Value: wire.NewValueString("")}, }}), wantError: "ArbitraryValue should have exactly one field: got 3 fields", }, { desc: "ArbitraryValue: full", serialize: &tu.ArbitraryValue{ BoolValue: boolp(true), Int64Value: int64p(42), StringValue: stringp(""), ListValue: []*tu.ArbitraryValue{ {BoolValue: boolp(true)}, {Int64Value: int64p(42)}, {StringValue: stringp("")}, }, MapValue: map[string]*tu.ArbitraryValue{ "bool": {BoolValue: boolp(true)}, "int": {Int64Value: int64p(42)}, "string": {StringValue: stringp("")}, }, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBool(true)}, {ID: 2, Value: wire.NewValueI64(42)}, {ID: 3, Value: wire.NewValueString("")}, { ID: 4, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TStruct, []wire.Value{ wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBool(true)}, }}), wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueI64(42)}, }}), wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 3, Value: wire.NewValueString("")}, }}), }), ), }, { ID: 5, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TStruct, []wire.MapItem{ { Key: wire.NewValueString("bool"), Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBool(true)}, }}), }, { Key: wire.NewValueString("int"), Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueI64(42)}, }}), }, { Key: wire.NewValueString("string"), Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 3, Value: wire.NewValueString("")}, }}), }, }), ), }, }}), wantError: "ArbitraryValue should have exactly one field: got 5 fields", }, { desc: "ArbitraryValue: error inside a list", serialize: &tu.ArbitraryValue{ ListValue: []*tu.ArbitraryValue{ {BoolValue: boolp(true)}, {}, }, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 4, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TStruct, []wire.Value{ wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBool(true)}, }}), wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), })), }, }}), wantError: "ArbitraryValue should have exactly one field: got 0 fields", }, { desc: "ArbitraryValue: error inside a map value", serialize: &tu.ArbitraryValue{ MapValue: map[string]*tu.ArbitraryValue{ "bool": {BoolValue: boolp(true)}, "empty": {}, }, }, deserialize: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 5, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TStruct, []wire.MapItem{ { Key: wire.NewValueString("bool"), Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueBool(true)}, }}), }, { Key: wire.NewValueString("empty"), Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{}}), }, }), ), }, }}), wantError: "ArbitraryValue should have exactly one field: got 0 fields", }, { desc: "FrameGroup: error inside a set", serialize: &td.FrameGroup{ &ts.Frame{ TopLeft: &ts.Point{X: 1, Y: 2}, Size: &ts.Size{Width: 3, Height: 4}, }, &ts.Frame{TopLeft: &ts.Point{X: 5, Y: 6}}, }, deserialize: wire.NewValueSet( wire.ValueListFromSlice(wire.TStruct, []wire.Value{ wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueDouble(1), }, { ID: 2, Value: wire.NewValueDouble(2), }, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueDouble(3), }, { ID: 2, Value: wire.NewValueDouble(4), }, }}), }, }}), wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueDouble(5), }, { ID: 2, Value: wire.NewValueDouble(6), }, }}), }, }}), }), ), wantError: "field Size of Frame is required", }, { desc: "EdgeMap: error inside a map key", serialize: &td.EdgeMap{ { Key: &ts.Edge{StartPoint: &ts.Point{X: 1, Y: 2}}, Value: &ts.Edge{StartPoint: &ts.Point{X: 3, Y: 4}, EndPoint: &ts.Point{X: 5, Y: 6}}, }, }, deserialize: wire.NewValueMap( wire.MapItemListFromSlice(wire.TStruct, wire.TStruct, []wire.MapItem{ { Key: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1)}, {ID: 2, Value: wire.NewValueDouble(2)}, }}), }, }}), Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(3)}, {ID: 2, Value: wire.NewValueDouble(4)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(5)}, {ID: 2, Value: wire.NewValueDouble(6)}, }}), }, }}), }, }), ), wantError: "field EndPoint of Edge is required", }, } for _, tt := range tests { var typ reflect.Type if tt.serialize != nil { typ = reflect.TypeOf(tt.serialize).Elem() v, err := tt.serialize.ToWire() if err == nil { err = wire.EvaluateValue(v) } if assert.Error(t, err, "%v: expected failure but got %v", tt.desc, v) { assert.Contains(t, err.Error(), tt.wantError, tt.desc) } } else { typ = tt.typ } if typ == nil { t.Fatalf("invalid test %q: either typ or serialize must be set", tt.desc) } x := reflect.New(typ) args := []reflect.Value{reflect.ValueOf(tt.deserialize)} e := x.MethodByName("FromWire").Call(args)[0].Interface() if assert.NotNil(t, e, "%v: expected failure but got %v", tt.desc, x) { assert.Contains(t, e.(error).Error(), tt.wantError, tt.desc) } } }
func TestStructWithDefaults(t *testing.T) { enumDefaultFoo := te.EnumDefaultFoo enumDefaultBar := te.EnumDefaultBar enumDefaultBaz := te.EnumDefaultBaz tests := []struct { give *ts.DefaultsStruct giveWire wire.Value wantToWire wire.Value wantFromWire *ts.DefaultsStruct }{ { give: &ts.DefaultsStruct{}, giveWire: wire.NewValueStruct(wire.Struct{}), wantToWire: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(100)}, {ID: 2, Value: wire.NewValueI32(200)}, {ID: 3, Value: wire.NewValueI32(1)}, {ID: 4, Value: wire.NewValueI32(2)}, { ID: 5, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("hello"), wire.NewValueString("world"), }), ), }, { ID: 6, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TDouble, []wire.Value{ wire.NewValueDouble(1.0), wire.NewValueDouble(2.0), wire.NewValueDouble(3.0), }), ), }, { ID: 7, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1.0)}, {ID: 2, Value: wire.NewValueDouble(2.0)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(100.0)}, {ID: 2, Value: wire.NewValueDouble(200.0)}, }}), }, }}), }, { ID: 8, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1.0)}, {ID: 2, Value: wire.NewValueDouble(2.0)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(3.0)}, {ID: 2, Value: wire.NewValueDouble(4.0)}, }}), }, }}), }, }}), wantFromWire: &ts.DefaultsStruct{ RequiredPrimitive: int32p(100), OptionalPrimitive: int32p(200), RequiredEnum: &enumDefaultBar, OptionalEnum: &enumDefaultBaz, RequiredList: []string{"hello", "world"}, OptionalList: []float64{1.0, 2.0, 3.0}, RequiredStruct: &ts.Frame{ TopLeft: &ts.Point{X: 1.0, Y: 2.0}, Size: &ts.Size{Width: 100.0, Height: 200.0}, }, OptionalStruct: &ts.Edge{ StartPoint: &ts.Point{X: 1.0, Y: 2.0}, EndPoint: &ts.Point{X: 3.0, Y: 4.0}, }, }, }, { give: &ts.DefaultsStruct{ RequiredPrimitive: int32p(0), OptionalEnum: &enumDefaultFoo, RequiredList: []string{}, }, giveWire: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(0)}, {ID: 4, Value: wire.NewValueI32(0)}, { ID: 5, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{}), ), }, }}), wantToWire: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(0)}, {ID: 2, Value: wire.NewValueI32(200)}, {ID: 3, Value: wire.NewValueI32(1)}, {ID: 4, Value: wire.NewValueI32(0)}, { ID: 5, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{}), ), }, { ID: 6, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TDouble, []wire.Value{ wire.NewValueDouble(1.0), wire.NewValueDouble(2.0), wire.NewValueDouble(3.0), }), ), }, { ID: 7, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1.0)}, {ID: 2, Value: wire.NewValueDouble(2.0)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(100.0)}, {ID: 2, Value: wire.NewValueDouble(200.0)}, }}), }, }}), }, { ID: 8, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ { ID: 1, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(1.0)}, {ID: 2, Value: wire.NewValueDouble(2.0)}, }}), }, { ID: 2, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueDouble(3.0)}, {ID: 2, Value: wire.NewValueDouble(4.0)}, }}), }, }}), }, }}), wantFromWire: &ts.DefaultsStruct{ RequiredPrimitive: int32p(0), OptionalPrimitive: int32p(200), RequiredEnum: &enumDefaultBar, OptionalEnum: &enumDefaultFoo, RequiredList: []string{}, OptionalList: []float64{1.0, 2.0, 3.0}, RequiredStruct: &ts.Frame{ TopLeft: &ts.Point{X: 1.0, Y: 2.0}, Size: &ts.Size{Width: 100.0, Height: 200.0}, }, OptionalStruct: &ts.Edge{ StartPoint: &ts.Point{X: 1.0, Y: 2.0}, EndPoint: &ts.Point{X: 3.0, Y: 4.0}, }, }, }, } for _, tt := range tests { if gotWire, err := tt.give.ToWire(); assert.NoError( t, err, "%v.ToWire() failed", tt.give) { assert.True( t, wire.ValuesAreEqual(tt.wantToWire, gotWire), "%v.ToWire() != %v", tt.give, tt.wantToWire) } var gotFromWire ts.DefaultsStruct if err := gotFromWire.FromWire(tt.giveWire); assert.NoError(t, err) { assert.Equal(t, tt.wantFromWire, &gotFromWire) } } }
func (v *PrimitiveOptionalStruct) ToWire() (wire.Value, error) { var ( fields [8]wire.Field i int = 0 w wire.Value err error ) if v.BoolField != nil { w, err = wire.NewValueBool(*(v.BoolField)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ } if v.ByteField != nil { w, err = wire.NewValueI8(*(v.ByteField)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 2, Value: w} i++ } if v.Int16Field != nil { w, err = wire.NewValueI16(*(v.Int16Field)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 3, Value: w} i++ } if v.Int32Field != nil { w, err = wire.NewValueI32(*(v.Int32Field)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 4, Value: w} i++ } if v.Int64Field != nil { w, err = wire.NewValueI64(*(v.Int64Field)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 5, Value: w} i++ } if v.DoubleField != nil { w, err = wire.NewValueDouble(*(v.DoubleField)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 6, Value: w} i++ } if v.StringField != nil { w, err = wire.NewValueString(*(v.StringField)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 7, Value: w} i++ } if v.BinaryField != nil { w, err = wire.NewValueBinary(v.BinaryField), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 8, Value: w} i++ } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func (v *DefaultsStruct) ToWire() (wire.Value, error) { var ( fields [8]wire.Field i int = 0 w wire.Value err error ) if v.RequiredPrimitive == nil { v.RequiredPrimitive = ptr.Int32(100) } { w, err = wire.NewValueI32(*(v.RequiredPrimitive)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 1, Value: w} i++ } if v.OptionalPrimitive == nil { v.OptionalPrimitive = ptr.Int32(200) } { w, err = wire.NewValueI32(*(v.OptionalPrimitive)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 2, Value: w} i++ } if v.RequiredEnum == nil { v.RequiredEnum = _EnumDefault_ptr(enums.EnumDefaultBar) } { w, err = v.RequiredEnum.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 3, Value: w} i++ } if v.OptionalEnum == nil { v.OptionalEnum = _EnumDefault_ptr(enums.EnumDefaultBaz) } { w, err = v.OptionalEnum.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 4, Value: w} i++ } if v.RequiredList == nil { v.RequiredList = []string{"hello", "world"} } { w, err = wire.NewValueList(_List_String_ValueList(v.RequiredList)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 5, Value: w} i++ } if v.OptionalList == nil { v.OptionalList = []float64{1, 2, 3} } { w, err = wire.NewValueList(_List_Double_ValueList(v.OptionalList)), error(nil) if err != nil { return w, err } fields[i] = wire.Field{ID: 6, Value: w} i++ } if v.RequiredStruct == nil { v.RequiredStruct = &Frame{Size: &Size{Height: 200, Width: 100}, TopLeft: &Point{X: 1, Y: 2}} } { w, err = v.RequiredStruct.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 7, Value: w} i++ } if v.OptionalStruct == nil { v.OptionalStruct = &Edge{EndPoint: &Point{X: 3, Y: 4}, StartPoint: &Point{X: 1, Y: 2}} } { w, err = v.OptionalStruct.ToWire() if err != nil { return w, err } fields[i] = wire.Field{ID: 8, Value: w} i++ } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil }
func TestClient(t *testing.T) { tests := []struct { desc string giveRequestBody envelope.Enveloper // outgoing request body giveResponseEnvelope *wire.Envelope // returned on DecodeEnveloped() giveResponseBody *wire.Value // return on Decode() clientOptions []ClientOption expectCall bool // whether outbound.Call is expected wantRequestEnvelope *wire.Envelope // expect EncodeEnveloped(x) wantRequestBody *wire.Value // expect Encode(x) wantError string // whether an error is expected }{ { desc: "happy case", clientOptions: []ClientOption{Enveloped}, giveRequestBody: fakeEnveloper(wire.Call), wantRequestEnvelope: &wire.Envelope{ Name: "someMethod", SeqID: 1, Type: wire.Call, Value: wire.NewValueStruct(wire.Struct{}), }, expectCall: true, giveResponseEnvelope: &wire.Envelope{ Name: "someMethod", SeqID: 1, Type: wire.Reply, Value: wire.NewValueStruct(wire.Struct{}), }, }, { desc: "happy case without enveloping", giveRequestBody: fakeEnveloper(wire.Call), wantRequestBody: valueptr(wire.NewValueStruct(wire.Struct{})), expectCall: true, giveResponseBody: valueptr(wire.NewValueStruct(wire.Struct{})), }, { desc: "wrong envelope type for request", clientOptions: []ClientOption{Enveloped}, giveRequestBody: fakeEnveloper(wire.Reply), wantError: `failed to encode "thrift" request body for procedure ` + `"MyService::someMethod" of service "service": unexpected envelope type: Reply`, }, { desc: "TApplicationException", clientOptions: []ClientOption{Enveloped}, giveRequestBody: fakeEnveloper(wire.Call), wantRequestEnvelope: &wire.Envelope{ Name: "someMethod", SeqID: 1, Type: wire.Call, Value: wire.NewValueStruct(wire.Struct{}), }, expectCall: true, giveResponseEnvelope: &wire.Envelope{ Name: "someMethod", SeqID: 1, Type: wire.Exception, Value: wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("great sadness")}, {ID: 2, Value: wire.NewValueI32(7)}, }}), }, wantError: `thrift request to procedure "MyService::someMethod" of ` + `service "service" encountered an internal failure: ` + "TApplicationException{Message: great sadness, Type: PROTOCOL_ERROR}", }, { desc: "wrong envelope type for response", clientOptions: []ClientOption{Enveloped}, giveRequestBody: fakeEnveloper(wire.Call), wantRequestEnvelope: &wire.Envelope{ Name: "someMethod", SeqID: 1, Type: wire.Call, Value: wire.NewValueStruct(wire.Struct{}), }, expectCall: true, giveResponseEnvelope: &wire.Envelope{ Name: "someMethod", SeqID: 1, Type: wire.Call, Value: wire.NewValueStruct(wire.Struct{}), }, wantError: `failed to decode "thrift" response body for procedure ` + `"MyService::someMethod" of service "service": unexpected envelope type: Call`, }, } for _, tt := range tests { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() proto := NewMockProtocol(mockCtrl) if tt.wantRequestEnvelope != nil { proto.EXPECT().EncodeEnveloped(*tt.wantRequestEnvelope, gomock.Any()). Do(func(_ wire.Envelope, w io.Writer) { _, err := w.Write([]byte("irrelevant")) require.NoError(t, err, "Write() failed") }).Return(nil) } if tt.wantRequestBody != nil { proto.EXPECT().Encode(*tt.wantRequestBody, gomock.Any()). Do(func(_ wire.Value, w io.Writer) { _, err := w.Write([]byte("irrelevant")) require.NoError(t, err, "Write() failed") }).Return(nil) } ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() trans := transporttest.NewMockUnaryOutbound(mockCtrl) if tt.expectCall { trans.EXPECT().Call(ctx, transporttest.NewRequestMatcher(t, &transport.Request{ Caller: "caller", Service: "service", Encoding: Encoding, Procedure: "MyService::someMethod", Body: bytes.NewReader([]byte("irrelevant")), }), ).Return(&transport.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte("irrelevant"))), }, nil) } if tt.giveResponseEnvelope != nil { proto.EXPECT().DecodeEnveloped(gomock.Any()).Return(*tt.giveResponseEnvelope, nil) } if tt.giveResponseBody != nil { proto.EXPECT().Decode(gomock.Any(), wire.TStruct).Return(*tt.giveResponseBody, nil) } opts := tt.clientOptions opts = append(opts, Protocol(proto)) c := New(Config{ Service: "MyService", Channel: channel.MultiOutbound("caller", "service", transport.Outbounds{ Unary: trans, }), }, opts...) _, _, err := c.Call(ctx, nil, tt.giveRequestBody) if tt.wantError != "" { if assert.Error(t, err, "%v: expected failure", tt.desc) { assert.Contains(t, err.Error(), tt.wantError, "%v: error mismatch", tt.desc) } } else { assert.NoError(t, err, "%v: expected success", tt.desc) } } }
// ReadValue reads a value off the given type off the wire starting at the // given offset. // // Returns the Value, the new offset, and an error if there was a decode error. func (br *Reader) ReadValue(t wire.Type, off int64) (wire.Value, int64, error) { switch t { case wire.TBool: b, off, err := br.readByte(off) if err != nil { return wire.Value{}, off, err } if b != 0 && b != 1 { return wire.Value{}, off, decodeErrorf( "invalid value %q for bool field", b, ) } return wire.NewValueBool(b == 1), off, nil case wire.TI8: b, off, err := br.readByte(off) return wire.NewValueI8(int8(b)), off, err case wire.TDouble: value, off, err := br.readInt64(off) d := math.Float64frombits(uint64(value)) return wire.NewValueDouble(d), off, err case wire.TI16: n, off, err := br.readInt16(off) return wire.NewValueI16(n), off, err case wire.TI32: n, off, err := br.readInt32(off) return wire.NewValueI32(n), off, err case wire.TI64: n, off, err := br.readInt64(off) return wire.NewValueI64(n), off, err case wire.TBinary: v, off, err := br.readBytes(off) return wire.NewValueBinary(v), off, err case wire.TStruct: s, off, err := br.readStruct(off) return wire.NewValueStruct(s), off, err case wire.TMap: m, off, err := br.readMap(off) return wire.NewValueMap(m), off, err case wire.TSet: s, off, err := br.readSet(off) return wire.NewValueSet(s), off, err case wire.TList: l, off, err := br.readList(off) return wire.NewValueList(l), off, err default: return wire.Value{}, off, decodeErrorf("unknown ttype %v", t) } }
func TestReadReply(t *testing.T) { tests := []struct { desc string bs []byte want wire.Value wantSeqID int32 wantErr string }{ { desc: "Invalid envelope", bs: []byte{0}, wantErr: "unexpected EOF", }, { desc: "Unexpected envelope type", bs: []byte{ 0x80, 0x01, 0x00, 0x01, // version|type:4 = 1 | call 0x00, 0x00, 0x00, 0x03, // name length = 3 'a', 'b', 'c', // "abc" 0x00, 0x00, 0x04, 0xd2, // seqID:4 = 1234 // <struct> 0x00, // stop }, want: wire.NewValueStruct(wire.Struct{}), wantSeqID: 1234, wantErr: "unknown envelope", }, { desc: "Valid reply", bs: []byte{ 0x80, 0x01, 0x00, 0x02, // version|type:4 = 2 | reply 0x00, 0x00, 0x00, 0x03, // name length = 3 'a', 'b', 'c', // "abc" 0x00, 0x00, 0x04, 0xd2, // seqID:4 = 1234 // <struct> 0x00, // stop }, want: wire.NewValueStruct(wire.Struct{}), wantSeqID: 1234, }, { desc: "Invalid exception", bs: []byte{ 0x80, 0x01, 0x00, 0x03, // version|type:4 = 3 | exception 0x00, 0x00, 0x00, 0x03, // name length = 3 'a', 'b', 'c', // "abc" 0x00, 0x00, 0x04, 0xd2, // seqID:4 = 1234 // <struct> (invalid) 0x08, // type:1 = i32 0x00, 0x01, // id:2 = 1 0x00, 0x00, 0x00, 0x01, // value = 1 0x00, // stop }, want: wire.NewValueStruct(wire.Struct{ Fields: []wire.Field{ {ID: 1, Value: wire.NewValueI32(1)}, }, }), wantSeqID: 1234, // TODO: This should probably fail to decode. Right now, it's being ignored. // wantErr: "failed to decode exception", wantErr: "TApplicationException{}", }, { desc: "Valid exception", bs: []byte{ 0x80, 0x01, 0x00, 0x03, // version|type:4 = 3 | exception 0x00, 0x00, 0x00, 0x03, // name length = 3 'a', 'b', 'c', // "abc" 0x00, 0x00, 0x04, 0xd2, // seqID:4 = 1234 // <struct> 0x0b, // type:1 = string 0x00, 0x01, // id:2 = 1 0x00, 0x00, 0x00, 0x06, // length = 3 'e', 'r', 'r', 'M', 's', 'g', // "errMsg" 0x08, // type:1 = i32 0x00, 0x02, // id:2 = 2 0x00, 0x00, 0x00, 0x01, // value = 1 (unknown method) 0x00, // stop }, want: wire.NewValueStruct(wire.Struct{ Fields: []wire.Field{ {ID: 1, Value: wire.NewValueString("errMsg")}, {ID: 2, Value: wire.NewValueI32(1)}, }, }), wantSeqID: 1234, wantErr: "TApplicationException{Message: errMsg, Type: UNKNOWN_METHOD}", }, } for _, tt := range tests { result, seqID, err := ReadReply(protocol.Binary, bytes.NewReader(tt.bs)) if tt.wantErr != "" { if assert.Error(t, err, tt.desc) { assert.Contains(t, err.Error(), tt.wantErr, "%v: error mismatch", tt.desc) } } else { assert.NoError(t, err, tt.desc) } assert.Equal(t, tt.want, result, "%v: result mismatch", tt.desc) assert.Equal(t, tt.wantSeqID, seqID, "%v: seqID mismatch", tt.desc) } }
func TestCrazyTown(t *testing.T) { tests := []struct { desc string x tc.ContainersOfContainers v wire.Value }{ { "ListOfLists", tc.ContainersOfContainers{ ListOfLists: [][]int32{ {1, 2, 3}, {4, 5, 6}, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 1, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TList, []wire.Value{ wire.NewValueList( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(1), wire.NewValueI32(2), wire.NewValueI32(3), }), ), wire.NewValueList( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(4), wire.NewValueI32(5), wire.NewValueI32(6), }), ), }), )}, }}), }, { "ListOfSets", tc.ContainersOfContainers{ ListOfSets: []map[int32]struct{}{ { 1: struct{}{}, 2: struct{}{}, 3: struct{}{}, }, { 4: struct{}{}, 5: struct{}{}, 6: struct{}{}, }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 2, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TSet, []wire.Value{ wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(1), wire.NewValueI32(2), wire.NewValueI32(3), }), ), wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(4), wire.NewValueI32(5), wire.NewValueI32(6), }), ), }), )}, }}), }, { "ListOfMaps", tc.ContainersOfContainers{ ListOfMaps: []map[int32]int32{ { 1: 100, 2: 200, 3: 300, }, { 4: 400, 5: 500, 6: 600, }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 3, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TMap, []wire.Value{ wire.NewValueMap( wire.MapItemListFromSlice(wire.TI32, wire.TI32, []wire.MapItem{ {Key: wire.NewValueI32(1), Value: wire.NewValueI32(100)}, {Key: wire.NewValueI32(2), Value: wire.NewValueI32(200)}, {Key: wire.NewValueI32(3), Value: wire.NewValueI32(300)}, }), ), wire.NewValueMap( wire.MapItemListFromSlice(wire.TI32, wire.TI32, []wire.MapItem{ {Key: wire.NewValueI32(4), Value: wire.NewValueI32(400)}, {Key: wire.NewValueI32(5), Value: wire.NewValueI32(500)}, {Key: wire.NewValueI32(6), Value: wire.NewValueI32(600)}, }), ), }), )}, }}), }, { "SetOfSets", tc.ContainersOfContainers{ SetOfSets: []map[string]struct{}{ { "1": struct{}{}, "2": struct{}{}, "3": struct{}{}, }, { "4": struct{}{}, "5": struct{}{}, "6": struct{}{}, }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 4, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TSet, []wire.Value{ wire.NewValueSet( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("1"), wire.NewValueString("2"), wire.NewValueString("3"), }), ), wire.NewValueSet( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("4"), wire.NewValueString("5"), wire.NewValueString("6"), }), ), }), )}, }}), }, { "SetOfLists", tc.ContainersOfContainers{ SetOfLists: [][]string{ {"1", "2", "3"}, {"4", "5", "6"}, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 5, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TList, []wire.Value{ wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("1"), wire.NewValueString("2"), wire.NewValueString("3"), }), ), wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("4"), wire.NewValueString("5"), wire.NewValueString("6"), }), ), }), )}, }}), }, { "SetOfMaps", tc.ContainersOfContainers{ SetOfMaps: []map[string]string{ { "1": "one", "2": "two", "3": "three", }, { "4": "four", "5": "five", "6": "six", }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 6, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TMap, []wire.Value{ wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TBinary, []wire.MapItem{ {Key: wire.NewValueString("1"), Value: wire.NewValueString("one")}, {Key: wire.NewValueString("2"), Value: wire.NewValueString("two")}, {Key: wire.NewValueString("3"), Value: wire.NewValueString("three")}, }), ), wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TBinary, []wire.MapItem{ {Key: wire.NewValueString("4"), Value: wire.NewValueString("four")}, {Key: wire.NewValueString("5"), Value: wire.NewValueString("five")}, {Key: wire.NewValueString("6"), Value: wire.NewValueString("six")}, }), ), }), )}, }}), }, { "MapOfMapToInt", tc.ContainersOfContainers{ MapOfMapToInt: []struct { Key map[string]int32 Value int64 }{ { Key: map[string]int32{"1": 1, "2": 2, "3": 3}, Value: 123, }, { Key: map[string]int32{"4": 4, "5": 5, "6": 6}, Value: 456, }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 7, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TMap, wire.TI64, []wire.MapItem{ { Key: wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TI32, []wire.MapItem{ {Key: wire.NewValueString("1"), Value: wire.NewValueI32(1)}, {Key: wire.NewValueString("2"), Value: wire.NewValueI32(2)}, {Key: wire.NewValueString("3"), Value: wire.NewValueI32(3)}, }), ), Value: wire.NewValueI64(123), }, { Key: wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TI32, []wire.MapItem{ {Key: wire.NewValueString("4"), Value: wire.NewValueI32(4)}, {Key: wire.NewValueString("5"), Value: wire.NewValueI32(5)}, {Key: wire.NewValueString("6"), Value: wire.NewValueI32(6)}, }), ), Value: wire.NewValueI64(456), }, }), )}, }}), }, { "MapOfListToSet", tc.ContainersOfContainers{ MapOfListToSet: []struct { Key []int32 Value map[int64]struct{} }{ { Key: []int32{1, 2, 3}, Value: map[int64]struct{}{ 1: {}, 2: {}, 3: {}, }, }, { Key: []int32{4, 5, 6}, Value: map[int64]struct{}{ 4: {}, 5: {}, 6: {}, }, }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 8, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TList, wire.TSet, []wire.MapItem{ { Key: wire.NewValueList( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(1), wire.NewValueI32(2), wire.NewValueI32(3), }), ), Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TI64, []wire.Value{ wire.NewValueI64(1), wire.NewValueI64(2), wire.NewValueI64(3), }), ), }, { Key: wire.NewValueList( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(4), wire.NewValueI32(5), wire.NewValueI32(6), }), ), Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TI64, []wire.Value{ wire.NewValueI64(4), wire.NewValueI64(5), wire.NewValueI64(6), }), ), }, }), )}, }}), }, { "MapOfSetToListOfDouble", tc.ContainersOfContainers{ MapOfSetToListOfDouble: []struct { Key map[int32]struct{} Value []float64 }{ { Key: map[int32]struct{}{ 1: {}, 2: {}, 3: {}, }, Value: []float64{1.0, 2.0, 3.0}, }, { Key: map[int32]struct{}{ 4: {}, 5: {}, 6: {}, }, Value: []float64{4.0, 5.0, 6.0}, }, }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{ {ID: 9, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TSet, wire.TList, []wire.MapItem{ { Key: wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(1), wire.NewValueI32(2), wire.NewValueI32(3), }), ), Value: wire.NewValueList( wire.ValueListFromSlice(wire.TDouble, []wire.Value{ wire.NewValueDouble(1.0), wire.NewValueDouble(2.0), wire.NewValueDouble(3.0), }), ), }, { Key: wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(4), wire.NewValueI32(5), wire.NewValueI32(6), }), ), Value: wire.NewValueList( wire.ValueListFromSlice(wire.TDouble, []wire.Value{ wire.NewValueDouble(4.0), wire.NewValueDouble(5.0), wire.NewValueDouble(6.0), }), ), }, }), )}, }}), }, } for _, tt := range tests { assertRoundTrip(t, &tt.x, tt.v, tt.desc) } }
func TestCollectionsOfPrimitives(t *testing.T) { tests := []struct { desc string p tc.PrimitiveContainers v wire.Value }{ // Lists ///////////////////////////////////////////////////////////// { "empty list", tc.PrimitiveContainers{ListOfInts: []int64{}}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 2, Value: wire.NewValueList(wire.ValueListFromSlice(wire.TI64, []wire.Value{})), }}}), }, { "list of ints", tc.PrimitiveContainers{ListOfInts: []int64{1, 2, 3}}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 2, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TI64, []wire.Value{ wire.NewValueI64(1), wire.NewValueI64(2), wire.NewValueI64(3), }), ), }}}), }, { "list of binary", tc.PrimitiveContainers{ ListOfBinary: [][]byte{ []byte("foo"), {}, []byte("bar"), []byte("baz"), }, }, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 1, Value: wire.NewValueList( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueBinary([]byte("foo")), wire.NewValueBinary([]byte{}), wire.NewValueBinary([]byte("bar")), wire.NewValueBinary([]byte("baz")), }), ), }}}), }, // Sets ////////////////////////////////////////////////////////////// { "empty set", tc.PrimitiveContainers{SetOfStrings: map[string]struct{}{}}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 3, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TBinary, []wire.Value{}), ), }}}), }, { "set of strings", tc.PrimitiveContainers{SetOfStrings: map[string]struct{}{ "foo": {}, "bar": {}, "baz": {}, }}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 3, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TBinary, []wire.Value{ wire.NewValueString("foo"), wire.NewValueString("bar"), wire.NewValueString("baz"), }), ), }}}), }, { "set of bytes", tc.PrimitiveContainers{SetOfBytes: map[int8]struct{}{ -1: {}, 1: {}, 125: {}, }}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 4, Value: wire.NewValueSet( wire.ValueListFromSlice(wire.TI8, []wire.Value{ wire.NewValueI8(-1), wire.NewValueI8(1), wire.NewValueI8(125), }), ), }}}), }, // Maps ////////////////////////////////////////////////////////////// { "empty map", tc.PrimitiveContainers{MapOfStringToBool: map[string]bool{}}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 6, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TBool, []wire.MapItem{}), ), }}}), }, { "map of int to string", tc.PrimitiveContainers{MapOfIntToString: map[int32]string{ -1: "foo", 1234: "bar", -9876: "baz", }}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 5, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TI32, wire.TBinary, []wire.MapItem{ {Key: wire.NewValueI32(-1), Value: wire.NewValueString("foo")}, {Key: wire.NewValueI32(1234), Value: wire.NewValueString("bar")}, {Key: wire.NewValueI32(-9876), Value: wire.NewValueString("baz")}, }), ), }}}), }, { "map of string to bool", tc.PrimitiveContainers{MapOfStringToBool: map[string]bool{ "foo": true, "bar": false, "baz": true, }}, wire.NewValueStruct(wire.Struct{Fields: []wire.Field{{ ID: 6, Value: wire.NewValueMap( wire.MapItemListFromSlice(wire.TBinary, wire.TBool, []wire.MapItem{ {Key: wire.NewValueString("foo"), Value: wire.NewValueBool(true)}, {Key: wire.NewValueString("bar"), Value: wire.NewValueBool(false)}, {Key: wire.NewValueString("baz"), Value: wire.NewValueBool(true)}, }), ), }}}), }, } for _, tt := range tests { assertRoundTrip(t, &tt.p, tt.v, tt.desc) } }
func TestEnumContainers(t *testing.T) { tests := []struct { s tc.EnumContainers v wire.Value }{ { tc.EnumContainers{ ListOfEnums: []te.EnumDefault{ te.EnumDefaultFoo, te.EnumDefaultBar, }, }, singleFieldStruct(1, wire.NewValueList( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(0), wire.NewValueI32(1), }), )), }, { tc.EnumContainers{ SetOfEnums: map[te.EnumWithValues]struct{}{ te.EnumWithValuesX: {}, te.EnumWithValuesZ: {}, }, }, singleFieldStruct(2, wire.NewValueSet( wire.ValueListFromSlice(wire.TI32, []wire.Value{ wire.NewValueI32(123), wire.NewValueI32(789), }), )), }, { tc.EnumContainers{ MapOfEnums: map[te.EnumWithDuplicateValues]int32{ te.EnumWithDuplicateValuesP: 123, te.EnumWithDuplicateValuesQ: 456, }, }, singleFieldStruct(3, wire.NewValueMap( wire.MapItemListFromSlice(wire.TI32, wire.TI32, []wire.MapItem{ {Key: wire.NewValueI32(0), Value: wire.NewValueI32(123)}, {Key: wire.NewValueI32(-1), Value: wire.NewValueI32(456)}, }), )), }, { // this is the same as the one above except we're using "R" intsead // of "P" (they both have the same value) tc.EnumContainers{ MapOfEnums: map[te.EnumWithDuplicateValues]int32{ te.EnumWithDuplicateValuesR: 123, te.EnumWithDuplicateValuesQ: 456, }, }, singleFieldStruct(3, wire.NewValueMap( wire.MapItemListFromSlice(wire.TI32, wire.TI32, []wire.MapItem{ {Key: wire.NewValueI32(0), Value: wire.NewValueI32(123)}, {Key: wire.NewValueI32(-1), Value: wire.NewValueI32(456)}, }), )), }, } for _, tt := range tests { assertRoundTrip(t, &tt.s, tt.v, "EnumContainers") } }
func (v MyEnum2) ToWire() (wire.Value, error) { return wire.NewValueI32(int32(v)), nil }