xref: /aosp_15_r20/external/golang-protobuf/types/known/anypb/any_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
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