1*1c12ee1eSDan Willemsen// Copyright 2018 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 "reflect" 11*1c12ee1eSDan Willemsen "testing" 12*1c12ee1eSDan Willemsen 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/prototext" 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 16*1c12ee1eSDan Willemsen "google.golang.org/protobuf/testing/protopack" 17*1c12ee1eSDan Willemsen 18*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/errors" 19*1c12ee1eSDan Willemsen testpb "google.golang.org/protobuf/internal/testprotos/test" 20*1c12ee1eSDan Willemsen test3pb "google.golang.org/protobuf/internal/testprotos/test3" 21*1c12ee1eSDan Willemsen) 22*1c12ee1eSDan Willemsen 23*1c12ee1eSDan Willemsenfunc TestDecode(t *testing.T) { 24*1c12ee1eSDan Willemsen for _, test := range testValidMessages { 25*1c12ee1eSDan Willemsen if len(test.decodeTo) == 0 { 26*1c12ee1eSDan Willemsen t.Errorf("%v: no test message types", test.desc) 27*1c12ee1eSDan Willemsen } 28*1c12ee1eSDan Willemsen for _, want := range test.decodeTo { 29*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) { 30*1c12ee1eSDan Willemsen opts := test.unmarshalOptions 31*1c12ee1eSDan Willemsen opts.AllowPartial = test.partial 32*1c12ee1eSDan Willemsen wire := append(([]byte)(nil), test.wire...) 33*1c12ee1eSDan Willemsen got := reflect.New(reflect.TypeOf(want).Elem()).Interface().(proto.Message) 34*1c12ee1eSDan Willemsen if err := opts.Unmarshal(wire, got); err != nil { 35*1c12ee1eSDan Willemsen t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want)) 36*1c12ee1eSDan Willemsen return 37*1c12ee1eSDan Willemsen } 38*1c12ee1eSDan Willemsen 39*1c12ee1eSDan Willemsen // Aliasing check: Unmarshal shouldn't modify the original wire 40*1c12ee1eSDan Willemsen // bytes, and modifying the original wire bytes shouldn't affect 41*1c12ee1eSDan Willemsen // the unmarshaled message. 42*1c12ee1eSDan Willemsen if !bytes.Equal(test.wire, wire) { 43*1c12ee1eSDan Willemsen t.Errorf("Unmarshal unexpectedly modified its input") 44*1c12ee1eSDan Willemsen } 45*1c12ee1eSDan Willemsen for i := range wire { 46*1c12ee1eSDan Willemsen wire[i] = 0 47*1c12ee1eSDan Willemsen } 48*1c12ee1eSDan Willemsen if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() { 49*1c12ee1eSDan Willemsen t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want)) 50*1c12ee1eSDan Willemsen } 51*1c12ee1eSDan Willemsen }) 52*1c12ee1eSDan Willemsen } 53*1c12ee1eSDan Willemsen } 54*1c12ee1eSDan Willemsen} 55*1c12ee1eSDan Willemsen 56*1c12ee1eSDan Willemsenfunc TestDecodeRequiredFieldChecks(t *testing.T) { 57*1c12ee1eSDan Willemsen for _, test := range testValidMessages { 58*1c12ee1eSDan Willemsen if !test.partial { 59*1c12ee1eSDan Willemsen continue 60*1c12ee1eSDan Willemsen } 61*1c12ee1eSDan Willemsen for _, m := range test.decodeTo { 62*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) { 63*1c12ee1eSDan Willemsen opts := test.unmarshalOptions 64*1c12ee1eSDan Willemsen opts.AllowPartial = false 65*1c12ee1eSDan Willemsen got := reflect.New(reflect.TypeOf(m).Elem()).Interface().(proto.Message) 66*1c12ee1eSDan Willemsen if err := proto.Unmarshal(test.wire, got); err == nil { 67*1c12ee1eSDan Willemsen t.Fatalf("Unmarshal succeeded (want error)\nMessage:\n%v", prototext.Format(got)) 68*1c12ee1eSDan Willemsen } 69*1c12ee1eSDan Willemsen }) 70*1c12ee1eSDan Willemsen } 71*1c12ee1eSDan Willemsen } 72*1c12ee1eSDan Willemsen} 73*1c12ee1eSDan Willemsen 74*1c12ee1eSDan Willemsenfunc TestDecodeInvalidMessages(t *testing.T) { 75*1c12ee1eSDan Willemsen for _, test := range testInvalidMessages { 76*1c12ee1eSDan Willemsen if len(test.decodeTo) == 0 { 77*1c12ee1eSDan Willemsen t.Errorf("%v: no test message types", test.desc) 78*1c12ee1eSDan Willemsen } 79*1c12ee1eSDan Willemsen for _, want := range test.decodeTo { 80*1c12ee1eSDan Willemsen t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) { 81*1c12ee1eSDan Willemsen opts := test.unmarshalOptions 82*1c12ee1eSDan Willemsen opts.AllowPartial = test.partial 83*1c12ee1eSDan Willemsen got := want.ProtoReflect().New().Interface() 84*1c12ee1eSDan Willemsen if err := opts.Unmarshal(test.wire, got); err == nil { 85*1c12ee1eSDan Willemsen t.Errorf("Unmarshal unexpectedly succeeded\ninput bytes: [%x]\nMessage:\n%v", test.wire, prototext.Format(got)) 86*1c12ee1eSDan Willemsen } else if !errors.Is(err, proto.Error) { 87*1c12ee1eSDan Willemsen t.Errorf("Unmarshal error is not a proto.Error: %v", err) 88*1c12ee1eSDan Willemsen } 89*1c12ee1eSDan Willemsen }) 90*1c12ee1eSDan Willemsen } 91*1c12ee1eSDan Willemsen } 92*1c12ee1eSDan Willemsen} 93*1c12ee1eSDan Willemsen 94*1c12ee1eSDan Willemsenfunc TestDecodeZeroLengthBytes(t *testing.T) { 95*1c12ee1eSDan Willemsen // Verify that proto3 bytes fields don't give the mistaken 96*1c12ee1eSDan Willemsen // impression that they preserve presence. 97*1c12ee1eSDan Willemsen wire := protopack.Message{ 98*1c12ee1eSDan Willemsen protopack.Tag{94, protopack.BytesType}, protopack.Bytes(nil), 99*1c12ee1eSDan Willemsen }.Marshal() 100*1c12ee1eSDan Willemsen m := &test3pb.TestAllTypes{} 101*1c12ee1eSDan Willemsen if err := proto.Unmarshal(wire, m); err != nil { 102*1c12ee1eSDan Willemsen t.Fatal(err) 103*1c12ee1eSDan Willemsen } 104*1c12ee1eSDan Willemsen if m.OptionalBytes != nil { 105*1c12ee1eSDan Willemsen t.Errorf("unmarshal zero-length proto3 bytes field: got %v, want nil", m.OptionalBytes) 106*1c12ee1eSDan Willemsen } 107*1c12ee1eSDan Willemsen} 108*1c12ee1eSDan Willemsen 109*1c12ee1eSDan Willemsenfunc TestDecodeOneofNilWrapper(t *testing.T) { 110*1c12ee1eSDan Willemsen wire := protopack.Message{ 111*1c12ee1eSDan Willemsen protopack.Tag{111, protopack.VarintType}, protopack.Varint(1111), 112*1c12ee1eSDan Willemsen }.Marshal() 113*1c12ee1eSDan Willemsen m := &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofUint32)(nil)} 114*1c12ee1eSDan Willemsen if err := proto.Unmarshal(wire, m); err != nil { 115*1c12ee1eSDan Willemsen t.Fatal(err) 116*1c12ee1eSDan Willemsen } 117*1c12ee1eSDan Willemsen if got := m.GetOneofUint32(); got != 1111 { 118*1c12ee1eSDan Willemsen t.Errorf("GetOneofUint32() = %v, want %v", got, 1111) 119*1c12ee1eSDan Willemsen } 120*1c12ee1eSDan Willemsen} 121*1c12ee1eSDan Willemsen 122*1c12ee1eSDan Willemsenfunc TestDecodeEmptyBytes(t *testing.T) { 123*1c12ee1eSDan Willemsen // There's really nothing wrong with a nil entry in a [][]byte, 124*1c12ee1eSDan Willemsen // but we take care to produce non-nil []bytes for zero-length 125*1c12ee1eSDan Willemsen // byte strings, so test for it. 126*1c12ee1eSDan Willemsen m := &testpb.TestAllTypes{} 127*1c12ee1eSDan Willemsen b := protopack.Message{ 128*1c12ee1eSDan Willemsen protopack.Tag{45, protopack.BytesType}, protopack.Bytes(nil), 129*1c12ee1eSDan Willemsen }.Marshal() 130*1c12ee1eSDan Willemsen if err := proto.Unmarshal(b, m); err != nil { 131*1c12ee1eSDan Willemsen t.Fatal(err) 132*1c12ee1eSDan Willemsen } 133*1c12ee1eSDan Willemsen if m.RepeatedBytes[0] == nil { 134*1c12ee1eSDan Willemsen t.Errorf("unmarshaling repeated bytes field containing zero-length value: Got nil bytes, want non-nil") 135*1c12ee1eSDan Willemsen } 136*1c12ee1eSDan Willemsen} 137*1c12ee1eSDan Willemsen 138*1c12ee1eSDan Willemsenfunc build(m proto.Message, opts ...buildOpt) proto.Message { 139*1c12ee1eSDan Willemsen for _, opt := range opts { 140*1c12ee1eSDan Willemsen opt(m) 141*1c12ee1eSDan Willemsen } 142*1c12ee1eSDan Willemsen return m 143*1c12ee1eSDan Willemsen} 144*1c12ee1eSDan Willemsen 145*1c12ee1eSDan Willemsentype buildOpt func(proto.Message) 146*1c12ee1eSDan Willemsen 147*1c12ee1eSDan Willemsenfunc unknown(raw protoreflect.RawFields) buildOpt { 148*1c12ee1eSDan Willemsen return func(m proto.Message) { 149*1c12ee1eSDan Willemsen m.ProtoReflect().SetUnknown(raw) 150*1c12ee1eSDan Willemsen } 151*1c12ee1eSDan Willemsen} 152*1c12ee1eSDan Willemsen 153*1c12ee1eSDan Willemsenfunc extend(desc protoreflect.ExtensionType, value interface{}) buildOpt { 154*1c12ee1eSDan Willemsen return func(m proto.Message) { 155*1c12ee1eSDan Willemsen proto.SetExtension(m, desc, value) 156*1c12ee1eSDan Willemsen } 157*1c12ee1eSDan Willemsen} 158