1// Go support for Protocol Buffers - Google's data interchange format 2// 3// Copyright 2017 The Go Authors. All rights reserved. 4// https://github.com/golang/protobuf 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are 8// met: 9// 10// * Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// * Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following disclaimer 14// in the documentation and/or other materials provided with the 15// distribution. 16// * Neither the name of Google Inc. nor the names of its 17// contributors may be used to endorse or promote products derived from 18// this software without specific prior written permission. 19// 20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32package proto_test 33 34import ( 35 "testing" 36 37 "github.com/gogo/protobuf/proto" 38 proto3pb "github.com/gogo/protobuf/proto/proto3_proto" 39 pb "github.com/gogo/protobuf/proto/test_proto" 40) 41 42func TestDiscardUnknown(t *testing.T) { 43 tests := []struct { 44 desc string 45 in, want proto.Message 46 }{{ 47 desc: "Nil", 48 in: nil, want: nil, // Should not panic 49 }, { 50 desc: "NilPtr", 51 in: (*proto3pb.Message)(nil), want: (*proto3pb.Message)(nil), // Should not panic 52 }, { 53 desc: "Nested", 54 in: &proto3pb.Message{ 55 Name: "Aaron", 56 Nested: &proto3pb.Nested{Cute: true, XXX_unrecognized: []byte("blah")}, 57 XXX_unrecognized: []byte("blah"), 58 }, 59 want: &proto3pb.Message{ 60 Name: "Aaron", 61 Nested: &proto3pb.Nested{Cute: true}, 62 }, 63 }, { 64 desc: "Slice", 65 in: &proto3pb.Message{ 66 Name: "Aaron", 67 Children: []*proto3pb.Message{ 68 {Name: "Sarah", XXX_unrecognized: []byte("blah")}, 69 {Name: "Abraham", XXX_unrecognized: []byte("blah")}, 70 }, 71 XXX_unrecognized: []byte("blah"), 72 }, 73 want: &proto3pb.Message{ 74 Name: "Aaron", 75 Children: []*proto3pb.Message{ 76 {Name: "Sarah"}, 77 {Name: "Abraham"}, 78 }, 79 }, 80 }, { 81 desc: "OneOf", 82 in: &pb.Communique{ 83 Union: &pb.Communique_Msg{Msg: &pb.Strings{ 84 StringField: proto.String("123"), 85 XXX_unrecognized: []byte("blah"), 86 }}, 87 XXX_unrecognized: []byte("blah"), 88 }, 89 want: &pb.Communique{ 90 Union: &pb.Communique_Msg{Msg: &pb.Strings{StringField: proto.String("123")}}, 91 }, 92 }, { 93 desc: "Map", 94 in: &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{ 95 0x4002: { 96 Exact: proto.Bool(true), 97 XXX_unrecognized: []byte("blah"), 98 }, 99 }}, 100 want: &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{ 101 0x4002: {Exact: proto.Bool(true)}, 102 }}, 103 }, { 104 desc: "Extension", 105 in: func() proto.Message { 106 m := &pb.MyMessage{ 107 Count: proto.Int32(42), 108 Somegroup: &pb.MyMessage_SomeGroup{ 109 GroupField: proto.Int32(6), 110 XXX_unrecognized: []byte("blah"), 111 }, 112 XXX_unrecognized: []byte("blah"), 113 } 114 proto.SetExtension(m, pb.E_Ext_More, &pb.Ext{ 115 Data: proto.String("extension"), 116 XXX_unrecognized: []byte("blah"), 117 }) 118 return m 119 }(), 120 want: func() proto.Message { 121 m := &pb.MyMessage{ 122 Count: proto.Int32(42), 123 Somegroup: &pb.MyMessage_SomeGroup{GroupField: proto.Int32(6)}, 124 } 125 proto.SetExtension(m, pb.E_Ext_More, &pb.Ext{Data: proto.String("extension")}) 126 return m 127 }(), 128 }} 129 130 // Test the legacy code path. 131 for _, tt := range tests { 132 // Clone the input so that we don't alter the original. 133 in := tt.in 134 if in != nil { 135 in = proto.Clone(tt.in) 136 } 137 138 var m LegacyMessage 139 m.Message, _ = in.(*proto3pb.Message) 140 m.Communique, _ = in.(*pb.Communique) 141 m.MessageWithMap, _ = in.(*pb.MessageWithMap) 142 m.MyMessage, _ = in.(*pb.MyMessage) 143 proto.DiscardUnknown(&m) 144 if !proto.Equal(in, tt.want) { 145 t.Errorf("test %s/Legacy, expected unknown fields to be discarded\ngot %v\nwant %v", tt.desc, in, tt.want) 146 } 147 } 148 149 for _, tt := range tests { 150 proto.DiscardUnknown(tt.in) 151 if !proto.Equal(tt.in, tt.want) { 152 t.Errorf("test %s, expected unknown fields to be discarded\ngot %v\nwant %v", tt.desc, tt.in, tt.want) 153 } 154 } 155} 156 157// LegacyMessage is a proto.Message that has several nested messages. 158// This does not have the XXX_DiscardUnknown method and so forces DiscardUnknown 159// to use the legacy fallback logic. 160type LegacyMessage struct { 161 Message *proto3pb.Message 162 Communique *pb.Communique 163 MessageWithMap *pb.MessageWithMap 164 MyMessage *pb.MyMessage 165} 166 167func (m *LegacyMessage) Reset() { *m = LegacyMessage{} } 168func (m *LegacyMessage) String() string { return proto.CompactTextString(m) } 169func (*LegacyMessage) ProtoMessage() {} 170