1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// The protoreflect tag disables fast-path methods, including legacy ones. 6//go:build !protoreflect 7// +build !protoreflect 8 9package proto_test 10 11import ( 12 "bytes" 13 "errors" 14 "fmt" 15 "testing" 16 17 "google.golang.org/protobuf/internal/impl" 18 "google.golang.org/protobuf/proto" 19 "google.golang.org/protobuf/runtime/protoiface" 20 21 legacypb "google.golang.org/protobuf/internal/testprotos/legacy" 22) 23 24type selfMarshaler struct { 25 bytes []byte 26 err error 27} 28 29func (m selfMarshaler) Reset() {} 30func (m selfMarshaler) ProtoMessage() {} 31 32func (m selfMarshaler) String() string { 33 return fmt.Sprintf("selfMarshaler{bytes:%v, err:%v}", m.bytes, m.err) 34} 35 36func (m selfMarshaler) Marshal() ([]byte, error) { 37 return m.bytes, m.err 38} 39 40func (m *selfMarshaler) Unmarshal(b []byte) error { 41 m.bytes = b 42 return m.err 43} 44 45func TestLegacyMarshalMethod(t *testing.T) { 46 for _, test := range []selfMarshaler{ 47 {bytes: []byte("marshal")}, 48 {bytes: []byte("marshal"), err: errors.New("some error")}, 49 } { 50 m := impl.Export{}.MessageOf(test).Interface() 51 b, err := proto.Marshal(m) 52 if err != test.err || !bytes.Equal(b, test.bytes) { 53 t.Errorf("proto.Marshal(%v) = %v, %v; want %v, %v", test, b, err, test.bytes, test.err) 54 } 55 if gotSize, wantSize := proto.Size(m), len(test.bytes); gotSize != wantSize { 56 t.Fatalf("proto.Size(%v) = %v, want %v", test, gotSize, wantSize) 57 } 58 59 prefix := []byte("prefix") 60 want := append(prefix, test.bytes...) 61 b, err = proto.MarshalOptions{}.MarshalAppend(prefix, m) 62 if err != test.err || !bytes.Equal(b, want) { 63 t.Errorf("MarshalAppend(%v, %v) = %v, %v; want %v, %v", prefix, test, b, err, test.bytes, test.err) 64 } 65 66 b, err = proto.MarshalOptions{ 67 Deterministic: true, 68 }.MarshalAppend(nil, m) 69 if err != test.err || !bytes.Equal(b, test.bytes) { 70 t.Errorf("MarshalOptions{Deterministic:true}.MarshalAppend(nil, %v) = %v, %v; want %v, %v", test, b, err, test.bytes, test.err) 71 } 72 } 73} 74 75func TestLegacyUnmarshalMethod(t *testing.T) { 76 sm := &selfMarshaler{} 77 m := impl.Export{}.MessageOf(sm).Interface() 78 want := []byte("unmarshal") 79 if err := proto.Unmarshal(want, m); err != nil { 80 t.Fatalf("proto.Unmarshal(selfMarshaler{}) = %v, want nil", err) 81 } 82 if !bytes.Equal(sm.bytes, want) { 83 t.Fatalf("proto.Unmarshal(selfMarshaler{}): Marshal method not called") 84 } 85} 86 87type descPanicSelfMarshaler struct{} 88 89const descPanicSelfMarshalerBytes = "bytes" 90 91func (m *descPanicSelfMarshaler) Reset() {} 92func (m *descPanicSelfMarshaler) ProtoMessage() {} 93func (m *descPanicSelfMarshaler) Descriptor() ([]byte, []int) { panic("Descriptor method panics") } 94func (m *descPanicSelfMarshaler) String() string { return "descPanicSelfMarshaler{}" } 95func (m *descPanicSelfMarshaler) Marshal() ([]byte, error) { 96 return []byte(descPanicSelfMarshalerBytes), nil 97} 98 99func TestSelfMarshalerDescriptorPanics(t *testing.T) { 100 m := &descPanicSelfMarshaler{} 101 got, err := proto.Marshal(impl.Export{}.MessageOf(m).Interface()) 102 want := []byte(descPanicSelfMarshalerBytes) 103 if err != nil || !bytes.Equal(got, want) { 104 t.Fatalf("proto.Marshal(%v) = %v, %v; want %v, nil", m, got, err, want) 105 } 106} 107 108type descSelfMarshaler struct { 109 someField int // some non-generated field 110} 111 112const descSelfMarshalerBytes = "bytes" 113 114func (m *descSelfMarshaler) Reset() {} 115func (m *descSelfMarshaler) ProtoMessage() {} 116func (m *descSelfMarshaler) Descriptor() ([]byte, []int) { 117 return ((*legacypb.Legacy)(nil)).GetF1().Descriptor() 118} 119func (m *descSelfMarshaler) String() string { 120 return "descSelfMarshaler{}" 121} 122func (m *descSelfMarshaler) Marshal() ([]byte, error) { 123 return []byte(descSelfMarshalerBytes), nil 124} 125 126func TestSelfMarshalerWithDescriptor(t *testing.T) { 127 m := &descSelfMarshaler{} 128 got, err := proto.Marshal(impl.Export{}.MessageOf(m).Interface()) 129 want := []byte(descSelfMarshalerBytes) 130 if err != nil || !bytes.Equal(got, want) { 131 t.Fatalf("proto.Marshal(%v) = %v, %v; want %v, nil", m, got, err, want) 132 } 133} 134 135func TestDecodeFastCheckInitialized(t *testing.T) { 136 for _, test := range testValidMessages { 137 if !test.checkFastInit { 138 continue 139 } 140 for _, message := range test.decodeTo { 141 t.Run(fmt.Sprintf("%s (%T)", test.desc, message), func(t *testing.T) { 142 m := message.ProtoReflect().New() 143 opts := proto.UnmarshalOptions{ 144 AllowPartial: true, 145 } 146 out, err := opts.UnmarshalState(protoiface.UnmarshalInput{ 147 Buf: test.wire, 148 Message: m, 149 }) 150 if err != nil { 151 t.Fatalf("Unmarshal error: %v", err) 152 } 153 if got, want := (out.Flags&protoiface.UnmarshalInitialized != 0), !test.partial; got != want { 154 t.Errorf("out.Initialized = %v, want %v", got, want) 155 } 156 }) 157 } 158 } 159} 160 161type selfMerger struct { 162 src protoiface.MessageV1 163} 164 165func (*selfMerger) Reset() {} 166func (*selfMerger) ProtoMessage() {} 167func (*selfMerger) String() string { return "selfMerger{}" } 168func (m *selfMerger) Merge(src protoiface.MessageV1) { 169 m.src = src 170} 171 172func TestLegacyMergeMethod(t *testing.T) { 173 src := &selfMerger{} 174 dst := &selfMerger{} 175 proto.Merge( 176 impl.Export{}.MessageOf(dst).Interface(), 177 impl.Export{}.MessageOf(src).Interface(), 178 ) 179 if got, want := dst.src, src; got != want { 180 t.Errorf("Merge(dst, src): want dst.src = src, got %v", got) 181 } 182 if got := src.src; got != nil { 183 t.Errorf("Merge(dst, src): want src.src = nil, got %v", got) 184 } 185} 186