xref: /aosp_15_r20/external/go-cmp/cmp/options_test.go (revision 88d15eac089d7f20c739ff1001d56b91872b21a1)
1// Copyright 2017, 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 cmp
6
7import (
8	"io"
9	"reflect"
10	"strings"
11	"testing"
12
13	ts "github.com/google/go-cmp/cmp/internal/teststructs"
14)
15
16// Test that the creation of Option values with non-sensible inputs produces
17// a run-time panic with a decent error message
18func TestOptionPanic(t *testing.T) {
19	type myBool bool
20	tests := []struct {
21		label     string        // Test description
22		fnc       interface{}   // Option function to call
23		args      []interface{} // Arguments to pass in
24		wantPanic string        // Expected panic message
25	}{{
26		label: "AllowUnexported",
27		fnc:   AllowUnexported,
28		args:  []interface{}{},
29	}, {
30		label:     "AllowUnexported",
31		fnc:       AllowUnexported,
32		args:      []interface{}{1},
33		wantPanic: "invalid struct type",
34	}, {
35		label: "AllowUnexported",
36		fnc:   AllowUnexported,
37		args:  []interface{}{ts.StructA{}},
38	}, {
39		label: "AllowUnexported",
40		fnc:   AllowUnexported,
41		args:  []interface{}{ts.StructA{}, ts.StructB{}, ts.StructA{}},
42	}, {
43		label:     "AllowUnexported",
44		fnc:       AllowUnexported,
45		args:      []interface{}{ts.StructA{}, &ts.StructB{}, ts.StructA{}},
46		wantPanic: "invalid struct type",
47	}, {
48		label:     "Comparer",
49		fnc:       Comparer,
50		args:      []interface{}{5},
51		wantPanic: "invalid comparer function",
52	}, {
53		label: "Comparer",
54		fnc:   Comparer,
55		args:  []interface{}{func(x, y interface{}) bool { return true }},
56	}, {
57		label: "Comparer",
58		fnc:   Comparer,
59		args:  []interface{}{func(x, y io.Reader) bool { return true }},
60	}, {
61		label:     "Comparer",
62		fnc:       Comparer,
63		args:      []interface{}{func(x, y io.Reader) myBool { return true }},
64		wantPanic: "invalid comparer function",
65	}, {
66		label:     "Comparer",
67		fnc:       Comparer,
68		args:      []interface{}{func(x string, y interface{}) bool { return true }},
69		wantPanic: "invalid comparer function",
70	}, {
71		label:     "Comparer",
72		fnc:       Comparer,
73		args:      []interface{}{(func(int, int) bool)(nil)},
74		wantPanic: "invalid comparer function",
75	}, {
76		label:     "Transformer",
77		fnc:       Transformer,
78		args:      []interface{}{"", 0},
79		wantPanic: "invalid transformer function",
80	}, {
81		label: "Transformer",
82		fnc:   Transformer,
83		args:  []interface{}{"", func(int) int { return 0 }},
84	}, {
85		label: "Transformer",
86		fnc:   Transformer,
87		args:  []interface{}{"", func(bool) bool { return true }},
88	}, {
89		label: "Transformer",
90		fnc:   Transformer,
91		args:  []interface{}{"", func(int) bool { return true }},
92	}, {
93		label:     "Transformer",
94		fnc:       Transformer,
95		args:      []interface{}{"", func(int, int) bool { return true }},
96		wantPanic: "invalid transformer function",
97	}, {
98		label:     "Transformer",
99		fnc:       Transformer,
100		args:      []interface{}{"", (func(int) uint)(nil)},
101		wantPanic: "invalid transformer function",
102	}, {
103		label: "Transformer",
104		fnc:   Transformer,
105		args:  []interface{}{"Func", func(Path) Path { return nil }},
106	}, {
107		label: "Transformer",
108		fnc:   Transformer,
109		args:  []interface{}{"世界", func(int) bool { return true }},
110	}, {
111		label:     "Transformer",
112		fnc:       Transformer,
113		args:      []interface{}{"/*", func(int) bool { return true }},
114		wantPanic: "invalid name",
115	}, {
116		label: "Transformer",
117		fnc:   Transformer,
118		args:  []interface{}{"_", func(int) bool { return true }},
119	}, {
120		label:     "FilterPath",
121		fnc:       FilterPath,
122		args:      []interface{}{(func(Path) bool)(nil), Ignore()},
123		wantPanic: "invalid path filter function",
124	}, {
125		label: "FilterPath",
126		fnc:   FilterPath,
127		args:  []interface{}{func(Path) bool { return true }, Ignore()},
128	}, {
129		label:     "FilterPath",
130		fnc:       FilterPath,
131		args:      []interface{}{func(Path) bool { return true }, Reporter(&defaultReporter{})},
132		wantPanic: "invalid option type",
133	}, {
134		label: "FilterPath",
135		fnc:   FilterPath,
136		args:  []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}},
137	}, {
138		label:     "FilterPath",
139		fnc:       FilterPath,
140		args:      []interface{}{func(Path) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}},
141		wantPanic: "invalid option type",
142	}, {
143		label:     "FilterValues",
144		fnc:       FilterValues,
145		args:      []interface{}{0, Ignore()},
146		wantPanic: "invalid values filter function",
147	}, {
148		label: "FilterValues",
149		fnc:   FilterValues,
150		args:  []interface{}{func(x, y int) bool { return true }, Ignore()},
151	}, {
152		label: "FilterValues",
153		fnc:   FilterValues,
154		args:  []interface{}{func(x, y interface{}) bool { return true }, Ignore()},
155	}, {
156		label:     "FilterValues",
157		fnc:       FilterValues,
158		args:      []interface{}{func(x, y interface{}) myBool { return true }, Ignore()},
159		wantPanic: "invalid values filter function",
160	}, {
161		label:     "FilterValues",
162		fnc:       FilterValues,
163		args:      []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()},
164		wantPanic: "invalid values filter function",
165	}, {
166		label:     "FilterValues",
167		fnc:       FilterValues,
168		args:      []interface{}{(func(int, int) bool)(nil), Ignore()},
169		wantPanic: "invalid values filter function",
170	}, {
171		label:     "FilterValues",
172		fnc:       FilterValues,
173		args:      []interface{}{func(int, int) bool { return true }, Reporter(&defaultReporter{})},
174		wantPanic: "invalid option type",
175	}, {
176		label: "FilterValues",
177		fnc:   FilterValues,
178		args:  []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}},
179	}, {
180		label:     "FilterValues",
181		fnc:       FilterValues,
182		args:      []interface{}{func(int, int) bool { return true }, Options{Ignore(), Reporter(&defaultReporter{})}},
183		wantPanic: "invalid option type",
184	}}
185
186	for _, tt := range tests {
187		t.Run(tt.label, func(t *testing.T) {
188			var gotPanic string
189			func() {
190				defer func() {
191					if ex := recover(); ex != nil {
192						if s, ok := ex.(string); ok {
193							gotPanic = s
194						} else {
195							panic(ex)
196						}
197					}
198				}()
199				var vargs []reflect.Value
200				for _, arg := range tt.args {
201					vargs = append(vargs, reflect.ValueOf(arg))
202				}
203				reflect.ValueOf(tt.fnc).Call(vargs)
204			}()
205			if tt.wantPanic == "" {
206				if gotPanic != "" {
207					t.Fatalf("unexpected panic message: %s", gotPanic)
208				}
209			} else {
210				if !strings.Contains(gotPanic, tt.wantPanic) {
211					t.Fatalf("panic message:\ngot:  %s\nwant: %s", gotPanic, tt.wantPanic)
212				}
213			}
214		})
215	}
216}
217