xref: /aosp_15_r20/external/golang-protobuf/proto/extension_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage proto_test
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"reflect"
10*1c12ee1eSDan Willemsen	"sync"
11*1c12ee1eSDan Willemsen	"testing"
12*1c12ee1eSDan Willemsen
13*1c12ee1eSDan Willemsen	"github.com/google/go-cmp/cmp"
14*1c12ee1eSDan Willemsen
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/proto"
16*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
17*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/runtime/protoimpl"
18*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/testing/protocmp"
19*1c12ee1eSDan Willemsen
20*1c12ee1eSDan Willemsen	legacy1pb "google.golang.org/protobuf/internal/testprotos/legacy/proto2_20160225_2fc053c5"
21*1c12ee1eSDan Willemsen	testpb "google.golang.org/protobuf/internal/testprotos/test"
22*1c12ee1eSDan Willemsen	test3pb "google.golang.org/protobuf/internal/testprotos/test3"
23*1c12ee1eSDan Willemsen	descpb "google.golang.org/protobuf/types/descriptorpb"
24*1c12ee1eSDan Willemsen)
25*1c12ee1eSDan Willemsen
26*1c12ee1eSDan Willemsenfunc TestExtensionFuncs(t *testing.T) {
27*1c12ee1eSDan Willemsen	for _, test := range []struct {
28*1c12ee1eSDan Willemsen		message     proto.Message
29*1c12ee1eSDan Willemsen		ext         protoreflect.ExtensionType
30*1c12ee1eSDan Willemsen		wantDefault interface{}
31*1c12ee1eSDan Willemsen		value       interface{}
32*1c12ee1eSDan Willemsen	}{
33*1c12ee1eSDan Willemsen		{
34*1c12ee1eSDan Willemsen			message:     &testpb.TestAllExtensions{},
35*1c12ee1eSDan Willemsen			ext:         testpb.E_OptionalInt32,
36*1c12ee1eSDan Willemsen			wantDefault: int32(0),
37*1c12ee1eSDan Willemsen			value:       int32(1),
38*1c12ee1eSDan Willemsen		},
39*1c12ee1eSDan Willemsen		{
40*1c12ee1eSDan Willemsen			message:     &testpb.TestAllExtensions{},
41*1c12ee1eSDan Willemsen			ext:         testpb.E_RepeatedString,
42*1c12ee1eSDan Willemsen			wantDefault: ([]string)(nil),
43*1c12ee1eSDan Willemsen			value:       []string{"a", "b", "c"},
44*1c12ee1eSDan Willemsen		},
45*1c12ee1eSDan Willemsen		{
46*1c12ee1eSDan Willemsen			message:     protoimpl.X.MessageOf(&legacy1pb.Message{}).Interface(),
47*1c12ee1eSDan Willemsen			ext:         legacy1pb.E_Message_ExtensionOptionalBool,
48*1c12ee1eSDan Willemsen			wantDefault: false,
49*1c12ee1eSDan Willemsen			value:       true,
50*1c12ee1eSDan Willemsen		},
51*1c12ee1eSDan Willemsen	} {
52*1c12ee1eSDan Willemsen		desc := fmt.Sprintf("Extension %v, value %v", test.ext.TypeDescriptor().FullName(), test.value)
53*1c12ee1eSDan Willemsen		if proto.HasExtension(test.message, test.ext) {
54*1c12ee1eSDan Willemsen			t.Errorf("%v:\nbefore setting extension HasExtension(...) = true, want false", desc)
55*1c12ee1eSDan Willemsen		}
56*1c12ee1eSDan Willemsen		got := proto.GetExtension(test.message, test.ext)
57*1c12ee1eSDan Willemsen		if d := cmp.Diff(test.wantDefault, got); d != "" {
58*1c12ee1eSDan Willemsen			t.Errorf("%v:\nbefore setting extension GetExtension(...) returns unexpected value (-want,+got):\n%v", desc, d)
59*1c12ee1eSDan Willemsen		}
60*1c12ee1eSDan Willemsen		proto.SetExtension(test.message, test.ext, test.value)
61*1c12ee1eSDan Willemsen		if !proto.HasExtension(test.message, test.ext) {
62*1c12ee1eSDan Willemsen			t.Errorf("%v:\nafter setting extension HasExtension(...) = false, want true", desc)
63*1c12ee1eSDan Willemsen		}
64*1c12ee1eSDan Willemsen		got = proto.GetExtension(test.message, test.ext)
65*1c12ee1eSDan Willemsen		if d := cmp.Diff(test.value, got); d != "" {
66*1c12ee1eSDan Willemsen			t.Errorf("%v:\nafter setting extension GetExtension(...) returns unexpected value (-want,+got):\n%v", desc, d)
67*1c12ee1eSDan Willemsen		}
68*1c12ee1eSDan Willemsen		proto.ClearExtension(test.message, test.ext)
69*1c12ee1eSDan Willemsen		if proto.HasExtension(test.message, test.ext) {
70*1c12ee1eSDan Willemsen			t.Errorf("%v:\nafter clearing extension HasExtension(...) = true, want false", desc)
71*1c12ee1eSDan Willemsen		}
72*1c12ee1eSDan Willemsen	}
73*1c12ee1eSDan Willemsen}
74*1c12ee1eSDan Willemsen
75*1c12ee1eSDan Willemsenfunc TestIsValid(t *testing.T) {
76*1c12ee1eSDan Willemsen	tests := []struct {
77*1c12ee1eSDan Willemsen		xt   protoreflect.ExtensionType
78*1c12ee1eSDan Willemsen		vi   interface{}
79*1c12ee1eSDan Willemsen		want bool
80*1c12ee1eSDan Willemsen	}{
81*1c12ee1eSDan Willemsen		{testpb.E_OptionalBool, nil, false},
82*1c12ee1eSDan Willemsen		{testpb.E_OptionalBool, bool(true), true},
83*1c12ee1eSDan Willemsen		{testpb.E_OptionalBool, new(bool), false},
84*1c12ee1eSDan Willemsen		{testpb.E_OptionalInt32, nil, false},
85*1c12ee1eSDan Willemsen		{testpb.E_OptionalInt32, int32(0), true},
86*1c12ee1eSDan Willemsen		{testpb.E_OptionalInt32, new(int32), false},
87*1c12ee1eSDan Willemsen		{testpb.E_OptionalInt64, nil, false},
88*1c12ee1eSDan Willemsen		{testpb.E_OptionalInt64, int64(0), true},
89*1c12ee1eSDan Willemsen		{testpb.E_OptionalInt64, new(int64), false},
90*1c12ee1eSDan Willemsen		{testpb.E_OptionalUint32, nil, false},
91*1c12ee1eSDan Willemsen		{testpb.E_OptionalUint32, uint32(0), true},
92*1c12ee1eSDan Willemsen		{testpb.E_OptionalUint32, new(uint32), false},
93*1c12ee1eSDan Willemsen		{testpb.E_OptionalUint64, nil, false},
94*1c12ee1eSDan Willemsen		{testpb.E_OptionalUint64, uint64(0), true},
95*1c12ee1eSDan Willemsen		{testpb.E_OptionalUint64, new(uint64), false},
96*1c12ee1eSDan Willemsen		{testpb.E_OptionalFloat, nil, false},
97*1c12ee1eSDan Willemsen		{testpb.E_OptionalFloat, float32(0), true},
98*1c12ee1eSDan Willemsen		{testpb.E_OptionalFloat, new(float32), false},
99*1c12ee1eSDan Willemsen		{testpb.E_OptionalDouble, nil, false},
100*1c12ee1eSDan Willemsen		{testpb.E_OptionalDouble, float64(0), true},
101*1c12ee1eSDan Willemsen		{testpb.E_OptionalDouble, new(float32), false},
102*1c12ee1eSDan Willemsen		{testpb.E_OptionalString, nil, false},
103*1c12ee1eSDan Willemsen		{testpb.E_OptionalString, string(""), true},
104*1c12ee1eSDan Willemsen		{testpb.E_OptionalString, new(string), false},
105*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedEnum, nil, false},
106*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedEnum, testpb.TestAllTypes_BAZ, true},
107*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedEnum, testpb.TestAllTypes_BAZ.Enum(), false},
108*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedMessage, nil, false},
109*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedMessage, (*testpb.TestAllExtensions_NestedMessage)(nil), true},
110*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedMessage, new(testpb.TestAllExtensions_NestedMessage), true},
111*1c12ee1eSDan Willemsen		{testpb.E_OptionalNestedMessage, new(testpb.TestAllExtensions), false},
112*1c12ee1eSDan Willemsen		{testpb.E_RepeatedBool, nil, false},
113*1c12ee1eSDan Willemsen		{testpb.E_RepeatedBool, []bool(nil), true},
114*1c12ee1eSDan Willemsen		{testpb.E_RepeatedBool, []bool{}, true},
115*1c12ee1eSDan Willemsen		{testpb.E_RepeatedBool, []bool{false}, true},
116*1c12ee1eSDan Willemsen		{testpb.E_RepeatedBool, []*bool{}, false},
117*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt32, nil, false},
118*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt32, []int32(nil), true},
119*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt32, []int32{}, true},
120*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt32, []int32{0}, true},
121*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt32, []*int32{}, false},
122*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt64, nil, false},
123*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt64, []int64(nil), true},
124*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt64, []int64{}, true},
125*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt64, []int64{0}, true},
126*1c12ee1eSDan Willemsen		{testpb.E_RepeatedInt64, []*int64{}, false},
127*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint32, nil, false},
128*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint32, []uint32(nil), true},
129*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint32, []uint32{}, true},
130*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint32, []uint32{0}, true},
131*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint32, []*uint32{}, false},
132*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint64, nil, false},
133*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint64, []uint64(nil), true},
134*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint64, []uint64{}, true},
135*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint64, []uint64{0}, true},
136*1c12ee1eSDan Willemsen		{testpb.E_RepeatedUint64, []*uint64{}, false},
137*1c12ee1eSDan Willemsen		{testpb.E_RepeatedFloat, nil, false},
138*1c12ee1eSDan Willemsen		{testpb.E_RepeatedFloat, []float32(nil), true},
139*1c12ee1eSDan Willemsen		{testpb.E_RepeatedFloat, []float32{}, true},
140*1c12ee1eSDan Willemsen		{testpb.E_RepeatedFloat, []float32{0}, true},
141*1c12ee1eSDan Willemsen		{testpb.E_RepeatedFloat, []*float32{}, false},
142*1c12ee1eSDan Willemsen		{testpb.E_RepeatedDouble, nil, false},
143*1c12ee1eSDan Willemsen		{testpb.E_RepeatedDouble, []float64(nil), true},
144*1c12ee1eSDan Willemsen		{testpb.E_RepeatedDouble, []float64{}, true},
145*1c12ee1eSDan Willemsen		{testpb.E_RepeatedDouble, []float64{0}, true},
146*1c12ee1eSDan Willemsen		{testpb.E_RepeatedDouble, []*float64{}, false},
147*1c12ee1eSDan Willemsen		{testpb.E_RepeatedString, nil, false},
148*1c12ee1eSDan Willemsen		{testpb.E_RepeatedString, []string(nil), true},
149*1c12ee1eSDan Willemsen		{testpb.E_RepeatedString, []string{}, true},
150*1c12ee1eSDan Willemsen		{testpb.E_RepeatedString, []string{""}, true},
151*1c12ee1eSDan Willemsen		{testpb.E_RepeatedString, []*string{}, false},
152*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedEnum, nil, false},
153*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedEnum, []testpb.TestAllTypes_NestedEnum(nil), true},
154*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedEnum, []testpb.TestAllTypes_NestedEnum{}, true},
155*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedEnum, []testpb.TestAllTypes_NestedEnum{0}, true},
156*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedEnum, []*testpb.TestAllTypes_NestedEnum{}, false},
157*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedMessage, nil, false},
158*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedMessage, []*testpb.TestAllExtensions_NestedMessage(nil), true},
159*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedMessage, []*testpb.TestAllExtensions_NestedMessage{}, true},
160*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedMessage, []*testpb.TestAllExtensions_NestedMessage{{}}, true},
161*1c12ee1eSDan Willemsen		{testpb.E_RepeatedNestedMessage, []*testpb.TestAllExtensions{}, false},
162*1c12ee1eSDan Willemsen	}
163*1c12ee1eSDan Willemsen
164*1c12ee1eSDan Willemsen	for _, tt := range tests {
165*1c12ee1eSDan Willemsen		// Check the results of IsValidInterface.
166*1c12ee1eSDan Willemsen		got := tt.xt.IsValidInterface(tt.vi)
167*1c12ee1eSDan Willemsen		if got != tt.want {
168*1c12ee1eSDan Willemsen			t.Errorf("%v.IsValidInterface() = %v, want %v", tt.xt.TypeDescriptor().FullName(), got, tt.want)
169*1c12ee1eSDan Willemsen		}
170*1c12ee1eSDan Willemsen		if !got {
171*1c12ee1eSDan Willemsen			continue
172*1c12ee1eSDan Willemsen		}
173*1c12ee1eSDan Willemsen
174*1c12ee1eSDan Willemsen		// Set the extension value and verify the results of Has.
175*1c12ee1eSDan Willemsen		wantHas := true
176*1c12ee1eSDan Willemsen		pv := tt.xt.ValueOf(tt.vi)
177*1c12ee1eSDan Willemsen		switch v := pv.Interface().(type) {
178*1c12ee1eSDan Willemsen		case protoreflect.List:
179*1c12ee1eSDan Willemsen			wantHas = v.Len() > 0
180*1c12ee1eSDan Willemsen		case protoreflect.Message:
181*1c12ee1eSDan Willemsen			wantHas = v.IsValid()
182*1c12ee1eSDan Willemsen		}
183*1c12ee1eSDan Willemsen		m := &testpb.TestAllExtensions{}
184*1c12ee1eSDan Willemsen		proto.SetExtension(m, tt.xt, tt.vi)
185*1c12ee1eSDan Willemsen		gotHas := proto.HasExtension(m, tt.xt)
186*1c12ee1eSDan Willemsen		if gotHas != wantHas {
187*1c12ee1eSDan Willemsen			t.Errorf("HasExtension(%q) = %v, want %v", tt.xt.TypeDescriptor().FullName(), gotHas, wantHas)
188*1c12ee1eSDan Willemsen		}
189*1c12ee1eSDan Willemsen
190*1c12ee1eSDan Willemsen		// Check consistency of IsValidInterface and IsValidValue.
191*1c12ee1eSDan Willemsen		got = tt.xt.IsValidValue(pv)
192*1c12ee1eSDan Willemsen		if got != tt.want {
193*1c12ee1eSDan Willemsen			t.Errorf("%v.IsValidValue() = %v, want %v", tt.xt.TypeDescriptor().FullName(), got, tt.want)
194*1c12ee1eSDan Willemsen		}
195*1c12ee1eSDan Willemsen		if !got {
196*1c12ee1eSDan Willemsen			continue
197*1c12ee1eSDan Willemsen		}
198*1c12ee1eSDan Willemsen
199*1c12ee1eSDan Willemsen		// Use of reflect.DeepEqual is intentional.
200*1c12ee1eSDan Willemsen		// We really do want to ensure that the memory layout is identical.
201*1c12ee1eSDan Willemsen		vi := tt.xt.InterfaceOf(pv)
202*1c12ee1eSDan Willemsen		if !reflect.DeepEqual(vi, tt.vi) {
203*1c12ee1eSDan Willemsen			t.Errorf("InterfaceOf(ValueOf(...)) round-trip mismatch: got %v, want %v", vi, tt.vi)
204*1c12ee1eSDan Willemsen		}
205*1c12ee1eSDan Willemsen	}
206*1c12ee1eSDan Willemsen}
207*1c12ee1eSDan Willemsen
208*1c12ee1eSDan Willemsenfunc TestExtensionRanger(t *testing.T) {
209*1c12ee1eSDan Willemsen	tests := []struct {
210*1c12ee1eSDan Willemsen		msg  proto.Message
211*1c12ee1eSDan Willemsen		want map[protoreflect.ExtensionType]interface{}
212*1c12ee1eSDan Willemsen	}{{
213*1c12ee1eSDan Willemsen		msg: &testpb.TestAllExtensions{},
214*1c12ee1eSDan Willemsen		want: map[protoreflect.ExtensionType]interface{}{
215*1c12ee1eSDan Willemsen			testpb.E_OptionalInt32:         int32(5),
216*1c12ee1eSDan Willemsen			testpb.E_OptionalString:        string("hello"),
217*1c12ee1eSDan Willemsen			testpb.E_OptionalNestedMessage: &testpb.TestAllExtensions_NestedMessage{},
218*1c12ee1eSDan Willemsen			testpb.E_OptionalNestedEnum:    testpb.TestAllTypes_BAZ,
219*1c12ee1eSDan Willemsen			testpb.E_RepeatedFloat:         []float32{+32.32, -32.32},
220*1c12ee1eSDan Willemsen			testpb.E_RepeatedNestedMessage: []*testpb.TestAllExtensions_NestedMessage{{}},
221*1c12ee1eSDan Willemsen			testpb.E_RepeatedNestedEnum:    []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAZ},
222*1c12ee1eSDan Willemsen		},
223*1c12ee1eSDan Willemsen	}, {
224*1c12ee1eSDan Willemsen		msg: &descpb.MessageOptions{},
225*1c12ee1eSDan Willemsen		want: map[protoreflect.ExtensionType]interface{}{
226*1c12ee1eSDan Willemsen			test3pb.E_OptionalInt32:          int32(5),
227*1c12ee1eSDan Willemsen			test3pb.E_OptionalString:         string("hello"),
228*1c12ee1eSDan Willemsen			test3pb.E_OptionalForeignMessage: &test3pb.ForeignMessage{},
229*1c12ee1eSDan Willemsen			test3pb.E_OptionalForeignEnum:    test3pb.ForeignEnum_FOREIGN_BAR,
230*1c12ee1eSDan Willemsen
231*1c12ee1eSDan Willemsen			test3pb.E_OptionalOptionalInt32:          int32(5),
232*1c12ee1eSDan Willemsen			test3pb.E_OptionalOptionalString:         string("hello"),
233*1c12ee1eSDan Willemsen			test3pb.E_OptionalOptionalForeignMessage: &test3pb.ForeignMessage{},
234*1c12ee1eSDan Willemsen			test3pb.E_OptionalOptionalForeignEnum:    test3pb.ForeignEnum_FOREIGN_BAR,
235*1c12ee1eSDan Willemsen		},
236*1c12ee1eSDan Willemsen	}}
237*1c12ee1eSDan Willemsen
238*1c12ee1eSDan Willemsen	for _, tt := range tests {
239*1c12ee1eSDan Willemsen		for xt, v := range tt.want {
240*1c12ee1eSDan Willemsen			proto.SetExtension(tt.msg, xt, v)
241*1c12ee1eSDan Willemsen		}
242*1c12ee1eSDan Willemsen
243*1c12ee1eSDan Willemsen		got := make(map[protoreflect.ExtensionType]interface{})
244*1c12ee1eSDan Willemsen		proto.RangeExtensions(tt.msg, func(xt protoreflect.ExtensionType, v interface{}) bool {
245*1c12ee1eSDan Willemsen			got[xt] = v
246*1c12ee1eSDan Willemsen			return true
247*1c12ee1eSDan Willemsen		})
248*1c12ee1eSDan Willemsen
249*1c12ee1eSDan Willemsen		if diff := cmp.Diff(tt.want, got, protocmp.Transform()); diff != "" {
250*1c12ee1eSDan Willemsen			t.Errorf("proto.RangeExtensions mismatch (-want +got):\n%s", diff)
251*1c12ee1eSDan Willemsen		}
252*1c12ee1eSDan Willemsen	}
253*1c12ee1eSDan Willemsen}
254*1c12ee1eSDan Willemsen
255*1c12ee1eSDan Willemsenfunc TestExtensionGetRace(t *testing.T) {
256*1c12ee1eSDan Willemsen	// Concurrently fetch an extension value while marshaling the message containing it.
257*1c12ee1eSDan Willemsen	// Create the message with proto.Unmarshal to give lazy extension decoding (if present)
258*1c12ee1eSDan Willemsen	// a chance to occur.
259*1c12ee1eSDan Willemsen	want := int32(42)
260*1c12ee1eSDan Willemsen	m1 := &testpb.TestAllExtensions{}
261*1c12ee1eSDan Willemsen	proto.SetExtension(m1, testpb.E_OptionalNestedMessage, &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(want)})
262*1c12ee1eSDan Willemsen	b, err := proto.Marshal(m1)
263*1c12ee1eSDan Willemsen	if err != nil {
264*1c12ee1eSDan Willemsen		t.Fatal(err)
265*1c12ee1eSDan Willemsen	}
266*1c12ee1eSDan Willemsen	m := &testpb.TestAllExtensions{}
267*1c12ee1eSDan Willemsen	if err := proto.Unmarshal(b, m); err != nil {
268*1c12ee1eSDan Willemsen		t.Fatal(err)
269*1c12ee1eSDan Willemsen	}
270*1c12ee1eSDan Willemsen	var wg sync.WaitGroup
271*1c12ee1eSDan Willemsen	for i := 0; i < 3; i++ {
272*1c12ee1eSDan Willemsen		wg.Add(1)
273*1c12ee1eSDan Willemsen		go func() {
274*1c12ee1eSDan Willemsen			defer wg.Done()
275*1c12ee1eSDan Willemsen			if _, err := proto.Marshal(m); err != nil {
276*1c12ee1eSDan Willemsen				t.Error(err)
277*1c12ee1eSDan Willemsen			}
278*1c12ee1eSDan Willemsen		}()
279*1c12ee1eSDan Willemsen		wg.Add(1)
280*1c12ee1eSDan Willemsen		go func() {
281*1c12ee1eSDan Willemsen			defer wg.Done()
282*1c12ee1eSDan Willemsen			got := proto.GetExtension(m, testpb.E_OptionalNestedMessage).(*testpb.TestAllExtensions_NestedMessage).GetA()
283*1c12ee1eSDan Willemsen			if got != want {
284*1c12ee1eSDan Willemsen				t.Errorf("GetExtension(optional_nested_message).a = %v, want %v", got, want)
285*1c12ee1eSDan Willemsen			}
286*1c12ee1eSDan Willemsen		}()
287*1c12ee1eSDan Willemsen	}
288*1c12ee1eSDan Willemsen	wg.Wait()
289*1c12ee1eSDan Willemsen}
290