github.com/kortschak/utter@v1.5.0/dump_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 /* 19 Test Summary: 20 NOTE: For each test, a nil pointer, a single pointer and double pointer to the 21 base test element are also tested to ensure proper indirection across all types. 22 23 - Max int8, int16, int32, int64, int 24 - Max uint8, uint16, uint32, uint64, uint 25 - Boolean true and false 26 - Standard complex64 and complex128 27 - Array containing standard ints 28 - Array containing type with custom formatter on pointer receiver only 29 - Array containing interfaces 30 - Array containing bytes 31 - Slice containing standard float32 values 32 - Slice containing type with custom formatter on pointer receiver only 33 - Slice containing interfaces 34 - Slice containing bytes 35 - Nil slice 36 - Standard string 37 - Nil interface 38 - Sub-interface 39 - Map with string keys and int vals 40 - Map with custom formatter type on pointer receiver only keys and vals 41 - Map with interface keys and values 42 - Map with nil interface value 43 - Struct with primitives 44 - Struct that contains another struct 45 - Struct that contains custom type with Stringer pointer interface via both 46 exported and unexported fields 47 - Struct that contains embedded struct and field to same struct 48 - Uintptr to 0 (null pointer) 49 - Uintptr address of real variable 50 - Unsafe.Pointer to 0 (null pointer) 51 - Unsafe.Pointer to address of real variable 52 - Nil channel 53 - Standard int channel 54 - Function with no params and no returns 55 - Function with param and no returns 56 - Function with multiple params and multiple returns 57 - Struct that is circular through self referencing 58 - Structs that are circular through cross referencing 59 - Structs that are indirectly circular 60 - Type that panics in its Stringer interface 61 */ 62 63 package utter_test 64 65 import ( 66 "bytes" 67 "fmt" 68 "math" 69 "testing" 70 "unsafe" 71 72 "github.com/kortschak/utter" 73 ) 74 75 // dumpTest is used to describe a test to be perfomed against the Dump method. 76 type dumpTest struct { 77 in interface{} 78 wants []string 79 } 80 81 // dumpTests houses all of the tests to be performed against the Dump method. 82 var dumpTests = make([]dumpTest, 0) 83 84 // addDumpTest is a helper method to append the passed input and desired result 85 // to dumpTests 86 func addDumpTest(in interface{}, wants ...string) { 87 test := dumpTest{in, wants} 88 dumpTests = append(dumpTests, test) 89 } 90 91 func addIntDumpTests() { 92 // Max int8. 93 v := int8(127) 94 nv := (*int8)(nil) 95 pv := &v 96 vt := "int8" 97 vs := "127" 98 addDumpTest(v, vt+"("+vs+")\n") 99 addDumpTest(pv, "&"+vt+"("+vs+")\n") 100 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 101 addDumpTest(nv, "(*"+vt+")(nil)\n") 102 103 // Max int16. 104 v2 := int16(32767) 105 nv2 := (*int16)(nil) 106 pv2 := &v2 107 v2t := "int16" 108 v2s := "32767" 109 addDumpTest(v2, v2t+"("+v2s+")\n") 110 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 111 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 112 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 113 114 // Max int32. 115 v3 := int32(2147483647) 116 nv3 := (*int32)(nil) 117 pv3 := &v3 118 v3t := "int32" 119 v3s := "2147483647" 120 addDumpTest(v3, v3t+"("+v3s+")\n") 121 addDumpTest(pv3, "&"+v3t+"("+v3s+")\n") 122 addDumpTest(&pv3, "&&"+v3t+"("+v3s+")\n") 123 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 124 125 // Max int64. 126 v4 := int64(9223372036854775807) 127 nv4 := (*int64)(nil) 128 pv4 := &v4 129 v4t := "int64" 130 v4s := "9223372036854775807" 131 addDumpTest(v4, v4t+"("+v4s+")\n") 132 addDumpTest(pv4, "&"+v4t+"("+v4s+")\n") 133 addDumpTest(&pv4, "&&"+v4t+"("+v4s+")\n") 134 addDumpTest(nv4, "(*"+v4t+")(nil)\n") 135 136 // Max int. 137 v5 := int(2147483647) 138 nv5 := (*int)(nil) 139 pv5 := &v5 140 v5t := "int" 141 v5s := "2147483647" 142 addDumpTest(v5, v5t+"("+v5s+")\n") 143 addDumpTest(pv5, "&"+v5t+"("+v5s+")\n") 144 addDumpTest(&pv5, "&&"+v5t+"("+v5s+")\n") 145 addDumpTest(nv5, "(*"+v5t+")(nil)\n") 146 } 147 148 func addUintDumpTests() { 149 // Max uint8. 150 v := uint8(255) 151 nv := (*uint8)(nil) 152 pv := &v 153 vt := "uint8" 154 vs := "0xff" 155 addDumpTest(v, vt+"("+vs+")\n") 156 addDumpTest(pv, "&"+vt+"("+vs+")\n") 157 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 158 addDumpTest(nv, "(*"+vt+")(nil)\n") 159 160 // Max uint16. 161 v2 := uint16(65535) 162 nv2 := (*uint16)(nil) 163 pv2 := &v2 164 v2t := "uint16" 165 v2s := "0xffff" 166 addDumpTest(v2, v2t+"("+v2s+")\n") 167 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 168 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 169 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 170 171 // Max uint32. 172 v3 := uint32(4294967295) 173 nv3 := (*uint32)(nil) 174 pv3 := &v3 175 v3t := "uint32" 176 v3s := "0xffffffff" 177 addDumpTest(v3, v3t+"("+v3s+")\n") 178 addDumpTest(pv3, "&"+v3t+"("+v3s+")\n") 179 addDumpTest(&pv3, "&&"+v3t+"("+v3s+")\n") 180 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 181 182 // Max uint64. 183 v4 := uint64(18446744073709551615) 184 nv4 := (*uint64)(nil) 185 pv4 := &v4 186 v4t := "uint64" 187 v4s := "0xffffffffffffffff" 188 addDumpTest(v4, v4t+"("+v4s+")\n") 189 addDumpTest(pv4, "&"+v4t+"("+v4s+")\n") 190 addDumpTest(&pv4, "&&"+v4t+"("+v4s+")\n") 191 addDumpTest(nv4, "(*"+v4t+")(nil)\n") 192 193 // Max uint. 194 v5 := uint(4294967295) 195 nv5 := (*uint)(nil) 196 pv5 := &v5 197 v5t := "uint" 198 v5s := "0xffffffff" 199 addDumpTest(v5, v5t+"("+v5s+")\n") 200 addDumpTest(pv5, "&"+v5t+"("+v5s+")\n") 201 addDumpTest(&pv5, "&&"+v5t+"("+v5s+")\n") 202 addDumpTest(nv5, "(*"+v5t+")(nil)\n") 203 } 204 205 func addBoolDumpTests() { 206 // Boolean true. 207 v := bool(true) 208 nv := (*bool)(nil) 209 pv := &v 210 vt := "bool" 211 vs := "true" 212 addDumpTest(v, vt+"("+vs+")\n") 213 addDumpTest(pv, "&"+vt+"("+vs+")\n") 214 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 215 addDumpTest(nv, "(*"+vt+")(nil)\n") 216 217 // Boolean false. 218 v2 := bool(false) 219 pv2 := &v2 220 v2t := "bool" 221 v2s := "false" 222 addDumpTest(v2, v2t+"("+v2s+")\n") 223 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 224 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 225 } 226 227 func addFloatDumpTests() { 228 // Standard float32. 229 v := float32(3.1415) 230 nv := (*float32)(nil) 231 pv := &v 232 vt := "float32" 233 vs := "3.1415" 234 addDumpTest(v, vt+"("+vs+")\n") 235 addDumpTest(pv, "&"+vt+"("+vs+")\n") 236 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 237 addDumpTest(nv, "(*"+vt+")(nil)\n") 238 239 // Standard float64. 240 v2 := float64(3.1415926) 241 nv2 := (*float64)(nil) 242 pv2 := &v2 243 v2t := "float64" 244 v2s := "3.1415926" 245 addDumpTest(v2, v2t+"("+v2s+")\n") 246 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 247 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 248 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 249 250 // Standard float32 - integral value. 251 v3 := float32(3) 252 nv3 := (*float32)(nil) 253 pv3 := &v3 254 v3t := "float32" 255 v3s := "3" 256 addDumpTest(v3, v3t+"("+v3s+")\n") 257 addDumpTest(pv3, "&"+v3t+"("+v3s+")\n") 258 addDumpTest(&pv3, "&&"+v3t+"("+v3s+")\n") 259 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 260 261 // Standard float64 - integral value. 262 v4 := float64(3) 263 nv4 := (*float64)(nil) 264 pv4 := &v4 265 v4t := "float64" 266 v4s := "3" 267 addDumpTest(v4, v4t+"("+v4s+")\n") 268 addDumpTest(pv4, "&"+v4t+"("+v4s+")\n") 269 addDumpTest(&pv4, "&&"+v4t+"("+v4s+")\n") 270 addDumpTest(nv4, "(*"+v4t+")(nil)\n") 271 } 272 273 func addComplexDumpTests() { 274 // Standard complex64. 275 v := complex(float32(6), -2) 276 nv := (*complex64)(nil) 277 pv := &v 278 vt := "complex64" 279 vs := "6-2i" 280 addDumpTest(v, vt+"("+vs+")\n") 281 addDumpTest(pv, "&"+vt+"("+vs+")\n") 282 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 283 addDumpTest(nv, "(*"+vt+")(nil)\n") 284 285 // Standard complex128. 286 v2 := complex(float64(-6), 2) 287 nv2 := (*complex128)(nil) 288 pv2 := &v2 289 v2t := "complex128" 290 v2s := "-6+2i" 291 addDumpTest(v2, v2t+"("+v2s+")\n") 292 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 293 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 294 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 295 } 296 297 func addArrayDumpTests() { 298 // Array containing standard ints. 299 v := [3]int{1, 2, 3} 300 nv := (*[3]int)(nil) 301 pv := &v 302 vt := "int" 303 vs := "{\n " + vt + "(1),\n " + vt + "(2),\n " + vt + "(3),\n}" 304 addDumpTest(v, "[3]"+vt+vs+"\n") 305 addDumpTest(pv, "&[3]"+vt+vs+"\n") 306 addDumpTest(&pv, "&&[3]"+vt+vs+"\n") 307 addDumpTest(nv, "(*[3]"+vt+")(nil)\n") 308 309 // Array containing type with custom formatter on pointer receiver only. 310 v2i0 := pstringer("1") 311 v2i1 := pstringer("2") 312 v2i2 := pstringer("3") 313 v2 := [3]pstringer{v2i0, v2i1, v2i2} 314 nv2 := (*[3]pstringer)(nil) 315 pv2 := &v2 316 v2t := "utter_test.pstringer" 317 v2s := "{\n " + v2t + "(\"1\"),\n " + v2t + "(\"2\"),\n " + v2t + "(\"3\"),\n}" 318 addDumpTest(v2, "[3]"+v2t+v2s+"\n") 319 addDumpTest(pv2, "&[3]"+v2t+v2s+"\n") 320 addDumpTest(&pv2, "&&[3]"+v2t+v2s+"\n") 321 addDumpTest(nv2, "(*[3]"+v2t+")(nil)\n") 322 323 // Array containing interfaces. 324 v3i0 := "one" 325 v3 := [3]interface{}{v3i0, int(2), uint(3)} 326 nv3 := (*[3]interface{})(nil) 327 pv3 := &v3 328 v3t := "[3]interface{}" 329 v3t2 := "string" 330 v3t3 := "int" 331 v3t4 := "uint" 332 v3s := "{\n " + v3t2 + "(\"one\"),\n " + v3t3 + "(2),\n " + v3t4 + "(0x3),\n}" 333 addDumpTest(v3, v3t+v3s+"\n") 334 addDumpTest(pv3, "&"+v3t+v3s+"\n") 335 addDumpTest(&pv3, "&&"+v3t+v3s+"\n") 336 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 337 338 // Array containing bytes. 339 v4 := [34]byte{ 340 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 341 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 342 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 343 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 344 0x31, 0x32, 345 } 346 nv4 := (*[34]byte)(nil) 347 pv4 := &v4 348 v4t := "[34]uint8" 349 v4s := "{\n" + 350 " 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, // |............... |\n" + 351 " 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, // |!\"#$%&'()*+,-./0|\n" + 352 " 0x31, 0x32, /* */ // |12|\n}" 353 addDumpTest(v4, v4t+v4s+"\n") 354 addDumpTest(pv4, "&"+v4t+v4s+"\n") 355 addDumpTest(&pv4, "&&"+v4t+v4s+"\n") 356 addDumpTest(nv4, "(*"+v4t+")(nil)\n") 357 } 358 359 func addSliceDumpTests() { 360 // Slice containing standard float32 values. 361 v := []float32{3.14, 6.28, 12.56} 362 nv := (*[]float32)(nil) 363 pv := &v 364 vt := "float32" 365 vs := "{\n " + vt + "(3.14),\n " + vt + "(6.28),\n " + vt + "(12.56),\n}" 366 addDumpTest(v, "[]"+vt+vs+"\n") 367 addDumpTest(pv, "&[]"+vt+vs+"\n") 368 addDumpTest(&pv, "&&[]"+vt+vs+"\n") 369 addDumpTest(nv, "(*[]"+vt+")(nil)\n") 370 371 // Slice containing type with custom formatter on pointer receiver only. 372 v2i0 := pstringer("1") 373 v2i1 := pstringer("2") 374 v2i2 := pstringer("3") 375 v2 := []pstringer{v2i0, v2i1, v2i2} 376 nv2 := (*[]pstringer)(nil) 377 pv2 := &v2 378 v2t := "utter_test.pstringer" 379 v2s := "{\n " + v2t + "(\"1\"),\n " + v2t + "(\"2\"),\n " + v2t + "(\"3\"),\n}" 380 addDumpTest(v2, "[]"+v2t+v2s+"\n") 381 addDumpTest(pv2, "&[]"+v2t+v2s+"\n") 382 addDumpTest(&pv2, "&&[]"+v2t+v2s+"\n") 383 addDumpTest(nv2, "(*[]"+v2t+")(nil)\n") 384 385 // Slice containing interfaces. 386 v3i0 := "one" 387 v3 := []interface{}{v3i0, int(2), uint(3), nil} 388 nv3 := (*[]interface{})(nil) 389 pv3 := &v3 390 v3t := "[]interface{}" 391 v3t2 := "string" 392 v3t3 := "int" 393 v3t4 := "uint" 394 v3t5 := "interface{}" 395 v3s := "{\n " + v3t2 + "(\"one\"),\n " + v3t3 + "(2),\n " + v3t4 + "(0x3),\n " + v3t5 + "(nil),\n}" 396 addDumpTest(v3, v3t+v3s+"\n") 397 addDumpTest(pv3, "&"+v3t+v3s+"\n") 398 addDumpTest(&pv3, "&&"+v3t+v3s+"\n") 399 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 400 401 // Slice containing bytes. 402 v4 := []byte{ 403 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 404 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 405 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 406 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 407 0x31, 0x32, 408 } 409 nv4 := (*[]byte)(nil) 410 pv4 := &v4 411 v4t := "[]uint8" 412 v4s := "{\n" + 413 " 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, // |............... |\n" + 414 " 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, // |!\"#$%&'()*+,-./0|\n" + 415 " 0x31, 0x32, /* */ // |12|\n}" 416 addDumpTest(v4, v4t+v4s+"\n") 417 addDumpTest(pv4, "&"+v4t+v4s+"\n") 418 addDumpTest(&pv4, "&&"+v4t+v4s+"\n") 419 addDumpTest(nv4, "(*"+v4t+")(nil)\n") 420 421 // Nil slice. 422 v5 := []int(nil) 423 nv5 := (*[]int)(nil) 424 pv5 := &v5 425 v5t := "[]int" 426 v5s := "nil" 427 addDumpTest(v5, v5t+"("+v5s+")\n") 428 addDumpTest(pv5, "&"+v5t+"("+v5s+")\n") 429 addDumpTest(&pv5, "&&"+v5t+"("+v5s+")\n") 430 addDumpTest(nv5, "(*"+v5t+")(nil)\n") 431 } 432 433 func addStringDumpTests() { 434 // Standard string. 435 v := "test" 436 nv := (*string)(nil) 437 pv := &v 438 vt := "string" 439 vs := "\"test\"" 440 addDumpTest(v, vt+"("+vs+")\n") 441 addDumpTest(pv, "&"+vt+"("+vs+")\n") 442 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 443 addDumpTest(nv, "(*"+vt+")(nil)\n") 444 } 445 446 func addInterfaceDumpTests() { 447 // Nil interface. 448 var v interface{} 449 nv := (*interface{})(nil) 450 pv := &v 451 vt := "interface{}" 452 vs := "(nil)" 453 addDumpTest(v, "interface{}"+vs+"\n") 454 addDumpTest(pv, "&"+vt+vs+"\n") 455 addDumpTest(&pv, "&&"+vt+vs+"\n") 456 addDumpTest(nv, "(*"+vt+")"+vs+"\n") 457 458 // Sub-interface. 459 v2 := interface{}(uint16(65535)) 460 pv2 := &v2 461 v2t := "uint16" 462 v2s := "0xffff" 463 addDumpTest(v2, v2t+"("+v2s+")\n") 464 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 465 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 466 } 467 468 func addMapDumpTests() { 469 // Map with string keys and int vals. 470 k := "one" 471 kk := "two" 472 m := map[string]int{k: 1, kk: 2} 473 nilMap := map[string]int(nil) 474 nm := (*map[string]int)(nil) 475 pm := &m 476 mt := "map[string]int" 477 mt1 := "string" 478 mt2 := "int" 479 ms := "{\n " + mt1 + "(\"one\"): " + mt2 + "(1),\n " + mt1 + "(\"two\"): " + mt2 + "(2),\n}" 480 ms2 := "{\n " + mt1 + "(\"two\"): " + mt2 + "(2),\n " + mt1 + "(\"one\"): " + mt2 + "(1),\n}" 481 addDumpTest(m, mt+ms+"\n", mt+ms2+"\n") 482 addDumpTest(pm, "&"+mt+ms+"\n", "&"+mt+ms2+"\n") 483 addDumpTest(&pm, "&&"+mt+ms+"\n", "&&"+mt+ms2+"\n") 484 addDumpTest(nm, "(*"+mt+")(nil)\n") 485 addDumpTest(nilMap, mt+"(nil)\n") 486 487 // Map with custom formatter type on pointer receiver only keys and vals. 488 k2 := pstringer("one") 489 v2 := pstringer("1") 490 m2 := map[pstringer]pstringer{k2: v2} 491 nilMap2 := map[pstringer]pstringer(nil) 492 nm2 := (*map[pstringer]pstringer)(nil) 493 pm2 := &m2 494 m2t := "map[utter_test.pstringer]utter_test.pstringer" 495 m2t1 := "utter_test.pstringer" 496 m2t2 := "utter_test.pstringer" 497 m2s := "{\n " + m2t1 + "(\"one\"): " + m2t2 + "(\"1\"),\n}" 498 addDumpTest(m2, m2t+m2s+"\n") 499 addDumpTest(pm2, "&"+m2t+m2s+"\n") 500 addDumpTest(&pm2, "&&"+m2t+m2s+"\n") 501 addDumpTest(nm2, "(*"+m2t+")(nil)\n") 502 addDumpTest(nilMap2, m2t+"(nil)\n") 503 504 // Map with interface keys and values. 505 k3 := "one" 506 m3 := map[interface{}]interface{}{k3: 1} 507 nilMap3 := map[interface{}]interface{}(nil) 508 nm3 := (*map[interface{}]interface{})(nil) 509 pm3 := &m3 510 m3t := "map[interface{}]interface{}" 511 m3t1 := "string" 512 m3t2 := "int" 513 m3s := "{\n " + m3t1 + "(\"one\"): " + m3t2 + "(1),\n}" 514 addDumpTest(m3, m3t+m3s+"\n") 515 addDumpTest(pm3, "&"+m3t+m3s+"\n") 516 addDumpTest(&pm3, "&&"+m3t+m3s+"\n") 517 addDumpTest(nm3, "(*"+m3t+")(nil)\n") 518 addDumpTest(nilMap3, m3t+"(nil)\n") 519 520 // Map with nil interface value. 521 k4 := "nil" 522 m4 := map[string]interface{}{k4: nil} 523 nilMap4 := map[string]interface{}(nil) 524 nm4 := (*map[string]interface{})(nil) 525 pm4 := &m4 526 m4t := "map[string]interface{}" 527 m4t1 := "string" 528 m4t2 := "interface{}" 529 m4s := "{\n " + m4t1 + "(\"nil\"): " + m4t2 + "(nil),\n}" 530 addDumpTest(m4, m4t+m4s+"\n") 531 addDumpTest(pm4, "&"+m4t+m4s+"\n") 532 addDumpTest(&pm4, "&&"+m4t+m4s+"\n") 533 addDumpTest(nm4, "(*"+m4t+")(nil)\n") 534 addDumpTest(nilMap4, m4t+"(nil)\n") 535 } 536 537 func addStructDumpTests() { 538 // Struct with primitives. 539 type s1 struct { 540 a int8 541 b uint8 542 } 543 v := s1{127, 255} 544 nv := (*s1)(nil) 545 pv := &v 546 vt := "utter_test.s1" 547 vt2 := "int8" 548 vt3 := "uint8" 549 vs := "{\n a: " + vt2 + "(127),\n b: " + vt3 + "(0xff),\n}" 550 addDumpTest(v, vt+vs+"\n") 551 addDumpTest(pv, "&"+vt+vs+"\n") 552 addDumpTest(&pv, "&&"+vt+vs+"\n") 553 addDumpTest(nv, "(*"+vt+")(nil)\n") 554 555 // Struct that contains another struct. 556 type s2 struct { 557 s1 s1 558 b bool 559 } 560 v2 := s2{s1{127, 255}, true} 561 nv2 := (*s2)(nil) 562 pv2 := &v2 563 v2t := "utter_test.s2" 564 v2t2 := "utter_test.s1" 565 v2t3 := "int8" 566 v2t4 := "uint8" 567 v2t5 := "bool" 568 v2s := "{\n s1: " + v2t2 + "{\n a: " + v2t3 + "(127),\n b: " + v2t4 + "(0xff),\n },\n b: " + v2t5 + "(true),\n}" 569 addDumpTest(v2, v2t+v2s+"\n") 570 addDumpTest(pv2, "&"+v2t+v2s+"\n") 571 addDumpTest(&pv2, "&&"+v2t+v2s+"\n") 572 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 573 574 // Struct that contains custom type with Stringer pointer interface via both 575 // exported and unexported fields. 576 type s3 struct { 577 s pstringer 578 S pstringer 579 } 580 v3 := s3{"test", "test2"} 581 nv3 := (*s3)(nil) 582 pv3 := &v3 583 v3t := "utter_test.s3" 584 v3t2 := "utter_test.pstringer" 585 v3s := "{\n s: " + v3t2 + "(\"test\"),\n S: " + v3t2 + "(\"test2\"),\n}" 586 addDumpTest(v3, v3t+v3s+"\n") 587 addDumpTest(pv3, "&"+v3t+v3s+"\n") 588 addDumpTest(&pv3, "&&"+v3t+v3s+"\n") 589 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 590 591 // Struct that contains embedded struct and field to same struct. 592 e := embed{"embedstr"} 593 v4 := embedwrap{embed: &e, e: &e} 594 nv4 := (*embedwrap)(nil) 595 pv4 := &v4 596 v4t := "utter_test.embedwrap" 597 v4t2 := "utter_test.embed" 598 v4t3 := "string" 599 v4s := "{\n embed: &" + v4t2 + "{\n a: " + v4t3 + "(\"embedstr\"),\n },\n e: (*" + v4t2 + ")(<already shown>),\n}" 600 addDumpTest(v4, v4t+v4s+"\n") 601 addDumpTest(pv4, "&"+v4t+v4s+"\n") 602 addDumpTest(&pv4, "&&"+v4t+v4s+"\n") 603 addDumpTest(nv4, "(*"+v4t+")(nil)\n") 604 605 // Struct that has fields that share a value in pointer that is not a cycle. 606 type ss5 struct{ s string } 607 type s5 struct { 608 p1 *ss5 609 p2 *ss5 610 } 611 ip1 := &ss5{"shared"} 612 v5 := s5{ip1, ip1} 613 v5t := "utter_test.s5" 614 v5s := "utter_test.ss5" 615 addDumpTest(v5, v5t+"{\n p1: &"+v5s+"{\n s: string(\"shared\"),\n },\n p2: (*"+v5s+")(<already shown>),\n}\n") 616 617 // Struct that has fields that share a value in pointer chain that is not a cycle. 618 type ss6 struct{ s string } 619 type s6 struct { 620 p1 **ss6 621 p2 **ss6 622 } 623 ipp1 := &ss6{"shared"} 624 v6 := s6{&ipp1, &ipp1} 625 v6t := "utter_test.s6" 626 v6s := "utter_test.ss6" 627 addDumpTest(v6, v6t+"{\n p1: &&"+v6s+"{\n s: string(\"shared\"),\n },\n p2: (**"+v6s+")(<already shown>),\n}\n") 628 } 629 630 func addUintptrDumpTests() { 631 // Null pointer. 632 v := uintptr(0) 633 pv := &v 634 vt := "uintptr" 635 vs := "0" 636 addDumpTest(v, vt+"("+vs+")\n") 637 addDumpTest(pv, "&"+vt+"("+vs+")\n") 638 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 639 640 // Address of real variable. 641 i := 1 642 v2 := uintptr(unsafe.Pointer(&i)) 643 nv2 := (*uintptr)(nil) 644 pv2 := &v2 645 v2t := "uintptr" 646 v2s := fmt.Sprintf("(%p)", &i) 647 addDumpTest(v2, v2t+v2s+"\n") 648 addDumpTest(pv2, "&"+v2t+v2s+"\n") 649 addDumpTest(&pv2, "&&"+v2t+v2s+"\n") 650 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 651 } 652 653 func addUnsafePointerDumpTests() { 654 // Null pointer. 655 v := unsafe.Pointer(uintptr(0)) 656 nv := (*unsafe.Pointer)(nil) 657 pv := &v 658 vt := "unsafe.Pointer" 659 vs := "nil" 660 addDumpTest(v, vt+"("+vs+")\n") 661 addDumpTest(pv, "&"+vt+"("+vs+")\n") 662 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 663 addDumpTest(nv, "(*"+vt+")(nil)\n") 664 665 // Address of real variable. 666 i := 1 667 v2 := unsafe.Pointer(&i) 668 pv2 := &v2 669 v2t := "unsafe.Pointer" 670 v2s := fmt.Sprintf("%p", &i) 671 addDumpTest(v2, v2t+"("+v2s+")\n") 672 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 673 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 674 addDumpTest(nv, "(*"+vt+")(nil)\n") 675 } 676 677 func addChanDumpTests() { 678 // Nil channel. 679 var v chan int 680 pv := &v 681 nv := (*chan int)(nil) 682 vt := "chan int" 683 vs := "nil" 684 addDumpTest(v, vt+"("+vs+")\n") 685 addDumpTest(pv, "&"+vt+"("+vs+")\n") 686 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 687 addDumpTest(nv, "(*"+vt+")(nil)\n") 688 689 // Real channel. 690 v2 := make(chan int) 691 pv2 := &v2 692 v2t := "chan int" 693 v2s := fmt.Sprintf("%p", v2) 694 addDumpTest(v2, v2t+"("+v2s+")\n") 695 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 696 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 697 698 // Real buffered channel, empty. 699 v3 := make(chan int, 1) 700 pv3 := &v3 701 v3t := "(chan int, 1)" 702 v3s := fmt.Sprintf("%p", v3) 703 addDumpTest(v3, v3t+"("+v3s+")\n") 704 addDumpTest(pv3, "&"+v3t+"("+v3s+")\n") 705 addDumpTest(&pv3, "&&"+v3t+"("+v3s+")\n") 706 707 // Real buffered channel with one element. 708 v4 := func() chan int { c := make(chan int, 2); c <- 1; return c }() 709 pv4 := &v4 710 v4t := "(chan int, 2 /* 1 element */)" 711 v4s := fmt.Sprintf("%p", v4) 712 addDumpTest(v4, v4t+"("+v4s+")\n") 713 addDumpTest(pv4, "&"+v4t+"("+v4s+")\n") 714 addDumpTest(&pv4, "&&"+v4t+"("+v4s+")\n") 715 716 // Real buffered channel with two elements. 717 v5 := func() chan int { c := make(chan int, 2); c <- 1; c <- 1; return c }() 718 pv5 := &v5 719 v5t := "(chan int, 2 /* 2 elements */)" 720 v5s := fmt.Sprintf("%p", v5) 721 addDumpTest(v5, v5t+"("+v5s+")\n") 722 addDumpTest(pv5, "&"+v5t+"("+v5s+")\n") 723 addDumpTest(&pv5, "&&"+v5t+"("+v5s+")\n") 724 725 // Real send only channel. 726 v6 := make(chan<- int) 727 pv6 := &v6 728 v6t := "chan<- int" 729 v6s := fmt.Sprintf("%p", v6) 730 addDumpTest(v6, v6t+"("+v6s+")\n") 731 addDumpTest(pv6, "&"+v6t+"("+v6s+")\n") 732 addDumpTest(&pv6, "&&"+v6t+"("+v6s+")\n") 733 734 // Real receive only channel. 735 v7 := make(<-chan int) 736 pv7 := &v7 737 v7t := "<-chan int" 738 v7s := fmt.Sprintf("%p", v7) 739 addDumpTest(v7, v7t+"("+v7s+")\n") 740 addDumpTest(pv7, "&"+v7t+"("+v7s+")\n") 741 addDumpTest(&pv7, "&&"+v7t+"("+v7s+")\n") 742 } 743 744 func addFuncDumpTests() { 745 // Function with no params and no returns. 746 v := addIntDumpTests 747 nv := (*func())(nil) 748 pv := &v 749 vt := "func()" 750 vs := fmt.Sprintf("%p", v) 751 addDumpTest(v, vt+"("+vs+")\n") 752 addDumpTest(pv, "&"+vt+"("+vs+")\n") 753 addDumpTest(&pv, "&&"+vt+"("+vs+")\n") 754 addDumpTest(nv, "(*"+vt+")(nil)\n") 755 756 // Function with param and no returns. 757 v2 := TestDump 758 nv2 := (*func(*testing.T))(nil) 759 pv2 := &v2 760 v2t := "func(*testing.T)" 761 v2s := fmt.Sprintf("%p", v2) 762 addDumpTest(v2, v2t+"("+v2s+")\n") 763 addDumpTest(pv2, "&"+v2t+"("+v2s+")\n") 764 addDumpTest(&pv2, "&&"+v2t+"("+v2s+")\n") 765 addDumpTest(nv2, "(*"+v2t+")(nil)\n") 766 767 // Function with multiple params and multiple returns. 768 var v3 = func(i int, s string) (b bool, err error) { 769 return true, nil 770 } 771 nv3 := (*func(int, string) (bool, error))(nil) 772 pv3 := &v3 773 v3t := "func(int, string) (bool, error)" 774 v3s := fmt.Sprintf("%p", v3) 775 addDumpTest(v3, v3t+"("+v3s+")\n") 776 addDumpTest(pv3, "&"+v3t+"("+v3s+")\n") 777 addDumpTest(&pv3, "&&"+v3t+"("+v3s+")\n") 778 addDumpTest(nv3, "(*"+v3t+")(nil)\n") 779 } 780 781 func addCircularDumpTests() { 782 // Struct that is circular through self referencing. 783 type circular struct { 784 c *circular 785 } 786 v := circular{nil} 787 v.c = &v 788 pv := &v 789 vt := "utter_test.circular" 790 vs := "{\n c: &" + vt + "{\n c: (*" + vt + ")(<already shown>),\n },\n}" 791 vs2 := "{\n c: (*" + vt + ")(<already shown>),\n}" 792 addDumpTest(v, vt+vs+"\n") 793 addDumpTest(pv, "&"+vt+vs2+"\n") 794 addDumpTest(&pv, "&&"+vt+vs2+"\n") 795 796 // Structs that are circular through cross referencing. 797 v2 := xref1{nil} 798 ts2 := xref2{&v2} 799 v2.ps2 = &ts2 800 pv2 := &v2 801 v2t := "utter_test.xref1" 802 v2t2 := "utter_test.xref2" 803 v2s := "{\n ps2: &" + v2t2 + 804 "{\n ps1: &" + v2t + 805 "{\n ps2: (*" + v2t2 + ")(<already shown>),\n },\n },\n}" 806 v2s2 := "{\n ps2: &" + v2t2 + "{\n ps1: (*" + v2t + ")(<already shown>),\n },\n}" 807 addDumpTest(v2, v2t+v2s+"\n") 808 addDumpTest(pv2, "&"+v2t+v2s2+"\n") 809 addDumpTest(&pv2, "&&"+v2t+v2s2+"\n") 810 811 // Structs that are indirectly circular. 812 v3 := indirCir1{nil} 813 tic2 := indirCir2{nil} 814 tic3 := indirCir3{&v3} 815 tic2.ps3 = &tic3 816 v3.ps2 = &tic2 817 pv3 := &v3 818 v3t := "utter_test.indirCir1" 819 v3t2 := "utter_test.indirCir2" 820 v3t3 := "utter_test.indirCir3" 821 v3s := "{\n ps2: &" + v3t2 + 822 "{\n ps3: &" + v3t3 + 823 "{\n ps1: &" + v3t + 824 "{\n ps2: (*" + v3t2 + ")(<already shown>),\n },\n },\n },\n}" 825 v3s2 := "{\n ps2: &" + v3t2 + 826 "{\n ps3: &" + v3t3 + 827 "{\n ps1: (*" + v3t + ")(<already shown>),\n },\n },\n}" 828 addDumpTest(v3, v3t+v3s+"\n") 829 addDumpTest(pv3, "&"+v3t+v3s2+"\n") 830 addDumpTest(&pv3, "&&"+v3t+v3s2+"\n") 831 } 832 833 // TestDump executes all of the tests described by dumpTests. 834 func TestDump(t *testing.T) { 835 // Setup tests. 836 addIntDumpTests() 837 addUintDumpTests() 838 addBoolDumpTests() 839 addFloatDumpTests() 840 addComplexDumpTests() 841 addArrayDumpTests() 842 addSliceDumpTests() 843 addStringDumpTests() 844 addInterfaceDumpTests() 845 addMapDumpTests() 846 addStructDumpTests() 847 addUintptrDumpTests() 848 addUnsafePointerDumpTests() 849 addChanDumpTests() 850 addFuncDumpTests() 851 addCircularDumpTests() 852 addCgoDumpTests() 853 854 t.Logf("Running %d tests", len(dumpTests)) 855 for i, test := range dumpTests { 856 buf := new(bytes.Buffer) 857 utter.Fdump(buf, test.in) 858 s := buf.String() 859 if testFailed(s, test.wants) { 860 t.Errorf("Dump #%d\n got: %q\n %s", i, s, stringizeWants(test.wants)) 861 continue 862 } 863 } 864 } 865 866 func TestDumpOmitZero(t *testing.T) { 867 cfg := utter.ConfigState{OmitZero: true, SortKeys: true} 868 type sub struct { 869 a, b int 870 } 871 type st struct { 872 i int 873 s string 874 v []int 875 m map[int]int 876 a [3]int 877 p *int 878 st sub 879 } 880 tests := []struct { 881 val st 882 expected string 883 }{ 884 { 885 val: st{}, 886 expected: "utter_test.st{\n}\n", 887 }, 888 { 889 val: st{i: 1}, 890 expected: "utter_test.st{\ni: int(1),\n}\n", 891 }, 892 { 893 val: st{s: "string"}, 894 expected: "utter_test.st{\ns: string(\"string\"),\n}\n", 895 }, 896 { 897 val: st{v: []int{1, 2}}, 898 expected: "utter_test.st{\nv: []int{int(1), int(2)},\n}\n", 899 }, 900 { 901 val: st{m: map[int]int{1: -1, 2: -2}}, 902 expected: "utter_test.st{\nm: map[int]int{\nint(1): int(-1),\nint(2): int(-2),\n},\n}\n", 903 }, 904 { 905 val: st{a: [3]int{1, 2, 3}}, 906 expected: "utter_test.st{\na: [3]int{int(1), int(2), int(3)},\n}\n", 907 }, 908 { 909 val: st{p: new(int)}, 910 expected: "utter_test.st{\np: &int(0),\n}\n", 911 }, 912 { 913 val: st{st: sub{a: 1, b: 2}}, 914 expected: "utter_test.st{\nst: utter_test.sub{\na: int(1),\nb: int(2),\n},\n}\n", 915 }, 916 { 917 val: st{st: sub{a: 0, b: 2}}, 918 expected: "utter_test.st{\nst: utter_test.sub{\nb: int(2),\n},\n}\n", 919 }, 920 } 921 for i, test := range tests { 922 s := cfg.Sdump(test.val) 923 if s != test.expected { 924 t.Errorf("Dump #%d\n got: %q\n %q", i, s, test.expected) 925 } 926 } 927 } 928 929 func TestDumpSortedKeys(t *testing.T) { 930 cfg := utter.ConfigState{SortKeys: true} 931 tests := []struct { 932 m interface{} 933 expected string 934 }{ 935 { 936 m: map[int]string{1: "1", 3: "3", 2: "2"}, 937 expected: `map[int]string{ 938 int(1): string("1"), 939 int(2): string("2"), 940 int(3): string("3"), 941 } 942 `, 943 }, 944 { 945 m: map[float64]int{math.NaN(): 1, math.NaN(): 2, 0: 0, 1: 3}, 946 expected: `map[float64]int{ 947 float64(NaN): int(1), 948 float64(NaN): int(2), 949 float64(0): int(0), 950 float64(1): int(3), 951 } 952 `, 953 }, 954 } 955 956 for _, test := range tests { 957 got := cfg.Sdump(test.m) 958 959 if got != test.expected { 960 t.Errorf("Sorted keys mismatch:\n %v %v", got, test.expected) 961 } 962 } 963 } 964 965 type limitedWriter struct { 966 limit int 967 buf bytes.Buffer 968 } 969 970 func newLimitedWriter(limit int) *limitedWriter { 971 return &limitedWriter{limit: limit} 972 } 973 974 func (w *limitedWriter) Write(b []byte) (int, error) { 975 n, err := w.buf.Write(b) 976 if err != nil { 977 return n, err 978 } 979 if len := w.buf.Len(); len > w.limit { 980 panic(fmt.Sprintf("buffer longer than limit: %d > %d:\n%s", 981 len, w.limit, w.buf.Bytes())) 982 } 983 return n, nil 984 } 985 986 var sliceElementCycles = []struct { 987 v interface{} 988 want string 989 }{ 990 { 991 v: func() interface{} { 992 r := make([]interface{}, 1) 993 r[0] = r 994 return r 995 }(), 996 // We cannot detect the cycle until at least once around 997 // the cycle as the initial v seen by utter.Dump was not 998 // addressable. 999 want: `[]interface{}{ 1000 []interface{}(<already shown>), 1001 } 1002 `, 1003 }, 1004 { 1005 v: func() interface{} { 1006 r := make([]interface{}, 1) 1007 r[0] = r 1008 return &r 1009 }(), 1010 want: `&[]interface{}{ 1011 []interface{}(<already shown>), 1012 } 1013 `, 1014 }, 1015 { 1016 v: func() interface{} { 1017 r := make([]interface{}, 1) 1018 r[0] = &r 1019 return &r 1020 }(), 1021 want: `&[]interface{}{ 1022 (*[]interface{})(<already shown>), 1023 } 1024 `, 1025 }, 1026 { 1027 v: func() interface{} { 1028 type recurrence struct { 1029 v []interface{} 1030 } 1031 r := recurrence{make([]interface{}, 1)} 1032 r.v[0] = r 1033 return r 1034 }(), 1035 // We cannot detect the cycle until at least once around 1036 // the cycle as the initial v seen by utter.Dump was not 1037 // addressable. 1038 want: `utter_test.recurrence{ 1039 v: []interface{}{ 1040 utter_test.recurrence{ 1041 v: []interface{}(<already shown>), 1042 }, 1043 }, 1044 } 1045 `, 1046 }, 1047 { 1048 v: func() interface{} { 1049 type recurrence struct { 1050 v []interface{} 1051 } 1052 r := recurrence{make([]interface{}, 1)} 1053 r.v[0] = r 1054 return &r 1055 }(), 1056 want: `&utter_test.recurrence{ 1057 v: []interface{}{ 1058 utter_test.recurrence{ 1059 v: []interface{}(<already shown>), 1060 }, 1061 }, 1062 } 1063 `, 1064 }, 1065 { 1066 v: func() interface{} { 1067 type container struct { 1068 v []int 1069 } 1070 return &container{[]int{1}} 1071 }(), 1072 want: `&utter_test.container{ 1073 v: []int{ 1074 int(1), 1075 }, 1076 } 1077 `, 1078 }, 1079 } 1080 1081 // https://github.com/kortschak/utter/issues/5 1082 func TestIssue5Slices(t *testing.T) { 1083 for _, test := range sliceElementCycles { 1084 w := newLimitedWriter(512) 1085 func() { 1086 defer func() { 1087 r := recover() 1088 if r != nil { 1089 t.Errorf("limited writer panicked: probable cycle: %v", r) 1090 } 1091 }() 1092 utter.Fdump(w, test.v) 1093 got := w.buf.String() 1094 if got != test.want { 1095 t.Errorf("unexpected value:\ngot:\n%swant:\n%s", got, test.want) 1096 } 1097 }() 1098 } 1099 } 1100 1101 var mapElementCycles = []struct { 1102 v interface{} 1103 want string 1104 }{ 1105 { 1106 v: func() interface{} { 1107 r := make(map[int]interface{}, 1) 1108 r[0] = r 1109 return r 1110 }(), 1111 want: `map[int]interface{}{ 1112 int(0): map[int]interface{}(<already shown>), 1113 } 1114 `, 1115 }, 1116 { 1117 v: func() interface{} { 1118 r := make(map[int]interface{}, 1) 1119 r[0] = r 1120 return &r 1121 }(), 1122 want: `&map[int]interface{}{ 1123 int(0): map[int]interface{}(<already shown>), 1124 } 1125 `, 1126 }, 1127 { 1128 v: func() interface{} { 1129 r := make(map[int]interface{}, 1) 1130 r[0] = &r 1131 return &r 1132 }(), 1133 want: `&map[int]interface{}{ 1134 int(0): (*map[int]interface{})(<already shown>), 1135 } 1136 `, 1137 }, 1138 { 1139 v: func() interface{} { 1140 type recurrence struct { 1141 v map[int]interface{} 1142 } 1143 r := recurrence{make(map[int]interface{}, 1)} 1144 r.v[0] = r 1145 return r 1146 }(), 1147 want: `utter_test.recurrence{ 1148 v: map[int]interface{}{ 1149 int(0): utter_test.recurrence{ 1150 v: map[int]interface{}(<already shown>), 1151 }, 1152 }, 1153 } 1154 `, 1155 }, 1156 { 1157 v: func() interface{} { 1158 type recurrence struct { 1159 v map[int]interface{} 1160 } 1161 r := recurrence{make(map[int]interface{}, 1)} 1162 r.v[0] = r 1163 return &r 1164 }(), 1165 want: `&utter_test.recurrence{ 1166 v: map[int]interface{}{ 1167 int(0): utter_test.recurrence{ 1168 v: map[int]interface{}(<already shown>), 1169 }, 1170 }, 1171 } 1172 `, 1173 }, 1174 // The following test is to confirm that the recursion detection 1175 // is not overly zealous by missing identifying the address of slices. 1176 // This is https://github.com/kortschak/utter/issues/12. 1177 { 1178 v: map[interface{}][]interface{}{ 1179 "outer": []interface{}{ 1180 map[interface{}]interface{}{ 1181 "inner": []interface{}{"value"}, 1182 }, 1183 }, 1184 }, 1185 want: `map[interface{}][]interface{}{ 1186 string("outer"): []interface{}{ 1187 map[interface{}]interface{}{ 1188 string("inner"): []interface{}{ 1189 string("value"), 1190 }, 1191 }, 1192 }, 1193 } 1194 `, 1195 }, 1196 } 1197 1198 // https://github.com/kortschak/utter/issues/5 1199 // https://github.com/kortschak/utter/issues/12 1200 func TestIssue5Maps(t *testing.T) { 1201 for _, test := range mapElementCycles { 1202 w := newLimitedWriter(512) 1203 func() { 1204 defer func() { 1205 r := recover() 1206 if r != nil { 1207 t.Errorf("limited writer panicked: probable cycle: %v", r) 1208 } 1209 }() 1210 utter.Fdump(w, test.v) 1211 got := w.buf.String() 1212 if got != test.want { 1213 t.Errorf("unexpected value:\ngot:\n%swant:\n%s", got, test.want) 1214 } 1215 }() 1216 } 1217 }