| package pretty |
| |
| import ( |
| "fmt" |
| "io" |
| "strings" |
| "testing" |
| "unsafe" |
| ) |
| |
| type test struct { |
| v interface{} |
| s string |
| } |
| |
| type passtest struct { |
| v interface{} |
| f, s string |
| } |
| |
| type LongStructTypeName struct { |
| longFieldName interface{} |
| otherLongFieldName interface{} |
| } |
| |
| type SA struct { |
| t *T |
| v T |
| } |
| |
| type T struct { |
| x, y int |
| } |
| |
| type F int |
| |
| func (f F) Format(s fmt.State, c rune) { |
| fmt.Fprintf(s, "F(%d)", int(f)) |
| } |
| |
| type Stringer struct{ i int } |
| |
| func (s *Stringer) String() string { return "foo" } |
| |
| var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" |
| |
| var passthrough = []passtest{ |
| {1, "%d", "1"}, |
| {"a", "%s", "a"}, |
| {&Stringer{}, "%s", "foo"}, |
| } |
| |
| func TestPassthrough(t *testing.T) { |
| for _, tt := range passthrough { |
| s := fmt.Sprintf(tt.f, Formatter(tt.v)) |
| if tt.s != s { |
| t.Errorf("expected %q", tt.s) |
| t.Errorf("got %q", s) |
| t.Errorf("expraw\n%s", tt.s) |
| t.Errorf("gotraw\n%s", s) |
| } |
| } |
| } |
| |
| type StructWithPrivateFields struct { |
| A string |
| b string |
| } |
| |
| func NewStructWithPrivateFields(a string) StructWithPrivateFields { |
| return StructWithPrivateFields{a, "fixedb"} |
| } |
| |
| func (s StructWithPrivateFields) GoString() string { |
| return fmt.Sprintf("NewStructWithPrivateFields(%q)", s.A) |
| } |
| |
| var gosyntax = []test{ |
| {nil, `nil`}, |
| {"", `""`}, |
| {"a", `"a"`}, |
| {1, "int(1)"}, |
| {1.0, "float64(1)"}, |
| {[]int(nil), "[]int(nil)"}, |
| {[0]int{}, "[0]int{}"}, |
| {complex(1, 0), "(1+0i)"}, |
| //{make(chan int), "(chan int)(0x1234)"}, |
| {unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("unsafe.Pointer(0x%02x)", uintptr(unsafe.Pointer(&long)))}, |
| {func(int) {}, "func(int) {...}"}, |
| {map[string]string{"a": "a", "b": "b"}, "map[string]string{\"a\":\"a\", \"b\":\"b\"}"}, |
| {map[int]int{1: 1}, "map[int]int{1:1}"}, |
| {int32(1), "int32(1)"}, |
| {io.EOF, `&errors.errorString{s:"EOF"}`}, |
| {[]string{"a"}, `[]string{"a"}`}, |
| { |
| []string{long}, |
| `[]string{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"}`, |
| }, |
| {F(5), "pretty.F(5)"}, |
| { NewStructWithPrivateFields("foo"), `NewStructWithPrivateFields("foo")`}, |
| { |
| SA{&T{1, 2}, T{3, 4}}, |
| `pretty.SA{ |
| t: &pretty.T{x:1, y:2}, |
| v: pretty.T{x:3, y:4}, |
| }`, |
| }, |
| { |
| map[int][]byte{1: {}}, |
| `map[int][]uint8{ |
| 1: {}, |
| }`, |
| }, |
| { |
| map[int]T{1: {}}, |
| `map[int]pretty.T{ |
| 1: {}, |
| }`, |
| }, |
| { |
| long, |
| `"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"`, |
| }, |
| { |
| LongStructTypeName{ |
| longFieldName: LongStructTypeName{}, |
| otherLongFieldName: long, |
| }, |
| `pretty.LongStructTypeName{ |
| longFieldName: pretty.LongStructTypeName{}, |
| otherLongFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", |
| }`, |
| }, |
| { |
| &LongStructTypeName{ |
| longFieldName: &LongStructTypeName{}, |
| otherLongFieldName: (*LongStructTypeName)(nil), |
| }, |
| `&pretty.LongStructTypeName{ |
| longFieldName: &pretty.LongStructTypeName{}, |
| otherLongFieldName: (*pretty.LongStructTypeName)(nil), |
| }`, |
| }, |
| { |
| []LongStructTypeName{ |
| {nil, nil}, |
| {3, 3}, |
| {long, nil}, |
| }, |
| `[]pretty.LongStructTypeName{ |
| {}, |
| { |
| longFieldName: int(3), |
| otherLongFieldName: int(3), |
| }, |
| { |
| longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", |
| otherLongFieldName: nil, |
| }, |
| }`, |
| }, |
| { |
| []interface{}{ |
| LongStructTypeName{nil, nil}, |
| []byte{1, 2, 3}, |
| T{3, 4}, |
| LongStructTypeName{long, nil}, |
| }, |
| `[]interface {}{ |
| pretty.LongStructTypeName{}, |
| []uint8{0x1, 0x2, 0x3}, |
| pretty.T{x:3, y:4}, |
| pretty.LongStructTypeName{ |
| longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", |
| otherLongFieldName: nil, |
| }, |
| }`, |
| }, |
| } |
| |
| func TestGoSyntax(t *testing.T) { |
| for _, tt := range gosyntax { |
| s := fmt.Sprintf("%# v", Formatter(tt.v)) |
| if tt.s != s { |
| t.Errorf("expected %q", tt.s) |
| t.Errorf("got %q", s) |
| t.Errorf("expraw\n%s", tt.s) |
| t.Errorf("gotraw\n%s", s) |
| } |
| } |
| } |
| |
| type I struct { |
| i int |
| R interface{} |
| } |
| |
| func (i *I) I() *I { return i.R.(*I) } |
| |
| func TestCycle(t *testing.T) { |
| type A struct{ *A } |
| v := &A{} |
| v.A = v |
| |
| // panics from stack overflow without cycle detection |
| t.Logf("Example cycle:\n%# v", Formatter(v)) |
| |
| p := &A{} |
| s := fmt.Sprintf("%# v", Formatter([]*A{p, p})) |
| if strings.Contains(s, "CYCLIC") { |
| t.Errorf("Repeated address detected as cyclic reference:\n%s", s) |
| } |
| |
| type R struct { |
| i int |
| *R |
| } |
| r := &R{ |
| i: 1, |
| R: &R{ |
| i: 2, |
| R: &R{ |
| i: 3, |
| }, |
| }, |
| } |
| r.R.R.R = r |
| t.Logf("Example longer cycle:\n%# v", Formatter(r)) |
| |
| r = &R{ |
| i: 1, |
| R: &R{ |
| i: 2, |
| R: &R{ |
| i: 3, |
| R: &R{ |
| i: 4, |
| R: &R{ |
| i: 5, |
| R: &R{ |
| i: 6, |
| R: &R{ |
| i: 7, |
| R: &R{ |
| i: 8, |
| R: &R{ |
| i: 9, |
| R: &R{ |
| i: 10, |
| R: &R{ |
| i: 11, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| // here be pirates |
| r.R.R.R.R.R.R.R.R.R.R.R = r |
| t.Logf("Example very long cycle:\n%# v", Formatter(r)) |
| |
| i := &I{ |
| i: 1, |
| R: &I{ |
| i: 2, |
| R: &I{ |
| i: 3, |
| R: &I{ |
| i: 4, |
| R: &I{ |
| i: 5, |
| R: &I{ |
| i: 6, |
| R: &I{ |
| i: 7, |
| R: &I{ |
| i: 8, |
| R: &I{ |
| i: 9, |
| R: &I{ |
| i: 10, |
| R: &I{ |
| i: 11, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| iv := i.I().I().I().I().I().I().I().I().I().I() |
| *iv = *i |
| t.Logf("Example long interface cycle:\n%# v", Formatter(i)) |
| } |