diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go index 7e95ec94..4df07a30 100644 --- a/internal/impl/legacy_test.go +++ b/internal/impl/legacy_test.go @@ -676,84 +676,114 @@ func TestLegactExtensions(t *testing.T) { ExtendedType: (*legacyTestMessage)(nil), ExtensionType: (*proto2_20180125.Message_ChildEnum)(nil), Field: 10006, - Name: "fizz.buzz.optional_enum", - Tag: "varint,10006,opt,name=optional_enum,json=optionalEnum,enum=google.golang.org.proto2_20180125.Message_ChildEnum,def=0", + Name: "fizz.buzz.optional_enum_v1", + Tag: "varint,10006,opt,name=optional_enum_v1,json=optionalEnumV1,enum=google.golang.org.proto2_20180125.Message_ChildEnum,def=0", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil), Field: 10007, - Name: "fizz.buzz.optional_message", - Tag: "bytes,10007,opt,name=optional_message,json=optionalMessage", + Name: "fizz.buzz.optional_message_v1", + Tag: "bytes,10007,opt,name=optional_message_v1,json=optionalMessageV1", + Filename: "fizz/buzz/test.proto", + }), + legacyExtensionTypeOf(&protoV1.ExtensionDesc{ + ExtendedType: (*legacyTestMessage)(nil), + ExtensionType: (*EnumProto2)(nil), + Field: 10008, + Name: "fizz.buzz.optional_enum_v2", + Tag: "varint,10008,opt,name=optional_enum_v2,json=optionalEnumV2,enum=EnumProto2,def=57005", + Filename: "fizz/buzz/test.proto", + }), + legacyExtensionTypeOf(&protoV1.ExtensionDesc{ + ExtendedType: (*legacyTestMessage)(nil), + ExtensionType: (*EnumMessages)(nil), + Field: 10009, + Name: "fizz.buzz.optional_message_v2", + Tag: "bytes,10009,opt,name=optional_message_v2,json=optionalMessageV2", Filename: "fizz/buzz/test.proto", }), - // TODO: Test v2 enum and messages. legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]bool)(nil), - Field: 10008, + Field: 10010, Name: "fizz.buzz.repeated_bool", - Tag: "varint,10008,rep,name=repeated_bool,json=repeatedBool", + Tag: "varint,10010,rep,name=repeated_bool,json=repeatedBool", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]int32)(nil), - Field: 10009, + Field: 10011, Name: "fizz.buzz.repeated_int32", - Tag: "varint,10009,rep,name=repeated_int32,json=repeatedInt32", + Tag: "varint,10011,rep,name=repeated_int32,json=repeatedInt32", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]uint32)(nil), - Field: 10010, + Field: 10012, Name: "fizz.buzz.repeated_uint32", - Tag: "varint,10010,rep,name=repeated_uint32,json=repeatedUint32", + Tag: "varint,10012,rep,name=repeated_uint32,json=repeatedUint32", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]float32)(nil), - Field: 10011, + Field: 10013, Name: "fizz.buzz.repeated_float", - Tag: "fixed32,10011,rep,name=repeated_float,json=repeatedFloat", + Tag: "fixed32,10013,rep,name=repeated_float,json=repeatedFloat", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]string)(nil), - Field: 10012, + Field: 10014, Name: "fizz.buzz.repeated_string", - Tag: "bytes,10012,rep,name=repeated_string,json=repeatedString", + Tag: "bytes,10014,rep,name=repeated_string,json=repeatedString", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([][]byte)(nil), - Field: 10013, + Field: 10015, Name: "fizz.buzz.repeated_bytes", - Tag: "bytes,10013,rep,name=repeated_bytes,json=repeatedBytes", + Tag: "bytes,10015,rep,name=repeated_bytes,json=repeatedBytes", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]proto2_20180125.Message_ChildEnum)(nil), - Field: 10014, - Name: "fizz.buzz.repeated_enum", - Tag: "varint,10014,rep,name=repeated_enum,json=repeatedEnum,enum=google.golang.org.proto2_20180125.Message_ChildEnum", + Field: 10016, + Name: "fizz.buzz.repeated_enum_v1", + Tag: "varint,10016,rep,name=repeated_enum_v1,json=repeatedEnumV1,enum=google.golang.org.proto2_20180125.Message_ChildEnum", Filename: "fizz/buzz/test.proto", }), legacyExtensionTypeOf(&protoV1.ExtensionDesc{ ExtendedType: (*legacyTestMessage)(nil), ExtensionType: ([]*proto2_20180125.Message_ChildMessage)(nil), - Field: 10015, - Name: "fizz.buzz.repeated_message", - Tag: "bytes,10015,rep,name=repeated_message,json=repeatedMessage", + Field: 10017, + Name: "fizz.buzz.repeated_message_v1", + Tag: "bytes,10017,rep,name=repeated_message_v1,json=repeatedMessageV1", + Filename: "fizz/buzz/test.proto", + }), + legacyExtensionTypeOf(&protoV1.ExtensionDesc{ + ExtendedType: (*legacyTestMessage)(nil), + ExtensionType: ([]EnumProto2)(nil), + Field: 10018, + Name: "fizz.buzz.repeated_enum_v2", + Tag: "varint,10018,rep,name=repeated_enum_v2,json=repeatedEnumV2,enum=EnumProto2", + Filename: "fizz/buzz/test.proto", + }), + legacyExtensionTypeOf(&protoV1.ExtensionDesc{ + ExtendedType: (*legacyTestMessage)(nil), + ExtensionType: ([]*EnumMessages)(nil), + Field: 10019, + Name: "fizz.buzz.repeated_message_v2", + Tag: "bytes,10019,rep,name=repeated_message_v2,json=repeatedMessageV2", Filename: "fizz/buzz/test.proto", }), - // TODO: Test v2 enum and messages. } opts := cmp.Options{cmp.Comparer(func(x, y *proto2_20180125.Message_ChildMessage) bool { return x == y // pointer compare messages for object identity @@ -786,6 +816,8 @@ func TestLegactExtensions(t *testing.T) { []byte("dead\xde\xad\xbe\xefbeef"), proto2_20180125.Message_ALPHA, nil, + EnumProto2(0xdead), + nil, new([]bool), new([]int32), new([]uint32), @@ -794,6 +826,8 @@ func TestLegactExtensions(t *testing.T) { new([][]byte), new([]proto2_20180125.Message_ChildEnum), new([]*proto2_20180125.Message_ChildMessage), + new([]EnumProto2), + new([]*EnumMessages), } for i, xt := range extensions { var got interface{} @@ -817,8 +851,10 @@ func TestLegactExtensions(t *testing.T) { } // Set some values and append to values to the lists. - m1 := &proto2_20180125.Message_ChildMessage{F1: protoV1.String("m1")} - m2 := &proto2_20180125.Message_ChildMessage{F1: protoV1.String("m2")} + m1a := &proto2_20180125.Message_ChildMessage{F1: protoV1.String("m1a")} + m1b := &proto2_20180125.Message_ChildMessage{F1: protoV1.String("m2b")} + m2a := &EnumMessages{EnumP2: EnumProto2(0x1b).Enum()} + m2b := &EnumMessages{EnumP2: EnumProto2(0x2b).Enum()} setValues := []interface{}{ bool(false), int32(-54321), @@ -827,7 +863,9 @@ func TestLegactExtensions(t *testing.T) { string("goodbye, \"world!\"\n"), []byte("live\xde\xad\xbe\xefchicken"), proto2_20180125.Message_CHARLIE, - m1, + m1a, + EnumProto2(0xbeef), + m2a, &[]bool{true}, &[]int32{-1000}, &[]uint32{1280}, @@ -835,7 +873,9 @@ func TestLegactExtensions(t *testing.T) { &[]string{"zero"}, &[][]byte{[]byte("zero")}, &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO}, - &[]*proto2_20180125.Message_ChildMessage{m2}, + &[]*proto2_20180125.Message_ChildMessage{m1b}, + &[]EnumProto2{0xdead}, + &[]*EnumMessages{m2b}, } for i, xt := range extensions { fs.Set(xt.Number(), xt.ValueOf(setValues[i])) @@ -854,7 +894,9 @@ func TestLegactExtensions(t *testing.T) { string("goodbye, \"world!\"\n"), []byte("live\xde\xad\xbe\xefchicken"), proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE), - m1, + m1a, + EnumProto2(0xbeef), + m2a, &[]bool{true, false}, &[]int32{-1000, -54321}, &[]uint32{1280, 6400}, @@ -862,7 +904,9 @@ func TestLegactExtensions(t *testing.T) { &[]string{"zero", "goodbye, \"world!\"\n"}, &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")}, &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE}, - &[]*proto2_20180125.Message_ChildMessage{m2, m1}, + &[]*proto2_20180125.Message_ChildMessage{m1b, m1a}, + &[]EnumProto2{0xdead, 0xbeef}, + &[]*EnumMessages{m2b, m2a}, } for i, xt := range extensions { got := xt.InterfaceOf(fs.Get(xt.Number())) @@ -872,11 +916,11 @@ func TestLegactExtensions(t *testing.T) { } } - if n := fs.Len(); n != 16 { + if n := fs.Len(); n != 20 { t.Errorf("KnownFields.Len() = %v, want 0", n) } - if n := ts.Len(); n != 16 { - t.Errorf("ExtensionFieldTypes.Len() = %v, want 16", n) + if n := ts.Len(); n != 20 { + t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n) } // Clear the field for all extension types. @@ -886,8 +930,8 @@ func TestLegactExtensions(t *testing.T) { if n := fs.Len(); n != 0 { t.Errorf("KnownFields.Len() = %v, want 0", n) } - if n := ts.Len(); n != 16 { - t.Errorf("ExtensionFieldTypes.Len() = %v, want 16", n) + if n := ts.Len(); n != 20 { + t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n) } // De-register all extension types. diff --git a/internal/impl/message_test.go b/internal/impl/message_test.go index 69b57649..5852896a 100644 --- a/internal/impl/message_test.go +++ b/internal/impl/message_test.go @@ -10,91 +10,116 @@ import ( "strings" "testing" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - protoV1 "github.com/golang/protobuf/proto" descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor" pref "github.com/golang/protobuf/v2/reflect/protoreflect" ptype "github.com/golang/protobuf/v2/reflect/prototype" -) + cmp "github.com/google/go-cmp/cmp" + cmpopts "github.com/google/go-cmp/cmp/cmpopts" -func mustMakeMessageDesc(t ptype.StandaloneMessage) pref.MessageDescriptor { - md, err := ptype.NewMessage(&t) - if err != nil { - panic(err) - } - return md -} - -var V = pref.ValueOf - -type ( - MyBool bool - MyInt32 int32 - MyInt64 int64 - MyUint32 uint32 - MyUint64 uint64 - MyFloat32 float32 - MyFloat64 float64 - MyString string - MyBytes []byte - - ListStrings []MyString - ListBytes []MyBytes - - MapStrings map[MyString]MyString - MapBytes map[MyString]MyBytes + proto2_20180125 "github.com/golang/protobuf/v2/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152" + pvalue "github.com/golang/protobuf/v2/internal/value" ) // List of test operations to perform on messages, lists, or maps. type ( - messageOp interface{} // equalMessage | hasFields | getFields | setFields | clearFields | listFields | mapFields + messageOp interface{ isMessageOp() } messageOps []messageOp - listOp interface{} // equalList | lenList | getList | setList | appendList | truncList + listOp interface{ isListOp() } listOps []listOp - mapOp interface{} // equalMap | lenMap | hasMap | getMap | setMap | clearMap | rangeMap + mapOp interface{ isMapOp() } mapOps []mapOp ) // Test operations performed on a message. type ( - equalMessage pref.Message - hasFields map[pref.FieldNumber]bool - getFields map[pref.FieldNumber]pref.Value - setFields map[pref.FieldNumber]pref.Value - clearFields map[pref.FieldNumber]bool - listFields map[pref.FieldNumber]listOps - mapFields map[pref.FieldNumber]mapOps + // check that the message contents match + equalMessage struct{ pref.Message } + // check presence for specific fields in the message + hasFields map[pref.FieldNumber]bool + // check that specific message fields match + getFields map[pref.FieldNumber]pref.Value + // set specific message fields + setFields map[pref.FieldNumber]pref.Value + // clear specific fields in the message + clearFields []pref.FieldNumber + // apply messageOps on each specified message field messageFields map[pref.FieldNumber]messageOps - // TODO: Mutable, Range, ExtensionTypes + // apply listOps on each specified list field + listFields map[pref.FieldNumber]listOps + // apply mapOps on each specified map fields + mapFields map[pref.FieldNumber]mapOps + // range through all fields and check that they match + rangeFields map[pref.FieldNumber]pref.Value ) +func (equalMessage) isMessageOp() {} +func (hasFields) isMessageOp() {} +func (getFields) isMessageOp() {} +func (setFields) isMessageOp() {} +func (clearFields) isMessageOp() {} +func (messageFields) isMessageOp() {} +func (listFields) isMessageOp() {} +func (mapFields) isMessageOp() {} +func (rangeFields) isMessageOp() {} + // Test operations performed on a list. type ( - equalList pref.List - lenList int - getList map[int]pref.Value - setList map[int]pref.Value + // check that the list contents match + equalList struct{ pref.List } + // check that list length matches + lenList int + // check that specific list entries match + getList map[int]pref.Value + // set specific list entries + setList map[int]pref.Value + // append entries to the list appendList []pref.Value - truncList int - // TODO: Mutable, MutableAppend + // apply messageOps on a newly appended message + appendMessageList messageOps + // truncate the list to the specified length + truncList int ) +func (equalList) isListOp() {} +func (lenList) isListOp() {} +func (getList) isListOp() {} +func (setList) isListOp() {} +func (appendList) isListOp() {} +func (appendMessageList) isListOp() {} +func (truncList) isListOp() {} + // Test operations performed on a map. type ( - equalMap pref.Map - lenMap int - hasMap map[interface{}]bool - getMap map[interface{}]pref.Value - setMap map[interface{}]pref.Value - clearMap map[interface{}]bool + // check that the map contents match + equalMap struct{ pref.Map } + // check that map length matches + lenMap int + // check presence for specific entries in the map + hasMap map[interface{}]bool + // check that specific map entries match + getMap map[interface{}]pref.Value + // set specific map entries + setMap map[interface{}]pref.Value + // clear specific entries in the map + clearMap []interface{} + // apply messageOps on each specified message entry + messageMap map[interface{}]messageOps + // range through all entries and check that they match rangeMap map[interface{}]pref.Value - // TODO: Mutable ) +func (equalMap) isMapOp() {} +func (lenMap) isMapOp() {} +func (hasMap) isMapOp() {} +func (getMap) isMapOp() {} +func (setMap) isMapOp() {} +func (clearMap) isMapOp() {} +func (messageMap) isMapOp() {} +func (rangeMap) isMapOp() {} + type ScalarProto2 struct { Bool *bool `protobuf:"1"` Int32 *int32 `protobuf:"2"` @@ -121,6 +146,43 @@ type ScalarProto2 struct { MyBytesA *MyString `protobuf:"22"` } +func mustMakeEnumDesc(t ptype.StandaloneEnum) pref.EnumDescriptor { + ed, err := ptype.NewEnum(&t) + if err != nil { + panic(err) + } + return ed +} + +func mustMakeMessageDesc(t ptype.StandaloneMessage) pref.MessageDescriptor { + md, err := ptype.NewMessage(&t) + if err != nil { + panic(err) + } + return md +} + +var V = pref.ValueOf +var VE = func(n pref.EnumNumber) pref.Value { return V(n) } + +type ( + MyBool bool + MyInt32 int32 + MyInt64 int64 + MyUint32 uint32 + MyUint64 uint64 + MyFloat32 float32 + MyFloat64 float64 + MyString string + MyBytes []byte + + ListStrings []MyString + ListBytes []MyBytes + + MapStrings map[MyString]MyString + MapBytes map[MyString]MyBytes +) + var scalarProto2Type = MessageType{Type: ptype.GoMessage( mustMakeMessageDesc(ptype.StandaloneMessage{ Syntax: pref.Proto2, @@ -181,15 +243,12 @@ func TestScalarProto2(t *testing.T) { 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, }, - equalMessage(&ScalarProto2{ + equalMessage{&ScalarProto2{ new(bool), new(int32), new(int64), new(uint32), new(uint64), new(float32), new(float64), new(string), []byte{}, []byte{}, new(string), new(MyBool), new(MyInt32), new(MyInt64), new(MyUint32), new(MyUint64), new(MyFloat32), new(MyFloat64), new(MyString), MyBytes{}, MyBytes{}, new(MyString), - }), - clearFields{ - 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, - 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, - }, - equalMessage(&ScalarProto2{}), + }}, + clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, + equalMessage{&ScalarProto2{}}, }) } @@ -279,7 +338,7 @@ func TestScalarProto3(t *testing.T) { 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false, }, - equalMessage(&ScalarProto3{}), + equalMessage{&ScalarProto3{}}, setFields{ 1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")), 12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")), @@ -288,15 +347,12 @@ func TestScalarProto3(t *testing.T) { 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, }, - equalMessage(&ScalarProto3{ + equalMessage{&ScalarProto3{ true, 2, 3, 4, 5, 6, 7, "8", []byte("9"), []byte("10"), "11", true, 13, 14, 15, 16, 17, 18, "19", []byte("20"), []byte("21"), "22", - }), - clearFields{ - 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, - 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, - }, - equalMessage(&ScalarProto3{}), + }}, + clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, + equalMessage{&ScalarProto3{}}, }) } @@ -402,7 +458,7 @@ func TestListScalars(t *testing.T) { lenList(0), appendList{V(int32(2)), V(int32(math.MinInt32)), V(int32(math.MaxInt32))}, getList{0: V(int32(2)), 1: V(int32(math.MinInt32)), 2: V(int32(math.MaxInt32))}, - equalList(wantFS.Get(2).List()), + equalList{wantFS.Get(2).List()}, }, 4: { appendList{V(uint32(0)), V(uint32(0)), V(uint32(0))}, @@ -411,45 +467,45 @@ func TestListScalars(t *testing.T) { }, 6: { appendList{V(float32(6)), V(float32(math.SmallestNonzeroFloat32)), V(float32(math.NaN())), V(float32(math.MaxFloat32))}, - equalList(wantFS.Get(6).List()), + equalList{wantFS.Get(6).List()}, }, 8: { appendList{V(""), V(""), V(""), V(""), V(""), V("")}, lenList(6), setList{0: V("8"), 2: V("eight")}, truncList(3), - equalList(wantFS.Get(8).List()), + equalList{wantFS.Get(8).List()}, }, 10: { appendList{V([]byte(nil)), V([]byte(nil))}, setList{0: V([]byte("10"))}, appendList{V([]byte("wrong"))}, setList{2: V([]byte("ten"))}, - equalList(wantFS.Get(10).List()), + equalList{wantFS.Get(10).List()}, }, 12: { appendList{V("12"), V("wrong"), V("twelve")}, setList{1: V("")}, - equalList(wantFS.Get(12).List()), + equalList{wantFS.Get(12).List()}, }, 14: { appendList{V([]byte("14")), V([]byte(nil)), V([]byte("fourteen"))}, - equalList(wantFS.Get(14).List()), + equalList{wantFS.Get(14).List()}, }, 16: { appendList{V("16"), V(""), V("sixteen"), V("extra")}, truncList(3), - equalList(wantFS.Get(16).List()), + equalList{wantFS.Get(16).List()}, }, 18: { appendList{V([]byte("18")), V([]byte(nil)), V([]byte("eighteen"))}, - equalList(wantFS.Get(18).List()), + equalList{wantFS.Get(18).List()}, }, }, hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true}, - equalMessage(want), - clearFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true}, - equalMessage(empty), + equalMessage{want}, + clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, + equalMessage{empty}, }) } @@ -605,38 +661,38 @@ func TestMapScalars(t *testing.T) { }, 4: { setMap{uint32(0): V("zero"), uint32(1): V("one"), uint32(2): V("two")}, - equalMap(wantFS.Get(4).Map()), + equalMap{wantFS.Get(4).Map()}, }, 6: { - clearMap{"noexist": true}, + clearMap{"noexist"}, setMap{"foo": V("bar")}, setMap{"": V("empty")}, getMap{"": V("empty"), "foo": V("bar"), "noexist": V(nil)}, setMap{"": V(""), "extra": V("extra")}, - clearMap{"extra": true, "noexist": true}, + clearMap{"extra", "noexist"}, }, 8: { - equalMap(emptyFS.Get(8).Map()), + equalMap{emptyFS.Get(8).Map()}, setMap{"one": V(int32(1)), "two": V(int32(2)), "three": V(int32(3))}, }, 10: { setMap{"0x00": V(uint32(0x00)), "0xff": V(uint32(0xff)), "0xdead": V(uint32(0xdead))}, lenMap(3), - equalMap(wantFS.Get(10).Map()), + equalMap{wantFS.Get(10).Map()}, getMap{"0x00": V(uint32(0x00)), "0xff": V(uint32(0xff)), "0xdead": V(uint32(0xdead)), "0xdeadbeef": V(nil)}, }, 12: { setMap{"nan": V(float32(math.NaN())), "pi": V(float32(math.Pi)), "e": V(float32(math.E))}, - clearMap{"e": true, "phi": true}, + clearMap{"e", "phi"}, rangeMap{"nan": V(float32(math.NaN())), "pi": V(float32(math.Pi))}, }, 14: { - equalMap(emptyFS.Get(14).Map()), + equalMap{emptyFS.Get(14).Map()}, setMap{"s1": V("s1"), "s2": V("s2")}, }, 16: { setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))}, - equalMap(wantFS.Get(16).Map()), + equalMap{wantFS.Get(16).Map()}, }, 18: { hasMap{"s1": false, "s2": false, "s3": false}, @@ -644,7 +700,7 @@ func TestMapScalars(t *testing.T) { hasMap{"s1": true, "s2": true, "s3": false}, }, 20: { - equalMap(emptyFS.Get(20).Map()), + equalMap{emptyFS.Get(20).Map()}, setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))}, }, 22: { @@ -655,69 +711,24 @@ func TestMapScalars(t *testing.T) { }, 24: { setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))}, - equalMap(wantFS.Get(24).Map()), + equalMap{wantFS.Get(24).Map()}, }, }, hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, 23: true, 24: true, 25: true}, - equalMessage(want), - clearFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, 23: true, 24: true, 25: true}, - equalMessage(empty), + equalMessage{want}, + clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + equalMessage{empty}, }) } -type ( - OneofScalars struct { - Union isOneofScalars_Union `protobuf_oneof:"union"` - } - isOneofScalars_Union interface { - isOneofScalars_Union() - } - - OneofScalars_Bool struct { - Bool bool `protobuf:"1"` - } - OneofScalars_Int32 struct { - Int32 MyInt32 `protobuf:"2"` - } - OneofScalars_Int64 struct { - Int64 int64 `protobuf:"3"` - } - OneofScalars_Uint32 struct { - Uint32 MyUint32 `protobuf:"4"` - } - OneofScalars_Uint64 struct { - Uint64 uint64 `protobuf:"5"` - } - OneofScalars_Float32 struct { - Float32 MyFloat32 `protobuf:"6"` - } - OneofScalars_Float64 struct { - Float64 float64 `protobuf:"7"` - } - OneofScalars_String struct { - String string `protobuf:"8"` - } - OneofScalars_StringA struct { - StringA []byte `protobuf:"9"` - } - OneofScalars_StringB struct { - StringB MyString `protobuf:"10"` - } - OneofScalars_Bytes struct { - Bytes []byte `protobuf:"11"` - } - OneofScalars_BytesA struct { - BytesA string `protobuf:"12"` - } - OneofScalars_BytesB struct { - BytesB MyBytes `protobuf:"13"` - } -) +type OneofScalars struct { + Union isOneofScalars_Union `protobuf_oneof:"union"` +} var oneofScalarsType = MessageType{Type: ptype.GoMessage( mustMakeMessageDesc(ptype.StandaloneMessage{ Syntax: pref.Proto2, - FullName: "ScalarProto2", + FullName: "OneofScalars", Fields: []ptype.Field{ {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true)), OneofName: "union"}, {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(2)), OneofName: "union"}, @@ -765,6 +776,51 @@ func (*OneofScalars) XXX_OneofFuncs() (func(protoV1.Message, *protoV1.Buffer) er } } +type ( + isOneofScalars_Union interface { + isOneofScalars_Union() + } + OneofScalars_Bool struct { + Bool bool `protobuf:"1"` + } + OneofScalars_Int32 struct { + Int32 MyInt32 `protobuf:"2"` + } + OneofScalars_Int64 struct { + Int64 int64 `protobuf:"3"` + } + OneofScalars_Uint32 struct { + Uint32 MyUint32 `protobuf:"4"` + } + OneofScalars_Uint64 struct { + Uint64 uint64 `protobuf:"5"` + } + OneofScalars_Float32 struct { + Float32 MyFloat32 `protobuf:"6"` + } + OneofScalars_Float64 struct { + Float64 float64 `protobuf:"7"` + } + OneofScalars_String struct { + String string `protobuf:"8"` + } + OneofScalars_StringA struct { + StringA []byte `protobuf:"9"` + } + OneofScalars_StringB struct { + StringB MyString `protobuf:"10"` + } + OneofScalars_Bytes struct { + Bytes []byte `protobuf:"11"` + } + OneofScalars_BytesA struct { + BytesA string `protobuf:"12"` + } + OneofScalars_BytesB struct { + BytesB MyBytes `protobuf:"13"` + } +) + func (*OneofScalars_Bool) isOneofScalars_Union() {} func (*OneofScalars_Int32) isOneofScalars_Union() {} func (*OneofScalars_Int64) isOneofScalars_Union() {} @@ -799,42 +855,273 @@ func TestOneofs(t *testing.T) { hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false}, getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("13"))}, - setFields{1: V(bool(true))}, hasFields{1: true}, equalMessage(want1), - setFields{2: V(int32(20))}, hasFields{2: true}, equalMessage(want2), - setFields{3: V(int64(30))}, hasFields{3: true}, equalMessage(want3), - setFields{4: V(uint32(40))}, hasFields{4: true}, equalMessage(want4), - setFields{5: V(uint64(50))}, hasFields{5: true}, equalMessage(want5), - setFields{6: V(float32(60))}, hasFields{6: true}, equalMessage(want6), - setFields{7: V(float64(70))}, hasFields{7: true}, equalMessage(want7), - setFields{8: V(string("80"))}, hasFields{8: true}, equalMessage(want8), - setFields{9: V(string("90"))}, hasFields{9: true}, equalMessage(want9), - setFields{10: V(string("100"))}, hasFields{10: true}, equalMessage(want10), - setFields{11: V([]byte("110"))}, hasFields{11: true}, equalMessage(want11), - setFields{12: V([]byte("120"))}, hasFields{12: true}, equalMessage(want12), - setFields{13: V([]byte("130"))}, hasFields{13: true}, equalMessage(want13), + setFields{1: V(bool(true))}, hasFields{1: true}, equalMessage{want1}, + setFields{2: V(int32(20))}, hasFields{2: true}, equalMessage{want2}, + setFields{3: V(int64(30))}, hasFields{3: true}, equalMessage{want3}, + setFields{4: V(uint32(40))}, hasFields{4: true}, equalMessage{want4}, + setFields{5: V(uint64(50))}, hasFields{5: true}, equalMessage{want5}, + setFields{6: V(float32(60))}, hasFields{6: true}, equalMessage{want6}, + setFields{7: V(float64(70))}, hasFields{7: true}, equalMessage{want7}, + setFields{8: V(string("80"))}, hasFields{8: true}, equalMessage{want8}, + setFields{9: V(string("90"))}, hasFields{9: true}, equalMessage{want9}, + setFields{10: V(string("100"))}, hasFields{10: true}, equalMessage{want10}, + setFields{11: V([]byte("110"))}, hasFields{11: true}, equalMessage{want11}, + setFields{12: V([]byte("120"))}, hasFields{12: true}, equalMessage{want12}, + setFields{13: V([]byte("130"))}, hasFields{13: true}, equalMessage{want13}, hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: true}, getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("130"))}, - clearFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true}, - equalMessage(want13), - clearFields{13: true}, - equalMessage(empty), + clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, + equalMessage{want13}, + clearFields{13}, + equalMessage{empty}, }) } -// TODO: Need to test singular and repeated messages +type EnumProto2 int32 + +var enumProto2Type = ptype.GoEnum( + mustMakeEnumDesc(ptype.StandaloneEnum{ + Syntax: pref.Proto2, + FullName: "EnumProto2", + Values: []ptype.EnumValue{{Name: "DEAD", Number: 0xdead}, {Name: "BEEF", Number: 0xbeef}}, + }), + func(_ pref.EnumType, n pref.EnumNumber) pref.ProtoEnum { + return EnumProto2(n) + }, +) + +func (e EnumProto2) Enum() *EnumProto2 { return &e } +func (e EnumProto2) Type() pref.EnumType { return enumProto2Type } +func (e EnumProto2) Number() pref.EnumNumber { return pref.EnumNumber(e) } +func (e EnumProto2) ProtoReflect() pref.Enum { return e } + +type EnumProto3 int32 + +var enumProto3Type = ptype.GoEnum( + mustMakeEnumDesc(ptype.StandaloneEnum{ + Syntax: pref.Proto3, + FullName: "EnumProto3", + Values: []ptype.EnumValue{{Name: "ALPHA", Number: 0}, {Name: "BRAVO", Number: 1}}, + }), + func(_ pref.EnumType, n pref.EnumNumber) pref.ProtoEnum { + return EnumProto3(n) + }, +) + +func (e EnumProto3) Enum() *EnumProto3 { return &e } +func (e EnumProto3) Type() pref.EnumType { return enumProto3Type } +func (e EnumProto3) Number() pref.EnumNumber { return pref.EnumNumber(e) } +func (e EnumProto3) ProtoReflect() pref.Enum { return e } + +type EnumMessages struct { + EnumP2 *EnumProto2 `protobuf:"1"` + EnumP3 *EnumProto3 `protobuf:"2"` + MessageLegacy *proto2_20180125.Message `protobuf:"3"` + MessageCycle *EnumMessages `protobuf:"4"` + EnumList []EnumProto2 `protobuf:"5"` + MessageList []*ScalarProto2 `protobuf:"6"` + EnumMap map[string]EnumProto3 `protobuf:"7"` + MessageMap map[string]*ScalarProto3 `protobuf:"8"` + Union isEnumMessages_Union `protobuf_oneof:"union"` +} + +var enumMessagesType = MessageType{Type: ptype.GoMessage( + mustMakeMessageDesc(ptype.StandaloneMessage{ + Syntax: pref.Proto2, + FullName: "EnumMessages", + Fields: []ptype.Field{ + {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BEEF"), EnumType: enumProto2Type}, + {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BRAVO"), EnumType: enumProto3Type}, + {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: MessageOf(new(proto2_20180125.Message)).Type()}, + {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("EnumMessages")}, + {Name: "f5", Number: 5, Cardinality: pref.Repeated, Kind: pref.EnumKind, EnumType: enumProto2Type}, + {Name: "f6", Number: 6, Cardinality: pref.Repeated, Kind: pref.MessageKind, MessageType: scalarProto2Type.Type}, + {Name: "f7", Number: 7, Cardinality: pref.Repeated, Kind: pref.MessageKind, MessageType: enumMapDesc}, + {Name: "f8", Number: 8, Cardinality: pref.Repeated, Kind: pref.MessageKind, MessageType: messageMapDesc}, + {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BEEF"), OneofName: "union", EnumType: enumProto2Type}, + {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.EnumKind, Default: V("BRAVO"), OneofName: "union", EnumType: enumProto3Type}, + {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.MessageKind, OneofName: "union", MessageType: scalarProto2Type.Type}, + {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.MessageKind, OneofName: "union", MessageType: scalarProto3Type.Type}, + }, + Oneofs: []ptype.Oneof{{Name: "union"}}, + }), + func(pref.MessageType) pref.ProtoMessage { + return new(EnumMessages) + }, +)} + +var enumMapDesc = mustMakeMessageDesc(ptype.StandaloneMessage{ + Syntax: pref.Proto2, + FullName: "EnumMessages.F7Entry", + Fields: []ptype.Field{ + {Name: "key", Number: 1, Cardinality: pref.Optional, Kind: pref.StringKind}, + {Name: "value", Number: 2, Cardinality: pref.Optional, Kind: pref.EnumKind, EnumType: enumProto3Type}, + }, + Options: &descriptorV1.MessageOptions{MapEntry: protoV1.Bool(true)}, +}) + +var messageMapDesc = mustMakeMessageDesc(ptype.StandaloneMessage{ + Syntax: pref.Proto2, + FullName: "EnumMessages.F8Entry", + Fields: []ptype.Field{ + {Name: "key", Number: 1, Cardinality: pref.Optional, Kind: pref.StringKind}, + {Name: "value", Number: 2, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: scalarProto3Type.Type}, + }, + Options: &descriptorV1.MessageOptions{MapEntry: protoV1.Bool(true)}, +}) + +func (m *EnumMessages) Type() pref.MessageType { return enumMessagesType.Type } +func (m *EnumMessages) KnownFields() pref.KnownFields { return enumMessagesType.KnownFieldsOf(m) } +func (m *EnumMessages) UnknownFields() pref.UnknownFields { return enumMessagesType.UnknownFieldsOf(m) } +func (m *EnumMessages) Interface() pref.ProtoMessage { return m } +func (m *EnumMessages) ProtoReflect() pref.Message { return m } +func (m *EnumMessages) ProtoMutable() {} + +func (*EnumMessages) XXX_OneofFuncs() (func(protoV1.Message, *protoV1.Buffer) error, func(protoV1.Message, int, int, *protoV1.Buffer) (bool, error), func(protoV1.Message) int, []interface{}) { + return nil, nil, nil, []interface{}{ + (*EnumMessages_OneofE2)(nil), + (*EnumMessages_OneofE3)(nil), + (*EnumMessages_OneofM2)(nil), + (*EnumMessages_OneofM3)(nil), + } +} + +type ( + isEnumMessages_Union interface { + isEnumMessages_Union() + } + EnumMessages_OneofE2 struct { + OneofE2 EnumProto2 `protobuf:"9"` + } + EnumMessages_OneofE3 struct { + OneofE3 EnumProto3 `protobuf:"10"` + } + EnumMessages_OneofM2 struct { + OneofM2 *ScalarProto2 `protobuf:"11"` + } + EnumMessages_OneofM3 struct { + OneofM3 *ScalarProto3 `protobuf:"12"` + } +) + +func (*EnumMessages_OneofE2) isEnumMessages_Union() {} +func (*EnumMessages_OneofE3) isEnumMessages_Union() {} +func (*EnumMessages_OneofM2) isEnumMessages_Union() {} +func (*EnumMessages_OneofM3) isEnumMessages_Union() {} + +func TestEnumMessages(t *testing.T) { + // TODO: Test behavior of Get on unpopulated message. + wantL := MessageOf(&proto2_20180125.Message{OptionalFloat: protoV1.Float32(math.E)}) + wantM := &EnumMessages{EnumP2: EnumProto2(1234).Enum()} + wantM2a := &ScalarProto2{Float32: protoV1.Float32(math.Pi)} + wantM2b := &ScalarProto2{Float32: protoV1.Float32(math.Phi)} + wantM3a := &ScalarProto3{Float32: math.Pi} + wantM3b := &ScalarProto3{Float32: math.Ln2} + + wantList5 := (&EnumMessages{EnumList: []EnumProto2{333, 222}}).KnownFields().Get(5) + wantList6 := (&EnumMessages{MessageList: []*ScalarProto2{wantM2a, wantM2b}}).KnownFields().Get(6) + + wantMap7 := (&EnumMessages{EnumMap: map[string]EnumProto3{"one": 1, "two": 2}}).KnownFields().Get(7) + wantMap8 := (&EnumMessages{MessageMap: map[string]*ScalarProto3{"pi": wantM3a, "ln2": wantM3b}}).KnownFields().Get(8) + + testMessage(t, nil, &EnumMessages{}, messageOps{ + hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false}, + getFields{1: VE(0xbeef), 2: VE(1), 9: VE(0xbeef), 10: VE(1)}, + + // Test singular enums. + setFields{1: VE(0xdead), 2: VE(0)}, + getFields{1: VE(0xdead), 2: VE(0)}, + hasFields{1: true, 2: true}, + + // Test singular messages. + messageFields{3: messageOps{setFields{109: V(float32(math.E))}}}, + messageFields{4: messageOps{setFields{1: VE(1234)}}}, + getFields{3: V(wantL), 4: V(wantM)}, + clearFields{3, 4}, + hasFields{3: false, 4: false}, + setFields{3: V(wantL), 4: V(wantM)}, + hasFields{3: true, 4: true}, + + // Test list of enums and messages. + listFields{ + 5: listOps{ + appendList{VE(111), VE(222)}, + setList{0: VE(333)}, + getList{0: VE(333), 1: VE(222)}, + lenList(2), + }, + 6: listOps{ + appendMessageList{setFields{4: V(uint32(1e6))}}, + appendMessageList{setFields{6: V(float32(math.Phi))}}, + setList{0: V(wantM2a)}, + getList{0: V(wantM2a), 1: V(wantM2b)}, + }, + }, + getFields{5: wantList5, 6: wantList6}, + hasFields{5: true, 6: true}, + listFields{5: listOps{truncList(0)}}, + hasFields{5: false, 6: true}, + + // Test maps of enums and messages. + mapFields{ + 7: mapOps{ + setMap{"one": VE(1), "two": VE(2)}, + hasMap{"one": true, "two": true, "three": false}, + lenMap(2), + }, + 8: mapOps{ + messageMap{"pi": messageOps{setFields{6: V(float32(math.Pi))}}}, + setMap{"ln2": V(wantM3b)}, + getMap{"pi": V(wantM3a), "ln2": V(wantM3b), "none": V(nil)}, + lenMap(2), + }, + }, + getFields{7: wantMap7, 8: wantMap8}, + hasFields{7: true, 8: true}, + mapFields{8: mapOps{clearMap{"pi", "ln2", "none"}}}, + hasFields{7: true, 8: false}, + + // Test oneofs of enums and messages. + setFields{9: VE(0xdead)}, + hasFields{1: true, 2: true, 9: true, 10: false, 11: false, 12: false}, + setFields{10: VE(0)}, + hasFields{1: true, 2: true, 9: false, 10: true, 11: false, 12: false}, + messageFields{11: messageOps{setFields{6: V(float32(math.Pi))}}}, + getFields{11: V(wantM2a)}, + hasFields{1: true, 2: true, 9: false, 10: false, 11: true, 12: false}, + messageFields{12: messageOps{setFields{6: V(float32(math.Pi))}}}, + getFields{12: V(wantM3a)}, + hasFields{1: true, 2: true, 9: false, 10: false, 11: false, 12: true}, + + // Check entire message. + rangeFields{1: VE(0xdead), 2: VE(0), 3: V(wantL), 4: V(wantM), 6: wantList6, 7: wantMap7, 12: V(wantM3a)}, + equalMessage{&EnumMessages{ + EnumP2: EnumProto2(0xdead).Enum(), + EnumP3: EnumProto3(0).Enum(), + MessageLegacy: &proto2_20180125.Message{OptionalFloat: protoV1.Float32(math.E)}, + MessageCycle: wantM, + MessageList: []*ScalarProto2{wantM2a, wantM2b}, + EnumMap: map[string]EnumProto3{"one": 1, "two": 2}, + Union: &EnumMessages_OneofM3{wantM3a}, + }}, + clearFields{1, 2, 3, 4, 6, 7, 12}, + equalMessage{&EnumMessages{}}, + }) +} var cmpOpts = cmp.Options{ - cmp.Transformer("UnwrapValue", func(v pref.Value) interface{} { - return v.Interface() + cmp.Comparer(func(x, y *proto2_20180125.Message) bool { + return protoV1.Equal(x, y) }), - cmp.Transformer("UnwrapList", func(v pref.List) interface{} { - return v.(interface{ Unwrap() interface{} }).Unwrap() + cmp.Transformer("UnwrapValue", func(pv pref.Value) interface{} { + return pv.Interface() }), - cmp.Transformer("UnwrapMap", func(m pref.Map) interface{} { - return m.(interface{ Unwrap() interface{} }).Unwrap() + cmp.Transformer("UnwrapGeneric", func(x pvalue.Unwrapper) interface{} { + return x.Unwrap() }), cmpopts.EquateNaNs(), + cmpopts.EquateEmpty(), } func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) { @@ -843,7 +1130,7 @@ func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) { p.Push(i) switch op := op.(type) { case equalMessage: - if diff := cmp.Diff(op, m, cmpOpts); diff != "" { + if diff := cmp.Diff(op.Message, m, cmpOpts); diff != "" { t.Errorf("operation %v, message mismatch (-want, +got):\n%s", p, diff) } case hasFields: @@ -869,10 +1156,14 @@ func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) { fs.Set(n, v) } case clearFields: - for n, ok := range op { - if ok { - fs.Clear(n) - } + for _, n := range op { + fs.Clear(n) + } + case messageFields: + for n, tt := range op { + p.Push(int(n)) + testMessage(t, p, fs.Mutable(n).(pref.Message), tt) + p.Pop() } case listFields: for n, tt := range op { @@ -886,6 +1177,16 @@ func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) { testMaps(t, p, fs.Mutable(n).(pref.Map), tt) p.Pop() } + case rangeFields: + got := map[pref.FieldNumber]pref.Value{} + want := map[pref.FieldNumber]pref.Value(op) + fs.Range(func(n pref.FieldNumber, v pref.Value) bool { + got[n] = v + return true + }) + if diff := cmp.Diff(want, got, cmpOpts); diff != "" { + t.Errorf("operation %v, KnownFields.Range mismatch (-want, +got):\n%s", p, diff) + } default: t.Fatalf("operation %v, invalid operation: %T", p, op) } @@ -898,7 +1199,7 @@ func testLists(t *testing.T, p path, v pref.List, tt listOps) { p.Push(i) switch op := op.(type) { case equalList: - if diff := cmp.Diff(op, v, cmpOpts); diff != "" { + if diff := cmp.Diff(op.List, v, cmpOpts); diff != "" { t.Errorf("operation %v, list mismatch (-want, +got):\n%s", p, diff) } case lenList: @@ -922,6 +1223,8 @@ func testLists(t *testing.T, p path, v pref.List, tt listOps) { for _, e := range op { v.Append(e) } + case appendMessageList: + testMessage(t, p, v.MutableAppend().(pref.Message), messageOps(op)) case truncList: v.Truncate(int(op)) default: @@ -936,7 +1239,7 @@ func testMaps(t *testing.T, p path, m pref.Map, tt mapOps) { p.Push(i) switch op := op.(type) { case equalMap: - if diff := cmp.Diff(op, m, cmpOpts); diff != "" { + if diff := cmp.Diff(op.Map, m, cmpOpts); diff != "" { t.Errorf("operation %v, map mismatch (-want, +got):\n%s", p, diff) } case lenMap: @@ -966,10 +1269,12 @@ func testMaps(t *testing.T, p path, m pref.Map, tt mapOps) { m.Set(V(k).MapKey(), v) } case clearMap: - for v, ok := range op { - if ok { - m.Clear(V(v).MapKey()) - } + for _, k := range op { + m.Clear(V(k).MapKey()) + } + case messageMap: + for k, tt := range op { + testMessage(t, p, m.Mutable(V(k).MapKey()).(pref.Message), tt) } case rangeMap: got := map[interface{}]pref.Value{}