// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package tabwriter import ( "io"; "os"; "testing"; ) type buffer struct { a []byte; } func (b *buffer) init(n int) { b.a = make([]byte, n)[0 : 0]; } func (b *buffer) clear() { b.a = b.a[0 : 0]; } func (b *buffer) Write(buf []byte) (written int, err os.Error) { n := len(b.a); m := len(buf); if n + m <= cap(b.a) { b.a = b.a[0 : n + m]; for i := 0; i < m; i++ { b.a[n+i] = buf[i]; } } else { panicln("buffer.Write: buffer too small", n, m, cap(b.a)); } return len(buf), nil; } func (b *buffer) String() string { return string(b.a); } func write(t *testing.T, testname string, w *Writer, src string) { written, err := io.WriteString(w, src); if err != nil { t.Errorf("--- test: %s\n--- src:\n%s\n--- write error: %v\n", testname, src, err); } if written != len(src) { t.Errorf("--- test: %s\n--- src:\n%s\n--- written = %d, len(src) = %d\n", testname, src, written, len(src)); } } func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) { err := w.Flush(); if err != nil { t.Errorf("--- test: %s\n--- src:\n%s\n--- flush error: %v\n", testname, src, err); } res := b.String(); if res != expected { t.Errorf("--- test: %s\n--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", testname, src, res, expected) } } func check(t *testing.T, testname string, tabwidth, padding int, padchar byte, flags uint, src, expected string) { var b buffer; b.init(1000); var w Writer; w.Init(&b, tabwidth, padding, padchar, flags); // write all at once b.clear(); write(t, testname, &w, src); verify(t, testname, &w, &b, src, expected); // write byte-by-byte b.clear(); for i := 0; i < len(src); i++ { write(t, testname, &w, src[i : i+1]); } verify(t, testname, &w, &b, src, expected); // write using Fibonacci slice sizes b.clear(); for i, d := 0, 0; i < len(src); { write(t, testname, &w, src[i : i+d]); i, d = i+d, d+1; if i+d > len(src) { d = len(src) - i; } } verify(t, testname, &w, &b, src, expected); } type entry struct { testname string; tabwidth, padding int; padchar byte; flags uint; src, expected string; } var tests = []entry { entry{ "1", 8, 1, '.', 0, "", "" }, entry{ "2", 8, 1, '.', 0, "\n\n\n", "\n\n\n" }, entry{ "3", 8, 1, '.', 0, "a\nb\nc", "a\nb\nc" }, entry{ "4a", 8, 1, '.', 0, "\t", // '\t' terminates an empty cell on last line - nothing to print "" }, entry{ "4b", 8, 1, '.', AlignRight, "\t", // '\t' terminates an empty cell on last line - nothing to print "" }, entry{ "5", 8, 1, '.', 0, "*\t*", "*.......*" }, entry{ "5b", 8, 1, '.', 0, "*\t*\n", "*.......*\n" }, entry{ "5c", 8, 1, '.', 0, "*\t*\t", "*.......*" }, entry{ "5d", 8, 1, '.', AlignRight, "*\t*\t", ".......**" }, entry{ "6", 8, 1, '.', 0, "\t\n", "........\n" }, entry{ "7a", 8, 1, '.', 0, "a) foo", "a) foo" }, entry{ "7b", 8, 1, ' ', 0, "b) foo\tbar", "b) foo bar" }, entry{ "7c", 8, 1, '.', 0, "c) foo\tbar\t", "c) foo..bar" }, entry{ "7d", 8, 1, '.', 0, "d) foo\tbar\n", "d) foo..bar\n" }, entry{ "7e", 8, 1, '.', 0, "e) foo\tbar\t\n", "e) foo..bar.....\n" }, entry{ "7f", 8, 1, '.', FilterHTML, "f) f<o\tbar\t\n", "f) f<o..bar.....\n" }, entry{ "7g", 8, 1, '.', FilterHTML, "g) f<o\tbar\t non-terminated entity &", "g) f<o..bar..... non-terminated entity &" }, entry{ "8", 8, 1, '*', 0, "Hello, world!\n", "Hello, world!\n" }, entry{ "9a", 0, 0, '.', 0, "1\t2\t3\t4\n" "11\t222\t3333\t44444\n", "1.2..3...4\n" "11222333344444\n" }, entry{ "9b", 0, 0, '.', FilterHTML, "1\t2\t3\t4\n" // \f inside HTML is ignored "11\t222\t3333\t44444\n", "1.2..3...4\n" "11222333344444\n" }, entry{ "9c", 0, 0, '.', 0, "1\t2\t3\t4\f" // \f causes a newline and flush "11\t222\t3333\t44444\n", "1234\n" "11222333344444\n" }, entry{ "10a", 5, 0, '.', 0, "1\t2\t3\t4\n", "1....2....3....4\n" }, entry{ "10b", 5, 0, '.', 0, "1\t2\t3\t4\t\n", "1....2....3....4....\n" }, entry{ "11", 8, 1, '.', 0, "本\tb\tc\n" "aa\t\u672c\u672c\u672c\tcccc\tddddd\n" "aaa\tbbbb\n", "本.......b.......c\n" "aa......本本本.....cccc....ddddd\n" "aaa.....bbbb\n" }, entry{ "12a", 8, 1, ' ', AlignRight, "a\tè\tc\t\n" "aa\tèèè\tcccc\tddddd\t\n" "aaa\tèèèè\t\n", " a è c\n" " aa èèè cccc ddddd\n" " aaa èèèè\n" }, entry{ "12b", 2, 0, ' ', 0, "a\tb\tc\n" "aa\tbbb\tcccc\n" "aaa\tbbbb\n", "a b c\n" "aa bbbcccc\n" "aaabbbb\n" }, entry{ "12c", 8, 1, '_', 0, "a\tb\tc\n" "aa\tbbb\tcccc\n" "aaa\tbbbb\n", "a_______b_______c\n" "aa______bbb_____cccc\n" "aaa_____bbbb\n" }, entry{ "13a", 4, 1, '-', 0, "4444\t日本語\t22\t1\t333\n" "999999999\t22\n" "7\t22\n" "\t\t\t88888888\n" "\n" "666666\t666666\t666666\t4444\n" "1\t1\t999999999\t0000000000\n", "4444------日本語-22--1---333\n" "999999999-22\n" "7---------22\n" "------------------88888888\n" "\n" "666666-666666-666666----4444\n" "1------1------999999999-0000000000\n" }, entry{ "13b", 4, 3, '.', 0, "4444\t333\t22\t1\t333\n" "999999999\t22\n" "7\t22\n" "\t\t\t88888888\n" "\n" "666666\t666666\t666666\t4444\n" "1\t1\t999999999\t0000000000\n", "4444........333...22...1...333\n" "999999999...22\n" "7...........22\n" "....................88888888\n" "\n" "666666...666666...666666......4444\n" "1........1........999999999...0000000000\n" }, entry{ "13c", 8, 1, '\t', FilterHTML, "4444\t333\t22\t1\t333\n" "999999999\t22\n" "7\t22\n" "\t\t\t88888888\n" "\n" "666666\t666666\t666666\t4444\n" "1\t1\t999999999\t0000000000\n", "4444\t\t333\t22\t1\t333\n" "999999999\t22\n" "7\t\t22\n" "\t\t\t\t88888888\n" "\n" "666666\t666666\t666666\t\t4444\n" "1\t1\t999999999\t0000000000\n" }, entry{ "14", 0, 2, ' ', AlignRight, ".0\t.3\t2.4\t-5.1\t\n" "23.0\t12345678.9\t2.4\t-989.4\t\n" "5.1\t12.0\t2.4\t-7.0\t\n" ".0\t0.0\t332.0\t8908.0\t\n" ".0\t-.3\t456.4\t22.1\t\n" ".0\t1.2\t44.4\t-13.3\t\t", " .0 .3 2.4 -5.1\n" " 23.0 12345678.9 2.4 -989.4\n" " 5.1 12.0 2.4 -7.0\n" " .0 0.0 332.0 8908.0\n" " .0 -.3 456.4 22.1\n" " .0 1.2 44.4 -13.3" }, entry{ "15a", 4, 0, '.', 0, "a\t\tb", "a.......b" }, entry{ "15b", 4, 0, '.', DiscardEmptyColumns, "a\t\tb", // htabs - do not discard column "a.......b" }, entry{ "15c", 4, 0, '.', DiscardEmptyColumns, "a\v\vb", "a...b" }, entry{ "15d", 4, 0, '.', AlignRight | DiscardEmptyColumns, "a\v\vb", "...ab" }, entry{ "16a", 100, 0, '\t', 0, "a\tb\t\td\n" "a\tb\t\td\te\n" "a\n" "a\tb\tc\td\n" "a\tb\tc\td\te\n", "a\tb\t\td\n" "a\tb\t\td\te\n" "a\n" "a\tb\tc\td\n" "a\tb\tc\td\te\n" }, entry{ "16b", 100, 0, '\t', DiscardEmptyColumns, "a\vb\v\vd\n" "a\vb\v\vd\ve\n" "a\n" "a\vb\vc\vd\n" "a\vb\vc\vd\ve\n", "a\tb\td\n" "a\tb\td\te\n" "a\n" "a\tb\tc\td\n" "a\tb\tc\td\te\n" }, entry{ "16c", 100, 0, '\t', DiscardEmptyColumns, "a\tb\t\td\n" // hard tabs - do not discard column "a\tb\t\td\te\n" "a\n" "a\tb\tc\td\n" "a\tb\tc\td\te\n", "a\tb\t\td\n" "a\tb\t\td\te\n" "a\n" "a\tb\tc\td\n" "a\tb\tc\td\te\n" }, } func Test(t *testing.T) { for _, e := range tests { check(t, e.testname, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected); } }