github.com/dvln/pretty@v0.0.0-20161024040402-00a5f9316993/formatter_test.go (about) 1 package pretty 2 3 import ( 4 "fmt" 5 "io" 6 "strings" 7 "testing" 8 "unsafe" 9 ) 10 11 type test struct { 12 v interface{} 13 s string 14 } 15 16 type passtest struct { 17 v interface{} 18 f, s string 19 } 20 21 type LongStructTypeName struct { 22 longFieldName interface{} 23 otherLongFieldName interface{} 24 } 25 26 type SA struct { 27 t *T 28 v T 29 } 30 31 type T struct { 32 x, y int 33 } 34 35 type F int 36 37 func (f F) Format(s fmt.State, c rune) { 38 fmt.Fprintf(s, "F(%d)", int(f)) 39 } 40 41 type Stringer struct { i int } 42 43 func (s *Stringer) String() string { return "foo" } 44 45 var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 46 47 var passthrough = []passtest{ 48 {1, "%d", "1"}, 49 {"a", "%s", "a"}, 50 {&Stringer{}, "%s", "foo"}, 51 } 52 53 func TestPassthrough(t *testing.T) { 54 for _, tt := range passthrough { 55 s := fmt.Sprintf(tt.f, Formatter(tt.v)) 56 if tt.s != s { 57 t.Errorf("expected %q", tt.s) 58 t.Errorf("got %q", s) 59 t.Errorf("expraw\n%s", tt.s) 60 t.Errorf("gotraw\n%s", s) 61 } 62 } 63 } 64 65 var gosyntax = []test{ 66 {nil, `nil`}, 67 {"", `""`}, 68 {"a", `"a"`}, 69 {1, "int(1)"}, 70 {1.0, "float64(1)"}, 71 {[]int(nil), "[]int(nil)"}, 72 {[0]int{}, "[0]int{}"}, 73 {complex(1, 0), "(1+0i)"}, 74 //{make(chan int), "(chan int)(0x1234)"}, 75 {unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("unsafe.Pointer(0x%02x)", uintptr(unsafe.Pointer(&long)))}, 76 {func(int) {}, "func(int) {...}"}, 77 {map[int]int{1: 1}, "map[int]int{1:1}"}, 78 {int32(1), "int32(1)"}, 79 {io.EOF, `&errors.errorString{s:"EOF"}`}, 80 {[]string{"a"}, `[]string{"a"}`}, 81 { 82 []string{long}, 83 `[]string{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"}`, 84 }, 85 {F(5), "pretty.F(5)"}, 86 { 87 SA{&T{1, 2}, T{3, 4}}, 88 `pretty.SA{ 89 t: &pretty.T{x:1, y:2}, 90 v: pretty.T{x:3, y:4}, 91 }`, 92 }, 93 { 94 map[int][]byte{1: {}}, 95 `map[int][]uint8{ 96 1: {}, 97 }`, 98 }, 99 { 100 map[int]T{1: {}}, 101 `map[int]pretty.T{ 102 1: {}, 103 }`, 104 }, 105 { 106 long, 107 `"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"`, 108 }, 109 { 110 LongStructTypeName{ 111 longFieldName: LongStructTypeName{}, 112 otherLongFieldName: long, 113 }, 114 `pretty.LongStructTypeName{ 115 longFieldName: pretty.LongStructTypeName{}, 116 otherLongFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 117 }`, 118 }, 119 { 120 &LongStructTypeName{ 121 longFieldName: &LongStructTypeName{}, 122 otherLongFieldName: (*LongStructTypeName)(nil), 123 }, 124 `&pretty.LongStructTypeName{ 125 longFieldName: &pretty.LongStructTypeName{}, 126 otherLongFieldName: (*pretty.LongStructTypeName)(nil), 127 }`, 128 }, 129 { 130 []LongStructTypeName{ 131 {nil, nil}, 132 {3, 3}, 133 {long, nil}, 134 }, 135 `[]pretty.LongStructTypeName{ 136 {}, 137 { 138 longFieldName: int(3), 139 otherLongFieldName: int(3), 140 }, 141 { 142 longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 143 otherLongFieldName: nil, 144 }, 145 }`, 146 }, 147 { 148 []interface{}{ 149 LongStructTypeName{nil, nil}, 150 []byte{1, 2, 3}, 151 T{3, 4}, 152 LongStructTypeName{long, nil}, 153 }, 154 `[]interface {}{ 155 pretty.LongStructTypeName{}, 156 []uint8{0x1, 0x2, 0x3}, 157 pretty.T{x:3, y:4}, 158 pretty.LongStructTypeName{ 159 longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 160 otherLongFieldName: nil, 161 }, 162 }`, 163 }, 164 } 165 166 func TestGoSyntax(t *testing.T) { 167 for _, tt := range gosyntax { 168 s := fmt.Sprintf("%# v", Formatter(tt.v)) 169 if tt.s != s { 170 t.Errorf("expected %q", tt.s) 171 t.Errorf("got %q", s) 172 t.Errorf("expraw\n%s", tt.s) 173 t.Errorf("gotraw\n%s", s) 174 } 175 } 176 } 177 178 var humanizesyntax = []test{ 179 {nil, `nil`}, 180 {"", ``}, 181 {" ", `" "`}, 182 {"a", `a`}, 183 {1, "1"}, 184 {1.0, "1"}, 185 {[]int(nil), "nil"}, 186 {[0]int{}, ""}, 187 {complex(1, 0), "(1+0i)"}, 188 {unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("0x%02x", uintptr(unsafe.Pointer(&long)))}, 189 {func(int) {}, "func(int) {...}"}, 190 {map[int]int{1: 1}, "1: 1\n"}, // CONSIDER: is \n needed here? 191 {int32(1), "1"}, 192 {io.EOF, "s: EOF\n"}, // CONSIDER: is \n needed here? 193 {[]string{"a"}, "a\n"}, // CONSIDER: is \n needed here? 194 { 195 []string{long}, 196 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n", // CONSIDER: is \n needed here? 197 }, 198 {F(5), "5"}, 199 { 200 SA{&T{1, 2}, T{3, 4}}, 201 "t: \n x: 1\n y: 2\nv: \n x: 3\n y: 4\n", 202 }, 203 { 204 map[int][]byte{1: []byte{}}, 205 "1: \n", 206 }, 207 { 208 map[int]T{1: T{}}, 209 "1: \n x: 0\n y: 0\n", 210 }, 211 { 212 long, 213 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 214 }, 215 { 216 LongStructTypeName{ 217 longFieldName: LongStructTypeName{}, 218 otherLongFieldName: long, 219 }, 220 `longFieldName: 221 longFieldName: nil 222 otherLongFieldName: nil 223 otherLongFieldName: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 224 `, 225 }, 226 { 227 &LongStructTypeName{ 228 longFieldName: &LongStructTypeName{}, 229 otherLongFieldName: (*LongStructTypeName)(nil), 230 }, 231 `longFieldName: 232 longFieldName: nil 233 otherLongFieldName: nil 234 otherLongFieldName: nil 235 `, 236 }, 237 { 238 []LongStructTypeName{ 239 {nil, nil}, 240 {3, 3}, 241 {long, nil}, 242 }, 243 `longFieldName: nil 244 otherLongFieldName: nil 245 longFieldName: 3 246 otherLongFieldName: 3 247 longFieldName: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 248 otherLongFieldName: nil 249 `, 250 }, 251 { 252 []interface{}{ 253 LongStructTypeName{nil, nil}, 254 []byte{1, 2, 3}, 255 T{3, 4}, 256 LongStructTypeName{long, nil}, 257 }, 258 `longFieldName: nil 259 otherLongFieldName: nil 260 0x10x20x3x: 3 261 y: 4 262 longFieldName: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 263 otherLongFieldName: nil 264 `, 265 }, 266 } 267 268 func TestHumanizeSyntax(t *testing.T) { 269 // test indentation setting and "humanized" output format 270 SetOutputIndentLevel(2) 271 SetHumanize(true) 272 for _, tt := range humanizesyntax { 273 s := fmt.Sprintf("%# v", Formatter(tt.v)) 274 if tt.s != s { 275 t.Errorf("expected %q", tt.s) 276 t.Errorf("got %q", s) 277 t.Errorf("expraw\n%s", tt.s) 278 t.Errorf("gotraw\n%s", s) 279 } 280 } 281 // reset to usual values: 282 SetOutputIndentLevel(4) 283 SetHumanize(false) 284 } 285 286 type I struct { 287 i int 288 R interface{} 289 } 290 291 func (i *I) I() *I { return i.R.(*I) } 292 293 func TestCycle(t *testing.T) { 294 type A struct{ *A } 295 v := &A{} 296 v.A = v 297 298 // panics from stack overflow without cycle detection 299 t.Logf("Example cycle:\n%# v", Formatter(v)) 300 301 p := &A{} 302 s := fmt.Sprintf("%# v", Formatter([]*A{p, p})) 303 if strings.Contains(s, "CYCLIC") { 304 t.Errorf("Repeated address detected as cyclic reference:\n%s", s) 305 } 306 307 type R struct { 308 i int 309 *R 310 } 311 r := &R{ 312 i: 1, 313 R: &R{ 314 i: 2, 315 R: &R{ 316 i: 3, 317 }, 318 }, 319 } 320 r.R.R.R = r 321 t.Logf("Example longer cycle:\n%# v", Formatter(r)) 322 323 r = &R{ 324 i: 1, 325 R: &R{ 326 i: 2, 327 R: &R{ 328 i: 3, 329 R: &R{ 330 i: 4, 331 R: &R{ 332 i: 5, 333 R: &R{ 334 i: 6, 335 R: &R{ 336 i: 7, 337 R: &R{ 338 i: 8, 339 R: &R{ 340 i: 9, 341 R: &R{ 342 i: 10, 343 R: &R{ 344 i: 11, 345 }, 346 }, 347 }, 348 }, 349 }, 350 }, 351 }, 352 }, 353 }, 354 }, 355 } 356 // here be pirates 357 r.R.R.R.R.R.R.R.R.R.R.R = r 358 t.Logf("Example very long cycle:\n%# v", Formatter(r)) 359 360 i := &I{ 361 i: 1, 362 R: &I{ 363 i: 2, 364 R: &I{ 365 i: 3, 366 R: &I{ 367 i: 4, 368 R: &I{ 369 i: 5, 370 R: &I{ 371 i: 6, 372 R: &I{ 373 i: 7, 374 R: &I{ 375 i: 8, 376 R: &I{ 377 i: 9, 378 R: &I{ 379 i: 10, 380 R: &I{ 381 i: 11, 382 }, 383 }, 384 }, 385 }, 386 }, 387 }, 388 }, 389 }, 390 }, 391 }, 392 } 393 iv := i.I().I().I().I().I().I().I().I().I().I() 394 *iv = *i 395 t.Logf("Example long interface cycle:\n%# v", Formatter(i)) 396 }