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