1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package anypb_test 6 7import ( 8 "testing" 9 10 "github.com/google/go-cmp/cmp" 11 "google.golang.org/protobuf/proto" 12 "google.golang.org/protobuf/reflect/protoreflect" 13 "google.golang.org/protobuf/testing/protocmp" 14 15 testpb "google.golang.org/protobuf/internal/testprotos/test" 16 apb "google.golang.org/protobuf/types/known/anypb" 17 epb "google.golang.org/protobuf/types/known/emptypb" 18 wpb "google.golang.org/protobuf/types/known/wrapperspb" 19) 20 21func mustMarshal(m proto.Message) []byte { 22 b, err := proto.MarshalOptions{AllowPartial: true, Deterministic: true}.Marshal(m) 23 if err != nil { 24 panic(err) 25 } 26 return b 27} 28 29func TestMessage(t *testing.T) { 30 tests := []struct { 31 inAny *apb.Any 32 inTarget proto.Message 33 wantIs bool 34 wantName protoreflect.FullName 35 }{{ 36 inAny: nil, 37 inTarget: nil, 38 wantIs: false, 39 wantName: "", 40 }, { 41 inAny: new(apb.Any), 42 inTarget: nil, 43 wantIs: false, 44 wantName: "", 45 }, { 46 inAny: new(apb.Any), 47 inTarget: (*testpb.TestAllTypes)(nil), 48 wantIs: false, 49 wantName: "", 50 }, { 51 inAny: &apb.Any{TypeUrl: "foo"}, 52 inTarget: (*testpb.TestAllTypes)(nil), 53 wantIs: false, 54 wantName: "foo", 55 }, { 56 inAny: &apb.Any{TypeUrl: "foo$"}, 57 inTarget: (*testpb.TestAllTypes)(nil), 58 wantIs: false, 59 wantName: "", 60 }, { 61 inAny: &apb.Any{TypeUrl: "/foo"}, 62 inTarget: (*testpb.TestAllTypes)(nil), 63 wantIs: false, 64 wantName: "foo", 65 }, { 66 inAny: &apb.Any{TypeUrl: "/bar/foo"}, 67 inTarget: (*testpb.TestAllTypes)(nil), 68 wantIs: false, 69 wantName: "foo", 70 }, { 71 inAny: &apb.Any{TypeUrl: "google.golang.org/bar/foo"}, 72 inTarget: (*testpb.TestAllTypes)(nil), 73 wantIs: false, 74 wantName: "foo", 75 }, { 76 inAny: &apb.Any{TypeUrl: "goproto.proto.test.TestAllTypes"}, 77 inTarget: (*testpb.TestAllTypes)(nil), 78 wantIs: true, 79 wantName: "goproto.proto.test.TestAllTypes", 80 }, { 81 inAny: &apb.Any{TypeUrl: "goproto.proto.test.TestAllTypes$"}, 82 inTarget: (*testpb.TestAllTypes)(nil), 83 wantIs: false, 84 wantName: "", 85 }, { 86 inAny: &apb.Any{TypeUrl: "/goproto.proto.test.TestAllTypes"}, 87 inTarget: (*testpb.TestAllTypes)(nil), 88 wantIs: true, 89 wantName: "goproto.proto.test.TestAllTypes", 90 }, { 91 inAny: &apb.Any{TypeUrl: "google.golang.org/foo/goproto.proto.test.TestAllTypes"}, 92 inTarget: (*testpb.TestAllTypes)(nil), 93 wantIs: true, 94 wantName: "goproto.proto.test.TestAllTypes", 95 }} 96 97 for _, tt := range tests { 98 gotIs := tt.inAny.MessageIs(tt.inTarget) 99 if gotIs != tt.wantIs { 100 t.Errorf("MessageIs(%v, %v) = %v, want %v", tt.inAny, tt.inTarget, gotIs, tt.wantIs) 101 } 102 gotName := tt.inAny.MessageName() 103 if gotName != tt.wantName { 104 t.Errorf("MessageName(%v) = %v, want %v", tt.inAny, gotName, tt.wantName) 105 } 106 } 107} 108 109func TestRoundtrip(t *testing.T) { 110 tests := []struct { 111 msg proto.Message 112 any *apb.Any 113 }{{ 114 msg: &testpb.TestAllTypes{}, 115 any: &apb.Any{ 116 TypeUrl: "type.googleapis.com/goproto.proto.test.TestAllTypes", 117 }, 118 }, { 119 msg: &testpb.TestAllTypes{ 120 OptionalString: proto.String("hello, world!"), 121 }, 122 any: &apb.Any{ 123 TypeUrl: "type.googleapis.com/goproto.proto.test.TestAllTypes", 124 Value: mustMarshal(&testpb.TestAllTypes{ 125 OptionalString: proto.String("hello, world!"), 126 }), 127 }, 128 }, { 129 msg: &wpb.StringValue{Value: ""}, 130 any: &apb.Any{ 131 TypeUrl: "type.googleapis.com/google.protobuf.StringValue", 132 }, 133 }, { 134 msg: wpb.String("hello, world"), 135 any: &apb.Any{ 136 TypeUrl: "type.googleapis.com/google.protobuf.StringValue", 137 Value: mustMarshal(wpb.String("hello, world")), 138 }, 139 }, { 140 msg: &apb.Any{ 141 TypeUrl: "type.googleapis.com/google.protobuf.StringValue", 142 Value: mustMarshal(wpb.String("hello, world")), 143 }, 144 any: &apb.Any{ 145 TypeUrl: "type.googleapis.com/google.protobuf.Any", 146 Value: mustMarshal(&apb.Any{ 147 TypeUrl: "type.googleapis.com/google.protobuf.StringValue", 148 Value: mustMarshal(wpb.String("hello, world")), 149 }), 150 }, 151 }} 152 153 for _, tt := range tests { 154 // Unmarshal to the wrong message type. 155 var empty epb.Empty 156 if err := tt.any.UnmarshalTo(&empty); err == nil { 157 t.Errorf("UnmarshalTo(empty) = nil, want non-nil") 158 } 159 160 gotAny := new(apb.Any) 161 if err := gotAny.MarshalFrom(tt.msg); err != nil { 162 t.Errorf("MarshalFrom() error: %v", err) 163 } 164 if diff := cmp.Diff(tt.any, gotAny, protocmp.Transform()); diff != "" { 165 t.Errorf("MarshalFrom() output mismatch (-want +got):\n%s", diff) 166 } 167 168 gotPB := tt.msg.ProtoReflect().New().Interface() 169 if err := tt.any.UnmarshalTo(gotPB); err != nil { 170 t.Errorf("UnmarshalTo() error: %v", err) 171 } 172 if diff := cmp.Diff(tt.msg, gotPB, protocmp.Transform()); diff != "" { 173 t.Errorf("UnmarshalTo() output mismatch (-want +got):\n%s", diff) 174 } 175 176 gotPB, err := tt.any.UnmarshalNew() 177 if err != nil { 178 t.Errorf("UnmarshalNew() error: %v", err) 179 } 180 if diff := cmp.Diff(tt.msg, gotPB, protocmp.Transform()); diff != "" { 181 t.Errorf("UnmarshalNew() output mismatch (-want +got):\n%s", diff) 182 } 183 } 184} 185