github.com/kortschak/utter@v1.5.0/common_test.go (about)

     1  /*
     2   * Copyright (c) 2013 Dave Collins <dave@davec.name>
     3   * Copyright (c) 2015 Dan Kortschak <dan.kortschak@adelaide.edu.au>
     4   *
     5   * Permission to use, copy, modify, and distribute this software for any
     6   * purpose with or without fee is hereby granted, provided that the above
     7   * copyright notice and this permission notice appear in all copies.
     8   *
     9   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    10   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    11   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    12   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    13   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    14   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    15   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    16   */
    17  
    18  package utter_test
    19  
    20  import (
    21  	"fmt"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/kortschak/utter"
    26  )
    27  
    28  // custom type to test Stinger interface on non-pointer receiver.
    29  type stringer string
    30  
    31  // String implements the Stringer interface for testing invocation of custom
    32  // stringers on types with non-pointer receivers.
    33  func (s stringer) String() string {
    34  	return "stringer " + string(s)
    35  }
    36  
    37  // custom type to test Stinger interface on pointer receiver.
    38  type pstringer string
    39  
    40  // String implements the Stringer interface for testing invocation of custom
    41  // stringers on types with only pointer receivers.
    42  func (s *pstringer) String() string {
    43  	return "stringer " + string(*s)
    44  }
    45  
    46  // xref1 and xref2 are cross referencing structs for testing circular reference
    47  // detection.
    48  type xref1 struct {
    49  	ps2 *xref2
    50  }
    51  type xref2 struct {
    52  	ps1 *xref1
    53  }
    54  
    55  // indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
    56  // reference for testing detection.
    57  type indirCir1 struct {
    58  	ps2 *indirCir2
    59  }
    60  type indirCir2 struct {
    61  	ps3 *indirCir3
    62  }
    63  type indirCir3 struct {
    64  	ps1 *indirCir1
    65  }
    66  
    67  // embed is used to test embedded structures.
    68  type embed struct {
    69  	a string
    70  }
    71  
    72  // embedwrap is used to test embedded structures.
    73  type embedwrap struct {
    74  	*embed
    75  	e *embed
    76  }
    77  
    78  // panicer is used to intentionally cause a panic for testing utter properly
    79  // handles them
    80  type panicer int
    81  
    82  func (p panicer) String() string {
    83  	panic("test panic")
    84  }
    85  
    86  // customError is used to test custom error interface invocation.
    87  type customError int
    88  
    89  func (e customError) Error() string {
    90  	return fmt.Sprintf("error: %d", int(e))
    91  }
    92  
    93  // stringizeWants converts a slice of wanted test output into a format suitable
    94  // for a test error message.
    95  func stringizeWants(wants []string) string {
    96  	s := ""
    97  	for i, want := range wants {
    98  		if i > 0 {
    99  			s += fmt.Sprintf("want%d: %q", i+1, want)
   100  		} else {
   101  			s += fmt.Sprintf("want: %q", want)
   102  		}
   103  	}
   104  	return s
   105  }
   106  
   107  // testFailed returns whether or not a test failed by checking if the result
   108  // of the test is in the slice of wanted strings.
   109  func testFailed(result string, wants []string) bool {
   110  	for _, want := range wants {
   111  		if result == want {
   112  			return false
   113  		}
   114  	}
   115  	return true
   116  }
   117  
   118  // TestSortValues ensures the sort functionality for reflect.Value based sorting
   119  // works as intended.
   120  func TestSortValues(t *testing.T) {
   121  	getInterfaces := func(values []reflect.Value) []interface{} {
   122  		interfaces := []interface{}{}
   123  		for _, v := range values {
   124  			interfaces = append(interfaces, v.Interface())
   125  		}
   126  		return interfaces
   127  	}
   128  
   129  	v := reflect.ValueOf
   130  
   131  	a := v("a")
   132  	b := v("b")
   133  	c := v("c")
   134  	embedA := v(embed{"a"})
   135  	embedB := v(embed{"b"})
   136  	embedC := v(embed{"c"})
   137  	tests := []struct {
   138  		input    []reflect.Value
   139  		expected []reflect.Value
   140  	}{
   141  		// No values.
   142  		{
   143  			[]reflect.Value{},
   144  			[]reflect.Value{},
   145  		},
   146  		// Bools.
   147  		{
   148  			[]reflect.Value{v(false), v(true), v(false)},
   149  			[]reflect.Value{v(false), v(false), v(true)},
   150  		},
   151  		// Ints.
   152  		{
   153  			[]reflect.Value{v(2), v(1), v(3)},
   154  			[]reflect.Value{v(1), v(2), v(3)},
   155  		},
   156  		// Uints.
   157  		{
   158  			[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
   159  			[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
   160  		},
   161  		// Floats.
   162  		{
   163  			[]reflect.Value{v(2.0), v(1.0), v(3.0)},
   164  			[]reflect.Value{v(1.0), v(2.0), v(3.0)},
   165  		},
   166  		// Strings.
   167  		{
   168  			[]reflect.Value{b, a, c},
   169  			[]reflect.Value{a, b, c},
   170  		},
   171  		// Array
   172  		{
   173  			[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
   174  			[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
   175  		},
   176  		// Uintptrs.
   177  		{
   178  			[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
   179  			[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
   180  		},
   181  		// Invalid.
   182  		{
   183  			[]reflect.Value{embedB, embedA, embedC},
   184  			[]reflect.Value{embedA, embedB, embedC},
   185  		},
   186  	}
   187  	for _, test := range tests {
   188  		vals := make([]reflect.Value, len(test.input))
   189  		copy(vals, test.input)
   190  		utter.SortMapByKeyVals(test.input, vals)
   191  		// reflect.DeepEqual cannot really make sense of reflect.Value,
   192  		// probably because of all the pointer tricks. For instance,
   193  		// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
   194  		// instead.
   195  		input := getInterfaces(test.input)
   196  		values := getInterfaces(vals)
   197  		expected := getInterfaces(test.expected)
   198  		if !reflect.DeepEqual(input, expected) {
   199  			t.Errorf("Sort keys mismatch:\n %v != %v", input, expected)
   200  		}
   201  		if !reflect.DeepEqual(values, expected) {
   202  			t.Errorf("Sort values mismatch:\n %v != %v", values, expected)
   203  		}
   204  	}
   205  }