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 32 package proto_test 33 34 import ( 35 "testing" 36 37 "github.com/golang/protobuf/proto" 38 39 proto3pb "github.com/golang/protobuf/proto/proto3_proto" 40 pb "github.com/golang/protobuf/proto/test_proto" 41 ) 42 43 func TestDiscardUnknown(t *testing.T) { 44 tests := []struct { 45 desc string 46 in, want proto.Message 47 }{{ 48 desc: "Nil", 49 in: nil, want: nil, // Should not panic 50 }, { 51 desc: "NilPtr", 52 in: (*proto3pb.Message)(nil), want: (*proto3pb.Message)(nil), // Should not panic 53 }, { 54 desc: "Nested", 55 in: &proto3pb.Message{ 56 Name: "Aaron", 57 Nested: &proto3pb.Nested{Cute: true, XXX_unrecognized: []byte("blah")}, 58 XXX_unrecognized: []byte("blah"), 59 }, 60 want: &proto3pb.Message{ 61 Name: "Aaron", 62 Nested: &proto3pb.Nested{Cute: true}, 63 }, 64 }, { 65 desc: "Slice", 66 in: &proto3pb.Message{ 67 Name: "Aaron", 68 Children: []*proto3pb.Message{ 69 {Name: "Sarah", XXX_unrecognized: []byte("blah")}, 70 {Name: "Abraham", XXX_unrecognized: []byte("blah")}, 71 }, 72 XXX_unrecognized: []byte("blah"), 73 }, 74 want: &proto3pb.Message{ 75 Name: "Aaron", 76 Children: []*proto3pb.Message{ 77 {Name: "Sarah"}, 78 {Name: "Abraham"}, 79 }, 80 }, 81 }, { 82 desc: "OneOf", 83 in: &pb.Communique{ 84 Union: &pb.Communique_Msg{&pb.Strings{ 85 StringField: proto.String("123"), 86 XXX_unrecognized: []byte("blah"), 87 }}, 88 XXX_unrecognized: []byte("blah"), 89 }, 90 want: &pb.Communique{ 91 Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123")}}, 92 }, 93 }, { 94 desc: "Map", 95 in: &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{ 96 0x4002: &pb.FloatingPoint{ 97 Exact: proto.Bool(true), 98 XXX_unrecognized: []byte("blah"), 99 }, 100 }}, 101 want: &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{ 102 0x4002: &pb.FloatingPoint{Exact: proto.Bool(true)}, 103 }}, 104 }, { 105 desc: "Extension", 106 in: func() proto.Message { 107 m := &pb.MyMessage{ 108 Count: proto.Int32(42), 109 Somegroup: &pb.MyMessage_SomeGroup{ 110 GroupField: proto.Int32(6), 111 XXX_unrecognized: []byte("blah"), 112 }, 113 XXX_unrecognized: []byte("blah"), 114 } 115 proto.SetExtension(m, pb.E_Ext_More, &pb.Ext{ 116 Data: proto.String("extension"), 117 XXX_unrecognized: []byte("blah"), 118 }) 119 return m 120 }(), 121 want: func() proto.Message { 122 m := &pb.MyMessage{ 123 Count: proto.Int32(42), 124 Somegroup: &pb.MyMessage_SomeGroup{GroupField: proto.Int32(6)}, 125 } 126 proto.SetExtension(m, pb.E_Ext_More, &pb.Ext{Data: proto.String("extension")}) 127 return m 128 }(), 129 }} 130 131 // Test the legacy code path. 132 for _, tt := range tests { 133 // Clone the input so that we don't alter the original. 134 in := tt.in 135 if in != nil { 136 in = proto.Clone(tt.in) 137 } 138 139 var m LegacyMessage 140 m.Message, _ = in.(*proto3pb.Message) 141 m.Communique, _ = in.(*pb.Communique) 142 m.MessageWithMap, _ = in.(*pb.MessageWithMap) 143 m.MyMessage, _ = in.(*pb.MyMessage) 144 proto.DiscardUnknown(&m) 145 if !proto.Equal(in, tt.want) { 146 t.Errorf("test %s/Legacy, expected unknown fields to be discarded\ngot %v\nwant %v", tt.desc, in, tt.want) 147 } 148 } 149 150 for _, tt := range tests { 151 proto.DiscardUnknown(tt.in) 152 if !proto.Equal(tt.in, tt.want) { 153 t.Errorf("test %s, expected unknown fields to be discarded\ngot %v\nwant %v", tt.desc, tt.in, tt.want) 154 } 155 } 156 } 157 158 // LegacyMessage is a proto.Message that has several nested messages. 159 // This does not have the XXX_DiscardUnknown method and so forces DiscardUnknown 160 // to use the legacy fallback logic. 161 type LegacyMessage struct { 162 Message *proto3pb.Message 163 Communique *pb.Communique 164 MessageWithMap *pb.MessageWithMap 165 MyMessage *pb.MyMessage 166 } 167 168 func (m *LegacyMessage) Reset() { *m = LegacyMessage{} } 169 func (m *LegacyMessage) String() string { return proto.CompactTextString(m) } 170 func (*LegacyMessage) ProtoMessage() {} 171