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 }