Bladeren bron

Dump non-zero len and cap for applicable types.

Closes #16.
Josh Rickmar 11 jaren geleden
bovenliggende
commit
3fdaf5cea8
8 gewijzigde bestanden met toevoegingen van 236 en 126 verwijderingen
  1. 2 0
      spew/common.go
  2. 3 3
      spew/doc.go
  3. 26 0
      spew/dump.go
  4. 148 82
      spew/dump_test.go
  5. 25 10
      spew/dumpcgo_test.go
  6. 9 9
      spew/example_test.go
  7. 4 4
      spew/spew_test.go
  8. 19 18
      spew/testdata/dumpcgo.go

+ 2 - 0
spew/common.go

@@ -142,6 +142,8 @@ var (
 	closeAngleBytes       = []byte(">")
 	openMapBytes          = []byte("map[")
 	closeMapBytes         = []byte("]")
+	lenEqualsBytes        = []byte("len=")
+	capEqualsBytes        = []byte("cap=")
 )
 
 // hexDigits is used to map a decimal value to a hex digit.

+ 3 - 3
spew/doc.go

@@ -128,14 +128,14 @@ shown here.
 	  flag: (main.Flag) flagTwo,
 	  data: (uintptr) <nil>
 	 }),
-	 ExportedField: (map[interface {}]interface {}) {
-	  (string) "one": (bool) true
+	 ExportedField: (map[interface {}]interface {}) (len=1) {
+	  (string) (len=3) "one": (bool) true
 	 }
 	}
 
 Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
 command as shown.
-	([]uint8) {
+	([]uint8) (len=32 cap=32) {
 	 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
 	 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
 	 00000020  31 32                                             |12|

+ 26 - 0
spew/dump.go

@@ -270,6 +270,32 @@ func (d *dumpState) dump(v reflect.Value) {
 	}
 	d.ignoreNextType = false
 
+	// Display length and capacity if the built-in len and cap functions
+	// work with the value's kind and the len/cap itself is non-zero.
+	valueLen, valueCap := 0, 0
+	switch v.Kind() {
+	case reflect.Array, reflect.Slice, reflect.Chan:
+		valueLen, valueCap = v.Len(), v.Cap()
+	case reflect.Map, reflect.String:
+		valueLen = v.Len()
+	}
+	if valueLen != 0 || valueCap != 0 {
+		d.w.Write(openParenBytes)
+		if valueLen != 0 {
+			d.w.Write(lenEqualsBytes)
+			printInt(d.w, int64(valueLen), 10)
+		}
+		if valueCap != 0 {
+			if valueLen != 0 {
+				d.w.Write(spaceBytes)
+			}
+			d.w.Write(capEqualsBytes)
+			printInt(d.w, int64(valueCap), 10)
+		}
+		d.w.Write(closeParenBytes)
+		d.w.Write(spaceBytes)
+	}
+
 	// Call Stringer/error interfaces if they exist and the handle methods flag
 	// is enabled
 	if !d.cs.DisableMethods {

+ 148 - 82
spew/dump_test.go

@@ -304,33 +304,50 @@ func addComplexDumpTests() {
 func addArrayDumpTests() {
 	// Array containing standard ints.
 	v := [3]int{1, 2, 3}
+	vLen := fmt.Sprintf("%d", len(v))
+	vCap := fmt.Sprintf("%d", cap(v))
 	nv := (*[3]int)(nil)
 	pv := &v
 	vAddr := fmt.Sprintf("%p", pv)
 	pvAddr := fmt.Sprintf("%p", &pv)
 	vt := "int"
-	vs := "{\n (" + vt + ") 1,\n (" + vt + ") 2,\n (" + vt + ") 3\n}"
+	vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
+		vt + ") 2,\n (" + vt + ") 3\n}"
 	addDumpTest(v, "([3]"+vt+") "+vs+"\n")
 	addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
 	addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
 	addDumpTest(nv, "(*[3]"+vt+")(<nil>)\n")
 
 	// Array containing type with custom formatter on pointer receiver only.
-	v2 := [3]pstringer{"1", "2", "3"}
+	v2i0 := pstringer("1")
+	v2i1 := pstringer("2")
+	v2i2 := pstringer("3")
+	v2 := [3]pstringer{v2i0, v2i1, v2i2}
+	v2i0Len := fmt.Sprintf("%d", len(v2i0))
+	v2i1Len := fmt.Sprintf("%d", len(v2i1))
+	v2i2Len := fmt.Sprintf("%d", len(v2i2))
+	v2Len := fmt.Sprintf("%d", len(v2))
+	v2Cap := fmt.Sprintf("%d", cap(v2))
 	nv2 := (*[3]pstringer)(nil)
 	pv2 := &v2
 	v2Addr := fmt.Sprintf("%p", pv2)
 	pv2Addr := fmt.Sprintf("%p", &pv2)
 	v2t := "spew_test.pstringer"
-	v2s := "{\n (" + v2t + ") stringer 1,\n (" + v2t + ") stringer 2,\n (" +
-		v2t + ") stringer 3\n}"
+	v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
+		v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
+		") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
+		"stringer 3\n}"
 	addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
 	addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2s+")\n")
 	addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
 	addDumpTest(nv2, "(*[3]"+v2t+")(<nil>)\n")
 
 	// Array containing interfaces.
-	v3 := [3]interface{}{"one", int(2), uint(3)}
+	v3i0 := "one"
+	v3 := [3]interface{}{v3i0, int(2), uint(3)}
+	v3i0Len := fmt.Sprintf("%d", len(v3i0))
+	v3Len := fmt.Sprintf("%d", len(v3))
+	v3Cap := fmt.Sprintf("%d", cap(v3))
 	nv3 := (*[3]interface{})(nil)
 	pv3 := &v3
 	v3Addr := fmt.Sprintf("%p", pv3)
@@ -339,8 +356,9 @@ func addArrayDumpTests() {
 	v3t2 := "string"
 	v3t3 := "int"
 	v3t4 := "uint"
-	v3s := "{\n (" + v3t2 + ") \"one\",\n (" + v3t3 + ") 2,\n (" + v3t4 +
-		") 3\n}"
+	v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+		"(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+		v3t4 + ") 3\n}"
 	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
 	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
 	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
@@ -354,12 +372,15 @@ func addArrayDumpTests() {
 		0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
 		0x31, 0x32,
 	}
+	v4Len := fmt.Sprintf("%d", len(v4))
+	v4Cap := fmt.Sprintf("%d", cap(v4))
 	nv4 := (*[34]byte)(nil)
 	pv4 := &v4
 	v4Addr := fmt.Sprintf("%p", pv4)
 	pv4Addr := fmt.Sprintf("%p", &pv4)
 	v4t := "[34]uint8"
-	v4s := "{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
+	v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+		"{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
 		"  |............... |\n" +
 		" 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30" +
 		"  |!\"#$%&'()*+,-./0|\n" +
@@ -374,33 +395,50 @@ func addArrayDumpTests() {
 func addSliceDumpTests() {
 	// Slice containing standard float32 values.
 	v := []float32{3.14, 6.28, 12.56}
+	vLen := fmt.Sprintf("%d", len(v))
+	vCap := fmt.Sprintf("%d", cap(v))
 	nv := (*[]float32)(nil)
 	pv := &v
 	vAddr := fmt.Sprintf("%p", pv)
 	pvAddr := fmt.Sprintf("%p", &pv)
 	vt := "float32"
-	vs := "{\n (" + vt + ") 3.14,\n (" + vt + ") 6.28,\n (" + vt + ") 12.56\n}"
+	vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
+		vt + ") 6.28,\n (" + vt + ") 12.56\n}"
 	addDumpTest(v, "([]"+vt+") "+vs+"\n")
 	addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
 	addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
 	addDumpTest(nv, "(*[]"+vt+")(<nil>)\n")
 
 	// Slice containing type with custom formatter on pointer receiver only.
-	v2 := []pstringer{"1", "2", "3"}
+	v2i0 := pstringer("1")
+	v2i1 := pstringer("2")
+	v2i2 := pstringer("3")
+	v2 := []pstringer{v2i0, v2i1, v2i2}
+	v2i0Len := fmt.Sprintf("%d", len(v2i0))
+	v2i1Len := fmt.Sprintf("%d", len(v2i1))
+	v2i2Len := fmt.Sprintf("%d", len(v2i2))
+	v2Len := fmt.Sprintf("%d", len(v2))
+	v2Cap := fmt.Sprintf("%d", cap(v2))
 	nv2 := (*[]pstringer)(nil)
 	pv2 := &v2
 	v2Addr := fmt.Sprintf("%p", pv2)
 	pv2Addr := fmt.Sprintf("%p", &pv2)
 	v2t := "spew_test.pstringer"
-	v2s := "{\n (" + v2t + ") stringer 1,\n (" + v2t + ") stringer 2,\n (" +
-		v2t + ") stringer 3\n}"
+	v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
+		v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
+		") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
+		"stringer 3\n}"
 	addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
 	addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
 	addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
 	addDumpTest(nv2, "(*[]"+v2t+")(<nil>)\n")
 
 	// Slice containing interfaces.
-	v3 := []interface{}{"one", int(2), uint(3), nil}
+	v3i0 := "one"
+	v3 := []interface{}{v3i0, int(2), uint(3), nil}
+	v3i0Len := fmt.Sprintf("%d", len(v3i0))
+	v3Len := fmt.Sprintf("%d", len(v3))
+	v3Cap := fmt.Sprintf("%d", cap(v3))
 	nv3 := (*[]interface{})(nil)
 	pv3 := &v3
 	v3Addr := fmt.Sprintf("%p", pv3)
@@ -410,8 +448,9 @@ func addSliceDumpTests() {
 	v3t3 := "int"
 	v3t4 := "uint"
 	v3t5 := "interface {}"
-	v3s := "{\n (" + v3t2 + ") \"one\",\n (" + v3t3 + ") 2,\n (" + v3t4 +
-		") 3,\n (" + v3t5 + ") <nil>\n}"
+	v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+		"(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+		v3t4 + ") 3,\n (" + v3t5 + ") <nil>\n}"
 	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
 	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
 	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
@@ -425,12 +464,15 @@ func addSliceDumpTests() {
 		0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
 		0x31, 0x32,
 	}
+	v4Len := fmt.Sprintf("%d", len(v4))
+	v4Cap := fmt.Sprintf("%d", cap(v4))
 	nv4 := (*[]byte)(nil)
 	pv4 := &v4
 	v4Addr := fmt.Sprintf("%p", pv4)
 	pv4Addr := fmt.Sprintf("%p", &pv4)
 	v4t := "[]uint8"
-	v4s := "{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
+	v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+		"{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
 		"  |............... |\n" +
 		" 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30" +
 		"  |!\"#$%&'()*+,-./0|\n" +
@@ -458,12 +500,13 @@ func addSliceDumpTests() {
 func addStringDumpTests() {
 	// Standard string.
 	v := "test"
+	vLen := fmt.Sprintf("%d", len(v))
 	nv := (*string)(nil)
 	pv := &v
 	vAddr := fmt.Sprintf("%p", pv)
 	pvAddr := fmt.Sprintf("%p", &pv)
 	vt := "string"
-	vs := "\"test\""
+	vs := "(len=" + vLen + ") \"test\""
 	addDumpTest(v, "("+vt+") "+vs+"\n")
 	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
 	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
@@ -498,69 +541,90 @@ func addInterfaceDumpTests() {
 
 func addMapDumpTests() {
 	// Map with string keys and int vals.
-	v := map[string]int{"one": 1, "two": 2}
-	nv := (*map[string]int)(nil)
-	pv := &v
-	vAddr := fmt.Sprintf("%p", pv)
-	pvAddr := fmt.Sprintf("%p", &pv)
-	vt := "map[string]int"
-	vt1 := "string"
-	vt2 := "int"
-	vs := "{\n (" + vt1 + ") \"one\": (" + vt2 + ") 1,\n (" + vt1 +
-		") \"two\": (" + vt2 + ") 2\n}"
-	vs2 := "{\n (" + vt1 + ") \"two\": (" + vt2 + ") 2,\n (" + vt1 +
-		") \"one\": (" + vt2 + ") 1\n}"
-	addDumpTest(v, "("+vt+") "+vs+"\n", "("+vt+") "+vs2+"\n")
-	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n",
-		"(*"+vt+")("+vAddr+")("+vs2+")\n")
-	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n",
-		"(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
-	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+	k := "one"
+	kk := "two"
+	m := map[string]int{k: 1, kk: 2}
+	klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
+	kkLen := fmt.Sprintf("%d", len(kk))
+	mLen := fmt.Sprintf("%d", len(m))
+	nm := (*map[string]int)(nil)
+	pm := &m
+	mAddr := fmt.Sprintf("%p", pm)
+	pmAddr := fmt.Sprintf("%p", &pm)
+	mt := "map[string]int"
+	mt1 := "string"
+	mt2 := "int"
+	ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
+		"\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
+		") \"two\": (" + mt2 + ") 2\n}"
+	ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
+		"\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
+		") \"one\": (" + mt2 + ") 1\n}"
+	addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
+	addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
+		"(*"+mt+")("+mAddr+")("+ms2+")\n")
+	addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
+		"(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
+	addDumpTest(nm, "(*"+mt+")(<nil>)\n")
 
 	// Map with custom formatter type on pointer receiver only keys and vals.
-	v2 := map[pstringer]pstringer{"one": "1"}
-	nv2 := (*map[pstringer]pstringer)(nil)
-	pv2 := &v2
-	v2Addr := fmt.Sprintf("%p", pv2)
-	pv2Addr := fmt.Sprintf("%p", &pv2)
-	v2t := "map[spew_test.pstringer]spew_test.pstringer"
-	v2t1 := "spew_test.pstringer"
-	v2t2 := "spew_test.pstringer"
-	v2s := "{\n (" + v2t1 + ") stringer one: (" + v2t2 + ") stringer 1\n}"
-	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
-	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
-	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+	k2 := pstringer("one")
+	v2 := pstringer("1")
+	m2 := map[pstringer]pstringer{k2: v2}
+	k2Len := fmt.Sprintf("%d", len(k2))
+	v2Len := fmt.Sprintf("%d", len(v2))
+	m2Len := fmt.Sprintf("%d", len(m2))
+	nm2 := (*map[pstringer]pstringer)(nil)
+	pm2 := &m2
+	m2Addr := fmt.Sprintf("%p", pm2)
+	pm2Addr := fmt.Sprintf("%p", &pm2)
+	m2t := "map[spew_test.pstringer]spew_test.pstringer"
+	m2t1 := "spew_test.pstringer"
+	m2t2 := "spew_test.pstringer"
+	m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
+		"stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
+	addDumpTest(m2, "("+m2t+") "+m2s+"\n")
+	addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
+	addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
+	addDumpTest(nm2, "(*"+m2t+")(<nil>)\n")
 
 	// Map with interface keys and values.
-	v3 := map[interface{}]interface{}{"one": 1}
-	nv3 := (*map[interface{}]interface{})(nil)
-	pv3 := &v3
-	v3Addr := fmt.Sprintf("%p", pv3)
-	pv3Addr := fmt.Sprintf("%p", &pv3)
-	v3t := "map[interface {}]interface {}"
-	v3t1 := "string"
-	v3t2 := "int"
-	v3s := "{\n (" + v3t1 + ") \"one\": (" + v3t2 + ") 1\n}"
-	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
-	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
-	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
-	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+	k3 := "one"
+	k3Len := fmt.Sprintf("%d", len(k3))
+	m3 := map[interface{}]interface{}{k3: 1}
+	m3Len := fmt.Sprintf("%d", len(m3))
+	nm3 := (*map[interface{}]interface{})(nil)
+	pm3 := &m3
+	m3Addr := fmt.Sprintf("%p", pm3)
+	pm3Addr := fmt.Sprintf("%p", &pm3)
+	m3t := "map[interface {}]interface {}"
+	m3t1 := "string"
+	m3t2 := "int"
+	m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
+		"\"one\": (" + m3t2 + ") 1\n}"
+	addDumpTest(m3, "("+m3t+") "+m3s+"\n")
+	addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
+	addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
+	addDumpTest(nm3, "(*"+m3t+")(<nil>)\n")
 
 	// Map with nil interface value.
-	v4 := map[string]interface{}{"nil": nil}
-	nv4 := (*map[string]interface{})(nil)
-	pv4 := &v4
-	v4Addr := fmt.Sprintf("%p", pv4)
-	pv4Addr := fmt.Sprintf("%p", &pv4)
-	v4t := "map[string]interface {}"
-	v4t1 := "string"
-	v4t2 := "interface {}"
-	v4s := "{\n (" + v4t1 + ") \"nil\": (" + v4t2 + ") <nil>\n}"
-	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
-	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
-	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
-	addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+	k4 := "nil"
+	k4Len := fmt.Sprintf("%d", len(k4))
+	m4 := map[string]interface{}{k4: nil}
+	m4Len := fmt.Sprintf("%d", len(m4))
+	nm4 := (*map[string]interface{})(nil)
+	pm4 := &m4
+	m4Addr := fmt.Sprintf("%p", pm4)
+	pm4Addr := fmt.Sprintf("%p", &pm4)
+	m4t := "map[string]interface {}"
+	m4t1 := "string"
+	m4t2 := "interface {}"
+	m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
+		" \"nil\": (" + m4t2 + ") <nil>\n}"
+	addDumpTest(m4, "("+m4t+") "+m4s+"\n")
+	addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
+	addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
+	addDumpTest(nm4, "(*"+m4t+")(<nil>)\n")
 }
 
 func addStructDumpTests() {
@@ -618,8 +682,8 @@ func addStructDumpTests() {
 	pv3Addr := fmt.Sprintf("%p", &pv3)
 	v3t := "spew_test.s3"
 	v3t2 := "spew_test.pstringer"
-	v3s := "{\n s: (" + v3t2 + ") stringer test,\n S: (" + v3t2 +
-		") stringer test2\n}"
+	v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
+		") (len=5) stringer test2\n}"
 	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
 	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
 	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
@@ -627,6 +691,7 @@ func addStructDumpTests() {
 
 	// Struct that contains embedded struct and field to same struct.
 	e := embed{"embedstr"}
+	eLen := fmt.Sprintf("%d", len("embedstr"))
 	v4 := embedwrap{embed: &e, e: &e}
 	nv4 := (*embedwrap)(nil)
 	pv4 := &v4
@@ -637,8 +702,9 @@ func addStructDumpTests() {
 	v4t2 := "spew_test.embed"
 	v4t3 := "string"
 	v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n  a: (" + v4t3 +
-		") \"embedstr\"\n }),\n e: (*" + v4t2 + ")(" + eAddr + ")({\n" +
-		"  a: (" + v4t3 + ") \"embedstr\"\n })\n}"
+		") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
+		")(" + eAddr + ")({\n  a: (" + v4t3 + ") (len=" + eLen + ")" +
+		" \"embedstr\"\n })\n}"
 	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
 	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
 	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
@@ -900,10 +966,10 @@ func TestDump(t *testing.T) {
 func TestDumpSortedKeys(t *testing.T) {
 	cfg := spew.ConfigState{SortKeys: true}
 	s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
-	expected := `(map[int]string) {
-(int) 1: (string) "1",
-(int) 2: (string) "2",
-(int) 3: (string) "3"
+	expected := `(map[int]string) (len=3) {
+(int) 1: (string) (len=1) "1",
+(int) 2: (string) (len=1) "2",
+(int) 3: (string) (len=1) "3"
 }
 `
 	if s != expected {

+ 25 - 10
spew/dumpcgo_test.go

@@ -44,39 +44,54 @@ func addCgoDumpTests() {
 	addDumpTest(nv, "("+vt+")(<nil>)\n")
 
 	// C char array.
-	v2 := testdata.GetCgoCharArray()
+	v2, v2l, v2c := testdata.GetCgoCharArray()
+	v2Len := fmt.Sprintf("%d", v2l)
+	v2Cap := fmt.Sprintf("%d", v2c)
 	v2t := "[6]testdata._Ctype_char"
-	v2s := "{\n 00000000  74 65 73 74 32 00                               " +
+	v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
+		"{\n 00000000  74 65 73 74 32 00                               " +
 		"  |test2.|\n}"
 	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
 
 	// C unsigned char array.
-	v3 := testdata.GetCgoUnsignedCharArray()
+	v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
+	v3Len := fmt.Sprintf("%d", v3l)
+	v3Cap := fmt.Sprintf("%d", v3c)
 	v3t := "[6]testdata._Ctype_unsignedchar"
-	v3s := "{\n 00000000  74 65 73 74 33 00                               " +
+	v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
+		"{\n 00000000  74 65 73 74 33 00                               " +
 		"  |test3.|\n}"
 	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
 
 	// C signed char array.
-	v4 := testdata.GetCgoSignedCharArray()
+	v4, v4l, v4c := testdata.GetCgoSignedCharArray()
+	v4Len := fmt.Sprintf("%d", v4l)
+	v4Cap := fmt.Sprintf("%d", v4c)
 	v4t := "[6]testdata._Ctype_schar"
 	v4t2 := "testdata._Ctype_schar"
-	v4s := "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
+	v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+		"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
 		") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
 		") 0\n}"
 	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
 
 	// C uint8_t array.
-	v5 := testdata.GetCgoUint8tArray()
+	v5, v5l, v5c := testdata.GetCgoUint8tArray()
+	v5Len := fmt.Sprintf("%d", v5l)
+	v5Cap := fmt.Sprintf("%d", v5c)
 	v5t := "[6]testdata._Ctype_uint8_t"
-	v5s := "{\n 00000000  74 65 73 74 35 00                               " +
+	v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
+		"{\n 00000000  74 65 73 74 35 00                               " +
 		"  |test5.|\n}"
 	addDumpTest(v5, "("+v5t+") "+v5s+"\n")
 
 	// C typedefed unsigned char array.
-	v6 := testdata.GetCgoTypdefedUnsignedCharArray()
+	v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
+	v6Len := fmt.Sprintf("%d", v6l)
+	v6Cap := fmt.Sprintf("%d", v6c)
 	v6t := "[6]testdata._Ctype_custom_uchar_t"
-	v6s := "{\n 00000000  74 65 73 74 36 00                               " +
+	v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
+		"{\n 00000000  74 65 73 74 36 00                               " +
 		"  |test6.|\n}"
 	addDumpTest(v6, "("+v6t+") "+v6s+"\n")
 }

+ 9 - 9
spew/example_test.go

@@ -105,12 +105,12 @@ func ExampleDump() {
 	//   flag: (spew_test.Flag) flagTwo,
 	//   data: (uintptr) <nil>
 	//  },
-	//  ExportedField: (map[interface {}]interface {}) {
-	//   (string) "one": (bool) true
+	//  ExportedField: (map[interface {}]interface {}) (len=1) {
+	//   (string) (len=3) "one": (bool) true
 	//  }
 	// }
 	// (spew_test.Flag) Unknown flag (5)
-	// ([]uint8) {
+	// ([]uint8) (len=34 cap=34) {
 	//  00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
 	//  00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
 	//  00000020  31 32                                             |12|
@@ -156,8 +156,8 @@ func ExampleConfigState() {
 
 	// Output:
 	// v: map[one:1]
-	// (map[string]int) {
-	// 	(string) "one": (int) 1
+	// (map[string]int) (len=1) {
+	// 	(string) (len=3) "one": (int) 1
 	// }
 }
 
@@ -185,8 +185,8 @@ func ExampleConfigState_Dump() {
 	// 		flag: (spew_test.Flag) flagTwo,
 	// 		data: (uintptr) <nil>
 	// 	},
-	// 	ExportedField: (map[interface {}]interface {}) {
-	//		(string) "one": (bool) true
+	// 	ExportedField: (map[interface {}]interface {}) (len=1) {
+	//		(string) (len=3) "one": (bool) true
 	// 	}
 	// }
 	// (spew_test.Foo) {
@@ -194,8 +194,8 @@ func ExampleConfigState_Dump() {
 	//   flag: (spew_test.Flag) flagTwo,
 	//   data: (uintptr) <nil>
 	//  },
-	//  ExportedField: (map[interface {}]interface {}) {
-	//   (string) "one": (bool) true
+	//  ExportedField: (map[interface {}]interface {}) (len=1) {
+	//   (string) (len=3) "one": (bool) true
 	//  }
 	// }
 	//

+ 4 - 4
spew/spew_test.go

@@ -182,12 +182,12 @@ func initSpewTests() {
 		{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
 		{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
 			" ic: (spew_test.indirCir1) {\n  <max depth reached>\n },\n" +
-			" arr: ([1]string) {\n  <max depth reached>\n },\n" +
-			" slice: ([]string) {\n  <max depth reached>\n },\n" +
-			" m: (map[string]int) {\n  <max depth reached>\n }\n}\n"},
+			" arr: ([1]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+			" slice: ([]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+			" m: (map[string]int) (len=1) {\n  <max depth reached>\n }\n}\n"},
 		{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
 		{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
-			"(stringer test) \"test\"\n"},
+			"(len=4) (stringer test) \"test\"\n"},
 		{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
 		{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
 			"(error: 10) 10\n"},

+ 19 - 18
spew/testdata/dumpcgo.go

@@ -51,31 +51,32 @@ func GetCgoCharPointer() interface{} {
 	return C.cp
 }
 
-// GetCgoCharArray returns a char array via cgo.  This is only used for tests.
-func GetCgoCharArray() interface{} {
-	return C.ca
+// GetCgoCharArray returns a char array via cgo and the array's len and cap.
+// This is only used for tests.
+func GetCgoCharArray() (interface{}, int, int) {
+	return C.ca, len(C.ca), cap(C.ca)
 }
 
-// GetCgoUnsignedCharArray returns an unsigned char array via cgo.  This is only
-// used for tests.
-func GetCgoUnsignedCharArray() interface{} {
-	return C.uca
+// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
+// array's len and cap.  This is only used for tests.
+func GetCgoUnsignedCharArray() (interface{}, int, int) {
+	return C.uca, len(C.uca), cap(C.uca)
 }
 
-// GetCgoSignedCharArray returns a signed char array via cgo.  This is only used
-// for tests.
-func GetCgoSignedCharArray() interface{} {
-	return C.sca
+// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
+// and cap.  This is only used for tests.
+func GetCgoSignedCharArray() (interface{}, int, int) {
+	return C.sca, len(C.sca), cap(C.sca)
 }
 
-// GetCgoUint8tArray returns a uint8_t array via cgo.  This is only used for
-// tests.
-func GetCgoUint8tArray() interface{} {
-	return C.ui8ta
+// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
+// cap.  This is only used for tests.
+func GetCgoUint8tArray() (interface{}, int, int) {
+	return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
 }
 
 // GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
-// cgo.  This is only used for tests.
-func GetCgoTypdefedUnsignedCharArray() interface{} {
-	return C.tuca
+// cgo and the array's len and cap.  This is only used for tests.
+func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
+	return C.tuca, len(C.tuca), cap(C.tuca)
 }