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 proto_test
6
7import (
8	"testing"
9
10	"google.golang.org/protobuf/proto"
11	"google.golang.org/protobuf/reflect/protoreflect"
12
13	testpb "google.golang.org/protobuf/internal/testprotos/test"
14)
15
16// TestNil tests for boundary conditions when nil and typed-nil messages
17// are passed to various top-level functions.
18// These tests are not necessarily a statement of proper behavior,
19// but exist to detect accidental changes in behavior.
20func TestNil(t *testing.T) {
21	nilMsg := (*testpb.TestAllExtensions)(nil)
22	extType := testpb.E_OptionalBool
23	extRanger := func(protoreflect.ExtensionType, interface{}) bool { return true }
24
25	tests := []struct {
26		label string
27		test  func()
28		panic bool
29	}{{
30		label: "Size",
31		test:  func() { proto.Size(nil) },
32	}, {
33		label: "Size",
34		test:  func() { proto.Size(nilMsg) },
35	}, {
36		label: "Marshal",
37		test:  func() { proto.Marshal(nil) },
38	}, {
39		label: "Marshal",
40		test:  func() { proto.Marshal(nilMsg) },
41	}, {
42		label: "Unmarshal",
43		test:  func() { proto.Unmarshal(nil, nil) },
44		panic: true,
45	}, {
46		label: "Unmarshal",
47		test:  func() { proto.Unmarshal(nil, nilMsg) },
48		panic: true,
49	}, {
50		label: "Merge",
51		test:  func() { proto.Merge(nil, nil) },
52		panic: true,
53	}, {
54		label: "Merge",
55		test:  func() { proto.Merge(nil, nilMsg) },
56		panic: true,
57	}, {
58		label: "Merge",
59		test:  func() { proto.Merge(nilMsg, nil) },
60		panic: true,
61	}, {
62		label: "Merge",
63		test:  func() { proto.Merge(nilMsg, nilMsg) },
64		panic: true,
65	}, {
66		label: "Clone",
67		test:  func() { proto.Clone(nil) },
68	}, {
69		label: "Clone",
70		test:  func() { proto.Clone(nilMsg) },
71	}, {
72		label: "Equal",
73		test:  func() { proto.Equal(nil, nil) },
74	}, {
75		label: "Equal",
76		test:  func() { proto.Equal(nil, nilMsg) },
77	}, {
78		label: "Equal",
79		test:  func() { proto.Equal(nilMsg, nil) },
80	}, {
81		label: "Equal",
82		test:  func() { proto.Equal(nilMsg, nilMsg) },
83	}, {
84		label: "Reset",
85		test:  func() { proto.Reset(nil) },
86		panic: true,
87	}, {
88		label: "Reset",
89		test:  func() { proto.Reset(nilMsg) },
90		panic: true,
91	}, {
92		label: "HasExtension",
93		test:  func() { proto.HasExtension(nil, nil) },
94	}, {
95		label: "HasExtension",
96		test:  func() { proto.HasExtension(nil, extType) },
97	}, {
98		label: "HasExtension",
99		test:  func() { proto.HasExtension(nilMsg, nil) },
100	}, {
101		label: "HasExtension",
102		test:  func() { proto.HasExtension(nilMsg, extType) },
103	}, {
104		label: "GetExtension",
105		test:  func() { proto.GetExtension(nil, nil) },
106		panic: true,
107	}, {
108		label: "GetExtension",
109		test:  func() { proto.GetExtension(nil, extType) },
110	}, {
111		label: "GetExtension",
112		test:  func() { proto.GetExtension(nilMsg, nil) },
113		panic: true,
114	}, {
115		label: "GetExtension",
116		test:  func() { proto.GetExtension(nilMsg, extType) },
117	}, {
118		label: "SetExtension",
119		test:  func() { proto.SetExtension(nil, nil, true) },
120		panic: true,
121	}, {
122		label: "SetExtension",
123		test:  func() { proto.SetExtension(nil, extType, true) },
124		panic: true,
125	}, {
126		label: "SetExtension",
127		test:  func() { proto.SetExtension(nilMsg, nil, true) },
128		panic: true,
129	}, {
130		label: "SetExtension",
131		test:  func() { proto.SetExtension(nilMsg, extType, true) },
132		panic: true,
133	}, {
134		label: "ClearExtension",
135		test:  func() { proto.ClearExtension(nil, nil) },
136		panic: true,
137	}, {
138		label: "ClearExtension",
139		test:  func() { proto.ClearExtension(nil, extType) },
140		panic: true,
141	}, {
142		label: "ClearExtension",
143		test:  func() { proto.ClearExtension(nilMsg, nil) },
144		panic: true,
145	}, {
146		label: "ClearExtension",
147		test:  func() { proto.ClearExtension(nilMsg, extType) },
148		panic: true,
149	}, {
150		label: "RangeExtensions",
151		test:  func() { proto.RangeExtensions(nil, nil) },
152	}, {
153		label: "RangeExtensions",
154		test:  func() { proto.RangeExtensions(nil, extRanger) },
155	}, {
156		label: "RangeExtensions",
157		test:  func() { proto.RangeExtensions(nilMsg, nil) },
158	}, {
159		label: "RangeExtensions",
160		test:  func() { proto.RangeExtensions(nilMsg, extRanger) },
161	}}
162
163	for _, tt := range tests {
164		t.Run(tt.label, func(t *testing.T) {
165			defer func() {
166				switch gotPanic := recover() != nil; {
167				case gotPanic && !tt.panic:
168					t.Errorf("unexpected panic")
169				case !gotPanic && tt.panic:
170					t.Errorf("expected panic")
171				}
172			}()
173			tt.test()
174		})
175	}
176}
177