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/golang/protobuf/proto" 38 39 proto3pb "github.com/golang/protobuf/proto/proto3_proto" 40 pb "github.com/golang/protobuf/proto/test_proto" 41) 42 43func 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. 161type LegacyMessage struct { 162 Message *proto3pb.Message 163 Communique *pb.Communique 164 MessageWithMap *pb.MessageWithMap 165 MyMessage *pb.MyMessage 166} 167 168func (m *LegacyMessage) Reset() { *m = LegacyMessage{} } 169func (m *LegacyMessage) String() string { return proto.CompactTextString(m) } 170func (*LegacyMessage) ProtoMessage() {} 171