From 3fdaf5cea8d23107b993d363e98992fa529dd713 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 5 May 2014 22:09:56 -0500 Subject: [PATCH] Dump non-zero len and cap for applicable types. Closes #16. --- spew/common.go | 2 + spew/doc.go | 6 +- spew/dump.go | 26 +++++ spew/dump_test.go | 230 +++++++++++++++++++++++++-------------- spew/dumpcgo_test.go | 35 ++++-- spew/example_test.go | 18 +-- spew/spew_test.go | 8 +- spew/testdata/dumpcgo.go | 37 ++++--- 8 files changed, 236 insertions(+), 126 deletions(-) diff --git a/spew/common.go b/spew/common.go index bc26e7e..1a03dc8 100644 --- a/spew/common.go +++ b/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. diff --git a/spew/doc.go b/spew/doc.go index 5a3e2ec..a0d73ac 100644 --- a/spew/doc.go +++ b/spew/doc.go @@ -128,14 +128,14 @@ shown here. flag: (main.Flag) flagTwo, data: (uintptr) }), - 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| diff --git a/spew/dump.go b/spew/dump.go index 3d57306..02d4c9d 100644 --- a/spew/dump.go +++ b/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 { diff --git a/spew/dump_test.go b/spew/dump_test.go index 84de707..f1a5644 100644 --- a/spew/dump_test.go +++ b/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+")()\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+")()\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+")()\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+")()\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 + ") \n}" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3,\n (" + v3t5 + ") \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+")()\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+")()\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+")()\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+")()\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+")()\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+")()\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 + ") \n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\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 + ") \n}" + addDumpTest(m4, "("+m4t+") "+m4s+"\n") + addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") + addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") + addDumpTest(nm4, "(*"+m4t+")()\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 { diff --git a/spew/dumpcgo_test.go b/spew/dumpcgo_test.go index 30e7f7c..9b8a358 100644 --- a/spew/dumpcgo_test.go +++ b/spew/dumpcgo_test.go @@ -44,39 +44,54 @@ func addCgoDumpTests() { addDumpTest(nv, "("+vt+")()\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") } diff --git a/spew/example_test.go b/spew/example_test.go index b1ec8a2..a7acd14 100644 --- a/spew/example_test.go +++ b/spew/example_test.go @@ -105,12 +105,12 @@ func ExampleDump() { // flag: (spew_test.Flag) flagTwo, // data: (uintptr) // }, - // 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) // }, - // 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) // }, - // ExportedField: (map[interface {}]interface {}) { - // (string) "one": (bool) true + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true // } // } // diff --git a/spew/spew_test.go b/spew/spew_test.go index bbb531b..3831ed2 100644 --- a/spew/spew_test.go +++ b/spew/spew_test.go @@ -182,12 +182,12 @@ func initSpewTests() { {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + " ic: (spew_test.indirCir1) {\n \n },\n" + - " arr: ([1]string) {\n \n },\n" + - " slice: ([]string) {\n \n },\n" + - " m: (map[string]int) {\n \n }\n}\n"}, + " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + + " slice: ([]string) (len=1 cap=1) {\n \n },\n" + + " m: (map[string]int) (len=1) {\n \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"}, diff --git a/spew/testdata/dumpcgo.go b/spew/testdata/dumpcgo.go index 2e98452..5c87dd4 100644 --- a/spew/testdata/dumpcgo.go +++ b/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) }