github.com/integration-system/go-cmp@v0.0.0-20190131081942-ac5582987a2f/cmp/options_test.go (about)

     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.md file.
     4  
     5  package cmp
     6  
     7  import (
     8  	"io"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  
    13  	ts "github.com/integration-system/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
    18  func 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  		wantPanic: "invalid name",
   120  	}, {
   121  		label:     "FilterPath",
   122  		fnc:       FilterPath,
   123  		args:      []interface{}{(func(Path) bool)(nil), Ignore()},
   124  		wantPanic: "invalid path filter function",
   125  	}, {
   126  		label: "FilterPath",
   127  		fnc:   FilterPath,
   128  		args:  []interface{}{func(Path) bool { return true }, Ignore()},
   129  	}, {
   130  		label:     "FilterPath",
   131  		fnc:       FilterPath,
   132  		args:      []interface{}{func(Path) bool { return true }, &defaultReporter{}},
   133  		wantPanic: "invalid option type",
   134  	}, {
   135  		label: "FilterPath",
   136  		fnc:   FilterPath,
   137  		args:  []interface{}{func(Path) bool { return true }, Options{Ignore(), Ignore()}},
   138  	}, {
   139  		label:     "FilterPath",
   140  		fnc:       FilterPath,
   141  		args:      []interface{}{func(Path) bool { return true }, Options{Ignore(), &defaultReporter{}}},
   142  		wantPanic: "invalid option type",
   143  	}, {
   144  		label:     "FilterValues",
   145  		fnc:       FilterValues,
   146  		args:      []interface{}{0, Ignore()},
   147  		wantPanic: "invalid values filter function",
   148  	}, {
   149  		label: "FilterValues",
   150  		fnc:   FilterValues,
   151  		args:  []interface{}{func(x, y int) bool { return true }, Ignore()},
   152  	}, {
   153  		label: "FilterValues",
   154  		fnc:   FilterValues,
   155  		args:  []interface{}{func(x, y interface{}) bool { return true }, Ignore()},
   156  	}, {
   157  		label:     "FilterValues",
   158  		fnc:       FilterValues,
   159  		args:      []interface{}{func(x, y interface{}) myBool { return true }, Ignore()},
   160  		wantPanic: "invalid values filter function",
   161  	}, {
   162  		label:     "FilterValues",
   163  		fnc:       FilterValues,
   164  		args:      []interface{}{func(x io.Reader, y interface{}) bool { return true }, Ignore()},
   165  		wantPanic: "invalid values filter function",
   166  	}, {
   167  		label:     "FilterValues",
   168  		fnc:       FilterValues,
   169  		args:      []interface{}{(func(int, int) bool)(nil), Ignore()},
   170  		wantPanic: "invalid values filter function",
   171  	}, {
   172  		label:     "FilterValues",
   173  		fnc:       FilterValues,
   174  		args:      []interface{}{func(int, int) bool { return true }, &defaultReporter{}},
   175  		wantPanic: "invalid option type",
   176  	}, {
   177  		label: "FilterValues",
   178  		fnc:   FilterValues,
   179  		args:  []interface{}{func(int, int) bool { return true }, Options{Ignore(), Ignore()}},
   180  	}, {
   181  		label:     "FilterValues",
   182  		fnc:       FilterValues,
   183  		args:      []interface{}{func(int, int) bool { return true }, Options{Ignore(), &defaultReporter{}}},
   184  		wantPanic: "invalid option type",
   185  	}}
   186  
   187  	for _, tt := range tests {
   188  		t.Run(tt.label, func(t *testing.T) {
   189  			var gotPanic string
   190  			func() {
   191  				defer func() {
   192  					if ex := recover(); ex != nil {
   193  						if s, ok := ex.(string); ok {
   194  							gotPanic = s
   195  						} else {
   196  							panic(ex)
   197  						}
   198  					}
   199  				}()
   200  				var vargs []reflect.Value
   201  				for _, arg := range tt.args {
   202  					vargs = append(vargs, reflect.ValueOf(arg))
   203  				}
   204  				reflect.ValueOf(tt.fnc).Call(vargs)
   205  			}()
   206  			if tt.wantPanic == "" {
   207  				if gotPanic != "" {
   208  					t.Fatalf("unexpected panic message: %s", gotPanic)
   209  				}
   210  			} else {
   211  				if !strings.Contains(gotPanic, tt.wantPanic) {
   212  					t.Fatalf("panic message:\ngot:  %s\nwant: %s", gotPanic, tt.wantPanic)
   213  				}
   214  			}
   215  		})
   216  	}
   217  }