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  }