github.com/kortschak/utter@v1.5.0/spew_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 "bytes" 22 "fmt" 23 "testing" 24 25 "github.com/kortschak/utter" 26 ) 27 28 // utterFunc is used to identify which public function of the utter package or 29 // ConfigState a test applies to. 30 type utterFunc int 31 32 const ( 33 fCSFdump utterFunc = iota 34 fCSSdump 35 fSdump 36 ) 37 38 // Map of utterFunc values to names for pretty printing. 39 var utterFuncStrings = map[utterFunc]string{ 40 fCSFdump: "ConfigState.Fdump", 41 fCSSdump: "ConfigState.Sdump", 42 fSdump: "utter.Sdump", 43 } 44 45 func (f utterFunc) String() string { 46 if s, ok := utterFuncStrings[f]; ok { 47 return s 48 } 49 return fmt.Sprintf("Unknown utterFunc (%d)", int(f)) 50 } 51 52 // utterTest is used to describe a test to be performed against the public 53 // functions of the utter package or ConfigState. 54 type utterTest struct { 55 cs *utter.ConfigState 56 f utterFunc 57 in interface{} 58 want string 59 } 60 61 // utterTests houses the tests to be performed against the public functions of 62 // the utter package and ConfigState. 63 // 64 // These tests are only intended to ensure the public functions are exercised 65 // and are intentionally not exhaustive of types. The exhaustive type 66 // tests are handled in the dump and format tests. 67 var utterTests []utterTest 68 69 func initSpewTests() { 70 // Config states with various settings. 71 scsDefault := utter.NewDefaultConfig() 72 73 // Byte slice without comments. 74 noComDefault := utter.NewDefaultConfig() 75 noComDefault.CommentBytes = false 76 77 // Pointer comments. 78 comPtrDefault := utter.NewDefaultConfig() 79 comPtrDefault.CommentPointers = true 80 81 // Byte slice with 8 columns. 82 bs8Default := utter.NewDefaultConfig() 83 bs8Default.BytesWidth = 8 84 85 // Numeric slice with 4 columns. 86 num4elideDefault := utter.NewDefaultConfig() 87 num4elideDefault.ElideType = true 88 num4elideDefault.NumericWidth = 4 89 90 // String slice with 4 columns. 91 string4elideDefault := utter.NewDefaultConfig() 92 string4elideDefault.ElideType = true 93 string4elideDefault.StringWidth = 4 94 95 // One line slice. 96 oneElideDefault := utter.NewDefaultConfig() 97 oneElideDefault.ElideType = true 98 oneElideDefault.NumericWidth = 0 99 oneElideDefault.StringWidth = 0 100 101 // Ignore unexported fields. 102 ignUnexDefault := utter.NewDefaultConfig() 103 ignUnexDefault.IgnoreUnexported = true 104 105 // Remove local package prefix. 106 elideLocalDefault := utter.NewDefaultConfig() 107 elideLocalDefault.LocalPackage = "utter_test" 108 109 // Elide implicit types. 110 elideTypeDefault := utter.NewDefaultConfig() 111 elideTypeDefault.ElideType = true 112 113 // AvoidEscape. 114 avoidEscape := utter.NewDefaultConfig() 115 avoidEscape.SortKeys = true 116 avoidEscape.Quoting = utter.AvoidEscapes 117 118 // AvoidEscape|Force. 119 avoidEscapeForce := utter.NewDefaultConfig() 120 avoidEscapeForce.SortKeys = true 121 avoidEscapeForce.Quoting = utter.AvoidEscapes | utter.Force 122 123 // Backquote. 124 backquote := utter.NewDefaultConfig() 125 backquote.SortKeys = true 126 backquote.Quoting = utter.Backquote 127 128 var ( 129 np *int 130 nip = new(interface{}) 131 nm map[int]int 132 ns []int 133 ) 134 135 v := new(int) 136 *v = 10 137 s := struct{ *int }{v} 138 sp := &s 139 spp := &sp 140 141 c := []interface{}{5, 5, nil, nil} 142 c[2] = &c[0] 143 c[3] = &c[1] 144 145 d := &struct { 146 a [2]int 147 p *int 148 }{} 149 d.a[1] = 10 150 d.p = &d.a[1] 151 152 type cs struct{ *cs } 153 var cyc cs 154 cyc.cs = &cyc 155 156 m := map[int][]interface{}{1: c} 157 158 type b map[string]interface{} 159 160 utterTests = []utterTest{ 161 {scsDefault, fCSFdump, int8(127), "int8(127)\n"}, 162 {scsDefault, fCSSdump, uint8(64), "uint8(0x40)\n"}, 163 {scsDefault, fSdump, complex(-10, -20), "complex128(-10-20i)\n"}, 164 {noComDefault, fCSFdump, []byte{1, 2, 3, 4, 5, 0}, 165 "[]uint8{\n 0x01, 0x02, 0x03, 0x04, 0x05, 0x00,\n}\n", 166 }, 167 {comPtrDefault, fCSFdump, &np, fmt.Sprintf("&(*int) /*%p*/ (nil)\n", &np)}, 168 {comPtrDefault, fCSFdump, nip, fmt.Sprintf("&interface{} /*%p*/ (nil)\n", nip)}, 169 {comPtrDefault, fCSFdump, &nm, fmt.Sprintf("&map[int]int /*%p*/ (nil)\n", &nm)}, 170 {comPtrDefault, fCSFdump, &ns, fmt.Sprintf("&[]int /*%p*/ (nil)\n", &ns)}, 171 {comPtrDefault, fCSFdump, s, fmt.Sprintf("struct { *int }{\n int: &int /*%p*/ (10),\n}\n", v)}, 172 {comPtrDefault, fCSFdump, sp, fmt.Sprintf("&struct { *int } /*%p*/ {\n int: &int /*%p*/ (10),\n}\n", sp, v)}, 173 {comPtrDefault, fCSFdump, spp, fmt.Sprintf("&&struct { *int } /*%p->%p*/ {\n int: &int /*%p*/ (10),\n}\n", spp, sp, v)}, 174 {comPtrDefault, fCSFdump, c, fmt.Sprintf("[]interface{}{\n"+ 175 " int( /*%p*/ 5),\n int( /*%p*/ 5),\n"+ 176 " (*interface{}) /*%[1]p*/ (<already shown>),\n &int /*%p*/ (5),\n}\n", &c[0], &c[1])}, 177 {comPtrDefault, fCSFdump, d, fmt.Sprintf("&struct { a [2]int; p *int } /*%p*/ {\n"+ 178 " a: [2]int{\n int(0),\n"+ 179 " int( /*%p*/ 10),\n },\n"+ 180 " p: &int /*%[2]p*/ (10),\n}\n", d, &d.a[1])}, 181 {comPtrDefault, fCSFdump, &cyc, fmt.Sprintf("&utter_test.cs /*%p*/ {\n"+ 182 " cs: (*utter_test.cs) /*%[1]p*/ (<already shown>),\n}\n", cyc.cs)}, 183 {comPtrDefault, fCSFdump, m, fmt.Sprintf("map[int][]interface{}{\n"+ 184 " int(1): []interface{}{\n"+ 185 " int( /*%p*/ 5),\n"+ 186 " int( /*%p*/ 5),\n"+ 187 " (*interface{}) /*%[1]p*/ (<already shown>),\n"+ 188 " &int /*%p*/ (5),\n },\n}\n", &c[0], &c[1])}, 189 {bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3}, "[]uint8{\n" + 190 " 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" + 191 " 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, 0x03, /* */ // |.......|\n}\n", 192 }, 193 {bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2}, "[]uint8{\n" + 194 " 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" + 195 " 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, /* */ // |......|\n}\n", 196 }, 197 {bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1}, "[]uint8{\n" + 198 " 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" + 199 " 0x03, 0x04, 0x05, 0x00, 0x01, /* */ // |.....|\n}\n", 200 }, 201 {bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0}, "[]uint8{\n" + 202 " 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" + 203 " 0x03, 0x04, 0x05, 0x00, /* */ // |....|\n}\n", 204 }, 205 {bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1}, "[]uint8{\n" + 206 " 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, // |.......|\n}\n", 207 }, 208 {ignUnexDefault, fCSFdump, Foo{Bar{flag: 1}, map[interface{}]interface{}{"one": true}}, 209 "utter_test.Foo{\n ExportedField: map[interface{}]interface{}{\n string(\"one\"): bool(true),\n },\n}\n", 210 }, 211 {elideLocalDefault, fCSFdump, Foo{Bar{flag: 1}, map[interface{}]interface{}{"one": true}}, 212 "Foo{\n unexportedField: Bar{\n flag: Flag(1),\n data: uintptr(0),\n },\n ExportedField: map[interface{}]interface{}{\n string(\"one\"): bool(true),\n },\n}\n", 213 }, 214 {elideLocalDefault, fCSFdump, map[cs]cs{{}: {}}, 215 "map[cs]cs{\n cs{\n cs: (*cs)(nil),\n }: cs{\n cs: (*cs)(nil),\n },\n}\n", 216 }, 217 {elideLocalDefault, fCSFdump, [2]cs{}, 218 "[2]cs{\n cs{\n cs: (*cs)(nil),\n },\n cs{\n cs: (*cs)(nil),\n },\n}\n", 219 }, 220 {elideLocalDefault, fCSFdump, []cs{{}}, 221 "[]cs{\n cs{\n cs: (*cs)(nil),\n },\n}\n", 222 }, 223 {elideLocalDefault, fCSFdump, chan cs(nil), 224 "chan cs(nil)\n", 225 }, 226 {elideLocalDefault, fCSFdump, chan<- cs(nil), 227 "chan<- cs(nil)\n", 228 }, 229 {elideLocalDefault, fCSFdump, b{"one": b{"two": "three"}}, "b{\n string(\"one\"): b{\n string(\"two\"): string(\"three\"),\n },\n}\n"}, 230 {elideTypeDefault, fCSFdump, float64(1), "1.0\n"}, 231 {elideTypeDefault, fCSFdump, float32(1), "float32(1)\n"}, 232 {elideTypeDefault, fCSFdump, int(1), "1\n"}, 233 {elideTypeDefault, fCSFdump, []interface{}{true, 1.0, float32(1), "one", 1, 'a'}, 234 "[]interface{}{\n true,\n 1.0,\n float32(1),\n \"one\",\n 1,\n int32(97),\n}\n", 235 }, 236 {elideTypeDefault, fCSFdump, Foo{Bar{flag: 1}, map[interface{}]interface{}{"one": true}}, "utter_test.Foo{\n" + 237 " unexportedField: utter_test.Bar{\n flag: 1,\n data: 0,\n },\n" + 238 " ExportedField: map[interface{}]interface{}{\n \"one\": true,\n },\n}\n", 239 }, 240 {elideTypeDefault, fCSFdump, map[interface{}]interface{}{"one": nil}, "map[interface{}]interface{}{\n \"one\": nil,\n}\n"}, 241 {elideTypeDefault, fCSFdump, float32(1), "float32(1)\n"}, 242 {elideTypeDefault, fCSFdump, float64(1), "1.0\n"}, 243 {elideTypeDefault, fCSFdump, func() *float64 { f := 1.0; return &f }(), "&float64(1)\n"}, 244 {elideTypeDefault, fCSFdump, []float32{1, 2, 3, 4, 5}, "[]float32{\n 1.0,\n 2.0,\n 3.0,\n 4.0,\n 5.0,\n}\n"}, 245 {elideTypeDefault, fCSFdump, map[struct{ int }]struct{ int }{{1}: {1}}, "map[struct { int }]struct { int }{\n {\n int: 1,\n }: {\n int: 1,\n },\n}\n"}, 246 {elideTypeDefault, fCSFdump, map[interface{}]struct{ int }{struct{ int }{1}: {1}}, "map[interface{}]struct { int }{\n struct { int }{\n int: 1,\n }: {\n int: 1,\n },\n}\n"}, 247 {elideTypeDefault, fCSFdump, map[struct{ int }]interface{}{{1}: struct{ int }{1}}, "map[struct { int }]interface{}{\n {\n int: 1,\n }: struct { int }{\n int: 1,\n },\n}\n"}, 248 {elideTypeDefault, fCSFdump, []struct{ int }{{1}}, "[]struct { int }{\n {\n int: 1,\n },\n}\n"}, 249 {elideTypeDefault, fCSFdump, []interface{}{struct{ int }{1}}, "[]interface{}{\n struct { int }{\n int: 1,\n },\n}\n"}, 250 {elideTypeDefault, fCSFdump, b{"one": b{"two": "three"}}, "utter_test.b{\n \"one\": utter_test.b{\n \"two\": \"three\",\n },\n}\n"}, 251 {num4elideDefault, fCSFdump, []interface{}{ 252 []int{1, 2, 3, 4}, 253 []uint{1, 2, 3, 4, 5}, 254 []float32{1, 2, 3, 4, 5, 6, 7, 8, 9}, 255 []bool{true, false, true}, 256 []complex128{1 + 1i, 0, 1 - 1i, 2, 4, 8}}, 257 "[]interface{}{\n" + 258 " []int{\n 1, 2, 3, 4,\n },\n" + 259 " []uint{\n 0x1, 0x2, 0x3, 0x4,\n 0x5,\n },\n" + 260 " []float32{\n 1.0, 2.0, 3.0, 4.0,\n 5.0, 6.0, 7.0, 8.0,\n 9.0,\n },\n" + 261 " []bool{\n true, false, true,\n },\n" + 262 " []complex128{\n 1+1i, 0+0i, 1-1i, 2+0i,\n 4+0i, 8+0i,\n },\n}\n", 263 }, 264 {num4elideDefault, fCSFdump, [][]int{ 265 {1, 2, 3}, 266 {1, 2, 3, 4}, 267 {1, 2, 3, 4, 5}}, 268 "[][]int{\n" + 269 " {\n 1, 2, 3,\n },\n" + 270 " {\n 1, 2, 3, 4,\n },\n" + 271 " {\n 1, 2, 3, 4,\n 5,\n },\n}\n", 272 }, 273 {string4elideDefault, fCSFdump, []string{"one", "two", "three", "four", "five"}, 274 "[]string{\n \"one\", \"two\", \"three\", \"four\",\n \"five\",\n}\n", 275 }, 276 {oneElideDefault, fCSFdump, []interface{}{ 277 []int{1, 2, 3, 4}, 278 []string{"one", "two", "three", "four", "five"}}, 279 "[]interface{}{\n" + 280 " []int{1, 2, 3, 4},\n" + 281 " []string{\"one\", \"two\", \"three\", \"four\", \"five\"},\n}\n", 282 }, 283 {avoidEscape, fCSFdump, map[string]string{ 284 "one": "\no\nn\ne\n", 285 "\nt\nw\no\n": "two", 286 "three": "`t\th\tr\te\te`", 287 "codeblock": "```\ncode\n```\n", 288 }, "map[string]string{\n string(`\nt\nw\no\n`): string(\"two\"),\n string(\"codeblock\"): string(\"```\\ncode\\n```\\n\"),\n string(\"one\"): string(`\no\nn\ne\n`),\n string(\"three\"): string(\"`t\\th\\tr\\te\\te`\"),\n}\n"}, 289 {avoidEscapeForce, fCSFdump, map[string]string{ 290 "one": "\no\nn\ne\n", 291 "\nt\nw\no\n": "two", 292 "three": "`t\th\tr\te\te`", 293 "codeblock": "```\ncode\n```\n", 294 }, "map[string]string{\n string(`\nt\nw\no\n`): string(\"two\"),\n string(\"codeblock\"): string(\"```\"+`\ncode\n`+\"```\"+`\n`),\n string(\"one\"): string(`\no\nn\ne\n`),\n string(\"three\"): string(\"`\"+`t\th\tr\te\te`+\"`\"),\n}\n"}, 295 {backquote, fCSFdump, map[string]string{ 296 "one": "\no\nn\ne\n", 297 "\nt\nw\no\n": "two", 298 "three": "`t\th\tr\te\te`", 299 "backquote": "`", 300 "tabbackquote": "\t`", 301 "backquotetab": "`\t", 302 "tabbackquotetab": "\t`\t", 303 "backquotetabbackquote": "`\t`", 304 "codeblock": "```\ncode\n```\n", 305 }, "map[string]string{\n string(`\nt\nw\no\n`): string(`two`),\n string(`backquote`): string(\"`\"),\n string(`backquotetab`): string(\"`\"+`\t`),\n string(`backquotetabbackquote`): string(\"`\"+`\t`+\"`\"),\n string(`codeblock`): string(\"```\"+`\ncode\n`+\"```\"+`\n`),\n string(`one`): string(`\no\nn\ne\n`),\n string(`tabbackquote`): string(`\t`+\"`\"),\n string(`tabbackquotetab`): string(`\t`+\"`\"+`\t`),\n string(`three`): string(\"`\"+`t\th\tr\te\te`+\"`\"),\n}\n"}, 306 } 307 } 308 309 // TestSpew executes all of the tests described by utterTests. 310 func TestSpew(t *testing.T) { 311 initSpewTests() 312 313 t.Logf("Running %d tests", len(utterTests)) 314 for i, test := range utterTests { 315 buf := new(bytes.Buffer) 316 switch test.f { 317 case fCSFdump: 318 test.cs.Fdump(buf, test.in) 319 320 case fCSSdump: 321 str := test.cs.Sdump(test.in) 322 buf.WriteString(str) 323 324 case fSdump: 325 str := utter.Sdump(test.in) 326 buf.WriteString(str) 327 328 default: 329 t.Errorf("%v #%d unrecognized function", test.f, i) 330 continue 331 } 332 s := buf.String() 333 if test.want != s { 334 t.Errorf("ConfigState #%d\n got: %q\nwant: %q", i, s, test.want) 335 continue 336 } 337 } 338 }