github.com/kr/pretty@v0.3.1/formatter_test.go (about)

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