github.com/kortschak/utter@v1.5.0/spew_test.go (about)

     1  /*
     2   * Copyright (c) 2013 Dave Collins <dave@davec.name>
     3   * Copyright (c) 2015 Dan Kortschak <dan.kortschak@adelaide.edu.au>
     4   *
     5   * Permission to use, copy, modify, and distribute this software for any
     6   * purpose with or without fee is hereby granted, provided that the above
     7   * copyright notice and this permission notice appear in all copies.
     8   *
     9   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    10   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    11   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    12   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    13   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    14   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    15   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    16   */
    17  
    18  package utter_test
    19  
    20  import (
    21  	"bytes"
    22  	"fmt"
    23  	"testing"
    24  
    25  	"github.com/kortschak/utter"
    26  )
    27  
    28  // utterFunc is used to identify which public function of the utter package or
    29  // ConfigState a test applies to.
    30  type utterFunc int
    31  
    32  const (
    33  	fCSFdump utterFunc = iota
    34  	fCSSdump
    35  	fSdump
    36  )
    37  
    38  // Map of utterFunc values to names for pretty printing.
    39  var utterFuncStrings = map[utterFunc]string{
    40  	fCSFdump: "ConfigState.Fdump",
    41  	fCSSdump: "ConfigState.Sdump",
    42  	fSdump:   "utter.Sdump",
    43  }
    44  
    45  func (f utterFunc) String() string {
    46  	if s, ok := utterFuncStrings[f]; ok {
    47  		return s
    48  	}
    49  	return fmt.Sprintf("Unknown utterFunc (%d)", int(f))
    50  }
    51  
    52  // utterTest is used to describe a test to be performed against the public
    53  // functions of the utter package or ConfigState.
    54  type utterTest struct {
    55  	cs   *utter.ConfigState
    56  	f    utterFunc
    57  	in   interface{}
    58  	want string
    59  }
    60  
    61  // utterTests houses the tests to be performed against the public functions of
    62  // the utter package and ConfigState.
    63  //
    64  // These tests are only intended to ensure the public functions are exercised
    65  // and are intentionally not exhaustive of types.  The exhaustive type
    66  // tests are handled in the dump and format tests.
    67  var utterTests []utterTest
    68  
    69  func initSpewTests() {
    70  	// Config states with various settings.
    71  	scsDefault := utter.NewDefaultConfig()
    72  
    73  	// Byte slice without comments.
    74  	noComDefault := utter.NewDefaultConfig()
    75  	noComDefault.CommentBytes = false
    76  
    77  	// Pointer comments.
    78  	comPtrDefault := utter.NewDefaultConfig()
    79  	comPtrDefault.CommentPointers = true
    80  
    81  	// Byte slice with 8 columns.
    82  	bs8Default := utter.NewDefaultConfig()
    83  	bs8Default.BytesWidth = 8
    84  
    85  	// Numeric slice with 4 columns.
    86  	num4elideDefault := utter.NewDefaultConfig()
    87  	num4elideDefault.ElideType = true
    88  	num4elideDefault.NumericWidth = 4
    89  
    90  	// String slice with 4 columns.
    91  	string4elideDefault := utter.NewDefaultConfig()
    92  	string4elideDefault.ElideType = true
    93  	string4elideDefault.StringWidth = 4
    94  
    95  	// One line slice.
    96  	oneElideDefault := utter.NewDefaultConfig()
    97  	oneElideDefault.ElideType = true
    98  	oneElideDefault.NumericWidth = 0
    99  	oneElideDefault.StringWidth = 0
   100  
   101  	// Ignore unexported fields.
   102  	ignUnexDefault := utter.NewDefaultConfig()
   103  	ignUnexDefault.IgnoreUnexported = true
   104  
   105  	// Remove local package prefix.
   106  	elideLocalDefault := utter.NewDefaultConfig()
   107  	elideLocalDefault.LocalPackage = "utter_test"
   108  
   109  	// Elide implicit types.
   110  	elideTypeDefault := utter.NewDefaultConfig()
   111  	elideTypeDefault.ElideType = true
   112  
   113  	// AvoidEscape.
   114  	avoidEscape := utter.NewDefaultConfig()
   115  	avoidEscape.SortKeys = true
   116  	avoidEscape.Quoting = utter.AvoidEscapes
   117  
   118  	// AvoidEscape|Force.
   119  	avoidEscapeForce := utter.NewDefaultConfig()
   120  	avoidEscapeForce.SortKeys = true
   121  	avoidEscapeForce.Quoting = utter.AvoidEscapes | utter.Force
   122  
   123  	// Backquote.
   124  	backquote := utter.NewDefaultConfig()
   125  	backquote.SortKeys = true
   126  	backquote.Quoting = utter.Backquote
   127  
   128  	var (
   129  		np  *int
   130  		nip = new(interface{})
   131  		nm  map[int]int
   132  		ns  []int
   133  	)
   134  
   135  	v := new(int)
   136  	*v = 10
   137  	s := struct{ *int }{v}
   138  	sp := &s
   139  	spp := &sp
   140  
   141  	c := []interface{}{5, 5, nil, nil}
   142  	c[2] = &c[0]
   143  	c[3] = &c[1]
   144  
   145  	d := &struct {
   146  		a [2]int
   147  		p *int
   148  	}{}
   149  	d.a[1] = 10
   150  	d.p = &d.a[1]
   151  
   152  	type cs struct{ *cs }
   153  	var cyc cs
   154  	cyc.cs = &cyc
   155  
   156  	m := map[int][]interface{}{1: c}
   157  
   158  	type b map[string]interface{}
   159  
   160  	utterTests = []utterTest{
   161  		{scsDefault, fCSFdump, int8(127), "int8(127)\n"},
   162  		{scsDefault, fCSSdump, uint8(64), "uint8(0x40)\n"},
   163  		{scsDefault, fSdump, complex(-10, -20), "complex128(-10-20i)\n"},
   164  		{noComDefault, fCSFdump, []byte{1, 2, 3, 4, 5, 0},
   165  			"[]uint8{\n 0x01, 0x02, 0x03, 0x04, 0x05, 0x00,\n}\n",
   166  		},
   167  		{comPtrDefault, fCSFdump, &np, fmt.Sprintf("&(*int) /*%p*/ (nil)\n", &np)},
   168  		{comPtrDefault, fCSFdump, nip, fmt.Sprintf("&interface{} /*%p*/ (nil)\n", nip)},
   169  		{comPtrDefault, fCSFdump, &nm, fmt.Sprintf("&map[int]int /*%p*/ (nil)\n", &nm)},
   170  		{comPtrDefault, fCSFdump, &ns, fmt.Sprintf("&[]int /*%p*/ (nil)\n", &ns)},
   171  		{comPtrDefault, fCSFdump, s, fmt.Sprintf("struct { *int }{\n int: &int /*%p*/ (10),\n}\n", v)},
   172  		{comPtrDefault, fCSFdump, sp, fmt.Sprintf("&struct { *int } /*%p*/ {\n int: &int /*%p*/ (10),\n}\n", sp, v)},
   173  		{comPtrDefault, fCSFdump, spp, fmt.Sprintf("&&struct { *int } /*%p->%p*/ {\n int: &int /*%p*/ (10),\n}\n", spp, sp, v)},
   174  		{comPtrDefault, fCSFdump, c, fmt.Sprintf("[]interface{}{\n"+
   175  			" int( /*%p*/ 5),\n int( /*%p*/ 5),\n"+
   176  			" (*interface{}) /*%[1]p*/ (<already shown>),\n &int /*%p*/ (5),\n}\n", &c[0], &c[1])},
   177  		{comPtrDefault, fCSFdump, d, fmt.Sprintf("&struct { a [2]int; p *int } /*%p*/ {\n"+
   178  			" a: [2]int{\n  int(0),\n"+
   179  			"  int( /*%p*/ 10),\n },\n"+
   180  			" p: &int /*%[2]p*/ (10),\n}\n", d, &d.a[1])},
   181  		{comPtrDefault, fCSFdump, &cyc, fmt.Sprintf("&utter_test.cs /*%p*/ {\n"+
   182  			" cs: (*utter_test.cs) /*%[1]p*/ (<already shown>),\n}\n", cyc.cs)},
   183  		{comPtrDefault, fCSFdump, m, fmt.Sprintf("map[int][]interface{}{\n"+
   184  			" int(1): []interface{}{\n"+
   185  			"  int( /*%p*/ 5),\n"+
   186  			"  int( /*%p*/ 5),\n"+
   187  			"  (*interface{}) /*%[1]p*/ (<already shown>),\n"+
   188  			"  &int /*%p*/ (5),\n },\n}\n", &c[0], &c[1])},
   189  		{bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3}, "[]uint8{\n" +
   190  			" 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" +
   191  			" 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, 0x03, /* */ // |.......|\n}\n",
   192  		},
   193  		{bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2}, "[]uint8{\n" +
   194  			" 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" +
   195  			" 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, /*       */ // |......|\n}\n",
   196  		},
   197  		{bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1}, "[]uint8{\n" +
   198  			" 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" +
   199  			" 0x03, 0x04, 0x05, 0x00, 0x01, /*             */ // |.....|\n}\n",
   200  		},
   201  		{bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0}, "[]uint8{\n" +
   202  			" 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, 0x02, // |........|\n" +
   203  			" 0x03, 0x04, 0x05, 0x00, /*                   */ // |....|\n}\n",
   204  		},
   205  		{bs8Default, fCSFdump, []byte{1, 2, 3, 4, 5, 0, 1}, "[]uint8{\n" +
   206  			" 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x01, // |.......|\n}\n",
   207  		},
   208  		{ignUnexDefault, fCSFdump, Foo{Bar{flag: 1}, map[interface{}]interface{}{"one": true}},
   209  			"utter_test.Foo{\n ExportedField: map[interface{}]interface{}{\n  string(\"one\"): bool(true),\n },\n}\n",
   210  		},
   211  		{elideLocalDefault, fCSFdump, Foo{Bar{flag: 1}, map[interface{}]interface{}{"one": true}},
   212  			"Foo{\n unexportedField: Bar{\n  flag: Flag(1),\n  data: uintptr(0),\n },\n ExportedField: map[interface{}]interface{}{\n  string(\"one\"): bool(true),\n },\n}\n",
   213  		},
   214  		{elideLocalDefault, fCSFdump, map[cs]cs{{}: {}},
   215  			"map[cs]cs{\n cs{\n  cs: (*cs)(nil),\n }: cs{\n  cs: (*cs)(nil),\n },\n}\n",
   216  		},
   217  		{elideLocalDefault, fCSFdump, [2]cs{},
   218  			"[2]cs{\n cs{\n  cs: (*cs)(nil),\n },\n cs{\n  cs: (*cs)(nil),\n },\n}\n",
   219  		},
   220  		{elideLocalDefault, fCSFdump, []cs{{}},
   221  			"[]cs{\n cs{\n  cs: (*cs)(nil),\n },\n}\n",
   222  		},
   223  		{elideLocalDefault, fCSFdump, chan cs(nil),
   224  			"chan cs(nil)\n",
   225  		},
   226  		{elideLocalDefault, fCSFdump, chan<- cs(nil),
   227  			"chan<- cs(nil)\n",
   228  		},
   229  		{elideLocalDefault, fCSFdump, b{"one": b{"two": "three"}}, "b{\n string(\"one\"): b{\n  string(\"two\"): string(\"three\"),\n },\n}\n"},
   230  		{elideTypeDefault, fCSFdump, float64(1), "1.0\n"},
   231  		{elideTypeDefault, fCSFdump, float32(1), "float32(1)\n"},
   232  		{elideTypeDefault, fCSFdump, int(1), "1\n"},
   233  		{elideTypeDefault, fCSFdump, []interface{}{true, 1.0, float32(1), "one", 1, 'a'},
   234  			"[]interface{}{\n true,\n 1.0,\n float32(1),\n \"one\",\n 1,\n int32(97),\n}\n",
   235  		},
   236  		{elideTypeDefault, fCSFdump, Foo{Bar{flag: 1}, map[interface{}]interface{}{"one": true}}, "utter_test.Foo{\n" +
   237  			" unexportedField: utter_test.Bar{\n  flag: 1,\n  data: 0,\n },\n" +
   238  			" ExportedField: map[interface{}]interface{}{\n  \"one\": true,\n },\n}\n",
   239  		},
   240  		{elideTypeDefault, fCSFdump, map[interface{}]interface{}{"one": nil}, "map[interface{}]interface{}{\n \"one\": nil,\n}\n"},
   241  		{elideTypeDefault, fCSFdump, float32(1), "float32(1)\n"},
   242  		{elideTypeDefault, fCSFdump, float64(1), "1.0\n"},
   243  		{elideTypeDefault, fCSFdump, func() *float64 { f := 1.0; return &f }(), "&float64(1)\n"},
   244  		{elideTypeDefault, fCSFdump, []float32{1, 2, 3, 4, 5}, "[]float32{\n 1.0,\n 2.0,\n 3.0,\n 4.0,\n 5.0,\n}\n"},
   245  		{elideTypeDefault, fCSFdump, map[struct{ int }]struct{ int }{{1}: {1}}, "map[struct { int }]struct { int }{\n {\n  int: 1,\n }: {\n  int: 1,\n },\n}\n"},
   246  		{elideTypeDefault, fCSFdump, map[interface{}]struct{ int }{struct{ int }{1}: {1}}, "map[interface{}]struct { int }{\n struct { int }{\n  int: 1,\n }: {\n  int: 1,\n },\n}\n"},
   247  		{elideTypeDefault, fCSFdump, map[struct{ int }]interface{}{{1}: struct{ int }{1}}, "map[struct { int }]interface{}{\n {\n  int: 1,\n }: struct { int }{\n  int: 1,\n },\n}\n"},
   248  		{elideTypeDefault, fCSFdump, []struct{ int }{{1}}, "[]struct { int }{\n {\n  int: 1,\n },\n}\n"},
   249  		{elideTypeDefault, fCSFdump, []interface{}{struct{ int }{1}}, "[]interface{}{\n struct { int }{\n  int: 1,\n },\n}\n"},
   250  		{elideTypeDefault, fCSFdump, b{"one": b{"two": "three"}}, "utter_test.b{\n \"one\": utter_test.b{\n  \"two\": \"three\",\n },\n}\n"},
   251  		{num4elideDefault, fCSFdump, []interface{}{
   252  			[]int{1, 2, 3, 4},
   253  			[]uint{1, 2, 3, 4, 5},
   254  			[]float32{1, 2, 3, 4, 5, 6, 7, 8, 9},
   255  			[]bool{true, false, true},
   256  			[]complex128{1 + 1i, 0, 1 - 1i, 2, 4, 8}},
   257  			"[]interface{}{\n" +
   258  				" []int{\n  1, 2, 3, 4,\n },\n" +
   259  				" []uint{\n  0x1, 0x2, 0x3, 0x4,\n  0x5,\n },\n" +
   260  				" []float32{\n  1.0, 2.0, 3.0, 4.0,\n  5.0, 6.0, 7.0, 8.0,\n  9.0,\n },\n" +
   261  				" []bool{\n  true, false, true,\n },\n" +
   262  				" []complex128{\n  1+1i, 0+0i, 1-1i, 2+0i,\n  4+0i, 8+0i,\n },\n}\n",
   263  		},
   264  		{num4elideDefault, fCSFdump, [][]int{
   265  			{1, 2, 3},
   266  			{1, 2, 3, 4},
   267  			{1, 2, 3, 4, 5}},
   268  			"[][]int{\n" +
   269  				" {\n  1, 2, 3,\n },\n" +
   270  				" {\n  1, 2, 3, 4,\n },\n" +
   271  				" {\n  1, 2, 3, 4,\n  5,\n },\n}\n",
   272  		},
   273  		{string4elideDefault, fCSFdump, []string{"one", "two", "three", "four", "five"},
   274  			"[]string{\n \"one\", \"two\", \"three\", \"four\",\n \"five\",\n}\n",
   275  		},
   276  		{oneElideDefault, fCSFdump, []interface{}{
   277  			[]int{1, 2, 3, 4},
   278  			[]string{"one", "two", "three", "four", "five"}},
   279  			"[]interface{}{\n" +
   280  				" []int{1, 2, 3, 4},\n" +
   281  				" []string{\"one\", \"two\", \"three\", \"four\", \"five\"},\n}\n",
   282  		},
   283  		{avoidEscape, fCSFdump, map[string]string{
   284  			"one":         "\no\nn\ne\n",
   285  			"\nt\nw\no\n": "two",
   286  			"three":       "`t\th\tr\te\te`",
   287  			"codeblock":   "```\ncode\n```\n",
   288  		}, "map[string]string{\n string(`\nt\nw\no\n`): string(\"two\"),\n string(\"codeblock\"): string(\"```\\ncode\\n```\\n\"),\n string(\"one\"): string(`\no\nn\ne\n`),\n string(\"three\"): string(\"`t\\th\\tr\\te\\te`\"),\n}\n"},
   289  		{avoidEscapeForce, fCSFdump, map[string]string{
   290  			"one":         "\no\nn\ne\n",
   291  			"\nt\nw\no\n": "two",
   292  			"three":       "`t\th\tr\te\te`",
   293  			"codeblock":   "```\ncode\n```\n",
   294  		}, "map[string]string{\n string(`\nt\nw\no\n`): string(\"two\"),\n string(\"codeblock\"): string(\"```\"+`\ncode\n`+\"```\"+`\n`),\n string(\"one\"): string(`\no\nn\ne\n`),\n string(\"three\"): string(\"`\"+`t\th\tr\te\te`+\"`\"),\n}\n"},
   295  		{backquote, fCSFdump, map[string]string{
   296  			"one":                   "\no\nn\ne\n",
   297  			"\nt\nw\no\n":           "two",
   298  			"three":                 "`t\th\tr\te\te`",
   299  			"backquote":             "`",
   300  			"tabbackquote":          "\t`",
   301  			"backquotetab":          "`\t",
   302  			"tabbackquotetab":       "\t`\t",
   303  			"backquotetabbackquote": "`\t`",
   304  			"codeblock":             "```\ncode\n```\n",
   305  		}, "map[string]string{\n string(`\nt\nw\no\n`): string(`two`),\n string(`backquote`): string(\"`\"),\n string(`backquotetab`): string(\"`\"+`\t`),\n string(`backquotetabbackquote`): string(\"`\"+`\t`+\"`\"),\n string(`codeblock`): string(\"```\"+`\ncode\n`+\"```\"+`\n`),\n string(`one`): string(`\no\nn\ne\n`),\n string(`tabbackquote`): string(`\t`+\"`\"),\n string(`tabbackquotetab`): string(`\t`+\"`\"+`\t`),\n string(`three`): string(\"`\"+`t\th\tr\te\te`+\"`\"),\n}\n"},
   306  	}
   307  }
   308  
   309  // TestSpew executes all of the tests described by utterTests.
   310  func TestSpew(t *testing.T) {
   311  	initSpewTests()
   312  
   313  	t.Logf("Running %d tests", len(utterTests))
   314  	for i, test := range utterTests {
   315  		buf := new(bytes.Buffer)
   316  		switch test.f {
   317  		case fCSFdump:
   318  			test.cs.Fdump(buf, test.in)
   319  
   320  		case fCSSdump:
   321  			str := test.cs.Sdump(test.in)
   322  			buf.WriteString(str)
   323  
   324  		case fSdump:
   325  			str := utter.Sdump(test.in)
   326  			buf.WriteString(str)
   327  
   328  		default:
   329  			t.Errorf("%v #%d unrecognized function", test.f, i)
   330  			continue
   331  		}
   332  		s := buf.String()
   333  		if test.want != s {
   334  			t.Errorf("ConfigState #%d\n got: %q\nwant: %q", i, s, test.want)
   335  			continue
   336  		}
   337  	}
   338  }