github.com/olekukonko/tablewriter: update to 8d0265a48283795806b872b4728c67bf5c777f20
Update the tablewriter package to a newer version, which provides more
fine-grained configurations. Used in madb.
Change-Id: I3c5923f248fc00591509340020c106ecdff34084
MultiPart: 1/2
diff --git a/go/src/github.com/olekukonko/tablewriter/LICENSE b/go/src/github.com/olekukonko/tablewriter/LICENCE.md
similarity index 100%
rename from go/src/github.com/olekukonko/tablewriter/LICENSE
rename to go/src/github.com/olekukonko/tablewriter/LICENCE.md
diff --git a/go/src/github.com/olekukonko/tablewriter/README.google b/go/src/github.com/olekukonko/tablewriter/README.google
index 38f6d5f..0b2e0a5 100644
--- a/go/src/github.com/olekukonko/tablewriter/README.google
+++ b/go/src/github.com/olekukonko/tablewriter/README.google
@@ -1,5 +1,5 @@
-URL: https://github.com/olekukonko/tablewriter/archive/1805332a9a6612da6603ccfdd99a036afb89cec6.zip
-Version: 1805332a9a6612da6603ccfdd99a036afb89cec6
+URL: https://github.com/olekukonko/tablewriter/archive/8d0265a48283795806b872b4728c67bf5c777f20.zip
+Version: 8d0265a48283795806b872b4728c67bf5c777f20
License: MIT
License File: LICENSE
diff --git a/go/src/github.com/olekukonko/tablewriter/README.md b/go/src/github.com/olekukonko/tablewriter/README.md
index 4ee4435..e7a501b 100644
--- a/go/src/github.com/olekukonko/tablewriter/README.md
+++ b/go/src/github.com/olekukonko/tablewriter/README.md
@@ -131,6 +131,33 @@
*------------*-----------*---------*
```
+##### Example 5 - Markdown Format
+```go
+data := [][]string{
+ []string{"1/1/2014", "Domain name", "2233", "$10.98"},
+ []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
+ []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
+ []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
+}
+
+table := tablewriter.NewWriter(os.Stdout)
+table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
+table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
+table.SetCenterSeparator("|")
+table.AppendBulk(data) // Add Bulk Data
+table.Render()
+```
+
+##### Output 5
+```
+| DATE | DESCRIPTION | CV2 | AMOUNT |
+|----------|--------------------------|------|--------|
+| 1/1/2014 | Domain name | 2233 | $10.98 |
+| 1/1/2014 | January Hosting | 2233 | $54.95 |
+| 1/4/2014 | February Hosting | 2233 | $51.00 |
+| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
+```
+
#### TODO
- ~~Import Directly from CSV~~ - `done`
- ~~Support for `SetFooter`~~ - `done`
diff --git a/go/src/github.com/olekukonko/tablewriter/csv2table/csv2table.go b/go/src/github.com/olekukonko/tablewriter/csv2table/csv2table.go
index 411f653..a4e9b13 100644
--- a/go/src/github.com/olekukonko/tablewriter/csv2table/csv2table.go
+++ b/go/src/github.com/olekukonko/tablewriter/csv2table/csv2table.go
@@ -14,7 +14,7 @@
fileName = flag.String("f", "", "Set file with eg. sample.csv")
delimiter = flag.String("d", ",", "Set CSV File delimiter eg. ,|;|\t ")
header = flag.Bool("h", true, "Set header options eg. true|false ")
- align = flag.String("a", "none", "Set aligmement with eg. none|left|right|centre")
+ align = flag.String("a", "none", "Set aligmement with eg. none|left|right|center")
pipe = flag.Bool("p", false, "Suport for Piping from STDIN")
border = flag.Bool("b", true, "Enable / disable table border")
)
@@ -72,7 +72,7 @@
case "right":
table.SetAlignment(tablewriter.ALIGN_RIGHT)
case "center":
- table.SetAlignment(tablewriter.ALIGN_CENTRE)
+ table.SetAlignment(tablewriter.ALIGN_CENTER)
}
table.SetBorder(*border)
table.Render()
diff --git a/go/src/github.com/olekukonko/tablewriter/table.go b/go/src/github.com/olekukonko/tablewriter/table.go
index 2837640..ffa5ffd 100644
--- a/go/src/github.com/olekukonko/tablewriter/table.go
+++ b/go/src/github.com/olekukonko/tablewriter/table.go
@@ -20,7 +20,7 @@
)
const (
- CENTRE = "+"
+ CENTER = "+"
ROW = "-"
COLUMN = "|"
SPACE = " "
@@ -28,69 +28,86 @@
const (
ALIGN_DEFAULT = iota
- ALIGN_CENTRE
+ ALIGN_CENTER
ALIGN_RIGHT
ALIGN_LEFT
)
var (
- decimal = regexp.MustCompile(`^[0-9]+(.[0-9]+?)$`)
- percent = regexp.MustCompile(`^[0-9]+(.[0-9]+?)%$`)
+ decimal = regexp.MustCompile(`^\d*\.?\d*$`)
+ percent = regexp.MustCompile(`^\d*\.?\d*$%$`)
)
+type Border struct {
+ Left bool
+ Right bool
+ Top bool
+ Bottom bool
+}
+
type Table struct {
- out io.Writer
- rows [][]string
- lines [][][]string
- cs map[int]int
- rs map[int]int
- headers []string
- footers []string
- mW int
- pCenter string
- pRow string
- pColumn string
- tColumn int
- tRow int
- align int
- rowLine bool
- border bool
- colSize int
+ out io.Writer
+ rows [][]string
+ lines [][][]string
+ cs map[int]int
+ rs map[int]int
+ headers []string
+ footers []string
+ autoFmt bool
+ autoWrap bool
+ mW int
+ pCenter string
+ pRow string
+ pColumn string
+ tColumn int
+ tRow int
+ hAlign int
+ fAlign int
+ align int
+ rowLine bool
+ hdrLine bool
+ borders Border
+ colSize int
}
// Start New Table
// Take io.Writer Directly
func NewWriter(writer io.Writer) *Table {
t := &Table{
- out: writer,
- rows: [][]string{},
- lines: [][][]string{},
- cs: make(map[int]int),
- rs: make(map[int]int),
- headers: []string{},
- footers: []string{},
- mW: MAX_ROW_WIDTH,
- pCenter: CENTRE,
- pRow: ROW,
- pColumn: COLUMN,
- tColumn: -1,
- tRow: -1,
- align: ALIGN_DEFAULT,
- rowLine: false,
- border: true,
- colSize: -1}
+ out: writer,
+ rows: [][]string{},
+ lines: [][][]string{},
+ cs: make(map[int]int),
+ rs: make(map[int]int),
+ headers: []string{},
+ footers: []string{},
+ autoFmt: true,
+ autoWrap: true,
+ mW: MAX_ROW_WIDTH,
+ pCenter: CENTER,
+ pRow: ROW,
+ pColumn: COLUMN,
+ tColumn: -1,
+ tRow: -1,
+ hAlign: ALIGN_DEFAULT,
+ fAlign: ALIGN_DEFAULT,
+ align: ALIGN_DEFAULT,
+ rowLine: false,
+ hdrLine: true,
+ borders: Border{Left: true, Right: true, Bottom: true, Top: true},
+ colSize: -1}
return t
}
// Render table output
func (t Table) Render() {
- if t.border {
+ if t.borders.Top {
t.printLine(true)
}
t.printHeading()
t.printRows()
- if !t.rowLine && t.border {
+ if !t.rowLine && t.borders.Bottom {
t.printLine(true)
}
t.printFooter()
@@ -102,7 +119,7 @@
t.colSize = len(keys)
for i, v := range keys {
t.parseDimension(v, i, -1)
- t.headers = append(t.headers, Title(v))
+ t.headers = append(t.headers, v)
}
}
@@ -111,10 +128,20 @@
//t.colSize = len(keys)
for i, v := range keys {
t.parseDimension(v, i, -1)
- t.footers = append(t.footers, Title(v))
+ t.footers = append(t.footers, v)
}
}
+// Turn header autoformatting on/off. Default is on (true).
+func (t *Table) SetAutoFormatHeaders(auto bool) {
+ t.autoFmt = auto
+}
+
+// Turn automatic multiline text adjustment on/off. Default is on (true).
+func (t *Table) SetAutoWrapText(auto bool) {
+ t.autoWrap = auto
+}
+
// Set the Default column width
func (t *Table) SetColWidth(width int) {
t.mW = width
@@ -135,11 +162,27 @@
t.pCenter = sep
}
+// Set Header Alignment
+func (t *Table) SetHeaderAlignment(hAlign int) {
+ t.hAlign = hAlign
+}
+
+// Set Footer Alignment
+func (t *Table) SetFooterAlignment(fAlign int) {
+ t.fAlign = fAlign
+}
+
// Set Table Alignment
func (t *Table) SetAlignment(align int) {
t.align = align
}
+// Set Header Line
+// This would enable / disable a line after the header
+func (t *Table) SetHeaderLine(line bool) {
+ t.hdrLine = line
+}
+
// Set Row Line
// This would enable / disable a line on each row of the table
func (t *Table) SetRowLine(line bool) {
@@ -149,11 +192,15 @@
// Set Table Border
// This would enable / disable line around the table
func (t *Table) SetBorder(border bool) {
- t.border = border
+ t.SetBorders(Border{border, border, border, border})
+}
+
+func (t *Table) SetBorders(border Border) {
+ t.borders = border
}
// Append row to table
-func (t *Table) Append(row []string) error {
+func (t *Table) Append(row []string) {
rowSize := len(t.headers)
if rowSize > t.colSize {
t.colSize = rowSize
@@ -172,19 +219,14 @@
line = append(line, out)
}
t.lines = append(t.lines, line)
- return nil
}
// Allow Support for Bulk Append
// Eliminates repeated for loops
-func (t *Table) AppendBulk(rows [][]string) (err error) {
+func (t *Table) AppendBulk(rows [][]string) {
for _, row := range rows {
- err = t.Append(row)
- if err != nil {
- return err
- }
+ t.Append(row)
}
- return nil
}
// Print line based on row width
@@ -203,6 +245,19 @@
}
}
+// Return the PadRight function if align is left, PadLeft if align is right,
+// and Pad by default
+func pad(align int) func(string, string, int) string {
+ padFunc := Pad
+ switch align {
+ case ALIGN_LEFT:
+ padFunc = PadRight
+ case ALIGN_RIGHT:
+ padFunc = PadLeft
+ }
+ return padFunc
+}
+
// Print heading information
func (t Table) printHeading() {
// Check if headers is available
@@ -212,22 +267,31 @@
// Check if border is set
// Replace with space if not set
- fmt.Fprint(t.out, ConditionString(t.border, t.pColumn, SPACE))
+ fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE))
// Identify last column
end := len(t.cs) - 1
+ // Get pad function
+ padFunc := pad(t.hAlign)
+
// Print Heading column
for i := 0; i <= end; i++ {
v := t.cs[i]
- pad := ConditionString((i == end && !t.border), SPACE, t.pColumn)
+ h := t.headers[i]
+ if t.autoFmt {
+ h = Title(h)
+ }
+ pad := ConditionString((i == end && !t.borders.Left), SPACE, t.pColumn)
fmt.Fprintf(t.out, " %s %s",
- Pad(t.headers[i], SPACE, v),
+ padFunc(h, SPACE, v),
pad)
}
// Next line
fmt.Fprintln(t.out)
- t.printLine(true)
+ if t.hdrLine {
+ t.printLine(true)
+ }
}
// Print heading information
@@ -238,26 +302,33 @@
}
// Only print line if border is not set
- if !t.border {
+ if !t.borders.Bottom {
t.printLine(true)
}
// Check if border is set
// Replace with space if not set
- fmt.Fprint(t.out, ConditionString(t.border, t.pColumn, SPACE))
+ fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.pColumn, SPACE))
// Identify last column
end := len(t.cs) - 1
+ // Get pad function
+ padFunc := pad(t.fAlign)
+
// Print Heading column
for i := 0; i <= end; i++ {
v := t.cs[i]
- pad := ConditionString((i == end && !t.border), SPACE, t.pColumn)
+ f := t.footers[i]
+ if t.autoFmt {
+ f = Title(f)
+ }
+ pad := ConditionString((i == end && !t.borders.Top), SPACE, t.pColumn)
if len(t.footers[i]) == 0 {
pad = SPACE
}
fmt.Fprintf(t.out, " %s %s",
- Pad(t.footers[i], SPACE, v),
+ padFunc(f, SPACE, v),
pad)
}
// Next line
@@ -277,7 +348,7 @@
}
// Set center to be space if length is 0
- if length == 0 && !t.border {
+ if length == 0 && !t.borders.Right {
center = SPACE
}
@@ -291,7 +362,7 @@
pad = SPACE
}
// Ignore left space of it has printed before
- if hasPrinted || t.border {
+ if hasPrinted || t.borders.Left {
pad = t.pRow
center = t.pCenter
}
@@ -356,7 +427,7 @@
for y := 0; y < total; y++ {
// Check if border is set
- fmt.Fprint(t.out, ConditionString((!t.border && y == 0), SPACE, t.pColumn))
+ fmt.Fprint(t.out, ConditionString((!t.borders.Left && y == 0), SPACE, t.pColumn))
fmt.Fprintf(t.out, SPACE)
str := columns[y][x]
@@ -364,7 +435,7 @@
// This would print alignment
// Default alignment would use multiple configuration
switch t.align {
- case ALIGN_CENTRE: //
+ case ALIGN_CENTER: //
fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y]))
case ALIGN_RIGHT:
fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y]))
@@ -389,7 +460,7 @@
}
// Check if border is set
// Replace with space if not set
- fmt.Fprint(t.out, ConditionString(t.border, t.pColumn, SPACE))
+ fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE))
fmt.Fprintln(t.out)
}
@@ -421,7 +492,11 @@
return raw
}
// Calculate Height
- raw, _ = WrapString(str, t.cs[colKey])
+ if t.autoWrap {
+ raw, _ = WrapString(str, t.cs[colKey])
+ } else {
+ raw = getLines(str)
+ }
for _, line := range raw {
if w := DisplayWidth(line); w > max {
diff --git a/go/src/github.com/olekukonko/tablewriter/table_test.go b/go/src/github.com/olekukonko/tablewriter/table_test.go
index 391597b..b2c5c66 100644
--- a/go/src/github.com/olekukonko/tablewriter/table_test.go
+++ b/go/src/github.com/olekukonko/tablewriter/table_test.go
@@ -87,7 +87,7 @@
table.Render()
}
-func TestBorder(t *testing.T) {
+func TestNoBorder(t *testing.T) {
data := [][]string{
[]string{"1/1/2014", "Domain name", "2233", "$10.98"},
[]string{"1/1/2014", "January Hosting", "2233", "$54.95"},
@@ -95,12 +95,90 @@
[]string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
}
- table := NewWriter(os.Stdout)
+ var buf bytes.Buffer
+ table := NewWriter(&buf)
table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
table.SetBorder(false) // Set Border to false
table.AppendBulk(data) // Add Bulk Data
table.Render()
+
+ want := ` DATE | DESCRIPTION | CV2 | AMOUNT
++----------+--------------------------+-------+---------+
+ 1/1/2014 | Domain name | 2233 | $10.98
+ 1/1/2014 | January Hosting | 2233 | $54.95
+ 1/4/2014 | February Hosting | 2233 | $51.00
+ 1/4/2014 | February Extra Bandwidth | 2233 | $30.00
++----------+--------------------------+-------+---------+
+ TOTAL | $146 93
+ +-------+---------+
+`
+ got := buf.String()
+ if got != want {
+ t.Errorf("border table rendering failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
+}
+
+func TestWithBorder(t *testing.T) {
+ data := [][]string{
+ []string{"1/1/2014", "Domain name", "2233", "$10.98"},
+ []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
+ []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
+ []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
+ }
+
+ var buf bytes.Buffer
+ table := NewWriter(&buf)
+ table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
+ table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
+ table.AppendBulk(data) // Add Bulk Data
+ table.Render()
+
+ want := `+----------+--------------------------+-------+---------+
+| DATE | DESCRIPTION | CV2 | AMOUNT |
++----------+--------------------------+-------+---------+
+| 1/1/2014 | Domain name | 2233 | $10.98 |
+| 1/1/2014 | January Hosting | 2233 | $54.95 |
+| 1/4/2014 | February Hosting | 2233 | $51.00 |
+| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
++----------+--------------------------+-------+---------+
+| TOTAL | $146 93 |
++----------+--------------------------+-------+---------+
+`
+ got := buf.String()
+ if got != want {
+ t.Errorf("border table rendering failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
+}
+
+func TestPrintingInMarkdown(t *testing.T) {
+ fmt.Println("TESTING")
+ data := [][]string{
+ []string{"1/1/2014", "Domain name", "2233", "$10.98"},
+ []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
+ []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
+ []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
+ }
+
+ var buf bytes.Buffer
+ table := NewWriter(&buf)
+ table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
+ table.AppendBulk(data) // Add Bulk Data
+ table.SetBorders(Border{Left: true, Top: false, Right: true, Bottom: false})
+ table.SetCenterSeparator("|")
+ table.Render()
+
+ want := `| DATE | DESCRIPTION | CV2 | AMOUNT |
+|----------|--------------------------|------|--------|
+| 1/1/2014 | Domain name | 2233 | $10.98 |
+| 1/1/2014 | January Hosting | 2233 | $54.95 |
+| 1/4/2014 | February Hosting | 2233 | $51.00 |
+| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
+`
+ got := buf.String()
+ if got != want {
+ t.Errorf("border table rendering failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
}
func TestPrintHeading(t *testing.T) {
@@ -117,6 +195,21 @@
}
}
+func TestPrintHeadingWithoutAutoFormat(t *testing.T) {
+ var buf bytes.Buffer
+ table := NewWriter(&buf)
+ table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
+ table.SetAutoFormatHeaders(false)
+ table.printHeading()
+ want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c |
++---+---+---+---+---+---+---+---+---+---+---+---+
+`
+ got := buf.String()
+ if got != want {
+ t.Errorf("header rendering failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
+}
+
func TestPrintFooter(t *testing.T) {
var buf bytes.Buffer
table := NewWriter(&buf)
@@ -132,6 +225,56 @@
}
}
+func TestPrintFooterWithoutAutoFormat(t *testing.T) {
+ var buf bytes.Buffer
+ table := NewWriter(&buf)
+ table.SetAutoFormatHeaders(false)
+ table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
+ table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"})
+ table.printFooter()
+ want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c |
++---+---+---+---+---+---+---+---+---+---+---+---+
+`
+ got := buf.String()
+ if got != want {
+ t.Errorf("footer rendering failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
+}
+
+func TestPrintTableWithAndWithoutAutoWrap(t *testing.T) {
+ var buf bytes.Buffer
+ var multiline = `A multiline
+string with some lines being really long.`
+
+ with := NewWriter(&buf)
+ with.Append([]string{multiline})
+ with.Render()
+ want := `+--------------------------------+
+| A multiline string with some |
+| lines being really long. |
++--------------------------------+
+`
+ got := buf.String()
+ if got != want {
+ t.Errorf("multiline text rendering with wrapping failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
+
+ buf.Truncate(0)
+ without := NewWriter(&buf)
+ without.SetAutoWrapText(false)
+ without.Append([]string{multiline})
+ without.Render()
+ want = `+-------------------------------------------+
+| A multiline |
+| string with some lines being really long. |
++-------------------------------------------+
+`
+ got = buf.String()
+ if got != want {
+ t.Errorf("multiline text rendering without wrapping rendering failed\ngot:\n%s\nwant:\n%s\n", got, want)
+ }
+}
+
func TestPrintLine(t *testing.T) {
header := make([]string, 12)
val := " "
diff --git a/go/src/github.com/olekukonko/tablewriter/util.go b/go/src/github.com/olekukonko/tablewriter/util.go
index e006ac6..2deefbc 100644
--- a/go/src/github.com/olekukonko/tablewriter/util.go
+++ b/go/src/github.com/olekukonko/tablewriter/util.go
@@ -11,15 +11,14 @@
"math"
"regexp"
"strings"
- "unicode/utf8"
+
+ "github.com/mattn/go-runewidth"
)
-var (
- ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]")
-)
+var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]")
func DisplayWidth(str string) int {
- return utf8.RuneCountInString(ansi.ReplaceAllLiteralString(str, ""))
+ return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, ""))
}
// Simple Condition for string
diff --git a/go/src/github.com/olekukonko/tablewriter/wrap.go b/go/src/github.com/olekukonko/tablewriter/wrap.go
index c2d607f..f3747d9 100644
--- a/go/src/github.com/olekukonko/tablewriter/wrap.go
+++ b/go/src/github.com/olekukonko/tablewriter/wrap.go
@@ -91,3 +91,13 @@
}
return lines
}
+
+// getLines decomposes a multiline string into a slice of strings.
+func getLines(s string) []string {
+ var lines []string
+
+ for _, line := range strings.Split(strings.TrimSpace(s), nl) {
+ lines = append(lines, line)
+ }
+ return lines
+}
diff --git a/go/src/github.com/olekukonko/tablewriter/wrap_test.go b/go/src/github.com/olekukonko/tablewriter/wrap_test.go
index a4e2642..2d510d1 100644
--- a/go/src/github.com/olekukonko/tablewriter/wrap_test.go
+++ b/go/src/github.com/olekukonko/tablewriter/wrap_test.go
@@ -42,3 +42,14 @@
t.Fail()
}
}
+
+func TestDisplayWidth(t *testing.T) {
+ input := "Česká řeřicha"
+ if n := DisplayWidth(input); n != 13 {
+ t.Errorf("Wants: %d Got: %d", 13, n)
+ }
+ input = "\033[43;30m" + input + "\033[00m"
+ if n := DisplayWidth(input); n != 13 {
+ t.Errorf("Wants: %d Got: %d", 13, n)
+ }
+}