1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage proto_test 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "bytes" 9*1c12ee1eSDan Willemsen "fmt" 10*1c12ee1eSDan Willemsen "math" 11*1c12ee1eSDan Willemsen "reflect" 12*1c12ee1eSDan Willemsen "testing" 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen "github.com/google/go-cmp/cmp" 15*1c12ee1eSDan Willemsen 16*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/prototext" 17*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 18*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 20*1c12ee1eSDan Willemsen 21*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/errors" 22*1c12ee1eSDan Willemsen orderpb "google.golang.org/protobuf/internal/testprotos/order" 23*1c12ee1eSDan Willemsen testpb "google.golang.org/protobuf/internal/testprotos/test" 24*1c12ee1eSDan Willemsen test3pb "google.golang.org/protobuf/internal/testprotos/test3" 25*1c12ee1eSDan Willemsen) 26*1c12ee1eSDan Willemsen 27*1c12ee1eSDan Willemsenfunc TestEncode(t *testing.T) { 28*1c12ee1eSDan Willemsen for _, test := range testValidMessages { 29*1c12ee1eSDan Willemsen for _, want := range test.decodeTo { 30*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) { 31*1c12ee1eSDan Willemsen opts := proto.MarshalOptions{ 32*1c12ee1eSDan Willemsen AllowPartial: test.partial, 33*1c12ee1eSDan Willemsen } 34*1c12ee1eSDan Willemsen wire, err := opts.Marshal(want) 35*1c12ee1eSDan Willemsen if err != nil { 36*1c12ee1eSDan Willemsen t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want)) 37*1c12ee1eSDan Willemsen } 38*1c12ee1eSDan Willemsen 39*1c12ee1eSDan Willemsen size := proto.Size(want) 40*1c12ee1eSDan Willemsen if size != len(wire) { 41*1c12ee1eSDan Willemsen t.Errorf("Size and marshal disagree: Size(m)=%v; len(Marshal(m))=%v\nMessage:\n%v", size, len(wire), prototext.Format(want)) 42*1c12ee1eSDan Willemsen } 43*1c12ee1eSDan Willemsen 44*1c12ee1eSDan Willemsen got := want.ProtoReflect().New().Interface() 45*1c12ee1eSDan Willemsen uopts := proto.UnmarshalOptions{ 46*1c12ee1eSDan Willemsen AllowPartial: test.partial, 47*1c12ee1eSDan Willemsen } 48*1c12ee1eSDan Willemsen if err := uopts.Unmarshal(wire, got); err != nil { 49*1c12ee1eSDan Willemsen t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want)) 50*1c12ee1eSDan Willemsen return 51*1c12ee1eSDan Willemsen } 52*1c12ee1eSDan Willemsen if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() { 53*1c12ee1eSDan Willemsen t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want)) 54*1c12ee1eSDan Willemsen } 55*1c12ee1eSDan Willemsen }) 56*1c12ee1eSDan Willemsen } 57*1c12ee1eSDan Willemsen } 58*1c12ee1eSDan Willemsen} 59*1c12ee1eSDan Willemsen 60*1c12ee1eSDan Willemsenfunc TestEncodeDeterministic(t *testing.T) { 61*1c12ee1eSDan Willemsen for _, test := range testValidMessages { 62*1c12ee1eSDan Willemsen for _, want := range test.decodeTo { 63*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) { 64*1c12ee1eSDan Willemsen opts := proto.MarshalOptions{ 65*1c12ee1eSDan Willemsen Deterministic: true, 66*1c12ee1eSDan Willemsen AllowPartial: test.partial, 67*1c12ee1eSDan Willemsen } 68*1c12ee1eSDan Willemsen wire, err := opts.Marshal(want) 69*1c12ee1eSDan Willemsen if err != nil { 70*1c12ee1eSDan Willemsen t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want)) 71*1c12ee1eSDan Willemsen } 72*1c12ee1eSDan Willemsen wire2, err := opts.Marshal(want) 73*1c12ee1eSDan Willemsen if err != nil { 74*1c12ee1eSDan Willemsen t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want)) 75*1c12ee1eSDan Willemsen } 76*1c12ee1eSDan Willemsen if !bytes.Equal(wire, wire2) { 77*1c12ee1eSDan Willemsen t.Fatalf("deterministic marshal returned varying results:\n%v", cmp.Diff(wire, wire2)) 78*1c12ee1eSDan Willemsen } 79*1c12ee1eSDan Willemsen 80*1c12ee1eSDan Willemsen got := want.ProtoReflect().New().Interface() 81*1c12ee1eSDan Willemsen uopts := proto.UnmarshalOptions{ 82*1c12ee1eSDan Willemsen AllowPartial: test.partial, 83*1c12ee1eSDan Willemsen } 84*1c12ee1eSDan Willemsen if err := uopts.Unmarshal(wire, got); err != nil { 85*1c12ee1eSDan Willemsen t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want)) 86*1c12ee1eSDan Willemsen return 87*1c12ee1eSDan Willemsen } 88*1c12ee1eSDan Willemsen if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() { 89*1c12ee1eSDan Willemsen t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want)) 90*1c12ee1eSDan Willemsen } 91*1c12ee1eSDan Willemsen }) 92*1c12ee1eSDan Willemsen } 93*1c12ee1eSDan Willemsen } 94*1c12ee1eSDan Willemsen} 95*1c12ee1eSDan Willemsen 96*1c12ee1eSDan Willemsenfunc TestEncodeRequiredFieldChecks(t *testing.T) { 97*1c12ee1eSDan Willemsen for _, test := range testValidMessages { 98*1c12ee1eSDan Willemsen if !test.partial { 99*1c12ee1eSDan Willemsen continue 100*1c12ee1eSDan Willemsen } 101*1c12ee1eSDan Willemsen for _, m := range test.decodeTo { 102*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) { 103*1c12ee1eSDan Willemsen _, err := proto.Marshal(m) 104*1c12ee1eSDan Willemsen if err == nil { 105*1c12ee1eSDan Willemsen t.Fatalf("Marshal succeeded (want error)\nMessage:\n%v", prototext.Format(m)) 106*1c12ee1eSDan Willemsen } 107*1c12ee1eSDan Willemsen }) 108*1c12ee1eSDan Willemsen } 109*1c12ee1eSDan Willemsen } 110*1c12ee1eSDan Willemsen} 111*1c12ee1eSDan Willemsen 112*1c12ee1eSDan Willemsenfunc TestEncodeAppend(t *testing.T) { 113*1c12ee1eSDan Willemsen want := []byte("prefix") 114*1c12ee1eSDan Willemsen got := append([]byte(nil), want...) 115*1c12ee1eSDan Willemsen got, err := proto.MarshalOptions{}.MarshalAppend(got, &test3pb.TestAllTypes{ 116*1c12ee1eSDan Willemsen SingularString: "value", 117*1c12ee1eSDan Willemsen }) 118*1c12ee1eSDan Willemsen if err != nil { 119*1c12ee1eSDan Willemsen t.Fatal(err) 120*1c12ee1eSDan Willemsen } 121*1c12ee1eSDan Willemsen if !bytes.HasPrefix(got, want) { 122*1c12ee1eSDan Willemsen t.Fatalf("MarshalAppend modified prefix: got %v, want prefix %v", got, want) 123*1c12ee1eSDan Willemsen } 124*1c12ee1eSDan Willemsen} 125*1c12ee1eSDan Willemsen 126*1c12ee1eSDan Willemsenfunc TestEncodeInvalidMessages(t *testing.T) { 127*1c12ee1eSDan Willemsen for _, test := range testInvalidMessages { 128*1c12ee1eSDan Willemsen for _, m := range test.decodeTo { 129*1c12ee1eSDan Willemsen if !m.ProtoReflect().IsValid() { 130*1c12ee1eSDan Willemsen continue 131*1c12ee1eSDan Willemsen } 132*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) { 133*1c12ee1eSDan Willemsen opts := proto.MarshalOptions{ 134*1c12ee1eSDan Willemsen AllowPartial: test.partial, 135*1c12ee1eSDan Willemsen } 136*1c12ee1eSDan Willemsen got, err := opts.Marshal(m) 137*1c12ee1eSDan Willemsen if err == nil { 138*1c12ee1eSDan Willemsen t.Fatalf("Marshal unexpectedly succeeded\noutput bytes: [%x]\nMessage:\n%v", got, prototext.Format(m)) 139*1c12ee1eSDan Willemsen } 140*1c12ee1eSDan Willemsen if !errors.Is(err, proto.Error) { 141*1c12ee1eSDan Willemsen t.Fatalf("Marshal error is not a proto.Error: %v", err) 142*1c12ee1eSDan Willemsen } 143*1c12ee1eSDan Willemsen }) 144*1c12ee1eSDan Willemsen } 145*1c12ee1eSDan Willemsen } 146*1c12ee1eSDan Willemsen} 147*1c12ee1eSDan Willemsen 148*1c12ee1eSDan Willemsenfunc TestEncodeOneofNilWrapper(t *testing.T) { 149*1c12ee1eSDan Willemsen m := &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofUint32)(nil)} 150*1c12ee1eSDan Willemsen b, err := proto.Marshal(m) 151*1c12ee1eSDan Willemsen if err != nil { 152*1c12ee1eSDan Willemsen t.Fatal(err) 153*1c12ee1eSDan Willemsen } 154*1c12ee1eSDan Willemsen if len(b) > 0 { 155*1c12ee1eSDan Willemsen t.Errorf("Marshal return non-empty, want empty") 156*1c12ee1eSDan Willemsen } 157*1c12ee1eSDan Willemsen} 158*1c12ee1eSDan Willemsen 159*1c12ee1eSDan Willemsenfunc TestMarshalAppendAllocations(t *testing.T) { 160*1c12ee1eSDan Willemsen m := &test3pb.TestAllTypes{SingularInt32: 1} 161*1c12ee1eSDan Willemsen size := proto.Size(m) 162*1c12ee1eSDan Willemsen const count = 1000 163*1c12ee1eSDan Willemsen b := make([]byte, size) 164*1c12ee1eSDan Willemsen // AllocsPerRun returns an integral value. 165*1c12ee1eSDan Willemsen marshalAllocs := testing.AllocsPerRun(count, func() { 166*1c12ee1eSDan Willemsen _, err := proto.MarshalOptions{}.MarshalAppend(b[:0], m) 167*1c12ee1eSDan Willemsen if err != nil { 168*1c12ee1eSDan Willemsen t.Fatal(err) 169*1c12ee1eSDan Willemsen } 170*1c12ee1eSDan Willemsen }) 171*1c12ee1eSDan Willemsen b = nil 172*1c12ee1eSDan Willemsen marshalAppendAllocs := testing.AllocsPerRun(count, func() { 173*1c12ee1eSDan Willemsen var err error 174*1c12ee1eSDan Willemsen b, err = proto.MarshalOptions{}.MarshalAppend(b, m) 175*1c12ee1eSDan Willemsen if err != nil { 176*1c12ee1eSDan Willemsen t.Fatal(err) 177*1c12ee1eSDan Willemsen } 178*1c12ee1eSDan Willemsen }) 179*1c12ee1eSDan Willemsen if marshalAllocs != marshalAppendAllocs { 180*1c12ee1eSDan Willemsen t.Errorf("%v allocs/op when writing to a preallocated buffer", marshalAllocs) 181*1c12ee1eSDan Willemsen t.Errorf("%v allocs/op when repeatedly appending to a slice", marshalAppendAllocs) 182*1c12ee1eSDan Willemsen t.Errorf("expect amortized allocs/op to be identical") 183*1c12ee1eSDan Willemsen } 184*1c12ee1eSDan Willemsen} 185*1c12ee1eSDan Willemsen 186*1c12ee1eSDan Willemsenfunc TestEncodeOrder(t *testing.T) { 187*1c12ee1eSDan Willemsen // We make no guarantees about the stability of wire marshal output. 188*1c12ee1eSDan Willemsen // The order in which fields are marshaled may change over time. 189*1c12ee1eSDan Willemsen // If deterministic marshaling is not enabled, it may change over 190*1c12ee1eSDan Willemsen // successive calls to proto.Marshal in the same binary. 191*1c12ee1eSDan Willemsen // 192*1c12ee1eSDan Willemsen // Unfortunately, many users have come to rely on the specific current 193*1c12ee1eSDan Willemsen // wire marshal output. Perhaps someday we will choose to deliberately 194*1c12ee1eSDan Willemsen // change the marshal output; until that day comes, this test verifies 195*1c12ee1eSDan Willemsen // that we don't unintentionally change it. 196*1c12ee1eSDan Willemsen m := &orderpb.Message{ 197*1c12ee1eSDan Willemsen Field_1: proto.String("one"), 198*1c12ee1eSDan Willemsen Field_2: proto.String("two"), 199*1c12ee1eSDan Willemsen Field_20: proto.String("twenty"), 200*1c12ee1eSDan Willemsen Oneof_1: &orderpb.Message_Field_10{"ten"}, 201*1c12ee1eSDan Willemsen } 202*1c12ee1eSDan Willemsen proto.SetExtension(m, orderpb.E_Field_30, "thirty") 203*1c12ee1eSDan Willemsen proto.SetExtension(m, orderpb.E_Field_31, "thirty-one") 204*1c12ee1eSDan Willemsen proto.SetExtension(m, orderpb.E_Field_32, "thirty-two") 205*1c12ee1eSDan Willemsen want := []protoreflect.FieldNumber{ 206*1c12ee1eSDan Willemsen 30, 31, 32, // extensions first, in number order 207*1c12ee1eSDan Willemsen 1, 2, 20, // non-extension, non-oneof in number order 208*1c12ee1eSDan Willemsen 10, // oneofs last, undefined order 209*1c12ee1eSDan Willemsen } 210*1c12ee1eSDan Willemsen 211*1c12ee1eSDan Willemsen // Test with deterministic serialization, since fields are not sorted without 212*1c12ee1eSDan Willemsen // it when -tags=protoreflect. 213*1c12ee1eSDan Willemsen b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) 214*1c12ee1eSDan Willemsen if err != nil { 215*1c12ee1eSDan Willemsen t.Fatal(err) 216*1c12ee1eSDan Willemsen } 217*1c12ee1eSDan Willemsen var got []protoreflect.FieldNumber 218*1c12ee1eSDan Willemsen for len(b) > 0 { 219*1c12ee1eSDan Willemsen num, _, n := protowire.ConsumeField(b) 220*1c12ee1eSDan Willemsen if n < 0 { 221*1c12ee1eSDan Willemsen t.Fatal(protowire.ParseError(n)) 222*1c12ee1eSDan Willemsen } 223*1c12ee1eSDan Willemsen b = b[n:] 224*1c12ee1eSDan Willemsen got = append(got, num) 225*1c12ee1eSDan Willemsen } 226*1c12ee1eSDan Willemsen if !reflect.DeepEqual(got, want) { 227*1c12ee1eSDan Willemsen t.Errorf("unexpected field marshal order:\ngot: %v\nwant: %v\nmessage:\n%v", got, want, m) 228*1c12ee1eSDan Willemsen } 229*1c12ee1eSDan Willemsen} 230*1c12ee1eSDan Willemsen 231*1c12ee1eSDan Willemsenfunc TestEncodeLarge(t *testing.T) { 232*1c12ee1eSDan Willemsen // Encode/decode a message large enough to overflow a 32-bit size cache. 233*1c12ee1eSDan Willemsen t.Skip("too slow and memory-hungry to run all the time") 234*1c12ee1eSDan Willemsen size := int64(math.MaxUint32 + 1) 235*1c12ee1eSDan Willemsen m := &testpb.TestAllTypes_NestedMessage{ 236*1c12ee1eSDan Willemsen Corecursive: &testpb.TestAllTypes{ 237*1c12ee1eSDan Willemsen OptionalBytes: make([]byte, size), 238*1c12ee1eSDan Willemsen }, 239*1c12ee1eSDan Willemsen } 240*1c12ee1eSDan Willemsen b, err := proto.Marshal(m) 241*1c12ee1eSDan Willemsen if err != nil { 242*1c12ee1eSDan Willemsen t.Fatalf("Marshal: %v", err) 243*1c12ee1eSDan Willemsen } 244*1c12ee1eSDan Willemsen if got, want := len(b), proto.Size(m); got != want { 245*1c12ee1eSDan Willemsen t.Fatalf("Size(m) = %v, but len(Marshal(m)) = %v", got, want) 246*1c12ee1eSDan Willemsen } 247*1c12ee1eSDan Willemsen if err := proto.Unmarshal(b, m); err != nil { 248*1c12ee1eSDan Willemsen t.Fatalf("Unmarshal: %v", err) 249*1c12ee1eSDan Willemsen } 250*1c12ee1eSDan Willemsen if got, want := int64(len(m.Corecursive.OptionalBytes)), size; got != want { 251*1c12ee1eSDan Willemsen t.Errorf("after round-trip marshal, got len(m.OptionalBytes) = %v, want %v", got, want) 252*1c12ee1eSDan Willemsen } 253*1c12ee1eSDan Willemsen} 254*1c12ee1eSDan Willemsen 255*1c12ee1eSDan Willemsen// TestEncodeEmpty tests for boundary conditions when producing an empty output. 256*1c12ee1eSDan Willemsen// These tests are not necessarily a statement of proper behavior, 257*1c12ee1eSDan Willemsen// but exist to detect accidental changes in behavior. 258*1c12ee1eSDan Willemsenfunc TestEncodeEmpty(t *testing.T) { 259*1c12ee1eSDan Willemsen for _, m := range []proto.Message{nil, (*testpb.TestAllTypes)(nil), &testpb.TestAllTypes{}} { 260*1c12ee1eSDan Willemsen isValid := m != nil && m.ProtoReflect().IsValid() 261*1c12ee1eSDan Willemsen 262*1c12ee1eSDan Willemsen b, err := proto.Marshal(m) 263*1c12ee1eSDan Willemsen if err != nil { 264*1c12ee1eSDan Willemsen t.Errorf("proto.Marshal() = %v", err) 265*1c12ee1eSDan Willemsen } 266*1c12ee1eSDan Willemsen if isNil := b == nil; isNil == isValid { 267*1c12ee1eSDan Willemsen t.Errorf("proto.Marshal() == nil: %v, want %v", isNil, !isValid) 268*1c12ee1eSDan Willemsen } 269*1c12ee1eSDan Willemsen 270*1c12ee1eSDan Willemsen b, err = proto.MarshalOptions{}.Marshal(m) 271*1c12ee1eSDan Willemsen if err != nil { 272*1c12ee1eSDan Willemsen t.Errorf("proto.MarshalOptions{}.Marshal() = %v", err) 273*1c12ee1eSDan Willemsen } 274*1c12ee1eSDan Willemsen if isNil := b == nil; isNil == isValid { 275*1c12ee1eSDan Willemsen t.Errorf("proto.MarshalOptions{}.Marshal() = %v, want %v", isNil, !isValid) 276*1c12ee1eSDan Willemsen } 277*1c12ee1eSDan Willemsen } 278*1c12ee1eSDan Willemsen} 279