github.com/jhump/protoreflect@v1.16.0/dynamic/binary_test.go (about) 1 package dynamic 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/golang/protobuf/proto" 8 9 "github.com/jhump/protoreflect/codec" 10 "github.com/jhump/protoreflect/desc" 11 "github.com/jhump/protoreflect/internal/testprotos" 12 "github.com/jhump/protoreflect/internal/testutil" 13 ) 14 15 func TestBinaryUnaryFields(t *testing.T) { 16 binaryTranslationParty(t, unaryFieldsPosMsg, false) 17 binaryTranslationParty(t, unaryFieldsNegMsg, false) 18 binaryTranslationParty(t, unaryFieldsPosInfMsg, false) 19 binaryTranslationParty(t, unaryFieldsNegInfMsg, false) 20 binaryTranslationParty(t, unaryFieldsNanMsg, true) 21 } 22 23 func TestBinaryRepeatedFields(t *testing.T) { 24 binaryTranslationParty(t, repeatedFieldsMsg, false) 25 binaryTranslationParty(t, repeatedFieldsInfNanMsg, true) 26 } 27 28 func TestBinaryPackedRepeatedFields(t *testing.T) { 29 binaryTranslationParty(t, repeatedPackedFieldsMsg, false) 30 binaryTranslationParty(t, repeatedPackedFieldsInfNanMsg, true) 31 } 32 33 func TestBinaryMapKeyFields(t *testing.T) { 34 // translation party wants deterministic marshalling to bytes 35 defaultDeterminism = true 36 defer func() { 37 defaultDeterminism = false 38 }() 39 40 binaryTranslationParty(t, mapKeyFieldsMsg, false) 41 } 42 43 func TestBinaryMapValueFields(t *testing.T) { 44 // translation party wants deterministic marshalling to bytes 45 defaultDeterminism = true 46 defer func() { 47 defaultDeterminism = false 48 }() 49 50 binaryTranslationParty(t, mapValueFieldsMsg, false) 51 binaryTranslationParty(t, mapValueFieldsInfNanMsg, true) 52 binaryTranslationParty(t, mapValueFieldsNilMsg, false) 53 binaryTranslationParty(t, mapValueFieldsNilUnknownMsg, false) 54 } 55 56 func TestBinaryExtensionFields(t *testing.T) { 57 // TODO 58 } 59 60 func TestBinaryUnknownFields(t *testing.T) { 61 // create a buffer with both known fields: 62 b, err := proto.Marshal(&testprotos.TestMessage{ 63 Nm: &testprotos.TestMessage_NestedMessage{ 64 Anm: &testprotos.TestMessage_NestedMessage_AnotherNestedMessage{ 65 Yanm: []*testprotos.TestMessage_NestedMessage_AnotherNestedMessage_YetAnotherNestedMessage{ 66 {Foo: proto.String("foo"), Bar: proto.Int32(100), Baz: []byte{1, 2, 3, 4}}, 67 }, 68 }}, 69 Ne: []testprotos.TestMessage_NestedEnum{testprotos.TestMessage_VALUE1, testprotos.TestMessage_VALUE1}, 70 }) 71 baseLen := len(b) 72 testutil.Ok(t, err) 73 buf := codec.NewBuffer(b) 74 75 // and unknown fields: 76 // varint encoded field 77 _ = buf.EncodeTagAndWireType(1234, proto.WireVarint) 78 _ = buf.EncodeVarint(987654) 79 // fixed 64 80 _ = buf.EncodeTagAndWireType(2345, proto.WireFixed64) 81 _ = buf.EncodeFixed64(123456789) 82 // fixed 32, also repeated 83 _ = buf.EncodeTagAndWireType(3456, proto.WireFixed32) 84 _ = buf.EncodeFixed32(123456) 85 _ = buf.EncodeTagAndWireType(3456, proto.WireFixed32) 86 _ = buf.EncodeFixed32(123457) 87 _ = buf.EncodeTagAndWireType(3456, proto.WireFixed32) 88 _ = buf.EncodeFixed32(123458) 89 _ = buf.EncodeTagAndWireType(3456, proto.WireFixed32) 90 _ = buf.EncodeFixed32(123459) 91 // length-encoded 92 _ = buf.EncodeTagAndWireType(4567, proto.WireBytes) 93 _ = buf.EncodeRawBytes([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) 94 // and... group! 95 _ = buf.EncodeTagAndWireType(5678, proto.WireStartGroup) 96 { 97 _ = buf.EncodeTagAndWireType(1, proto.WireVarint) 98 _ = buf.EncodeVarint(1) 99 _ = buf.EncodeTagAndWireType(2, proto.WireFixed32) 100 _ = buf.EncodeFixed32(2) 101 _ = buf.EncodeTagAndWireType(3, proto.WireFixed64) 102 _ = buf.EncodeFixed64(3) 103 _ = buf.EncodeTagAndWireType(4, proto.WireBytes) 104 _ = buf.EncodeRawBytes([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) 105 // nested group 106 _ = buf.EncodeTagAndWireType(5, proto.WireStartGroup) 107 { 108 _ = buf.EncodeTagAndWireType(1, proto.WireVarint) 109 _ = buf.EncodeVarint(1) 110 _ = buf.EncodeTagAndWireType(1, proto.WireVarint) 111 _ = buf.EncodeVarint(2) 112 _ = buf.EncodeTagAndWireType(1, proto.WireVarint) 113 _ = buf.EncodeVarint(3) 114 _ = buf.EncodeTagAndWireType(2, proto.WireBytes) 115 _ = buf.EncodeRawBytes([]byte("lorem ipsum")) 116 } 117 _ = buf.EncodeTagAndWireType(5, proto.WireEndGroup) 118 } 119 _ = buf.EncodeTagAndWireType(5678, proto.WireEndGroup) 120 testutil.Require(t, buf.Len() > baseLen) // sanity check 121 122 var msg testprotos.TestMessage 123 err = proto.Unmarshal(buf.Bytes(), &msg) 124 testutil.Ok(t, err) 125 // make sure unrecognized fields parsed correctly 126 testutil.Eq(t, buf.Bytes()[baseLen:], []byte(msg.ProtoReflect().GetUnknown())) 127 128 // make sure dynamic message's round trip generates same bytes 129 md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestMessage)(nil)) 130 testutil.Ok(t, err) 131 dm := NewMessage(md) 132 err = dm.Unmarshal(buf.Bytes()) 133 testutil.Ok(t, err) 134 bb, err := dm.Marshal() 135 testutil.Ok(t, err) 136 testutil.Eq(t, buf.Bytes(), bb) 137 138 // now try a full translation party to ensure unknown bits remain correct throughout 139 binaryTranslationParty(t, &msg, false) 140 } 141 142 func binaryTranslationParty(t *testing.T, msg proto.Message, includesNaN bool) { 143 marshalAppendSimple := func(m *Message) ([]byte, error) { 144 // Declare a function that has the same interface as (*Message.Marshal) but uses 145 // MarshalAppend internally so we can reuse the translation party tests to verify 146 // the behavior of MarshalAppend in addition to Marshal. 147 b := make([]byte, 0, 2048) 148 marshaledB, err := m.MarshalAppend(b) 149 150 // Verify it doesn't allocate a new byte slice. 151 assertByteSlicesBackedBySameData(t, b, marshaledB) 152 return marshaledB, err 153 } 154 155 marshalAppendPrefix := func(m *Message) ([]byte, error) { 156 // Same thing as MarshalAppendSimple, but we verify that prefix data is retained. 157 prefix := "prefix" 158 marshaledB, err := m.MarshalAppend([]byte(prefix)) 159 160 // Verify the prefix data is retained. 161 testutil.Eq(t, prefix, string(marshaledB[:len(prefix)])) 162 return marshaledB[len(prefix):], err 163 } 164 165 marshalMethods := []func(m *Message) ([]byte, error){ 166 (*Message).Marshal, 167 marshalAppendSimple, 168 marshalAppendPrefix, 169 } 170 171 protoMarshal := func(m proto.Message) ([]byte, error) { 172 if defaultDeterminism { 173 var buf proto.Buffer 174 buf.SetDeterministic(true) 175 if err := buf.Marshal(m); err != nil { 176 return nil, err 177 } 178 return buf.Bytes(), nil 179 } 180 return proto.Marshal(m) 181 } 182 183 for _, marshalFn := range marshalMethods { 184 doTranslationParty(t, msg, protoMarshal, proto.Unmarshal, marshalFn, (*Message).Unmarshal, includesNaN, true, false) 185 } 186 } 187 188 // byteSlicesBackedBySameData returns a bool indicating if the raw backing bytes 189 // under the []byte slice point to the same memory. 190 func assertByteSlicesBackedBySameData(t *testing.T, a, b []byte) { 191 origPtr := reflect.ValueOf(a).Pointer() 192 resultPtr := reflect.ValueOf(b).Pointer() 193 testutil.Eq(t, origPtr, resultPtr) 194 }