...
Run Format

Source file src/text/tabwriter/tabwriter_test.go

Documentation: text/tabwriter

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

View as plain text