Format a slice of bytes as printable string when possible
Based on `strconv.IsPrint()`, when the slice is fully made of printable bytes,
format it as a string using `formatString()`.
Also reverts `format_test.go` to its previous state including printable byte slices.
diff --git a/format/format.go b/format/format.go
index 38d5d79..06355d9 100644
--- a/format/format.go
+++ b/format/format.go
@@ -7,6 +7,7 @@
"fmt"
"reflect"
"strings"
+ "strconv"
)
// Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
@@ -186,6 +187,10 @@
}
func formatSlice(v reflect.Value, indentation uint) string {
+ if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())){
+ return formatString(v.Bytes(), indentation)
+ }
+
l := v.Len()
result := make([]string, l)
longest := 0
@@ -258,3 +263,15 @@
return false
}
+
+/*
+Returns true when the string is entirely made of printable runes, false otherwise.
+*/
+func isPrintableString(str string) bool {
+ for _, runeValue := range str {
+ if !strconv.IsPrint(runeValue) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/format/format_test.go b/format/format_test.go
index 1fdf29a..1391fe7 100644
--- a/format/format_test.go
+++ b/format/format_test.go
@@ -162,11 +162,19 @@
})
Describe("formatting []byte slices", func() {
- It("should present them as slices", func() {
- b := []byte("a\nb\nc")
- Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `\[97, 10, 98, 10, 99\]`))
- })
- })
+ Context("when the slice is made of printable bytes", func () {
+ It("should present it as string", func() {
+ b := []byte("a b c")
+ Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`))
+ })
+ })
+ Context("when the slice contains non-printable bytes", func () {
+ It("should present it as slice", func() {
+ b := []byte("a b c\n\x01\x02\x03\xff\x1bH")
+ Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`))
+ })
+ })
+ })
Describe("formatting functions", func() {
It("should give the type and format values correctly", func() {
@@ -253,11 +261,10 @@
m["Toby Ziegler"] = []byte("Richard Schiff")
m["CJ Cregg"] = []byte("Allison Janney")
expected := `{
-( "Josiah Edward Bartlet": \[77, 97, 114, 116, 105, 110, 32, 83, 104, 101, 101, 110\],
-| "Toby Ziegler": \[82, 105, 99, 104, 97, 114, 100, 32, 83, 99, 104, 105, 102, 102\],
-| "CJ Cregg": \[65, 108, 108, 105, 115, 111, 110, 32, 74, 97, 110, 110, 101, 121\],
-){3} }`
-
+ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
+ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
+ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
+ }`
Ω(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected))
})
})
@@ -269,11 +276,11 @@
Name: "Oswald",
Enumeration: 17,
Veritas: true,
- Data: []byte(""),
+ Data: []byte("datum"),
secret: 1983,
}
- Ω(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: [], secret: 1983}`))
+ Ω(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`))
})
Context("when the struct contains long entries", func() {
@@ -290,7 +297,7 @@
Name: "Mithrandir Gandalf Greyhame",
Enumeration: 2021,
Veritas: true,
- Data: [119, 105, 122, 97, 114, 100],
+ Data: "wizard",
secret: 3,
}`))
})
@@ -314,7 +321,7 @@
Describe("formatting aliased types", func() {
It("should print out the correct alias type", func() {
Ω(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`))
- Ω(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `\[97, 108, 105, 97, 115\]`))
+ Ω(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`))
Ω(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3"))
})
})
@@ -324,7 +331,7 @@
s := ComplexStruct{
Strings: []string{"lots", "of", "short", "strings"},
SimpleThings: []*SimpleStruct{
- {"short", 7, true, []byte("sm"), 17},
+ {"short", 7, true, []byte("succinct"), 17},
{"something longer", 427, true, []byte("designed to wrap around nicely"), 30},
},
DataMaps: map[int]ByteAlias{
@@ -335,19 +342,19 @@
expected := `{
Strings: \["lots", "of", "short", "strings"\],
SimpleThings: \[
- {Name: "short", Enumeration: 7, Veritas: true, Data: \[115, 109\], secret: 17},
+ {Name: "short", Enumeration: 7, Veritas: true, Data: "succinct", secret: 17},
{
Name: "something longer",
Enumeration: 427,
Veritas: true,
- Data: \[100, 101, 115, 105, 103, 110, 101, 100, 32, 116, 111, 32, 119, 114, 97, 112, 32, 97, 114, 111, 117, 110, 100, 32, 110, 105, 99, 101, 108, 121\],
+ Data: "designed to wrap around nicely",
secret: 30,
},
\],
DataMaps: {
-( 17: \[115, 111, 109, 101, 32, 115, 117, 98, 115, 116, 97, 110, 116, 105, 97, 108, 108, 121, 32, 108, 111, 110, 103, 101, 114, 32, 99, 104, 117, 110, 107, 115, 32, 111, 102, 32, 100, 97, 116, 97\],
-| 1138: \[116, 104, 97, 116, 32, 115, 104, 111, 117, 108, 100, 32, 109, 97, 107, 101, 32, 116, 104, 105, 110, 103, 115, 32, 119, 114, 97, 112\],
-){2} },
+ (17: "some substantially longer chunks of data"|1138: "that should make things wrap"),
+ (17: "some substantially longer chunks of data"|1138: "that should make things wrap"),
+ },
}`
Ω(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected))
})
@@ -388,7 +395,7 @@
funcValue: %p,
pointerValue: 5,
sliceValue: \["string", "slice"\],
- byteSliceValue: \[98, 121, 116, 101, 115\],
+ byteSliceValue: "bytes",
stringValue: "a string",
arrValue: \[11, 12, 13\],
byteArrValue: \[17, 20, 32\],