aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go')
-rw-r--r--vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go262
1 files changed, 208 insertions, 54 deletions
diff --git a/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go b/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go
index e070a6b3..313611ef 100644
--- a/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go
+++ b/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go
@@ -12,32 +12,46 @@ import (
"strconv"
)
-var implicitTypeMap = map[reflect.Kind]string{
+var builtinTypeMap = map[reflect.Kind]string{
reflect.Bool: "bool",
- reflect.String: "string",
- reflect.Int: "int",
- reflect.Int8: "int8",
+ reflect.Complex128: "complex128",
+ reflect.Complex64: "complex64",
+ reflect.Float32: "float32",
+ reflect.Float64: "float64",
reflect.Int16: "int16",
reflect.Int32: "int32",
reflect.Int64: "int64",
- reflect.Uint: "uint",
- reflect.Uint8: "uint8",
+ reflect.Int8: "int8",
+ reflect.Int: "int",
+ reflect.String: "string",
reflect.Uint16: "uint16",
reflect.Uint32: "uint32",
reflect.Uint64: "uint64",
- reflect.Float32: "float32",
- reflect.Float64: "float64",
- reflect.Complex64: "complex64",
- reflect.Complex128: "complex128",
+ reflect.Uint8: "uint8",
+ reflect.Uint: "uint",
+ reflect.Uintptr: "uintptr",
+}
+
+var builtinTypeSet = map[string]struct{}{}
+
+func init() {
+ for _, v := range builtinTypeMap {
+ builtinTypeSet[v] = struct{}{}
+ }
}
+var typeOfString = reflect.TypeOf("")
+var typeOfInt = reflect.TypeOf(int(1))
+var typeOfUint = reflect.TypeOf(uint(1))
+var typeOfFloat = reflect.TypeOf(10.1)
+
// Render converts a structure to a string representation. Unline the "%#v"
// format string, this resolves pointer types' contents in structs, maps, and
// slices/arrays and prints their field values.
func Render(v interface{}) string {
buf := bytes.Buffer{}
s := (*traverseState)(nil)
- s.render(&buf, 0, reflect.ValueOf(v))
+ s.render(&buf, 0, reflect.ValueOf(v), false)
return buf.String()
}
@@ -72,7 +86,7 @@ func (s *traverseState) forkFor(ptr uintptr) *traverseState {
return fs
}
-func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
+func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value, implicit bool) {
if v.Kind() == reflect.Invalid {
buf.WriteString("nil")
return
@@ -107,49 +121,80 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
s = s.forkFor(pe)
if s == nil {
buf.WriteString("<REC(")
- writeType(buf, ptrs, vt)
+ if !implicit {
+ writeType(buf, ptrs, vt)
+ }
buf.WriteString(")>")
return
}
}
+ isAnon := func(t reflect.Type) bool {
+ if t.Name() != "" {
+ if _, ok := builtinTypeSet[t.Name()]; !ok {
+ return false
+ }
+ }
+ return t.Kind() != reflect.Interface
+ }
+
switch vk {
case reflect.Struct:
- writeType(buf, ptrs, vt)
+ if !implicit {
+ writeType(buf, ptrs, vt)
+ }
buf.WriteRune('{')
- for i := 0; i < vt.NumField(); i++ {
- if i > 0 {
- buf.WriteString(", ")
- }
- buf.WriteString(vt.Field(i).Name)
- buf.WriteRune(':')
+ if rendered, ok := renderTime(v); ok {
+ buf.WriteString(rendered)
+ } else {
+ structAnon := vt.Name() == ""
+ for i := 0; i < vt.NumField(); i++ {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ anon := structAnon && isAnon(vt.Field(i).Type)
- s.render(buf, 0, v.Field(i))
+ if !anon {
+ buf.WriteString(vt.Field(i).Name)
+ buf.WriteRune(':')
+ }
+
+ s.render(buf, 0, v.Field(i), anon)
+ }
}
buf.WriteRune('}')
case reflect.Slice:
if v.IsNil() {
- writeType(buf, ptrs, vt)
- buf.WriteString("(nil)")
+ if !implicit {
+ writeType(buf, ptrs, vt)
+ buf.WriteString("(nil)")
+ } else {
+ buf.WriteString("nil")
+ }
return
}
fallthrough
case reflect.Array:
- writeType(buf, ptrs, vt)
+ if !implicit {
+ writeType(buf, ptrs, vt)
+ }
+ anon := vt.Name() == "" && isAnon(vt.Elem())
buf.WriteString("{")
for i := 0; i < v.Len(); i++ {
if i > 0 {
buf.WriteString(", ")
}
- s.render(buf, 0, v.Index(i))
+ s.render(buf, 0, v.Index(i), anon)
}
buf.WriteRune('}')
case reflect.Map:
- writeType(buf, ptrs, vt)
+ if !implicit {
+ writeType(buf, ptrs, vt)
+ }
if v.IsNil() {
buf.WriteString("(nil)")
} else {
@@ -158,14 +203,17 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
mkeys := v.MapKeys()
tryAndSortMapKeys(vt, mkeys)
+ kt := vt.Key()
+ keyAnon := typeOfString.ConvertibleTo(kt) || typeOfInt.ConvertibleTo(kt) || typeOfUint.ConvertibleTo(kt) || typeOfFloat.ConvertibleTo(kt)
+ valAnon := vt.Name() == "" && isAnon(vt.Elem())
for i, mk := range mkeys {
if i > 0 {
buf.WriteString(", ")
}
- s.render(buf, 0, mk)
+ s.render(buf, 0, mk, keyAnon)
buf.WriteString(":")
- s.render(buf, 0, v.MapIndex(mk))
+ s.render(buf, 0, v.MapIndex(mk), valAnon)
}
buf.WriteRune('}')
}
@@ -176,11 +224,9 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
case reflect.Interface:
if v.IsNil() {
writeType(buf, ptrs, v.Type())
- buf.WriteRune('(')
- fmt.Fprint(buf, "nil")
- buf.WriteRune(')')
+ buf.WriteString("(nil)")
} else {
- s.render(buf, ptrs, v.Elem())
+ s.render(buf, ptrs, v.Elem(), false)
}
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
@@ -191,7 +237,7 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
default:
tstr := vt.String()
- implicit := ptrs == 0 && implicitTypeMap[vk] == tstr
+ implicit = implicit || (ptrs == 0 && builtinTypeMap[vk] == tstr)
if !implicit {
writeType(buf, ptrs, vt)
buf.WriteRune('(')
@@ -206,7 +252,7 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fmt.Fprintf(buf, "%d", v.Int())
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
fmt.Fprintf(buf, "%d", v.Uint())
case reflect.Float32, reflect.Float64:
@@ -288,40 +334,148 @@ func writeType(buf *bytes.Buffer, ptrs int, t reflect.Type) {
}
}
+type cmpFn func(a, b reflect.Value) int
+
type sortableValueSlice struct {
- kind reflect.Kind
+ cmp cmpFn
elements []reflect.Value
}
-func (s *sortableValueSlice) Len() int {
+func (s sortableValueSlice) Len() int {
return len(s.elements)
}
-func (s *sortableValueSlice) Less(i, j int) bool {
- switch s.kind {
+func (s sortableValueSlice) Less(i, j int) bool {
+ return s.cmp(s.elements[i], s.elements[j]) < 0
+}
+
+func (s sortableValueSlice) Swap(i, j int) {
+ s.elements[i], s.elements[j] = s.elements[j], s.elements[i]
+}
+
+// cmpForType returns a cmpFn which sorts the data for some type t in the same
+// order that a go-native map key is compared for equality.
+func cmpForType(t reflect.Type) cmpFn {
+ switch t.Kind() {
case reflect.String:
- return s.elements[i].String() < s.elements[j].String()
+ return func(av, bv reflect.Value) int {
+ a, b := av.String(), bv.String()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Bool:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Bool(), bv.Bool()
+ if !a && b {
+ return -1
+ } else if a && !b {
+ return 1
+ }
+ return 0
+ }
- case reflect.Int:
- return s.elements[i].Int() < s.elements[j].Int()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Int(), bv.Int()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
- default:
- panic(fmt.Errorf("unsupported sort kind: %s", s.kind))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64, reflect.Uintptr, reflect.UnsafePointer:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Uint(), bv.Uint()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Float32, reflect.Float64:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Float(), bv.Float()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Interface:
+ return func(av, bv reflect.Value) int {
+ a, b := av.InterfaceData(), bv.InterfaceData()
+ if a[0] < b[0] {
+ return -1
+ } else if a[0] > b[0] {
+ return 1
+ }
+ if a[1] < b[1] {
+ return -1
+ } else if a[1] > b[1] {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Complex64, reflect.Complex128:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Complex(), bv.Complex()
+ if real(a) < real(b) {
+ return -1
+ } else if real(a) > real(b) {
+ return 1
+ }
+ if imag(a) < imag(b) {
+ return -1
+ } else if imag(a) > imag(b) {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Ptr, reflect.Chan:
+ return func(av, bv reflect.Value) int {
+ a, b := av.Pointer(), bv.Pointer()
+ if a < b {
+ return -1
+ } else if a > b {
+ return 1
+ }
+ return 0
+ }
+
+ case reflect.Struct:
+ cmpLst := make([]cmpFn, t.NumField())
+ for i := range cmpLst {
+ cmpLst[i] = cmpForType(t.Field(i).Type)
+ }
+ return func(a, b reflect.Value) int {
+ for i, cmp := range cmpLst {
+ if rslt := cmp(a.Field(i), b.Field(i)); rslt != 0 {
+ return rslt
+ }
+ }
+ return 0
+ }
}
-}
-func (s *sortableValueSlice) Swap(i, j int) {
- s.elements[i], s.elements[j] = s.elements[j], s.elements[i]
+ return nil
}
func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) {
- // Try our stock sortable values.
- switch mt.Key().Kind() {
- case reflect.String, reflect.Int:
- vs := &sortableValueSlice{
- kind: mt.Key().Kind(),
- elements: k,
- }
- sort.Sort(vs)
+ if cmp := cmpForType(mt.Key()); cmp != nil {
+ sort.Sort(sortableValueSlice{cmp, k})
}
}