github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/test/go-spew/spew/common_test.go (about)

     1  /*
     2   * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
     3   *
     4   * Permission to use, copy, modify, and distribute this software for any
     5   * purpose with or without fee is hereby granted, provided that the above
     6   * copyright notice and this permission notice appear in all copies.
     7   *
     8   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     9   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    10   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    11   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    12   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    13   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    14   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    15   */
    16  
    17  package spew_test
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/davecgh/go-spew/spew"
    25  )
    26  
    27  // custom type to test Stinger interface on non-pointer receiver.
    28  type stringer string
    29  
    30  // String implements the Stringer interface for testing invocation of custom
    31  // stringers on types with non-pointer receivers.
    32  func (s stringer) String() string {
    33  	return "stringer " + string(s)
    34  }
    35  
    36  // custom type to test Stinger interface on pointer receiver.
    37  type pstringer string
    38  
    39  // String implements the Stringer interface for testing invocation of custom
    40  // stringers on types with only pointer receivers.
    41  func (s *pstringer) String() string {
    42  	return "stringer " + string(*s)
    43  }
    44  
    45  // xref1 and xref2 are cross referencing structs for testing circular reference
    46  // detection.
    47  type xref1 struct {
    48  	ps2 *xref2
    49  }
    50  type xref2 struct {
    51  	ps1 *xref1
    52  }
    53  
    54  // indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
    55  // reference for testing detection.
    56  type indirCir1 struct {
    57  	ps2 *indirCir2
    58  }
    59  type indirCir2 struct {
    60  	ps3 *indirCir3
    61  }
    62  type indirCir3 struct {
    63  	ps1 *indirCir1
    64  }
    65  
    66  // embed is used to test embedded structures.
    67  type embed struct {
    68  	a string
    69  }
    70  
    71  // embedwrap is used to test embedded structures.
    72  type embedwrap struct {
    73  	*embed
    74  	e *embed
    75  }
    76  
    77  // panicer is used to intentionally cause a panic for testing spew properly
    78  // handles them
    79  type panicer int
    80  
    81  func (p panicer) String() string {
    82  	panic("test panic")
    83  }
    84  
    85  // customError is used to test custom error interface invocation.
    86  type customError int
    87  
    88  func (e customError) Error() string {
    89  	return fmt.Sprintf("error: %d", int(e))
    90  }
    91  
    92  // stringizeWants converts a slice of wanted test output into a format suitable
    93  // for a test error message.
    94  func stringizeWants(wants []string) string {
    95  	s := ""
    96  	for i, want := range wants {
    97  		if i > 0 {
    98  			s += fmt.Sprintf("want%d: %s", i+1, want)
    99  		} else {
   100  			s += "want: " + want
   101  		}
   102  	}
   103  	return s
   104  }
   105  
   106  // testFailed returns whether or not a test failed by checking if the result
   107  // of the test is in the slice of wanted strings.
   108  func testFailed(result string, wants []string) bool {
   109  	for _, want := range wants {
   110  		if result == want {
   111  			return false
   112  		}
   113  	}
   114  	return true
   115  }
   116  
   117  type sortableStruct struct {
   118  	x int
   119  }
   120  
   121  func (ss sortableStruct) String() string {
   122  	return fmt.Sprintf("ss.%d", ss.x)
   123  }
   124  
   125  type unsortableStruct struct {
   126  	x int
   127  }
   128  
   129  type sortTestCase struct {
   130  	input    []reflect.Value
   131  	expected []reflect.Value
   132  }
   133  
   134  func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
   135  	getInterfaces := func(values []reflect.Value) []interface{} {
   136  		interfaces := []interface{}{}
   137  		for _, v := range values {
   138  			interfaces = append(interfaces, v.Interface())
   139  		}
   140  		return interfaces
   141  	}
   142  
   143  	for _, test := range tests {
   144  		spew.SortValues(test.input, cs)
   145  		// reflect.DeepEqual cannot really make sense of reflect.Value,
   146  		// probably because of all the pointer tricks. For instance,
   147  		// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
   148  		// instead.
   149  		input := getInterfaces(test.input)
   150  		expected := getInterfaces(test.expected)
   151  		if !reflect.DeepEqual(input, expected) {
   152  			t.Errorf("Sort mismatch:\n %v != %v", input, expected)
   153  		}
   154  	}
   155  }
   156  
   157  // TestSortValues ensures the sort functionality for relect.Value based sorting
   158  // works as intended.
   159  func TestSortValues(t *testing.T) {
   160  	v := reflect.ValueOf
   161  
   162  	a := v("a")
   163  	b := v("b")
   164  	c := v("c")
   165  	embedA := v(embed{"a"})
   166  	embedB := v(embed{"b"})
   167  	embedC := v(embed{"c"})
   168  	tests := []sortTestCase{
   169  		// No values.
   170  		{
   171  			[]reflect.Value{},
   172  			[]reflect.Value{},
   173  		},
   174  		// Bools.
   175  		{
   176  			[]reflect.Value{v(false), v(true), v(false)},
   177  			[]reflect.Value{v(false), v(false), v(true)},
   178  		},
   179  		// Ints.
   180  		{
   181  			[]reflect.Value{v(2), v(1), v(3)},
   182  			[]reflect.Value{v(1), v(2), v(3)},
   183  		},
   184  		// Uints.
   185  		{
   186  			[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
   187  			[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
   188  		},
   189  		// Floats.
   190  		{
   191  			[]reflect.Value{v(2.0), v(1.0), v(3.0)},
   192  			[]reflect.Value{v(1.0), v(2.0), v(3.0)},
   193  		},
   194  		// Strings.
   195  		{
   196  			[]reflect.Value{b, a, c},
   197  			[]reflect.Value{a, b, c},
   198  		},
   199  		// Array
   200  		{
   201  			[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
   202  			[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
   203  		},
   204  		// Uintptrs.
   205  		{
   206  			[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
   207  			[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
   208  		},
   209  		// SortableStructs.
   210  		{
   211  			// Note: not sorted - DisableMethods is set.
   212  			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
   213  			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
   214  		},
   215  		// UnsortableStructs.
   216  		{
   217  			// Note: not sorted - SpewKeys is false.
   218  			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
   219  			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
   220  		},
   221  		// Invalid.
   222  		{
   223  			[]reflect.Value{embedB, embedA, embedC},
   224  			[]reflect.Value{embedB, embedA, embedC},
   225  		},
   226  	}
   227  	cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
   228  	helpTestSortValues(tests, &cs, t)
   229  }
   230  
   231  // TestSortValuesWithMethods ensures the sort functionality for relect.Value
   232  // based sorting works as intended when using string methods.
   233  func TestSortValuesWithMethods(t *testing.T) {
   234  	v := reflect.ValueOf
   235  
   236  	a := v("a")
   237  	b := v("b")
   238  	c := v("c")
   239  	tests := []sortTestCase{
   240  		// Ints.
   241  		{
   242  			[]reflect.Value{v(2), v(1), v(3)},
   243  			[]reflect.Value{v(1), v(2), v(3)},
   244  		},
   245  		// Strings.
   246  		{
   247  			[]reflect.Value{b, a, c},
   248  			[]reflect.Value{a, b, c},
   249  		},
   250  		// SortableStructs.
   251  		{
   252  			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
   253  			[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
   254  		},
   255  		// UnsortableStructs.
   256  		{
   257  			// Note: not sorted - SpewKeys is false.
   258  			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
   259  			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
   260  		},
   261  	}
   262  	cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
   263  	helpTestSortValues(tests, &cs, t)
   264  }
   265  
   266  // TestSortValuesWithSpew ensures the sort functionality for relect.Value
   267  // based sorting works as intended when using spew to stringify keys.
   268  func TestSortValuesWithSpew(t *testing.T) {
   269  	v := reflect.ValueOf
   270  
   271  	a := v("a")
   272  	b := v("b")
   273  	c := v("c")
   274  	tests := []sortTestCase{
   275  		// Ints.
   276  		{
   277  			[]reflect.Value{v(2), v(1), v(3)},
   278  			[]reflect.Value{v(1), v(2), v(3)},
   279  		},
   280  		// Strings.
   281  		{
   282  			[]reflect.Value{b, a, c},
   283  			[]reflect.Value{a, b, c},
   284  		},
   285  		// SortableStructs.
   286  		{
   287  			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
   288  			[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
   289  		},
   290  		// UnsortableStructs.
   291  		{
   292  			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
   293  			[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
   294  		},
   295  	}
   296  	cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
   297  	helpTestSortValues(tests, &cs, t)
   298  }