1package pretty 2 3import ( 4 "fmt" 5 "io" 6 "strings" 7 "testing" 8 "unsafe" 9) 10 11type test struct { 12 v interface{} 13 s string 14} 15 16type passtest struct { 17 v interface{} 18 f, s string 19} 20 21type LongStructTypeName struct { 22 longFieldName interface{} 23 otherLongFieldName interface{} 24} 25 26type SA struct { 27 t *T 28 v T 29} 30 31type T struct { 32 x, y int 33} 34 35type F int 36 37func (f F) Format(s fmt.State, c rune) { 38 fmt.Fprintf(s, "F(%d)", int(f)) 39} 40 41type Stringer struct { i int } 42 43func (s *Stringer) String() string { return "foo" } 44 45var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 46 47var passthrough = []passtest{ 48 {1, "%d", "1"}, 49 {"a", "%s", "a"}, 50 {&Stringer{}, "%s", "foo"}, 51} 52 53func 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 65var 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 166func 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 178type I struct { 179 i int 180 R interface{} 181} 182 183func (i *I) I() *I { return i.R.(*I) } 184 185func TestCycle(t *testing.T) { 186 type A struct{ *A } 187 v := &A{} 188 v.A = v 189 190 // panics from stack overflow without cycle detection 191 t.Logf("Example cycle:\n%# v", Formatter(v)) 192 193 p := &A{} 194 s := fmt.Sprintf("%# v", Formatter([]*A{p, p})) 195 if strings.Contains(s, "CYCLIC") { 196 t.Errorf("Repeated address detected as cyclic reference:\n%s", s) 197 } 198 199 type R struct { 200 i int 201 *R 202 } 203 r := &R{ 204 i: 1, 205 R: &R{ 206 i: 2, 207 R: &R{ 208 i: 3, 209 }, 210 }, 211 } 212 r.R.R.R = r 213 t.Logf("Example longer cycle:\n%# v", Formatter(r)) 214 215 r = &R{ 216 i: 1, 217 R: &R{ 218 i: 2, 219 R: &R{ 220 i: 3, 221 R: &R{ 222 i: 4, 223 R: &R{ 224 i: 5, 225 R: &R{ 226 i: 6, 227 R: &R{ 228 i: 7, 229 R: &R{ 230 i: 8, 231 R: &R{ 232 i: 9, 233 R: &R{ 234 i: 10, 235 R: &R{ 236 i: 11, 237 }, 238 }, 239 }, 240 }, 241 }, 242 }, 243 }, 244 }, 245 }, 246 }, 247 } 248 // here be pirates 249 r.R.R.R.R.R.R.R.R.R.R.R = r 250 t.Logf("Example very long cycle:\n%# v", Formatter(r)) 251 252 i := &I{ 253 i: 1, 254 R: &I{ 255 i: 2, 256 R: &I{ 257 i: 3, 258 R: &I{ 259 i: 4, 260 R: &I{ 261 i: 5, 262 R: &I{ 263 i: 6, 264 R: &I{ 265 i: 7, 266 R: &I{ 267 i: 8, 268 R: &I{ 269 i: 9, 270 R: &I{ 271 i: 10, 272 R: &I{ 273 i: 11, 274 }, 275 }, 276 }, 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 }, 284 } 285 iv := i.I().I().I().I().I().I().I().I().I().I() 286 *iv = *i 287 t.Logf("Example long interface cycle:\n%# v", Formatter(i)) 288} 289