github.com/influx6/npkg@v0.8.8/ntext/ntabwriter/tabwriter_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ntabwriter_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"testing"
    13  
    14  	. "github.com/influx6/npkg/ntext/ntabwriter"
    15  )
    16  
    17  type buffer struct {
    18  	a []byte
    19  }
    20  
    21  func (b *buffer) init(n int) { b.a = make([]byte, 0, n) }
    22  
    23  func (b *buffer) clear() { b.a = b.a[0:0] }
    24  
    25  func (b *buffer) Write(buf []byte) (written int, err error) {
    26  	n := len(b.a)
    27  	m := len(buf)
    28  	if n+m <= cap(b.a) {
    29  		b.a = b.a[0 : n+m]
    30  		for i := 0; i < m; i++ {
    31  			b.a[n+i] = buf[i]
    32  		}
    33  	} else {
    34  		panic("buffer.Write: buffer too small")
    35  	}
    36  	return len(buf), nil
    37  }
    38  
    39  func (b *buffer) String() string { return string(b.a) }
    40  
    41  func write(t *testing.T, testname string, w *Writer, src string) {
    42  	written, err := io.WriteString(w, src)
    43  	if err != nil {
    44  		t.Errorf("--- test: %s\n--- src:\n%q\n--- write error: %v\n", testname, src, err)
    45  	}
    46  	if written != len(src) {
    47  		t.Errorf("--- test: %s\n--- src:\n%q\n--- written = %d, len(src) = %d\n", testname, src, written, len(src))
    48  	}
    49  }
    50  
    51  func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
    52  	err := w.Flush()
    53  	if err != nil {
    54  		t.Errorf("--- test: %s\n--- src:\n%q\n--- flush error: %v\n", testname, src, err)
    55  	}
    56  
    57  	res := b.String()
    58  	if res != expected {
    59  		t.Errorf("--- test: %s\n--- src:\n%q\n--- found:\n%q\n--- expected:\n%q\n", testname, src, res, expected)
    60  	}
    61  }
    62  
    63  func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
    64  	var b buffer
    65  	b.init(1000)
    66  
    67  	var w Writer
    68  	w.Init(&b, minwidth, tabwidth, padding, padchar, flags)
    69  
    70  	// write all at once
    71  	title := testname + " (written all at once)"
    72  	b.clear()
    73  	write(t, title, &w, src)
    74  	verify(t, title, &w, &b, src, expected)
    75  
    76  	// write byte-by-byte
    77  	title = testname + " (written byte-by-byte)"
    78  	b.clear()
    79  	for i := 0; i < len(src); i++ {
    80  		write(t, title, &w, src[i:i+1])
    81  	}
    82  	verify(t, title, &w, &b, src, expected)
    83  
    84  	// write using Fibonacci slice sizes
    85  	title = testname + " (written in fibonacci slices)"
    86  	b.clear()
    87  	for i, d := 0, 0; i < len(src); {
    88  		write(t, title, &w, src[i:i+d])
    89  		i, d = i+d, d+1
    90  		if i+d > len(src) {
    91  			d = len(src) - i
    92  		}
    93  	}
    94  	verify(t, title, &w, &b, src, expected)
    95  }
    96  
    97  var tests = []struct {
    98  	testname                    string
    99  	minwidth, tabwidth, padding int
   100  	padchar                     byte
   101  	flags                       uint
   102  	src, expected               string
   103  }{
   104  	{
   105  		"1a",
   106  		8, 0, 1, '.', 0,
   107  		"",
   108  		"",
   109  	},
   110  
   111  	{
   112  		"1a debug",
   113  		8, 0, 1, '.', Debug,
   114  		"",
   115  		"",
   116  	},
   117  
   118  	{
   119  		"1b esc stripped",
   120  		8, 0, 1, '.', StripEscape,
   121  		"\xff\xff",
   122  		"",
   123  	},
   124  
   125  	{
   126  		"1b esc",
   127  		8, 0, 1, '.', 0,
   128  		"\xff\xff",
   129  		"\xff\xff",
   130  	},
   131  
   132  	{
   133  		"1c esc stripped",
   134  		8, 0, 1, '.', StripEscape,
   135  		"\xff\t\xff",
   136  		"\t",
   137  	},
   138  
   139  	{
   140  		"1c esc",
   141  		8, 0, 1, '.', 0,
   142  		"\xff\t\xff",
   143  		"\xff\t\xff",
   144  	},
   145  
   146  	{
   147  		"1d esc stripped",
   148  		8, 0, 1, '.', StripEscape,
   149  		"\xff\"foo\t\n\tbar\"\xff",
   150  		"\"foo\t\n\tbar\"",
   151  	},
   152  
   153  	{
   154  		"1d esc",
   155  		8, 0, 1, '.', 0,
   156  		"\xff\"foo\t\n\tbar\"\xff",
   157  		"\xff\"foo\t\n\tbar\"\xff",
   158  	},
   159  
   160  	{
   161  		"1e esc stripped",
   162  		8, 0, 1, '.', StripEscape,
   163  		"abc\xff\tdef", // unterminated escape
   164  		"abc\tdef",
   165  	},
   166  
   167  	{
   168  		"1e esc",
   169  		8, 0, 1, '.', 0,
   170  		"abc\xff\tdef", // unterminated escape
   171  		"abc\xff\tdef",
   172  	},
   173  
   174  	{
   175  		"2",
   176  		8, 0, 1, '.', 0,
   177  		"\n\n\n",
   178  		"\n\n\n",
   179  	},
   180  
   181  	{
   182  		"3",
   183  		8, 0, 1, '.', 0,
   184  		"a\nb\nc",
   185  		"a\nb\nc",
   186  	},
   187  
   188  	{
   189  		"4a",
   190  		8, 0, 1, '.', 0,
   191  		"\t", // '\t' terminates an empty cell on last line - nothing to print
   192  		"",
   193  	},
   194  
   195  	{
   196  		"4b",
   197  		8, 0, 1, '.', AlignRight,
   198  		"\t", // '\t' terminates an empty cell on last line - nothing to print
   199  		"",
   200  	},
   201  
   202  	{
   203  		"5",
   204  		8, 0, 1, '.', 0,
   205  		"*\t*",
   206  		"*.......*",
   207  	},
   208  
   209  	{
   210  		"5b",
   211  		8, 0, 1, '.', 0,
   212  		"*\t*\n",
   213  		"*.......*\n",
   214  	},
   215  
   216  	{
   217  		"5c",
   218  		8, 0, 1, '.', 0,
   219  		"*\t*\t",
   220  		"*.......*",
   221  	},
   222  
   223  	{
   224  		"5c debug",
   225  		8, 0, 1, '.', Debug,
   226  		"*\t*\t",
   227  		"*.......|*",
   228  	},
   229  
   230  	{
   231  		"5d",
   232  		8, 0, 1, '.', AlignRight,
   233  		"*\t*\t",
   234  		".......**",
   235  	},
   236  
   237  	{
   238  		"6",
   239  		8, 0, 1, '.', 0,
   240  		"\t\n",
   241  		"........\n",
   242  	},
   243  
   244  	{
   245  		"7a",
   246  		8, 0, 1, '.', 0,
   247  		"a) foo",
   248  		"a) foo",
   249  	},
   250  
   251  	{
   252  		"7b",
   253  		8, 0, 1, ' ', 0,
   254  		"b) foo\tbar",
   255  		"b) foo  bar",
   256  	},
   257  
   258  	{
   259  		"7c",
   260  		8, 0, 1, '.', 0,
   261  		"c) foo\tbar\t",
   262  		"c) foo..bar",
   263  	},
   264  
   265  	{
   266  		"7d",
   267  		8, 0, 1, '.', 0,
   268  		"d) foo\tbar\n",
   269  		"d) foo..bar\n",
   270  	},
   271  
   272  	{
   273  		"7e",
   274  		8, 0, 1, '.', 0,
   275  		"e) foo\tbar\t\n",
   276  		"e) foo..bar.....\n",
   277  	},
   278  
   279  	{
   280  		"7f",
   281  		8, 0, 1, '.', FilterHTML,
   282  		"f) f&lt;o\t<b>bar</b>\t\n",
   283  		"f) f&lt;o..<b>bar</b>.....\n",
   284  	},
   285  
   286  	{
   287  		"7g",
   288  		8, 0, 1, '.', FilterHTML,
   289  		"g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
   290  		"g) f&lt;o..<b>bar</b>..... non-terminated entity &amp",
   291  	},
   292  
   293  	{
   294  		"7g debug",
   295  		8, 0, 1, '.', FilterHTML | Debug,
   296  		"g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
   297  		"g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp",
   298  	},
   299  
   300  	{
   301  		"8",
   302  		8, 0, 1, '*', 0,
   303  		"Hello, world!\n",
   304  		"Hello, world!\n",
   305  	},
   306  
   307  	{
   308  		"9a",
   309  		1, 0, 0, '.', 0,
   310  		"1\t2\t3\t4\n" +
   311  			"11\t222\t3333\t44444\n",
   312  
   313  		"1.2..3...4\n" +
   314  			"11222333344444\n",
   315  	},
   316  
   317  	{
   318  		"9b",
   319  		1, 0, 0, '.', FilterHTML,
   320  		"1\t2<!---\f--->\t3\t4\n" + // \f inside HTML is ignored
   321  			"11\t222\t3333\t44444\n",
   322  
   323  		"1.2<!---\f--->..3...4\n" +
   324  			"11222333344444\n",
   325  	},
   326  
   327  	{
   328  		"9c",
   329  		1, 0, 0, '.', 0,
   330  		"1\t2\t3\t4\f" + // \f causes a newline and flush
   331  			"11\t222\t3333\t44444\n",
   332  
   333  		"1234\n" +
   334  			"11222333344444\n",
   335  	},
   336  
   337  	{
   338  		"9c debug",
   339  		1, 0, 0, '.', Debug,
   340  		"1\t2\t3\t4\f" + // \f causes a newline and flush
   341  			"11\t222\t3333\t44444\n",
   342  
   343  		"1|2|3|4\n" +
   344  			"---\n" +
   345  			"11|222|3333|44444\n",
   346  	},
   347  
   348  	{
   349  		"10a",
   350  		5, 0, 0, '.', 0,
   351  		"1\t2\t3\t4\n",
   352  		"1....2....3....4\n",
   353  	},
   354  
   355  	{
   356  		"10b",
   357  		5, 0, 0, '.', 0,
   358  		"1\t2\t3\t4\t\n",
   359  		"1....2....3....4....\n",
   360  	},
   361  
   362  	{
   363  		"11",
   364  		8, 0, 1, '.', 0,
   365  		"本\tb\tc\n" +
   366  			"aa\t\u672c\u672c\u672c\tcccc\tddddd\n" +
   367  			"aaa\tbbbb\n",
   368  
   369  		"本.......b.......c\n" +
   370  			"aa......本本本.....cccc....ddddd\n" +
   371  			"aaa.....bbbb\n",
   372  	},
   373  
   374  	{
   375  		"12a",
   376  		8, 0, 1, ' ', AlignRight,
   377  		"a\tè\tc\t\n" +
   378  			"aa\tèèè\tcccc\tddddd\t\n" +
   379  			"aaa\tèèèè\t\n",
   380  
   381  		"       a       è       c\n" +
   382  			"      aa     èèè    cccc   ddddd\n" +
   383  			"     aaa    èèèè\n",
   384  	},
   385  
   386  	{
   387  		"12b",
   388  		2, 0, 0, ' ', 0,
   389  		"a\tb\tc\n" +
   390  			"aa\tbbb\tcccc\n" +
   391  			"aaa\tbbbb\n",
   392  
   393  		"a  b  c\n" +
   394  			"aa bbbcccc\n" +
   395  			"aaabbbb\n",
   396  	},
   397  
   398  	{
   399  		"12c",
   400  		8, 0, 1, '_', 0,
   401  		"a\tb\tc\n" +
   402  			"aa\tbbb\tcccc\n" +
   403  			"aaa\tbbbb\n",
   404  
   405  		"a_______b_______c\n" +
   406  			"aa______bbb_____cccc\n" +
   407  			"aaa_____bbbb\n",
   408  	},
   409  
   410  	{
   411  		"13a",
   412  		4, 0, 1, '-', 0,
   413  		"4444\t日本語\t22\t1\t333\n" +
   414  			"999999999\t22\n" +
   415  			"7\t22\n" +
   416  			"\t\t\t88888888\n" +
   417  			"\n" +
   418  			"666666\t666666\t666666\t4444\n" +
   419  			"1\t1\t999999999\t0000000000\n",
   420  
   421  		"4444------日本語-22--1---333\n" +
   422  			"999999999-22\n" +
   423  			"7---------22\n" +
   424  			"------------------88888888\n" +
   425  			"\n" +
   426  			"666666-666666-666666----4444\n" +
   427  			"1------1------999999999-0000000000\n",
   428  	},
   429  
   430  	{
   431  		"13b",
   432  		4, 0, 3, '.', 0,
   433  		"4444\t333\t22\t1\t333\n" +
   434  			"999999999\t22\n" +
   435  			"7\t22\n" +
   436  			"\t\t\t88888888\n" +
   437  			"\n" +
   438  			"666666\t666666\t666666\t4444\n" +
   439  			"1\t1\t999999999\t0000000000\n",
   440  
   441  		"4444........333...22...1...333\n" +
   442  			"999999999...22\n" +
   443  			"7...........22\n" +
   444  			"....................88888888\n" +
   445  			"\n" +
   446  			"666666...666666...666666......4444\n" +
   447  			"1........1........999999999...0000000000\n",
   448  	},
   449  
   450  	{
   451  		"13c",
   452  		8, 8, 1, '\t', FilterHTML,
   453  		"4444\t333\t22\t1\t333\n" +
   454  			"999999999\t22\n" +
   455  			"7\t22\n" +
   456  			"\t\t\t88888888\n" +
   457  			"\n" +
   458  			"666666\t666666\t666666\t4444\n" +
   459  			"1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
   460  
   461  		"4444\t\t333\t22\t1\t333\n" +
   462  			"999999999\t22\n" +
   463  			"7\t\t22\n" +
   464  			"\t\t\t\t88888888\n" +
   465  			"\n" +
   466  			"666666\t666666\t666666\t\t4444\n" +
   467  			"1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
   468  	},
   469  
   470  	{
   471  		"14",
   472  		1, 0, 2, ' ', AlignRight,
   473  		".0\t.3\t2.4\t-5.1\t\n" +
   474  			"23.0\t12345678.9\t2.4\t-989.4\t\n" +
   475  			"5.1\t12.0\t2.4\t-7.0\t\n" +
   476  			".0\t0.0\t332.0\t8908.0\t\n" +
   477  			".0\t-.3\t456.4\t22.1\t\n" +
   478  			".0\t1.2\t44.4\t-13.3\t\t",
   479  
   480  		"    .0          .3    2.4    -5.1\n" +
   481  			"  23.0  12345678.9    2.4  -989.4\n" +
   482  			"   5.1        12.0    2.4    -7.0\n" +
   483  			"    .0         0.0  332.0  8908.0\n" +
   484  			"    .0         -.3  456.4    22.1\n" +
   485  			"    .0         1.2   44.4   -13.3",
   486  	},
   487  
   488  	{
   489  		"14 debug",
   490  		1, 0, 2, ' ', AlignRight | Debug,
   491  		".0\t.3\t2.4\t-5.1\t\n" +
   492  			"23.0\t12345678.9\t2.4\t-989.4\t\n" +
   493  			"5.1\t12.0\t2.4\t-7.0\t\n" +
   494  			".0\t0.0\t332.0\t8908.0\t\n" +
   495  			".0\t-.3\t456.4\t22.1\t\n" +
   496  			".0\t1.2\t44.4\t-13.3\t\t",
   497  
   498  		"    .0|          .3|    2.4|    -5.1|\n" +
   499  			"  23.0|  12345678.9|    2.4|  -989.4|\n" +
   500  			"   5.1|        12.0|    2.4|    -7.0|\n" +
   501  			"    .0|         0.0|  332.0|  8908.0|\n" +
   502  			"    .0|         -.3|  456.4|    22.1|\n" +
   503  			"    .0|         1.2|   44.4|   -13.3|",
   504  	},
   505  
   506  	{
   507  		"15a",
   508  		4, 0, 0, '.', 0,
   509  		"a\t\tb",
   510  		"a.......b",
   511  	},
   512  
   513  	{
   514  		"15b",
   515  		4, 0, 0, '.', DiscardEmptyColumns,
   516  		"a\t\tb", // htabs - do not discard column
   517  		"a.......b",
   518  	},
   519  
   520  	{
   521  		"15c",
   522  		4, 0, 0, '.', DiscardEmptyColumns,
   523  		"a\v\vb",
   524  		"a...b",
   525  	},
   526  
   527  	{
   528  		"15d",
   529  		4, 0, 0, '.', AlignRight | DiscardEmptyColumns,
   530  		"a\v\vb",
   531  		"...ab",
   532  	},
   533  
   534  	{
   535  		"16a",
   536  		100, 100, 0, '\t', 0,
   537  		"a\tb\t\td\n" +
   538  			"a\tb\t\td\te\n" +
   539  			"a\n" +
   540  			"a\tb\tc\td\n" +
   541  			"a\tb\tc\td\te\n",
   542  
   543  		"a\tb\t\td\n" +
   544  			"a\tb\t\td\te\n" +
   545  			"a\n" +
   546  			"a\tb\tc\td\n" +
   547  			"a\tb\tc\td\te\n",
   548  	},
   549  
   550  	{
   551  		"16b",
   552  		100, 100, 0, '\t', DiscardEmptyColumns,
   553  		"a\vb\v\vd\n" +
   554  			"a\vb\v\vd\ve\n" +
   555  			"a\n" +
   556  			"a\vb\vc\vd\n" +
   557  			"a\vb\vc\vd\ve\n",
   558  
   559  		"a\tb\td\n" +
   560  			"a\tb\td\te\n" +
   561  			"a\n" +
   562  			"a\tb\tc\td\n" +
   563  			"a\tb\tc\td\te\n",
   564  	},
   565  
   566  	{
   567  		"16b debug",
   568  		100, 100, 0, '\t', DiscardEmptyColumns | Debug,
   569  		"a\vb\v\vd\n" +
   570  			"a\vb\v\vd\ve\n" +
   571  			"a\n" +
   572  			"a\vb\vc\vd\n" +
   573  			"a\vb\vc\vd\ve\n",
   574  
   575  		"a\t|b\t||d\n" +
   576  			"a\t|b\t||d\t|e\n" +
   577  			"a\n" +
   578  			"a\t|b\t|c\t|d\n" +
   579  			"a\t|b\t|c\t|d\t|e\n",
   580  	},
   581  
   582  	{
   583  		"16c",
   584  		100, 100, 0, '\t', DiscardEmptyColumns,
   585  		"a\tb\t\td\n" + // hard tabs - do not discard column
   586  			"a\tb\t\td\te\n" +
   587  			"a\n" +
   588  			"a\tb\tc\td\n" +
   589  			"a\tb\tc\td\te\n",
   590  
   591  		"a\tb\t\td\n" +
   592  			"a\tb\t\td\te\n" +
   593  			"a\n" +
   594  			"a\tb\tc\td\n" +
   595  			"a\tb\tc\td\te\n",
   596  	},
   597  
   598  	{
   599  		"16c debug",
   600  		100, 100, 0, '\t', DiscardEmptyColumns | Debug,
   601  		"a\tb\t\td\n" + // hard tabs - do not discard column
   602  			"a\tb\t\td\te\n" +
   603  			"a\n" +
   604  			"a\tb\tc\td\n" +
   605  			"a\tb\tc\td\te\n",
   606  
   607  		"a\t|b\t|\t|d\n" +
   608  			"a\t|b\t|\t|d\t|e\n" +
   609  			"a\n" +
   610  			"a\t|b\t|c\t|d\n" +
   611  			"a\t|b\t|c\t|d\t|e\n",
   612  	},
   613  }
   614  
   615  func Test(t *testing.T) {
   616  	for _, e := range tests {
   617  		check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
   618  	}
   619  }
   620  
   621  type panicWriter struct{}
   622  
   623  func (panicWriter) Write([]byte) (int, error) {
   624  	panic("cannot write")
   625  }
   626  
   627  func wantPanicString(t *testing.T, want string) {
   628  	if e := recover(); e != nil {
   629  		got, ok := e.(string)
   630  		switch {
   631  		case !ok:
   632  			t.Errorf("got %v (%T), want panic string", e, e)
   633  		case got != want:
   634  			t.Errorf("wrong panic message: got %q, want %q", got, want)
   635  		}
   636  	}
   637  }
   638  
   639  func TestPanicDuringFlush(t *testing.T) {
   640  	defer wantPanicString(t, "tabwriter: panic during Flush")
   641  	var p panicWriter
   642  	w := new(Writer)
   643  	w.Init(p, 0, 0, 5, ' ', 0)
   644  	io.WriteString(w, "a")
   645  	w.Flush()
   646  	t.Errorf("failed to panic during Flush")
   647  }
   648  
   649  func TestPanicDuringWrite(t *testing.T) {
   650  	defer wantPanicString(t, "tabwriter: panic during Write")
   651  	var p panicWriter
   652  	w := new(Writer)
   653  	w.Init(p, 0, 0, 5, ' ', 0)
   654  	io.WriteString(w, "a\n\n") // the second \n triggers a call to w.Write and thus a panic
   655  	t.Errorf("failed to panic during Write")
   656  }
   657  
   658  func BenchmarkTable(b *testing.B) {
   659  	for _, w := range [...]int{1, 10, 100} {
   660  		// Build a line with w cells.
   661  		line := bytes.Repeat([]byte("a\t"), w)
   662  		line = append(line, '\n')
   663  		for _, h := range [...]int{10, 1000, 100000} {
   664  			b.Run(fmt.Sprintf("%dx%d", w, h), func(b *testing.B) {
   665  				b.Run("new", func(b *testing.B) {
   666  					b.ReportAllocs()
   667  					for i := 0; i < b.N; i++ {
   668  						w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings
   669  						// Write the line h times.
   670  						for j := 0; j < h; j++ {
   671  							w.Write(line)
   672  						}
   673  						w.Flush()
   674  					}
   675  				})
   676  
   677  				b.Run("reuse", func(b *testing.B) {
   678  					b.ReportAllocs()
   679  					w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings
   680  					for i := 0; i < b.N; i++ {
   681  						// Write the line h times.
   682  						for j := 0; j < h; j++ {
   683  							w.Write(line)
   684  						}
   685  						w.Flush()
   686  					}
   687  				})
   688  			})
   689  		}
   690  	}
   691  }
   692  
   693  func BenchmarkPyramid(b *testing.B) {
   694  	for _, x := range [...]int{10, 100, 1000} {
   695  		// Build a line with x cells.
   696  		line := bytes.Repeat([]byte("a\t"), x)
   697  		b.Run(fmt.Sprintf("%d", x), func(b *testing.B) {
   698  			b.ReportAllocs()
   699  			for i := 0; i < b.N; i++ {
   700  				w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings
   701  				// Write increasing prefixes of that line.
   702  				for j := 0; j < x; j++ {
   703  					w.Write(line[:j*2])
   704  					w.Write([]byte{'\n'})
   705  				}
   706  				w.Flush()
   707  			}
   708  		})
   709  	}
   710  }
   711  
   712  func BenchmarkRagged(b *testing.B) {
   713  	var lines [8][]byte
   714  	for i, w := range [8]int{6, 2, 9, 5, 5, 7, 3, 8} {
   715  		// Build a line with w cells.
   716  		lines[i] = bytes.Repeat([]byte("a\t"), w)
   717  	}
   718  	for _, h := range [...]int{10, 100, 1000} {
   719  		b.Run(fmt.Sprintf("%d", h), func(b *testing.B) {
   720  			b.ReportAllocs()
   721  			for i := 0; i < b.N; i++ {
   722  				w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings
   723  				// Write the lines in turn h times.
   724  				for j := 0; j < h; j++ {
   725  					w.Write(lines[j%len(lines)])
   726  					w.Write([]byte{'\n'})
   727  				}
   728  				w.Flush()
   729  			}
   730  		})
   731  	}
   732  }
   733  
   734  const codeSnippet = `
   735  some command
   736  
   737  foo	# aligned
   738  barbaz	# comments
   739  
   740  but
   741  mostly
   742  single
   743  cell
   744  lines
   745  `
   746  
   747  func BenchmarkCode(b *testing.B) {
   748  	b.ReportAllocs()
   749  	for i := 0; i < b.N; i++ {
   750  		w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings
   751  		// The code is small, so it's reasonable for the tabwriter user
   752  		// to write it all at once, or buffer the writes.
   753  		w.Write([]byte(codeSnippet))
   754  		w.Flush()
   755  	}
   756  }