| // Copyright 2017, The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE.md file. |
| |
| package cmp |
| |
| import ( |
| "io" |
| "reflect" |
| "strings" |
| "testing" |
| |
| ts "github.com/google/go-cmp/cmp/internal/teststructs" |
| ) |
| |
| // Test that the creation of Option values with non-sensible inputs produces |
| // a run-time panic with a decent error message |
| func TestOptionPanic(t *testing.T) { |
| type myBool bool |
| tests := []struct { |
| label string // Test description |
| fnc interface{} // Option function to call |
| args []interface{} // Arguments to pass in |
| wantPanic string // Expected panic message |
| }{{ |
| label: "AllowUnexported", |
| fnc: AllowUnexported, |
| args: []interface{}{}, |
| }, { |
| label: "AllowUnexported", |
| fnc: AllowUnexported, |
| args: []interface{}{1}, |
| wantPanic: "invalid struct type", |
| }, { |
| label: "AllowUnexported", |
| fnc: AllowUnexported, |
| args: []interface{}{ts.StructA{}}, |
| }, { |
| label: "AllowUnexported", |
| fnc: AllowUnexported, |
| args: []interface{}{ts.StructA{}, ts.StructB{}, ts.StructA{}}, |
| }, { |
| label: "AllowUnexported", |
| fnc: AllowUnexported, |
| args: []interface{}{ts.StructA{}, &ts.StructB{}, ts.StructA{}}, |
| wantPanic: "invalid struct type", |
| }, { |
| label: "Comparer", |
| fnc: Comparer, |
| args: []interface{}{5}, |
| wantPanic: "invalid comparer function", |
| }, { |
| label: "Comparer", |
| fnc: Comparer, |
| args: []interface{}{func(x, y interface{}) bool { return true }}, |
| }, { |
| label: "Comparer", |
| fnc: Comparer, |
| args: []interface{}{func(x, y io.Reader) bool { return true }}, |
| }, { |
| label: "Comparer", |
| fnc: Comparer, |
| args: []interface{}{func(x, y io.Reader) myBool { return true }}, |
| wantPanic: "invalid comparer function", |
| }, { |
| label: "Comparer", |
| fnc: Comparer, |
| args: []interface{}{func(x string, y interface{}) bool { return true }}, |
| wantPanic: "invalid comparer function", |
| }, { |
| label: "Comparer", |
| fnc: Comparer, |
| args: []interface{}{(func(int, int) bool)(nil)}, |
| wantPanic: "invalid comparer function", |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"", 0}, |
| wantPanic: "invalid transformer function", |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"", func(int) int { return 0 }}, |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"", func(bool) bool { return true }}, |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"", func(int) bool { return true }}, |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"", func(int, int) bool { return true }}, |
| wantPanic: "invalid transformer function", |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"", (func(int) uint)(nil)}, |
| wantPanic: "invalid transformer function", |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"Func", func(Path) Path { return nil }}, |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"世界", func(int) bool { return true }}, |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"/*", func(int) bool { return true }}, |
| wantPanic: "invalid name", |
| }, { |
| label: "Transformer", |
| fnc: Transformer, |
| args: []interface{}{"_", func(int) bool { return true }}, |
| wantPanic: "invalid name", |
| }, { |
| label: "FilterPath", |
| fnc: FilterPath, |
| args: []interface{}{(func(Path) bool)(nil), Ignore()}, |
| wantPanic: "invalid path filter function", |
| }, { |
| label: "FilterPath", |
| fnc: FilterPath, |
| args: []interface{}{func(Path) bool { return true }, Ignore()}, |
| }, { |
| label: "FilterPath", |
| fnc: FilterPath, |
| args: []interface{}{func(Path) bool { return true }, &defaultReporter{}}, |
| wantPanic: "invalid option type", |
| }, { |
| label: "FilterPath", |
| fnc: FilterPath, |
| args: []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}}, |
| }, { |
| label: "FilterPath", |
| fnc: FilterPath, |
| args: []interface{}{func(Path) bool { return true }, Options{Ignore(), &defaultReporter{}}}, |
| wantPanic: "invalid option type", |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{0, Ignore()}, |
| wantPanic: "invalid values filter function", |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(x, y int) bool { return true }, Ignore()}, |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(x, y interface{}) bool { return true }, Ignore()}, |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(x, y interface{}) myBool { return true }, Ignore()}, |
| wantPanic: "invalid values filter function", |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()}, |
| wantPanic: "invalid values filter function", |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{(func(int, int) bool)(nil), Ignore()}, |
| wantPanic: "invalid values filter function", |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(int, int) bool { return true }, &defaultReporter{}}, |
| wantPanic: "invalid option type", |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}}, |
| }, { |
| label: "FilterValues", |
| fnc: FilterValues, |
| args: []interface{}{func(int, int) bool { return true }, Options{Ignore(), &defaultReporter{}}}, |
| wantPanic: "invalid option type", |
| }} |
| |
| for _, tt := range tests { |
| tRun(t, tt.label, func(t *testing.T) { |
| var gotPanic string |
| func() { |
| defer func() { |
| if ex := recover(); ex != nil { |
| if s, ok := ex.(string); ok { |
| gotPanic = s |
| } else { |
| panic(ex) |
| } |
| } |
| }() |
| var vargs []reflect.Value |
| for _, arg := range tt.args { |
| vargs = append(vargs, reflect.ValueOf(arg)) |
| } |
| reflect.ValueOf(tt.fnc).Call(vargs) |
| }() |
| if tt.wantPanic == "" { |
| if gotPanic != "" { |
| t.Fatalf("unexpected panic message: %s", gotPanic) |
| } |
| } else { |
| if !strings.Contains(gotPanic, tt.wantPanic) { |
| t.Fatalf("panic message:\ngot: %s\nwant: %s", gotPanic, tt.wantPanic) |
| } |
| } |
| }) |
| } |
| } |
| |
| // TODO: Delete this hack when we drop Go1.6 support. |
| func tRun(t *testing.T, name string, f func(t *testing.T)) { |
| type runner interface { |
| Run(string, func(t *testing.T)) bool |
| } |
| var ti interface{} = t |
| if r, ok := ti.(runner); ok { |
| r.Run(name, f) |
| } else { |
| t.Logf("Test: %s", name) |
| f(t) |
| } |
| } |