github.com/olekukonko/tablewriter@v0.0.5/table_test.go (about)

     1  // Copyright 2014 Oleku Konko All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  // This module is a Table Writer  API for the Go Programming Language.
     6  // The protocols were written in pure Go and works on windows and unix systems
     7  
     8  package tablewriter
     9  
    10  import (
    11  	"bytes"
    12  	"fmt"
    13  	"io"
    14  	"os"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  func checkEqual(t *testing.T, got, want interface{}, msgs ...interface{}) {
    21  	if !reflect.DeepEqual(got, want) {
    22  		buf := bytes.Buffer{}
    23  		buf.WriteString("got:\n[%v]\nwant:\n[%v]\n")
    24  		for _, v := range msgs {
    25  			buf.WriteString(v.(string))
    26  		}
    27  		t.Errorf(buf.String(), got, want)
    28  	}
    29  }
    30  
    31  func ExampleShort() {
    32  	data := [][]string{
    33  		{"A", "The Good", "500"},
    34  		{"B", "The Very very Bad Man", "288"},
    35  		{"C", "The Ugly", "120"},
    36  		{"D", "The Gopher", "800"},
    37  	}
    38  
    39  	table := NewWriter(os.Stdout)
    40  	table.SetHeader([]string{"Name", "Sign", "Rating"})
    41  
    42  	for _, v := range data {
    43  		table.Append(v)
    44  	}
    45  	table.Render()
    46  
    47  	// Output: +------+-----------------------+--------+
    48  	// | NAME |         SIGN          | RATING |
    49  	// +------+-----------------------+--------+
    50  	// | A    | The Good              |    500 |
    51  	// | B    | The Very very Bad Man |    288 |
    52  	// | C    | The Ugly              |    120 |
    53  	// | D    | The Gopher            |    800 |
    54  	// +------+-----------------------+--------+
    55  }
    56  
    57  func ExampleLong() {
    58  	data := [][]string{
    59  		{"Learn East has computers with adapted keyboards with enlarged print etc", "  Some Data  ", " Another Data"},
    60  		{"Instead of lining up the letters all ", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards", "See Data"},
    61  	}
    62  
    63  	table := NewWriter(os.Stdout)
    64  	table.SetHeader([]string{"Name", "Sign", "Rating"})
    65  	table.SetCenterSeparator("*")
    66  	table.SetRowSeparator("=")
    67  
    68  	for _, v := range data {
    69  		table.Append(v)
    70  	}
    71  	table.Render()
    72  
    73  	// Output: *================================*================================*===============================*==========*
    74  	// |              NAME              |              SIGN              |            RATING             |          |
    75  	// *================================*================================*===============================*==========*
    76  	// | Learn East has computers       |   Some Data                    |  Another Data                 |
    77  	// | with adapted keyboards with    |                                |                               |
    78  	// | enlarged print etc             |                                |                               |
    79  	// | Instead of lining up the       | the way across, he splits the  | Like most ergonomic keyboards | See Data |
    80  	// | letters all                    | keyboard in two                |                               |          |
    81  	// *================================*================================*===============================*==========*
    82  }
    83  
    84  func ExampleCSV() {
    85  	table, _ := NewCSV(os.Stdout, "testdata/test.csv", true)
    86  	table.SetCenterSeparator("*")
    87  	table.SetRowSeparator("=")
    88  
    89  	table.Render()
    90  
    91  	// Output: *============*===========*=========*
    92  	// | FIRST NAME | LAST NAME |   SSN   |
    93  	// *============*===========*=========*
    94  	// | John       | Barry     |  123456 |
    95  	// | Kathy      | Smith     |  687987 |
    96  	// | Bob        | McCornick | 3979870 |
    97  	// *============*===========*=========*
    98  }
    99  
   100  // TestNumLines to test the numbers of lines
   101  func TestNumLines(t *testing.T) {
   102  	data := [][]string{
   103  		{"A", "The Good", "500"},
   104  		{"B", "The Very very Bad Man", "288"},
   105  		{"C", "The Ugly", "120"},
   106  		{"D", "The Gopher", "800"},
   107  	}
   108  
   109  	buf := &bytes.Buffer{}
   110  	table := NewWriter(buf)
   111  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   112  
   113  	for i, v := range data {
   114  		table.Append(v)
   115  		checkEqual(t, table.NumLines(), i+1, "Number of lines failed")
   116  	}
   117  
   118  	checkEqual(t, table.NumLines(), len(data), "Number of lines failed")
   119  }
   120  
   121  func TestCSVInfo(t *testing.T) {
   122  	buf := &bytes.Buffer{}
   123  	table, err := NewCSV(buf, "testdata/test_info.csv", true)
   124  	if err != nil {
   125  		t.Error(err)
   126  		return
   127  	}
   128  	table.SetAlignment(ALIGN_LEFT)
   129  	table.SetBorder(false)
   130  	table.Render()
   131  
   132  	got := buf.String()
   133  	want := `   FIELD   |     TYPE     | NULL | KEY | DEFAULT |     EXTRA       
   134  -----------+--------------+------+-----+---------+-----------------
   135    user_id  | smallint(5)  | NO   | PRI | NULL    | auto_increment  
   136    username | varchar(10)  | NO   |     | NULL    |                 
   137    password | varchar(100) | NO   |     | NULL    |                 
   138  `
   139  	checkEqual(t, got, want, "CSV info failed")
   140  }
   141  
   142  func TestCSVSeparator(t *testing.T) {
   143  	buf := &bytes.Buffer{}
   144  	table, err := NewCSV(buf, "testdata/test.csv", true)
   145  	if err != nil {
   146  		t.Error(err)
   147  		return
   148  	}
   149  	table.SetRowLine(true)
   150  	table.SetCenterSeparator("+")
   151  	table.SetColumnSeparator("|")
   152  	table.SetRowSeparator("-")
   153  	table.SetAlignment(ALIGN_LEFT)
   154  	table.Render()
   155  
   156  	want := `+------------+-----------+---------+
   157  | FIRST NAME | LAST NAME |   SSN   |
   158  +------------+-----------+---------+
   159  | John       | Barry     | 123456  |
   160  +------------+-----------+---------+
   161  | Kathy      | Smith     | 687987  |
   162  +------------+-----------+---------+
   163  | Bob        | McCornick | 3979870 |
   164  +------------+-----------+---------+
   165  `
   166  
   167  	checkEqual(t, buf.String(), want, "CSV info failed")
   168  }
   169  
   170  func TestNoBorder(t *testing.T) {
   171  	data := [][]string{
   172  		{"1/1/2014", "Domain name", "2233", "$10.98"},
   173  		{"1/1/2014", "January Hosting", "2233", "$54.95"},
   174  		{"", "    (empty)\n    (empty)", "", ""},
   175  		{"1/4/2014", "February Hosting", "2233", "$51.00"},
   176  		{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
   177  		{"1/4/2014", "    (Discount)", "2233", "-$1.00"},
   178  	}
   179  
   180  	var buf bytes.Buffer
   181  	table := NewWriter(&buf)
   182  	table.SetAutoWrapText(false)
   183  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
   184  	table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
   185  	table.SetBorder(false)                                // Set Border to false
   186  	table.AppendBulk(data)                                // Add Bulk Data
   187  	table.Render()
   188  
   189  	want := `    DATE   |       DESCRIPTION        |  CV2  | AMOUNT   
   190  -----------+--------------------------+-------+----------
   191    1/1/2014 | Domain name              |  2233 | $10.98   
   192    1/1/2014 | January Hosting          |  2233 | $54.95   
   193             |     (empty)              |       |          
   194             |     (empty)              |       |          
   195    1/4/2014 | February Hosting         |  2233 | $51.00   
   196    1/4/2014 | February Extra Bandwidth |  2233 | $30.00   
   197    1/4/2014 |     (Discount)           |  2233 | -$1.00   
   198  -----------+--------------------------+-------+----------
   199                                          TOTAL | $145.93  
   200                                        --------+----------
   201  `
   202  
   203  	checkEqual(t, buf.String(), want, "border table rendering failed")
   204  }
   205  
   206  func TestWithBorder(t *testing.T) {
   207  	data := [][]string{
   208  		{"1/1/2014", "Domain name", "2233", "$10.98"},
   209  		{"1/1/2014", "January Hosting", "2233", "$54.95"},
   210  		{"", "    (empty)\n    (empty)", "", ""},
   211  		{"1/4/2014", "February Hosting", "2233", "$51.00"},
   212  		{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
   213  		{"1/4/2014", "    (Discount)", "2233", "-$1.00"},
   214  	}
   215  
   216  	var buf bytes.Buffer
   217  	table := NewWriter(&buf)
   218  	table.SetAutoWrapText(false)
   219  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
   220  	table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
   221  	table.AppendBulk(data)                                // Add Bulk Data
   222  	table.Render()
   223  
   224  	want := `+----------+--------------------------+-------+---------+
   225  |   DATE   |       DESCRIPTION        |  CV2  | AMOUNT  |
   226  +----------+--------------------------+-------+---------+
   227  | 1/1/2014 | Domain name              |  2233 | $10.98  |
   228  | 1/1/2014 | January Hosting          |  2233 | $54.95  |
   229  |          |     (empty)              |       |         |
   230  |          |     (empty)              |       |         |
   231  | 1/4/2014 | February Hosting         |  2233 | $51.00  |
   232  | 1/4/2014 | February Extra Bandwidth |  2233 | $30.00  |
   233  | 1/4/2014 |     (Discount)           |  2233 | -$1.00  |
   234  +----------+--------------------------+-------+---------+
   235  |                                       TOTAL | $145.93 |
   236  +----------+--------------------------+-------+---------+
   237  `
   238  
   239  	checkEqual(t, buf.String(), want, "border table rendering failed")
   240  }
   241  
   242  func TestPrintingInMarkdown(t *testing.T) {
   243  	data := [][]string{
   244  		{"1/1/2014", "Domain name", "2233", "$10.98"},
   245  		{"1/1/2014", "January Hosting", "2233", "$54.95"},
   246  		{"1/4/2014", "February Hosting", "2233", "$51.00"},
   247  		{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
   248  	}
   249  
   250  	var buf bytes.Buffer
   251  	table := NewWriter(&buf)
   252  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
   253  	table.AppendBulk(data) // Add Bulk Data
   254  	table.SetBorders(Border{Left: true, Top: false, Right: true, Bottom: false})
   255  	table.SetCenterSeparator("|")
   256  	table.Render()
   257  
   258  	want := `|   DATE   |       DESCRIPTION        | CV2  | AMOUNT |
   259  |----------|--------------------------|------|--------|
   260  | 1/1/2014 | Domain name              | 2233 | $10.98 |
   261  | 1/1/2014 | January Hosting          | 2233 | $54.95 |
   262  | 1/4/2014 | February Hosting         | 2233 | $51.00 |
   263  | 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
   264  `
   265  	checkEqual(t, buf.String(), want, "border table rendering failed")
   266  }
   267  
   268  func TestPrintHeading(t *testing.T) {
   269  	var buf bytes.Buffer
   270  	table := NewWriter(&buf)
   271  	table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
   272  	table.printHeading()
   273  	want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C |
   274  +---+---+---+---+---+---+---+---+---+---+---+---+
   275  `
   276  	checkEqual(t, buf.String(), want, "header rendering failed")
   277  }
   278  
   279  func TestPrintHeadingWithoutAutoFormat(t *testing.T) {
   280  	var buf bytes.Buffer
   281  	table := NewWriter(&buf)
   282  	table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
   283  	table.SetAutoFormatHeaders(false)
   284  	table.printHeading()
   285  	want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c |
   286  +---+---+---+---+---+---+---+---+---+---+---+---+
   287  `
   288  	checkEqual(t, buf.String(), want, "header rendering failed")
   289  }
   290  
   291  func TestPrintFooter(t *testing.T) {
   292  	var buf bytes.Buffer
   293  	table := NewWriter(&buf)
   294  	table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
   295  	table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
   296  	table.printFooter()
   297  	want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C |
   298  +---+---+---+---+---+---+---+---+---+---+---+---+
   299  `
   300  	checkEqual(t, buf.String(), want, "footer rendering failed")
   301  }
   302  
   303  func TestPrintFooterWithoutAutoFormat(t *testing.T) {
   304  	var buf bytes.Buffer
   305  	table := NewWriter(&buf)
   306  	table.SetAutoFormatHeaders(false)
   307  	table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
   308  	table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
   309  	table.printFooter()
   310  	want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c |
   311  +---+---+---+---+---+---+---+---+---+---+---+---+
   312  `
   313  	checkEqual(t, buf.String(), want, "footer rendering failed")
   314  }
   315  
   316  func TestPrintShortCaption(t *testing.T) {
   317  	var buf bytes.Buffer
   318  	data := [][]string{
   319  		{"A", "The Good", "500"},
   320  		{"B", "The Very very Bad Man", "288"},
   321  		{"C", "The Ugly", "120"},
   322  		{"D", "The Gopher", "800"},
   323  	}
   324  
   325  	table := NewWriter(&buf)
   326  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   327  	table.SetCaption(true, "Short caption.")
   328  
   329  	for _, v := range data {
   330  		table.Append(v)
   331  	}
   332  	table.Render()
   333  
   334  	want := `+------+-----------------------+--------+
   335  | NAME |         SIGN          | RATING |
   336  +------+-----------------------+--------+
   337  | A    | The Good              |    500 |
   338  | B    | The Very very Bad Man |    288 |
   339  | C    | The Ugly              |    120 |
   340  | D    | The Gopher            |    800 |
   341  +------+-----------------------+--------+
   342  Short caption.
   343  `
   344  	checkEqual(t, buf.String(), want, "long caption for short example rendering failed")
   345  }
   346  
   347  func TestPrintLongCaptionWithShortExample(t *testing.T) {
   348  	var buf bytes.Buffer
   349  	data := [][]string{
   350  		{"A", "The Good", "500"},
   351  		{"B", "The Very very Bad Man", "288"},
   352  		{"C", "The Ugly", "120"},
   353  		{"D", "The Gopher", "800"},
   354  	}
   355  
   356  	table := NewWriter(&buf)
   357  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   358  	table.SetCaption(true, "This is a very long caption. The text should wrap. If not, we have a problem that needs to be solved.")
   359  
   360  	for _, v := range data {
   361  		table.Append(v)
   362  	}
   363  	table.Render()
   364  
   365  	want := `+------+-----------------------+--------+
   366  | NAME |         SIGN          | RATING |
   367  +------+-----------------------+--------+
   368  | A    | The Good              |    500 |
   369  | B    | The Very very Bad Man |    288 |
   370  | C    | The Ugly              |    120 |
   371  | D    | The Gopher            |    800 |
   372  +------+-----------------------+--------+
   373  This is a very long caption. The text
   374  should wrap. If not, we have a problem
   375  that needs to be solved.
   376  `
   377  	checkEqual(t, buf.String(), want, "long caption for short example rendering failed")
   378  }
   379  
   380  func TestPrintCaptionWithFooter(t *testing.T) {
   381  	data := [][]string{
   382  		{"1/1/2014", "Domain name", "2233", "$10.98"},
   383  		{"1/1/2014", "January Hosting", "2233", "$54.95"},
   384  		{"1/4/2014", "February Hosting", "2233", "$51.00"},
   385  		{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
   386  	}
   387  
   388  	var buf bytes.Buffer
   389  	table := NewWriter(&buf)
   390  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
   391  	table.SetFooter([]string{"", "", "Total", "$146.93"})                                                  // Add Footer
   392  	table.SetCaption(true, "This is a very long caption. The text should wrap to the width of the table.") // Add caption
   393  	table.SetBorder(false)                                                                                 // Set Border to false
   394  	table.AppendBulk(data)                                                                                 // Add Bulk Data
   395  	table.Render()
   396  
   397  	want := `    DATE   |       DESCRIPTION        |  CV2  | AMOUNT   
   398  -----------+--------------------------+-------+----------
   399    1/1/2014 | Domain name              |  2233 | $10.98   
   400    1/1/2014 | January Hosting          |  2233 | $54.95   
   401    1/4/2014 | February Hosting         |  2233 | $51.00   
   402    1/4/2014 | February Extra Bandwidth |  2233 | $30.00   
   403  -----------+--------------------------+-------+----------
   404                                          TOTAL | $146.93  
   405                                        --------+----------
   406  This is a very long caption. The text should wrap to the
   407  width of the table.
   408  `
   409  	checkEqual(t, buf.String(), want, "border table rendering failed")
   410  }
   411  
   412  func TestPrintLongCaptionWithLongExample(t *testing.T) {
   413  	var buf bytes.Buffer
   414  	data := [][]string{
   415  		{"Learn East has computers with adapted keyboards with enlarged print etc", "Some Data", "Another Data"},
   416  		{"Instead of lining up the letters all", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards"},
   417  	}
   418  
   419  	table := NewWriter(&buf)
   420  	table.SetCaption(true, "This is a very long caption. The text should wrap. If not, we have a problem that needs to be solved.")
   421  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   422  
   423  	for _, v := range data {
   424  		table.Append(v)
   425  	}
   426  	table.Render()
   427  
   428  	want := `+--------------------------------+--------------------------------+-------------------------------+
   429  |              NAME              |              SIGN              |            RATING             |
   430  +--------------------------------+--------------------------------+-------------------------------+
   431  | Learn East has computers       | Some Data                      | Another Data                  |
   432  | with adapted keyboards with    |                                |                               |
   433  | enlarged print etc             |                                |                               |
   434  | Instead of lining up the       | the way across, he splits the  | Like most ergonomic keyboards |
   435  | letters all                    | keyboard in two                |                               |
   436  +--------------------------------+--------------------------------+-------------------------------+
   437  This is a very long caption. The text should wrap. If not, we have a problem that needs to be
   438  solved.
   439  `
   440  	checkEqual(t, buf.String(), want, "long caption for long example rendering failed")
   441  }
   442  
   443  func Example_autowrap() {
   444  	var multiline = `A multiline
   445  string with some lines being really long.`
   446  
   447  	const (
   448  		testRow = iota
   449  		testHeader
   450  		testFooter
   451  		testFooter2
   452  	)
   453  	for mode := testRow; mode <= testFooter2; mode++ {
   454  		for _, autoFmt := range []bool{false, true} {
   455  			if mode == testRow && autoFmt {
   456  				// Nothing special to test, skip
   457  				continue
   458  			}
   459  			for _, autoWrap := range []bool{false, true} {
   460  				for _, reflow := range []bool{false, true} {
   461  					if !autoWrap && reflow {
   462  						// Invalid configuration, skip
   463  						continue
   464  					}
   465  					fmt.Println("mode", mode, "autoFmt", autoFmt, "autoWrap", autoWrap, "reflow", reflow)
   466  					t := NewWriter(os.Stdout)
   467  					t.SetAutoFormatHeaders(autoFmt)
   468  					t.SetAutoWrapText(autoWrap)
   469  					t.SetReflowDuringAutoWrap(reflow)
   470  					if mode == testHeader {
   471  						t.SetHeader([]string{"woo", multiline})
   472  					} else {
   473  						t.SetHeader([]string{"woo", "waa"})
   474  					}
   475  					if mode == testRow {
   476  						t.Append([]string{"woo", multiline})
   477  					} else {
   478  						t.Append([]string{"woo", "waa"})
   479  					}
   480  					if mode == testFooter {
   481  						t.SetFooter([]string{"woo", multiline})
   482  					} else if mode == testFooter2 {
   483  						t.SetFooter([]string{"", multiline})
   484  					} else {
   485  						t.SetFooter([]string{"woo", "waa"})
   486  					}
   487  					t.Render()
   488  				}
   489  			}
   490  		}
   491  		fmt.Println()
   492  	}
   493  
   494  	// Output:
   495  	// mode 0 autoFmt false autoWrap false reflow false
   496  	// +-----+-------------------------------------------+
   497  	// | woo |                    waa                    |
   498  	// +-----+-------------------------------------------+
   499  	// | woo | A multiline                               |
   500  	// |     | string with some lines being really long. |
   501  	// +-----+-------------------------------------------+
   502  	// | woo |                    waa                    |
   503  	// +-----+-------------------------------------------+
   504  	// mode 0 autoFmt false autoWrap true reflow false
   505  	// +-----+--------------------------------+
   506  	// | woo |              waa               |
   507  	// +-----+--------------------------------+
   508  	// | woo | A multiline                    |
   509  	// |     |                                |
   510  	// |     | string with some lines being   |
   511  	// |     | really long.                   |
   512  	// +-----+--------------------------------+
   513  	// | woo |              waa               |
   514  	// +-----+--------------------------------+
   515  	// mode 0 autoFmt false autoWrap true reflow true
   516  	// +-----+--------------------------------+
   517  	// | woo |              waa               |
   518  	// +-----+--------------------------------+
   519  	// | woo | A multiline string with some   |
   520  	// |     | lines being really long.       |
   521  	// +-----+--------------------------------+
   522  	// | woo |              waa               |
   523  	// +-----+--------------------------------+
   524  	//
   525  	// mode 1 autoFmt false autoWrap false reflow false
   526  	// +-----+-------------------------------------------+
   527  	// | woo |                A multiline                |
   528  	// |     | string with some lines being really long. |
   529  	// +-----+-------------------------------------------+
   530  	// | woo | waa                                       |
   531  	// +-----+-------------------------------------------+
   532  	// | woo |                    waa                    |
   533  	// +-----+-------------------------------------------+
   534  	// mode 1 autoFmt false autoWrap true reflow false
   535  	// +-----+--------------------------------+
   536  	// | woo |          A multiline           |
   537  	// |     |                                |
   538  	// |     |  string with some lines being  |
   539  	// |     |          really long.          |
   540  	// +-----+--------------------------------+
   541  	// | woo | waa                            |
   542  	// +-----+--------------------------------+
   543  	// | woo |              waa               |
   544  	// +-----+--------------------------------+
   545  	// mode 1 autoFmt false autoWrap true reflow true
   546  	// +-----+--------------------------------+
   547  	// | woo |  A multiline string with some  |
   548  	// |     |    lines being really long.    |
   549  	// +-----+--------------------------------+
   550  	// | woo | waa                            |
   551  	// +-----+--------------------------------+
   552  	// | woo |              waa               |
   553  	// +-----+--------------------------------+
   554  	// mode 1 autoFmt true autoWrap false reflow false
   555  	// +-----+-------------------------------------------+
   556  	// | WOO |                A MULTILINE                |
   557  	// |     | STRING WITH SOME LINES BEING REALLY LONG  |
   558  	// +-----+-------------------------------------------+
   559  	// | woo | waa                                       |
   560  	// +-----+-------------------------------------------+
   561  	// | WOO |                    WAA                    |
   562  	// +-----+-------------------------------------------+
   563  	// mode 1 autoFmt true autoWrap true reflow false
   564  	// +-----+--------------------------------+
   565  	// | WOO |          A MULTILINE           |
   566  	// |     |                                |
   567  	// |     |  STRING WITH SOME LINES BEING  |
   568  	// |     |          REALLY LONG           |
   569  	// +-----+--------------------------------+
   570  	// | woo | waa                            |
   571  	// +-----+--------------------------------+
   572  	// | WOO |              WAA               |
   573  	// +-----+--------------------------------+
   574  	// mode 1 autoFmt true autoWrap true reflow true
   575  	// +-----+--------------------------------+
   576  	// | WOO |  A MULTILINE STRING WITH SOME  |
   577  	// |     |    LINES BEING REALLY LONG     |
   578  	// +-----+--------------------------------+
   579  	// | woo | waa                            |
   580  	// +-----+--------------------------------+
   581  	// | WOO |              WAA               |
   582  	// +-----+--------------------------------+
   583  	//
   584  	// mode 2 autoFmt false autoWrap false reflow false
   585  	// +-----+-------------------------------------------+
   586  	// | woo |                    waa                    |
   587  	// +-----+-------------------------------------------+
   588  	// | woo | waa                                       |
   589  	// +-----+-------------------------------------------+
   590  	// | woo |                A multiline                |
   591  	// |     | string with some lines being really long. |
   592  	// +-----+-------------------------------------------+
   593  	// mode 2 autoFmt false autoWrap true reflow false
   594  	// +-----+--------------------------------+
   595  	// | woo |              waa               |
   596  	// +-----+--------------------------------+
   597  	// | woo | waa                            |
   598  	// +-----+--------------------------------+
   599  	// | woo |          A multiline           |
   600  	// |     |                                |
   601  	// |     |  string with some lines being  |
   602  	// |     |          really long.          |
   603  	// +-----+--------------------------------+
   604  	// mode 2 autoFmt false autoWrap true reflow true
   605  	// +-----+--------------------------------+
   606  	// | woo |              waa               |
   607  	// +-----+--------------------------------+
   608  	// | woo | waa                            |
   609  	// +-----+--------------------------------+
   610  	// | woo |  A multiline string with some  |
   611  	// |     |    lines being really long.    |
   612  	// +-----+--------------------------------+
   613  	// mode 2 autoFmt true autoWrap false reflow false
   614  	// +-----+-------------------------------------------+
   615  	// | WOO |                    WAA                    |
   616  	// +-----+-------------------------------------------+
   617  	// | woo | waa                                       |
   618  	// +-----+-------------------------------------------+
   619  	// | WOO |                A MULTILINE                |
   620  	// |     | STRING WITH SOME LINES BEING REALLY LONG  |
   621  	// +-----+-------------------------------------------+
   622  	// mode 2 autoFmt true autoWrap true reflow false
   623  	// +-----+--------------------------------+
   624  	// | WOO |              WAA               |
   625  	// +-----+--------------------------------+
   626  	// | woo | waa                            |
   627  	// +-----+--------------------------------+
   628  	// | WOO |          A MULTILINE           |
   629  	// |     |                                |
   630  	// |     |  STRING WITH SOME LINES BEING  |
   631  	// |     |          REALLY LONG           |
   632  	// +-----+--------------------------------+
   633  	// mode 2 autoFmt true autoWrap true reflow true
   634  	// +-----+--------------------------------+
   635  	// | WOO |              WAA               |
   636  	// +-----+--------------------------------+
   637  	// | woo | waa                            |
   638  	// +-----+--------------------------------+
   639  	// | WOO |  A MULTILINE STRING WITH SOME  |
   640  	// |     |    LINES BEING REALLY LONG     |
   641  	// +-----+--------------------------------+
   642  	//
   643  	// mode 3 autoFmt false autoWrap false reflow false
   644  	// +-----+-------------------------------------------+
   645  	// | woo |                    waa                    |
   646  	// +-----+-------------------------------------------+
   647  	// | woo | waa                                       |
   648  	// +-----+-------------------------------------------+
   649  	// |                      A multiline                |
   650  	// |       string with some lines being really long. |
   651  	// +-----+-------------------------------------------+
   652  	// mode 3 autoFmt false autoWrap true reflow false
   653  	// +-----+--------------------------------+
   654  	// | woo |              waa               |
   655  	// +-----+--------------------------------+
   656  	// | woo | waa                            |
   657  	// +-----+--------------------------------+
   658  	// |                A multiline           |
   659  	// |                                      |
   660  	// |        string with some lines being  |
   661  	// |                really long.          |
   662  	// +-----+--------------------------------+
   663  	// mode 3 autoFmt false autoWrap true reflow true
   664  	// +-----+--------------------------------+
   665  	// | woo |              waa               |
   666  	// +-----+--------------------------------+
   667  	// | woo | waa                            |
   668  	// +-----+--------------------------------+
   669  	// |        A multiline string with some  |
   670  	// |          lines being really long.    |
   671  	// +-----+--------------------------------+
   672  	// mode 3 autoFmt true autoWrap false reflow false
   673  	// +-----+-------------------------------------------+
   674  	// | WOO |                    WAA                    |
   675  	// +-----+-------------------------------------------+
   676  	// | woo | waa                                       |
   677  	// +-----+-------------------------------------------+
   678  	// |                      A MULTILINE                |
   679  	// |       STRING WITH SOME LINES BEING REALLY LONG  |
   680  	// +-----+-------------------------------------------+
   681  	// mode 3 autoFmt true autoWrap true reflow false
   682  	// +-----+--------------------------------+
   683  	// | WOO |              WAA               |
   684  	// +-----+--------------------------------+
   685  	// | woo | waa                            |
   686  	// +-----+--------------------------------+
   687  	// |                A MULTILINE           |
   688  	// |                                      |
   689  	// |        STRING WITH SOME LINES BEING  |
   690  	// |                REALLY LONG           |
   691  	// +-----+--------------------------------+
   692  	// mode 3 autoFmt true autoWrap true reflow true
   693  	// +-----+--------------------------------+
   694  	// | WOO |              WAA               |
   695  	// +-----+--------------------------------+
   696  	// | woo | waa                            |
   697  	// +-----+--------------------------------+
   698  	// |        A MULTILINE STRING WITH SOME  |
   699  	// |          LINES BEING REALLY LONG     |
   700  	// +-----+--------------------------------+
   701  }
   702  
   703  func TestPrintLine(t *testing.T) {
   704  	header := make([]string, 12)
   705  	val := " "
   706  	want := ""
   707  	for i := range header {
   708  		header[i] = val
   709  		want = fmt.Sprintf("%s+-%s-", want, strings.Replace(val, " ", "-", -1))
   710  		val = val + " "
   711  	}
   712  	want = want + "+"
   713  	var buf bytes.Buffer
   714  	table := NewWriter(&buf)
   715  	table.SetHeader(header)
   716  	table.printLine(false)
   717  	checkEqual(t, buf.String(), want, "line rendering failed")
   718  }
   719  
   720  func TestAnsiStrip(t *testing.T) {
   721  	header := make([]string, 12)
   722  	val := " "
   723  	want := ""
   724  	for i := range header {
   725  		header[i] = "\033[43;30m" + val + "\033[00m"
   726  		want = fmt.Sprintf("%s+-%s-", want, strings.Replace(val, " ", "-", -1))
   727  		val = val + " "
   728  	}
   729  	want = want + "+"
   730  	var buf bytes.Buffer
   731  	table := NewWriter(&buf)
   732  	table.SetHeader(header)
   733  	table.printLine(false)
   734  	checkEqual(t, buf.String(), want, "line rendering failed")
   735  }
   736  
   737  func NewCustomizedTable(out io.Writer) *Table {
   738  	table := NewWriter(out)
   739  	table.SetCenterSeparator("")
   740  	table.SetColumnSeparator("")
   741  	table.SetRowSeparator("")
   742  	table.SetBorder(false)
   743  	table.SetAlignment(ALIGN_LEFT)
   744  	table.SetHeader([]string{})
   745  	return table
   746  }
   747  
   748  func TestSubclass(t *testing.T) {
   749  	buf := new(bytes.Buffer)
   750  	table := NewCustomizedTable(buf)
   751  
   752  	data := [][]string{
   753  		{"A", "The Good", "500"},
   754  		{"B", "The Very very Bad Man", "288"},
   755  		{"C", "The Ugly", "120"},
   756  		{"D", "The Gopher", "800"},
   757  	}
   758  
   759  	for _, v := range data {
   760  		table.Append(v)
   761  	}
   762  	table.Render()
   763  
   764  	want := `  A  The Good               500  
   765    B  The Very very Bad Man  288  
   766    C  The Ugly               120  
   767    D  The Gopher             800  
   768  `
   769  	checkEqual(t, buf.String(), want, "test subclass failed")
   770  }
   771  
   772  func TestAutoMergeRows(t *testing.T) {
   773  	data := [][]string{
   774  		{"A", "The Good", "500"},
   775  		{"A", "The Very very Bad Man", "288"},
   776  		{"B", "The Very very Bad Man", "120"},
   777  		{"B", "The Very very Bad Man", "200"},
   778  	}
   779  	var buf bytes.Buffer
   780  	table := NewWriter(&buf)
   781  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   782  
   783  	for _, v := range data {
   784  		table.Append(v)
   785  	}
   786  	table.SetAutoMergeCells(true)
   787  	table.Render()
   788  	want := `+------+-----------------------+--------+
   789  | NAME |         SIGN          | RATING |
   790  +------+-----------------------+--------+
   791  | A    | The Good              |    500 |
   792  |      | The Very very Bad Man |    288 |
   793  | B    |                       |    120 |
   794  |      |                       |    200 |
   795  +------+-----------------------+--------+
   796  `
   797  	got := buf.String()
   798  	if got != want {
   799  		t.Errorf("\ngot:\n%s\nwant:\n%s\n", got, want)
   800  	}
   801  
   802  	buf.Reset()
   803  	table = NewWriter(&buf)
   804  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   805  
   806  	for _, v := range data {
   807  		table.Append(v)
   808  	}
   809  	table.SetAutoMergeCells(true)
   810  	table.SetRowLine(true)
   811  	table.Render()
   812  	want = `+------+-----------------------+--------+
   813  | NAME |         SIGN          | RATING |
   814  +------+-----------------------+--------+
   815  | A    | The Good              |    500 |
   816  +      +-----------------------+--------+
   817  |      | The Very very Bad Man |    288 |
   818  +------+                       +--------+
   819  | B    |                       |    120 |
   820  +      +                       +--------+
   821  |      |                       |    200 |
   822  +------+-----------------------+--------+
   823  `
   824  	checkEqual(t, buf.String(), want)
   825  
   826  	buf.Reset()
   827  	table = NewWriter(&buf)
   828  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   829  
   830  	dataWithlongText := [][]string{
   831  		{"A", "The Good", "500"},
   832  		{"A", "The Very very very very very Bad Man", "288"},
   833  		{"B", "The Very very very very very Bad Man", "120"},
   834  		{"C", "The Very very Bad Man", "200"},
   835  	}
   836  	table.AppendBulk(dataWithlongText)
   837  	table.SetAutoMergeCells(true)
   838  	table.SetRowLine(true)
   839  	table.Render()
   840  	want = `+------+--------------------------------+--------+
   841  | NAME |              SIGN              | RATING |
   842  +------+--------------------------------+--------+
   843  | A    | The Good                       |    500 |
   844  +      +--------------------------------+--------+
   845  |      | The Very very very very very   |    288 |
   846  |      | Bad Man                        |        |
   847  +------+                                +--------+
   848  | B    |                                |    120 |
   849  |      |                                |        |
   850  +------+--------------------------------+--------+
   851  | C    | The Very very Bad Man          |    200 |
   852  +------+--------------------------------+--------+
   853  `
   854  	checkEqual(t, buf.String(), want)
   855  
   856  	buf.Reset()
   857  	table = NewWriter(&buf)
   858  	table.SetHeader([]string{"Name", "Sign", "Rating"})
   859  
   860  	dataWithlongText2 := [][]string{
   861  		{"A", "The Good", "500"},
   862  		{"A", "The Very very very very very Bad Man", "288"},
   863  		{"B", "The Very very Bad Man", "120"},
   864  	}
   865  	table.AppendBulk(dataWithlongText2)
   866  	table.SetAutoMergeCells(true)
   867  	table.SetRowLine(true)
   868  	table.Render()
   869  	want = `+------+--------------------------------+--------+
   870  | NAME |              SIGN              | RATING |
   871  +------+--------------------------------+--------+
   872  | A    | The Good                       |    500 |
   873  +      +--------------------------------+--------+
   874  |      | The Very very very very very   |    288 |
   875  |      | Bad Man                        |        |
   876  +------+--------------------------------+--------+
   877  | B    | The Very very Bad Man          |    120 |
   878  +------+--------------------------------+--------+
   879  `
   880  	checkEqual(t, buf.String(), want)
   881  }
   882  
   883  func TestClearRows(t *testing.T) {
   884  	data := [][]string{
   885  		{"1/1/2014", "Domain name", "2233", "$10.98"},
   886  	}
   887  
   888  	var buf bytes.Buffer
   889  	table := NewWriter(&buf)
   890  	table.SetAutoWrapText(false)
   891  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
   892  	table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
   893  	table.AppendBulk(data)                                // Add Bulk Data
   894  	table.Render()
   895  
   896  	originalWant := `+----------+-------------+-------+---------+
   897  |   DATE   | DESCRIPTION |  CV2  | AMOUNT  |
   898  +----------+-------------+-------+---------+
   899  | 1/1/2014 | Domain name |  2233 | $10.98  |
   900  +----------+-------------+-------+---------+
   901  |                          TOTAL | $145.93 |
   902  +----------+-------------+-------+---------+
   903  `
   904  	want := originalWant
   905  
   906  	checkEqual(t, buf.String(), want, "table clear rows failed")
   907  
   908  	buf.Reset()
   909  	table.ClearRows()
   910  	table.Render()
   911  
   912  	want = `+----------+-------------+-------+---------+
   913  |   DATE   | DESCRIPTION |  CV2  | AMOUNT  |
   914  +----------+-------------+-------+---------+
   915  +----------+-------------+-------+---------+
   916  |                          TOTAL | $145.93 |
   917  +----------+-------------+-------+---------+
   918  `
   919  
   920  	checkEqual(t, buf.String(), want, "table clear rows failed")
   921  
   922  	buf.Reset()
   923  	table.AppendBulk(data) // Add Bulk Data
   924  	table.Render()
   925  
   926  	want = `+----------+-------------+-------+---------+
   927  |   DATE   | DESCRIPTION |  CV2  | AMOUNT  |
   928  +----------+-------------+-------+---------+
   929  | 1/1/2014 | Domain name |  2233 | $10.98  |
   930  +----------+-------------+-------+---------+
   931  |                          TOTAL | $145.93 |
   932  +----------+-------------+-------+---------+
   933  `
   934  
   935  	checkEqual(t, buf.String(), want, "table clear rows failed")
   936  }
   937  
   938  func TestClearFooters(t *testing.T) {
   939  	data := [][]string{
   940  		{"1/1/2014", "Domain name", "2233", "$10.98"},
   941  	}
   942  
   943  	var buf bytes.Buffer
   944  	table := NewWriter(&buf)
   945  	table.SetAutoWrapText(false)
   946  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
   947  	table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer
   948  	table.AppendBulk(data)                                // Add Bulk Data
   949  	table.Render()
   950  
   951  	buf.Reset()
   952  	table.ClearFooter()
   953  	table.Render()
   954  
   955  	want := `+----------+-------------+-------+---------+
   956  |   DATE   | DESCRIPTION |  CV2  | AMOUNT  |
   957  +----------+-------------+-------+---------+
   958  | 1/1/2014 | Domain name |  2233 | $10.98  |
   959  +----------+-------------+-------+---------+
   960  `
   961  
   962  	checkEqual(t, buf.String(), want)
   963  }
   964  
   965  func TestMoreDataColumnsThanHeaders(t *testing.T) {
   966  	var (
   967  		buf    = &bytes.Buffer{}
   968  		table  = NewWriter(buf)
   969  		header = []string{"A", "B", "C"}
   970  		data   = [][]string{
   971  			{"a", "b", "c", "d"},
   972  			{"1", "2", "3", "4"},
   973  		}
   974  		want = `+---+---+---+---+
   975  | A | B | C |   |
   976  +---+---+---+---+
   977  | a | b | c | d |
   978  | 1 | 2 | 3 | 4 |
   979  +---+---+---+---+
   980  `
   981  	)
   982  	table.SetHeader(header)
   983  	// table.SetFooter(ctx.tableCtx.footer)
   984  	table.AppendBulk(data)
   985  	table.Render()
   986  
   987  	checkEqual(t, buf.String(), want)
   988  }
   989  
   990  func TestMoreFooterColumnsThanHeaders(t *testing.T) {
   991  	var (
   992  		buf    = &bytes.Buffer{}
   993  		table  = NewWriter(buf)
   994  		header = []string{"A", "B", "C"}
   995  		data   = [][]string{
   996  			{"a", "b", "c", "d"},
   997  			{"1", "2", "3", "4"},
   998  		}
   999  		footer = []string{"a", "b", "c", "d", "e"}
  1000  		want   = `+---+---+---+---+---+
  1001  | A | B | C |   |   |
  1002  +---+---+---+---+---+
  1003  | a | b | c | d |
  1004  | 1 | 2 | 3 | 4 |
  1005  +---+---+---+---+---+
  1006  | A | B | C | D | E |
  1007  +---+---+---+---+---+
  1008  `
  1009  	)
  1010  	table.SetHeader(header)
  1011  	table.SetFooter(footer)
  1012  	table.AppendBulk(data)
  1013  	table.Render()
  1014  
  1015  	checkEqual(t, buf.String(), want)
  1016  }
  1017  
  1018  func TestSetColMinWidth(t *testing.T) {
  1019  	var (
  1020  		buf    = &bytes.Buffer{}
  1021  		table  = NewWriter(buf)
  1022  		header = []string{"AAA", "BBB", "CCC"}
  1023  		data   = [][]string{
  1024  			{"a", "b", "c"},
  1025  			{"1", "2", "3"},
  1026  		}
  1027  		footer = []string{"a", "b", "cccc"}
  1028  		want   = `+-----+-----+-------+
  1029  | AAA | BBB |  CCC  |
  1030  +-----+-----+-------+
  1031  | a   | b   | c     |
  1032  |   1 |   2 |     3 |
  1033  +-----+-----+-------+
  1034  |  A  |  B  | CCCC  |
  1035  +-----+-----+-------+
  1036  `
  1037  	)
  1038  	table.SetHeader(header)
  1039  	table.SetFooter(footer)
  1040  	table.AppendBulk(data)
  1041  	table.SetColMinWidth(2, 5)
  1042  	table.Render()
  1043  
  1044  	checkEqual(t, buf.String(), want)
  1045  }
  1046  
  1047  func TestWrapString(t *testing.T) {
  1048  	want := []string{"ああああああああああああああああああああああああ", "あああああああ"}
  1049  	got, _ := WrapString("ああああああああああああああああああああああああ あああああああ", 55)
  1050  	checkEqual(t, got, want)
  1051  }
  1052  
  1053  func TestNumberAlign(t *testing.T) {
  1054  	var (
  1055  		buf   = &bytes.Buffer{}
  1056  		table = NewWriter(buf)
  1057  		data  = [][]string{
  1058  			{"AAAAAAAAAAAAA", "BBBBBBBBBBBBB", "CCCCCCCCCCCCCC"},
  1059  			{"A", "B", "C"},
  1060  			{"123456789", "2", "3"},
  1061  			{"1", "2", "123,456,789"},
  1062  			{"1", "123,456.789", "3"},
  1063  			{"-123,456", "-2", "-3"},
  1064  		}
  1065  		want = `+---------------+---------------+----------------+
  1066  | AAAAAAAAAAAAA | BBBBBBBBBBBBB | CCCCCCCCCCCCCC |
  1067  | A             | B             | C              |
  1068  |     123456789 |             2 |              3 |
  1069  |             1 |             2 |    123,456,789 |
  1070  |             1 |   123,456.789 |              3 |
  1071  |      -123,456 |            -2 |             -3 |
  1072  +---------------+---------------+----------------+
  1073  `
  1074  	)
  1075  	table.AppendBulk(data)
  1076  	table.Render()
  1077  
  1078  	checkEqual(t, buf.String(), want)
  1079  }
  1080  
  1081  func TestCustomAlign(t *testing.T) {
  1082  	var (
  1083  		buf    = &bytes.Buffer{}
  1084  		table  = NewWriter(buf)
  1085  		header = []string{"AAA", "BBB", "CCC"}
  1086  		data   = [][]string{
  1087  			{"a", "b", "c"},
  1088  			{"1", "2", "3"},
  1089  		}
  1090  		footer = []string{"a", "b", "cccc"}
  1091  		want   = `+-----+-----+-------+
  1092  | AAA | BBB |  CCC  |
  1093  +-----+-----+-------+
  1094  | a   |  b  |     c |
  1095  | 1   |  2  |     3 |
  1096  +-----+-----+-------+
  1097  |  A  |  B  | CCCC  |
  1098  +-----+-----+-------+
  1099  `
  1100  	)
  1101  	table.SetHeader(header)
  1102  	table.SetFooter(footer)
  1103  	table.AppendBulk(data)
  1104  	table.SetColMinWidth(2, 5)
  1105  	table.SetColumnAlignment([]int{ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT})
  1106  	table.Render()
  1107  
  1108  	checkEqual(t, buf.String(), want)
  1109  }
  1110  
  1111  func TestTitle(t *testing.T) {
  1112  	ts := []struct {
  1113  		text string
  1114  		want string
  1115  	}{
  1116  		{"", ""},
  1117  		{"foo", "FOO"},
  1118  		{"Foo", "FOO"},
  1119  		{"foO", "FOO"},
  1120  		{".foo", "FOO"},
  1121  		{"foo.", "FOO"},
  1122  		{".foo.", "FOO"},
  1123  		{".foo.bar.", "FOO BAR"},
  1124  		{"_foo", "FOO"},
  1125  		{"foo_", "FOO"},
  1126  		{"_foo_", "FOO"},
  1127  		{"_foo_bar_", "FOO BAR"},
  1128  		{" foo", "FOO"},
  1129  		{"foo ", "FOO"},
  1130  		{" foo ", "FOO"},
  1131  		{" foo bar ", "FOO BAR"},
  1132  		{"0.1", "0.1"},
  1133  		{"FOO 0.1", "FOO 0.1"},
  1134  		{".1 0.1", ".1 0.1"},
  1135  		{"1. 0.1", "1. 0.1"},
  1136  		{"1. 0.", "1. 0."},
  1137  		{".1. 0.", ".1. 0."},
  1138  		{".$ . $.", "$ . $"},
  1139  		{".$. $.", "$  $"},
  1140  	}
  1141  	for _, tt := range ts {
  1142  		got := Title(tt.text)
  1143  		if got != tt.want {
  1144  			t.Errorf("want %q, bot got %q", tt.want, got)
  1145  		}
  1146  	}
  1147  }
  1148  
  1149  func TestKubeFormat(t *testing.T) {
  1150  	data := [][]string{
  1151  		{"1/1/2014", "jan_hosting", "2233", "$10.98"},
  1152  		{"1/1/2014", "feb_hosting", "2233", "$54.95"},
  1153  		{"1/4/2014", "feb_extra_bandwidth", "2233", "$51.00"},
  1154  		{"1/4/2014", "mar_hosting", "2233", "$30.00"},
  1155  	}
  1156  
  1157  	var buf bytes.Buffer
  1158  	table := NewWriter(&buf)
  1159  	table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
  1160  	table.SetAutoWrapText(false)
  1161  	table.SetAutoFormatHeaders(true)
  1162  	table.SetHeaderAlignment(ALIGN_LEFT)
  1163  	table.SetAlignment(ALIGN_LEFT)
  1164  	table.SetCenterSeparator("")
  1165  	table.SetColumnSeparator("")
  1166  	table.SetRowSeparator("")
  1167  	table.SetHeaderLine(false)
  1168  	table.SetBorder(false)
  1169  	table.SetTablePadding("\t") // pad with tabs
  1170  	table.SetNoWhiteSpace(true)
  1171  	table.AppendBulk(data) // Add Bulk Data
  1172  	table.Render()
  1173  
  1174  	want := `DATE    	DESCRIPTION        	CV2 	AMOUNT 
  1175  1/1/2014	jan_hosting        	2233	$10.98	
  1176  1/1/2014	feb_hosting        	2233	$54.95	
  1177  1/4/2014	feb_extra_bandwidth	2233	$51.00	
  1178  1/4/2014	mar_hosting        	2233	$30.00	
  1179  `
  1180  
  1181  	checkEqual(t, buf.String(), want, "kube format rendering failed")
  1182  }