1// Copyright 2016 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Package pretty implements a simple pretty-printer. It is intended for 16// debugging the output of tests. 17// 18// It follows pointers and produces multi-line output for complex values like 19// slices, maps and structs. 20package pretty 21 22import ( 23 "fmt" 24 "io" 25 "reflect" 26 "sort" 27 "strings" 28 "time" 29) 30 31// Indent is the string output at each level of indentation. 32var Indent = " " 33 34// Value returns a value that will print prettily when used as an 35// argument for the %v or %s format specifiers. 36// With no flags, struct fields and map keys with default values are omitted. 37// With the '+' or '#' flags, all values are displayed. 38// 39// This package does not detect cycles. Attempting to print a Value that 40// contains cycles will result in unbounded recursion. 41func Value(v interface{}) val { return val{v: v} } 42 43// val is a value. 44type val struct{ v interface{} } 45 46// Format implements the fmt.Formatter interface. 47func (v val) Format(s fmt.State, c rune) { 48 if c == 'v' || c == 's' { 49 fprint(s, reflect.ValueOf(v.v), state{ 50 defaults: s.Flag('+') || s.Flag('#'), 51 }) 52 } else { 53 fmt.Fprintf(s, "%%!%c(pretty.val)", c) 54 } 55} 56 57type state struct { 58 level int 59 prefix, suffix string 60 defaults bool 61} 62 63const maxLevel = 100 64 65var typeOfTime = reflect.TypeOf(time.Time{}) 66 67func fprint(w io.Writer, v reflect.Value, s state) { 68 if s.level > maxLevel { 69 fmt.Fprintln(w, "pretty: max nested depth exceeded") 70 return 71 } 72 indent := strings.Repeat(Indent, s.level) 73 fmt.Fprintf(w, "%s%s", indent, s.prefix) 74 if isNil(v) { 75 fmt.Fprintf(w, "nil%s", s.suffix) 76 return 77 } 78 if v.Type().Kind() == reflect.Interface { 79 v = v.Elem() 80 } 81 if v.Type() == typeOfTime { 82 fmt.Fprintf(w, "%s%s", v.Interface(), s.suffix) 83 return 84 } 85 for v.Type().Kind() == reflect.Ptr { 86 fmt.Fprintf(w, "&") 87 v = v.Elem() 88 } 89 switch v.Type().Kind() { 90 default: 91 fmt.Fprintf(w, "%s%s", short(v), s.suffix) 92 93 case reflect.Array: 94 fmt.Fprintf(w, "%s{\n", v.Type()) 95 for i := 0; i < v.Len(); i++ { 96 fprint(w, v.Index(i), state{ 97 level: s.level + 1, 98 prefix: "", 99 suffix: ",", 100 defaults: s.defaults, 101 }) 102 fmt.Fprintln(w) 103 } 104 fmt.Fprintf(w, "%s}", indent) 105 106 case reflect.Slice: 107 fmt.Fprintf(w, "%s{", v.Type()) 108 if v.Len() > 0 { 109 fmt.Fprintln(w) 110 for i := 0; i < v.Len(); i++ { 111 fprint(w, v.Index(i), state{ 112 level: s.level + 1, 113 prefix: "", 114 suffix: ",", 115 defaults: s.defaults, 116 }) 117 fmt.Fprintln(w) 118 } 119 } 120 fmt.Fprintf(w, "%s}%s", indent, s.suffix) 121 122 case reflect.Map: 123 fmt.Fprintf(w, "%s{", v.Type()) 124 if v.Len() > 0 { 125 fmt.Fprintln(w) 126 keys := v.MapKeys() 127 maybeSort(keys, v.Type().Key()) 128 for _, key := range keys { 129 val := v.MapIndex(key) 130 if s.defaults || !isDefault(val) { 131 fprint(w, val, state{ 132 level: s.level + 1, 133 prefix: short(key) + ": ", 134 suffix: ",", 135 defaults: s.defaults, 136 }) 137 fmt.Fprintln(w) 138 } 139 } 140 } 141 fmt.Fprintf(w, "%s}%s", indent, s.suffix) 142 143 case reflect.Struct: 144 t := v.Type() 145 fmt.Fprintf(w, "%s{\n", t) 146 for i := 0; i < t.NumField(); i++ { 147 f := v.Field(i) 148 if s.defaults || !isDefault(f) { 149 fprint(w, f, state{ 150 level: s.level + 1, 151 prefix: t.Field(i).Name + ": ", 152 suffix: ",", 153 defaults: s.defaults, 154 }) 155 fmt.Fprintln(w) 156 } 157 } 158 fmt.Fprintf(w, "%s}%s", indent, s.suffix) 159 } 160} 161 162func isNil(v reflect.Value) bool { 163 if !v.IsValid() { 164 return true 165 } 166 switch v.Type().Kind() { 167 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 168 return v.IsNil() 169 default: 170 return false 171 } 172} 173 174func isDefault(v reflect.Value) bool { 175 if !v.IsValid() { 176 return true 177 } 178 t := v.Type() 179 switch t.Kind() { 180 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 181 return v.IsNil() 182 default: 183 if !v.CanInterface() { 184 return false 185 } 186 return t.Comparable() && v.Interface() == reflect.Zero(t).Interface() 187 } 188} 189 190// short returns a short, one-line string for v. 191func short(v reflect.Value) string { 192 if !v.IsValid() { 193 return "nil" 194 } 195 if v.Type().Kind() == reflect.String { 196 return fmt.Sprintf("%q", v) 197 } 198 return fmt.Sprintf("%v", v) 199} 200 201func maybeSort(vs []reflect.Value, t reflect.Type) { 202 if less := lessFunc(t); less != nil { 203 sort.Sort(&sorter{vs, less}) 204 } 205} 206 207// lessFunc returns a function that implements the "<" operator 208// for the given type, or nil if the type doesn't support "<" . 209func lessFunc(t reflect.Type) func(v1, v2 interface{}) bool { 210 switch t.Kind() { 211 case reflect.String: 212 return func(v1, v2 interface{}) bool { return v1.(string) < v2.(string) } 213 case reflect.Int: 214 return func(v1, v2 interface{}) bool { return v1.(int) < v2.(int) } 215 case reflect.Int8: 216 return func(v1, v2 interface{}) bool { return v1.(int8) < v2.(int8) } 217 case reflect.Int16: 218 return func(v1, v2 interface{}) bool { return v1.(int16) < v2.(int16) } 219 case reflect.Int32: 220 return func(v1, v2 interface{}) bool { return v1.(int32) < v2.(int32) } 221 case reflect.Int64: 222 return func(v1, v2 interface{}) bool { return v1.(int64) < v2.(int64) } 223 case reflect.Uint: 224 return func(v1, v2 interface{}) bool { return v1.(uint) < v2.(uint) } 225 case reflect.Uint8: 226 return func(v1, v2 interface{}) bool { return v1.(uint8) < v2.(uint8) } 227 case reflect.Uint16: 228 return func(v1, v2 interface{}) bool { return v1.(uint16) < v2.(uint16) } 229 case reflect.Uint32: 230 return func(v1, v2 interface{}) bool { return v1.(uint32) < v2.(uint32) } 231 case reflect.Uint64: 232 return func(v1, v2 interface{}) bool { return v1.(uint64) < v2.(uint64) } 233 case reflect.Float32: 234 return func(v1, v2 interface{}) bool { return v1.(float32) < v2.(float32) } 235 case reflect.Float64: 236 return func(v1, v2 interface{}) bool { return v1.(float64) < v2.(float64) } 237 default: 238 return nil 239 } 240} 241 242type sorter struct { 243 vs []reflect.Value 244 less func(v1, v2 interface{}) bool 245} 246 247func (s *sorter) Len() int { return len(s.vs) } 248func (s *sorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } 249func (s *sorter) Less(i, j int) bool { return s.less(s.vs[i].Interface(), s.vs[j].Interface()) } 250