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