Skip to content

Commit

Permalink
table: fix merging issues in rows with wrapped columns (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
jedib0t committed Jul 14, 2022
1 parent b7796fb commit ba4b835
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 180 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -3,7 +3,7 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/jedib0t/go-pretty/v6.svg)](https://pkg.go.dev/github.com/jedib0t/go-pretty/v6)
[![Build Status](https://github.com/jedib0t/go-pretty/workflows/CI/badge.svg?branch=main)](https://github.com/jedib0t/go-pretty/actions?query=workflow%3ACI+event%3Apush+branch%3Amain)
[![Coverage Status](https://coveralls.io/repos/github/jedib0t/go-pretty/badge.svg?branch=main)](https://coveralls.io/github/jedib0t/go-pretty?branch=main)
[![Go Report Card](https://goreportcard.com/badge/github.com/jedib0t/go-pretty)](https://goreportcard.com/report/github.com/jedib0t/go-pretty)
[![Go Report Card](https://goreportcard.com/badge/github.com/jedib0t/go-pretty/v6)](https://goreportcard.com/report/github.com/jedib0t/go-pretty/v6)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jedib0t_go-pretty&metric=alert_status)](https://sonarcloud.io/dashboard?id=jedib0t_go-pretty)

Utilities to prettify console output of tables, lists, progress-bars, text, etc.
Expand Down
7 changes: 5 additions & 2 deletions table/render.go
Expand Up @@ -80,8 +80,11 @@ func (t *Table) renderColumn(out *strings.Builder, row rowStr, colIdx int, maxCo
// content is found; override alignment to Center in this case
rowConfig := t.getRowConfig(hint)
if rowConfig.AutoMerge && !hint.isSeparatorRow {
for idx := colIdx + 1; idx < len(row); idx++ {
if row[colIdx] != row[idx] {
// get the real row to consider all lines in each column instead of just
// looking at the current "line"
rowUnwrapped := t.getRow(hint.rowNumber-1, hint)
for idx := colIdx + 1; idx < len(rowUnwrapped); idx++ {
if rowUnwrapped[colIdx] != rowUnwrapped[idx] {
break
}
align = rowConfig.getAutoMergeAlign()
Expand Down
33 changes: 13 additions & 20 deletions table/render_csv_test.go
Expand Up @@ -17,7 +17,7 @@ func TestTable_RenderCSV(t *testing.T) {
tw.SetCaption(testCaption)
tw.SetTitle(testTitle1)

expectedOut := `Game of Thrones
compareOutput(t, tw.RenderCSV(), `Game of Thrones
#,First Name,Last Name,Salary,
1,Arya,Stark,3000,
20,Jon,Snow,2000,"You know nothing\, Jon Snow!"
Expand All @@ -27,8 +27,7 @@ The North Remembers!
This is known."
0,Valar,Morghulis,0,Faceless Men
,,Total,10000,
A Song of Ice and Fire`
assert.Equal(t, expectedOut, tw.RenderCSV())
A Song of Ice and Fire`)
}

func TestTable_RenderCSV_AutoIndex(t *testing.T) {
Expand All @@ -50,7 +49,7 @@ func TestTable_RenderCSV_AutoIndex(t *testing.T) {
tw.SetAutoIndex(true)
tw.SetStyle(StyleLight)

expectedOut := `,A,B,C,D,E,F,G,H,I,J
compareOutput(t, tw.RenderCSV(), `,A,B,C,D,E,F,G,H,I,J
1,A1,B1,C1,D1,E1,F1,G1,H1,I1,J1
2,A2,B2,C2,D2,E2,F2,G2,H2,I2,J2
3,A3,B3,C3,D3,E3,F3,G3,H3,I3,J3
Expand All @@ -61,8 +60,7 @@ func TestTable_RenderCSV_AutoIndex(t *testing.T) {
8,A8,B8,C8,D8,E8,F8,G8,H8,I8,J8
9,A9,B9,C9,D9,E9,F9,G9,H9,I9,J9
10,A10,B10,C10,D10,E10,F10,G10,H10,I10,J10
,AF,BF,CF,DF,EF,FF,GF,HF,IF,JF`
assert.Equal(t, expectedOut, tw.RenderCSV())
,AF,BF,CF,DF,EF,FF,GF,HF,IF,JF`)
}

func TestTable_RenderCSV_Empty(t *testing.T) {
Expand All @@ -84,41 +82,37 @@ func TestTable_RenderCSV_HiddenColumns(t *testing.T) {
t.Run("every column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{0, 1, 2, 3, 4}))

expectedOut := ``
assert.Equal(t, expectedOut, tw.RenderCSV())
compareOutput(t, tw.RenderCSV(), "")
})

t.Run("first column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{0}))

expectedOut := `First Name,Last Name,Salary,
compareOutput(t, tw.RenderCSV(), `First Name,Last Name,Salary,
>>Tyrion,Lannister<<,5013,
>>Arya,Stark<<,3013,
>>Jon,Snow<<,2013,"~You know nothing\, Jon Snow!~"
,Total,10000,`
assert.Equal(t, expectedOut, tw.RenderCSV())
,Total,10000,`)
})

t.Run("column hidden in the middle", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{1}))

expectedOut := `#,Last Name,Salary,
compareOutput(t, tw.RenderCSV(), `#,Last Name,Salary,
307,Lannister<<,5013,
8,Stark<<,3013,
27,Snow<<,2013,"~You know nothing\, Jon Snow!~"
,Total,10000,`
assert.Equal(t, expectedOut, tw.RenderCSV())
,Total,10000,`)
})

t.Run("last column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{4}))

expectedOut := `#,First Name,Last Name,Salary
compareOutput(t, tw.RenderCSV(), `#,First Name,Last Name,Salary
307,>>Tyrion,Lannister<<,5013
8,>>Arya,Stark<<,3013
27,>>Jon,Snow<<,2013
,,Total,10000`
assert.Equal(t, expectedOut, tw.RenderCSV())
,,Total,10000`)
})
}

Expand All @@ -130,11 +124,10 @@ func TestTable_RenderCSV_Sorted(t *testing.T) {
tw.AppendFooter(testFooter)
tw.SortBy([]SortBy{{Name: "Last Name", Mode: Asc}, {Name: "First Name", Mode: Asc}})

expectedOut := `#,First Name,Last Name,Salary,
compareOutput(t, tw.RenderCSV(), `#,First Name,Last Name,Salary,
300,Tyrion,Lannister,5000,
20,Jon,Snow,2000,"You know nothing\, Jon Snow!"
1,Arya,Stark,3000,
11,Sansa,Stark,6000,
,,Total,10000,`
assert.Equal(t, expectedOut, tw.RenderCSV())
,,Total,10000,`)
}
44 changes: 17 additions & 27 deletions table/render_html_test.go
Expand Up @@ -26,7 +26,7 @@ func TestTable_RenderHTML(t *testing.T) {
Format: text.FormatTitle,
}

expectedOut := `<table class="go-pretty-table">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
<caption class="title" align="left" class="bg-black bold fg-hi-blue">Game Of Thrones</caption>
<thead>
<tr>
Expand Down Expand Up @@ -77,9 +77,7 @@ func TestTable_RenderHTML(t *testing.T) {
</tr>
</tfoot>
<caption class="caption" style="caption-side: bottom;">A Song of Ice and Fire</caption>
</table>`

assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
}

func TestTable_RenderHTML_AutoIndex(t *testing.T) {
Expand All @@ -102,7 +100,7 @@ func TestTable_RenderHTML_AutoIndex(t *testing.T) {
tw.SetAutoIndex(true)
tw.SetStyle(StyleLight)

expectedOut := `<table class="go-pretty-table">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
<thead>
<tr>
<th>&nbsp;</th>
Expand Down Expand Up @@ -139,8 +137,7 @@ func TestTable_RenderHTML_AutoIndex(t *testing.T) {
<td>CF</td>
</tr>
</tfoot>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
}

func TestTable_RenderHTML_Colored(t *testing.T) {
Expand Down Expand Up @@ -181,7 +178,7 @@ func TestTable_RenderHTML_Colored(t *testing.T) {
},
})

expectedOut := `<table class="go-pretty-table-colored">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table-colored">
<caption class="title">Game of Thrones</caption>
<thead>
<tr>
Expand Down Expand Up @@ -232,8 +229,7 @@ func TestTable_RenderHTML_Colored(t *testing.T) {
</tr>
</tfoot>
<caption class="caption" style="caption-side: bottom;">A Song of Ice and Fire</caption>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
}

func TestTable_RenderHTML_CustomStyle(t *testing.T) {
Expand All @@ -252,7 +248,7 @@ func TestTable_RenderHTML_CustomStyle(t *testing.T) {
}
tw.SetOutputMirror(nil)

expectedOut := `<table class="game-of-thrones">
compareOutput(t, tw.RenderHTML(), `<table class="game-of-thrones">
<thead>
<tr>
<th><!-- test -->&nbsp;</th>
Expand Down Expand Up @@ -299,8 +295,7 @@ func TestTable_RenderHTML_CustomStyle(t *testing.T) {
<td><!-- test -->&nbsp;</td>
</tr>
</tfoot>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
}

func TestTable_RenderHTML_Empty(t *testing.T) {
Expand All @@ -322,14 +317,13 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
t.Run("every column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{0, 1, 2, 3, 4}))

expectedOut := ``
assert.Equal(t, expectedOut, tw.RenderHTML())
compareOutput(t, tw.RenderHTML(), "")
})

t.Run("first column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{0}))

expectedOut := `<table class="go-pretty-table">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
<thead>
<tr>
<th>First Name</th>
Expand Down Expand Up @@ -366,14 +360,13 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
<td>&nbsp;</td>
</tr>
</tfoot>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
})

t.Run("column hidden in the middle", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{1}))

expectedOut := `<table class="go-pretty-table">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
<thead>
<tr>
<th align="right">#</th>
Expand Down Expand Up @@ -410,14 +403,13 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
<td>&nbsp;</td>
</tr>
</tfoot>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
})

t.Run("last column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{4}))

expectedOut := `<table class="go-pretty-table">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
<thead>
<tr>
<th align="right">#</th>
Expand Down Expand Up @@ -454,8 +446,7 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
<td align="right">10000</td>
</tr>
</tfoot>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
})
}

Expand All @@ -467,7 +458,7 @@ func TestTable_RenderHTML_Sorted(t *testing.T) {
tw.AppendFooter(testFooter)
tw.SortBy([]SortBy{{Name: "Last Name", Mode: Asc}, {Name: "First Name", Mode: Asc}})

expectedOut := `<table class="go-pretty-table">
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
<thead>
<tr>
<th align="right">#</th>
Expand Down Expand Up @@ -516,6 +507,5 @@ func TestTable_RenderHTML_Sorted(t *testing.T) {
<td>&nbsp;</td>
</tr>
</tfoot>
</table>`
assert.Equal(t, expectedOut, tw.RenderHTML())
</table>`)
}
34 changes: 13 additions & 21 deletions table/render_markdown_test.go
Expand Up @@ -17,7 +17,7 @@ func TestTable_RenderMarkdown(t *testing.T) {
tw.SetCaption(testCaption)
tw.SetTitle(testTitle1)

expectedOut := `# Game of Thrones
compareOutput(t, tw.RenderMarkdown(), `# Game of Thrones
| # | First Name | Last Name | Salary | |
| ---:| --- | --- | ---:| --- |
| 1 | Arya | Stark | 3000 | |
Expand All @@ -26,9 +26,7 @@ func TestTable_RenderMarkdown(t *testing.T) {
| 0 | Valar | Morghulis | 0 | Faceless<br/>Men |
| 0 | Valar | Morghulis | 0 | Faceless\|Men |
| | | Total | 10000 | |
_A Song of Ice and Fire_`

assert.Equal(t, expectedOut, tw.RenderMarkdown())
_A Song of Ice and Fire_`)
}

func TestTable_RenderMarkdown_AutoIndex(t *testing.T) {
Expand All @@ -50,7 +48,7 @@ func TestTable_RenderMarkdown_AutoIndex(t *testing.T) {
tw.SetAutoIndex(true)
tw.SetStyle(StyleLight)

expectedOut := `| | A | B | C | D | E | F | G | H | I | J |
compareOutput(t, tw.RenderMarkdown(), `| | A | B | C | D | E | F | G | H | I | J |
| ---:| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | A1 | B1 | C1 | D1 | E1 | F1 | G1 | H1 | I1 | J1 |
| 2 | A2 | B2 | C2 | D2 | E2 | F2 | G2 | H2 | I2 | J2 |
Expand All @@ -62,8 +60,7 @@ func TestTable_RenderMarkdown_AutoIndex(t *testing.T) {
| 8 | A8 | B8 | C8 | D8 | E8 | F8 | G8 | H8 | I8 | J8 |
| 9 | A9 | B9 | C9 | D9 | E9 | F9 | G9 | H9 | I9 | J9 |
| 10 | A10 | B10 | C10 | D10 | E10 | F10 | G10 | H10 | I10 | J10 |
| | AF | BF | CF | DF | EF | FF | GF | HF | IF | JF |`
assert.Equal(t, expectedOut, tw.RenderMarkdown())
| | AF | BF | CF | DF | EF | FF | GF | HF | IF | JF |`)
}

func TestTable_RenderMarkdown_Empty(t *testing.T) {
Expand All @@ -85,44 +82,40 @@ func TestTable_RenderMarkdown_HiddenColumns(t *testing.T) {
t.Run("every column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{0, 1, 2, 3, 4}))

expectedOut := ``
assert.Equal(t, expectedOut, tw.RenderMarkdown())
compareOutput(t, tw.RenderMarkdown(), "")
})

t.Run("first column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{0}))

expectedOut := `| First Name | Last Name | Salary | |
compareOutput(t, tw.RenderMarkdown(), `| First Name | Last Name | Salary | |
| --- | --- | ---:| --- |
| >>Tyrion | Lannister<< | 5013 | |
| >>Arya | Stark<< | 3013 | |
| >>Jon | Snow<< | 2013 | ~You know nothing, Jon Snow!~ |
| | Total | 10000 | |`
assert.Equal(t, expectedOut, tw.RenderMarkdown())
| | Total | 10000 | |`)
})

t.Run("column hidden in the middle", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{1}))

expectedOut := `| # | Last Name | Salary | |
compareOutput(t, tw.RenderMarkdown(), `| # | Last Name | Salary | |
| ---:| --- | ---:| --- |
| 307 | Lannister<< | 5013 | |
| 8 | Stark<< | 3013 | |
| 27 | Snow<< | 2013 | ~You know nothing, Jon Snow!~ |
| | Total | 10000 | |`
assert.Equal(t, expectedOut, tw.RenderMarkdown())
| | Total | 10000 | |`)
})

t.Run("last column hidden", func(t *testing.T) {
tw.SetColumnConfigs(generateColumnConfigsWithHiddenColumns([]int{4}))

expectedOut := `| # | First Name | Last Name | Salary |
compareOutput(t, tw.RenderMarkdown(), `| # | First Name | Last Name | Salary |
| ---:| --- | --- | ---:|
| 307 | >>Tyrion | Lannister<< | 5013 |
| 8 | >>Arya | Stark<< | 3013 |
| 27 | >>Jon | Snow<< | 2013 |
| | | Total | 10000 |`
assert.Equal(t, expectedOut, tw.RenderMarkdown())
| | | Total | 10000 |`)
})
}

Expand All @@ -134,12 +127,11 @@ func TestTable_RendeMarkdown_Sorted(t *testing.T) {
tw.AppendFooter(testFooter)
tw.SortBy([]SortBy{{Name: "Last Name", Mode: Asc}, {Name: "First Name", Mode: Asc}})

expectedOut := `| # | First Name | Last Name | Salary | |
compareOutput(t, tw.RenderMarkdown(), `| # | First Name | Last Name | Salary | |
| ---:| --- | --- | ---:| --- |
| 300 | Tyrion | Lannister | 5000 | |
| 20 | Jon | Snow | 2000 | You know nothing, Jon Snow! |
| 1 | Arya | Stark | 3000 | |
| 11 | Sansa | Stark | 6000 | |
| | | Total | 10000 | |`
assert.Equal(t, expectedOut, tw.RenderMarkdown())
| | | Total | 10000 | |`)
}

0 comments on commit ba4b835

Please sign in to comment.