Skip to content

Commit ba4b835

Browse files
authored
table: fix merging issues in rows with wrapped columns (#214)
1 parent b7796fb commit ba4b835

7 files changed

+175
-180
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Go Reference](https://pkg.go.dev/badge/github.com/jedib0t/go-pretty/v6.svg)](https://pkg.go.dev/github.com/jedib0t/go-pretty/v6)
44
[![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)
55
[![Coverage Status](https://coveralls.io/repos/github/jedib0t/go-pretty/badge.svg?branch=main)](https://coveralls.io/github/jedib0t/go-pretty?branch=main)
6-
[![Go Report Card](https://goreportcard.com/badge/github.com/jedib0t/go-pretty)](https://goreportcard.com/report/github.com/jedib0t/go-pretty)
6+
[![Go Report Card](https://goreportcard.com/badge/github.com/jedib0t/go-pretty/v6)](https://goreportcard.com/report/github.com/jedib0t/go-pretty/v6)
77
[![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)
88

99
Utilities to prettify console output of tables, lists, progress-bars, text, etc.

table/render.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,11 @@ func (t *Table) renderColumn(out *strings.Builder, row rowStr, colIdx int, maxCo
8080
// content is found; override alignment to Center in this case
8181
rowConfig := t.getRowConfig(hint)
8282
if rowConfig.AutoMerge && !hint.isSeparatorRow {
83-
for idx := colIdx + 1; idx < len(row); idx++ {
84-
if row[colIdx] != row[idx] {
83+
// get the real row to consider all lines in each column instead of just
84+
// looking at the current "line"
85+
rowUnwrapped := t.getRow(hint.rowNumber-1, hint)
86+
for idx := colIdx + 1; idx < len(rowUnwrapped); idx++ {
87+
if rowUnwrapped[colIdx] != rowUnwrapped[idx] {
8588
break
8689
}
8790
align = rowConfig.getAutoMergeAlign()

table/render_csv_test.go

+13-20
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestTable_RenderCSV(t *testing.T) {
1717
tw.SetCaption(testCaption)
1818
tw.SetTitle(testTitle1)
1919

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

3433
func TestTable_RenderCSV_AutoIndex(t *testing.T) {
@@ -50,7 +49,7 @@ func TestTable_RenderCSV_AutoIndex(t *testing.T) {
5049
tw.SetAutoIndex(true)
5150
tw.SetStyle(StyleLight)
5251

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

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

87-
expectedOut := ``
88-
assert.Equal(t, expectedOut, tw.RenderCSV())
85+
compareOutput(t, tw.RenderCSV(), "")
8986
})
9087

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

94-
expectedOut := `First Name,Last Name,Salary,
91+
compareOutput(t, tw.RenderCSV(), `First Name,Last Name,Salary,
9592
>>Tyrion,Lannister<<,5013,
9693
>>Arya,Stark<<,3013,
9794
>>Jon,Snow<<,2013,"~You know nothing\, Jon Snow!~"
98-
,Total,10000,`
99-
assert.Equal(t, expectedOut, tw.RenderCSV())
95+
,Total,10000,`)
10096
})
10197

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

105-
expectedOut := `#,Last Name,Salary,
101+
compareOutput(t, tw.RenderCSV(), `#,Last Name,Salary,
106102
307,Lannister<<,5013,
107103
8,Stark<<,3013,
108104
27,Snow<<,2013,"~You know nothing\, Jon Snow!~"
109-
,Total,10000,`
110-
assert.Equal(t, expectedOut, tw.RenderCSV())
105+
,Total,10000,`)
111106
})
112107

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

116-
expectedOut := `#,First Name,Last Name,Salary
111+
compareOutput(t, tw.RenderCSV(), `#,First Name,Last Name,Salary
117112
307,>>Tyrion,Lannister<<,5013
118113
8,>>Arya,Stark<<,3013
119114
27,>>Jon,Snow<<,2013
120-
,,Total,10000`
121-
assert.Equal(t, expectedOut, tw.RenderCSV())
115+
,,Total,10000`)
122116
})
123117
}
124118

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

133-
expectedOut := `#,First Name,Last Name,Salary,
127+
compareOutput(t, tw.RenderCSV(), `#,First Name,Last Name,Salary,
134128
300,Tyrion,Lannister,5000,
135129
20,Jon,Snow,2000,"You know nothing\, Jon Snow!"
136130
1,Arya,Stark,3000,
137131
11,Sansa,Stark,6000,
138-
,,Total,10000,`
139-
assert.Equal(t, expectedOut, tw.RenderCSV())
132+
,,Total,10000,`)
140133
}

table/render_html_test.go

+17-27
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestTable_RenderHTML(t *testing.T) {
2626
Format: text.FormatTitle,
2727
}
2828

29-
expectedOut := `<table class="go-pretty-table">
29+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
3030
<caption class="title" align="left" class="bg-black bold fg-hi-blue">Game Of Thrones</caption>
3131
<thead>
3232
<tr>
@@ -77,9 +77,7 @@ func TestTable_RenderHTML(t *testing.T) {
7777
</tr>
7878
</tfoot>
7979
<caption class="caption" style="caption-side: bottom;">A Song of Ice and Fire</caption>
80-
</table>`
81-
82-
assert.Equal(t, expectedOut, tw.RenderHTML())
80+
</table>`)
8381
}
8482

8583
func TestTable_RenderHTML_AutoIndex(t *testing.T) {
@@ -102,7 +100,7 @@ func TestTable_RenderHTML_AutoIndex(t *testing.T) {
102100
tw.SetAutoIndex(true)
103101
tw.SetStyle(StyleLight)
104102

105-
expectedOut := `<table class="go-pretty-table">
103+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
106104
<thead>
107105
<tr>
108106
<th>&nbsp;</th>
@@ -139,8 +137,7 @@ func TestTable_RenderHTML_AutoIndex(t *testing.T) {
139137
<td>CF</td>
140138
</tr>
141139
</tfoot>
142-
</table>`
143-
assert.Equal(t, expectedOut, tw.RenderHTML())
140+
</table>`)
144141
}
145142

146143
func TestTable_RenderHTML_Colored(t *testing.T) {
@@ -181,7 +178,7 @@ func TestTable_RenderHTML_Colored(t *testing.T) {
181178
},
182179
})
183180

184-
expectedOut := `<table class="go-pretty-table-colored">
181+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table-colored">
185182
<caption class="title">Game of Thrones</caption>
186183
<thead>
187184
<tr>
@@ -232,8 +229,7 @@ func TestTable_RenderHTML_Colored(t *testing.T) {
232229
</tr>
233230
</tfoot>
234231
<caption class="caption" style="caption-side: bottom;">A Song of Ice and Fire</caption>
235-
</table>`
236-
assert.Equal(t, expectedOut, tw.RenderHTML())
232+
</table>`)
237233
}
238234

239235
func TestTable_RenderHTML_CustomStyle(t *testing.T) {
@@ -252,7 +248,7 @@ func TestTable_RenderHTML_CustomStyle(t *testing.T) {
252248
}
253249
tw.SetOutputMirror(nil)
254250

255-
expectedOut := `<table class="game-of-thrones">
251+
compareOutput(t, tw.RenderHTML(), `<table class="game-of-thrones">
256252
<thead>
257253
<tr>
258254
<th><!-- test -->&nbsp;</th>
@@ -299,8 +295,7 @@ func TestTable_RenderHTML_CustomStyle(t *testing.T) {
299295
<td><!-- test -->&nbsp;</td>
300296
</tr>
301297
</tfoot>
302-
</table>`
303-
assert.Equal(t, expectedOut, tw.RenderHTML())
298+
</table>`)
304299
}
305300

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

325-
expectedOut := ``
326-
assert.Equal(t, expectedOut, tw.RenderHTML())
320+
compareOutput(t, tw.RenderHTML(), "")
327321
})
328322

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

332-
expectedOut := `<table class="go-pretty-table">
326+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
333327
<thead>
334328
<tr>
335329
<th>First Name</th>
@@ -366,14 +360,13 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
366360
<td>&nbsp;</td>
367361
</tr>
368362
</tfoot>
369-
</table>`
370-
assert.Equal(t, expectedOut, tw.RenderHTML())
363+
</table>`)
371364
})
372365

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

376-
expectedOut := `<table class="go-pretty-table">
369+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
377370
<thead>
378371
<tr>
379372
<th align="right">#</th>
@@ -410,14 +403,13 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
410403
<td>&nbsp;</td>
411404
</tr>
412405
</tfoot>
413-
</table>`
414-
assert.Equal(t, expectedOut, tw.RenderHTML())
406+
</table>`)
415407
})
416408

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

420-
expectedOut := `<table class="go-pretty-table">
412+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
421413
<thead>
422414
<tr>
423415
<th align="right">#</th>
@@ -454,8 +446,7 @@ func TestTable_RenderHTML_HiddenColumns(t *testing.T) {
454446
<td align="right">10000</td>
455447
</tr>
456448
</tfoot>
457-
</table>`
458-
assert.Equal(t, expectedOut, tw.RenderHTML())
449+
</table>`)
459450
})
460451
}
461452

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

470-
expectedOut := `<table class="go-pretty-table">
461+
compareOutput(t, tw.RenderHTML(), `<table class="go-pretty-table">
471462
<thead>
472463
<tr>
473464
<th align="right">#</th>
@@ -516,6 +507,5 @@ func TestTable_RenderHTML_Sorted(t *testing.T) {
516507
<td>&nbsp;</td>
517508
</tr>
518509
</tfoot>
519-
</table>`
520-
assert.Equal(t, expectedOut, tw.RenderHTML())
510+
</table>`)
521511
}

table/render_markdown_test.go

+13-21
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestTable_RenderMarkdown(t *testing.T) {
1717
tw.SetCaption(testCaption)
1818
tw.SetTitle(testTitle1)
1919

20-
expectedOut := `# Game of Thrones
20+
compareOutput(t, tw.RenderMarkdown(), `# Game of Thrones
2121
| # | First Name | Last Name | Salary | |
2222
| ---:| --- | --- | ---:| --- |
2323
| 1 | Arya | Stark | 3000 | |
@@ -26,9 +26,7 @@ func TestTable_RenderMarkdown(t *testing.T) {
2626
| 0 | Valar | Morghulis | 0 | Faceless<br/>Men |
2727
| 0 | Valar | Morghulis | 0 | Faceless\|Men |
2828
| | | Total | 10000 | |
29-
_A Song of Ice and Fire_`
30-
31-
assert.Equal(t, expectedOut, tw.RenderMarkdown())
29+
_A Song of Ice and Fire_`)
3230
}
3331

3432
func TestTable_RenderMarkdown_AutoIndex(t *testing.T) {
@@ -50,7 +48,7 @@ func TestTable_RenderMarkdown_AutoIndex(t *testing.T) {
5048
tw.SetAutoIndex(true)
5149
tw.SetStyle(StyleLight)
5250

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

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

88-
expectedOut := ``
89-
assert.Equal(t, expectedOut, tw.RenderMarkdown())
85+
compareOutput(t, tw.RenderMarkdown(), "")
9086
})
9187

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

95-
expectedOut := `| First Name | Last Name | Salary | |
91+
compareOutput(t, tw.RenderMarkdown(), `| First Name | Last Name | Salary | |
9692
| --- | --- | ---:| --- |
9793
| >>Tyrion | Lannister<< | 5013 | |
9894
| >>Arya | Stark<< | 3013 | |
9995
| >>Jon | Snow<< | 2013 | ~You know nothing, Jon Snow!~ |
100-
| | Total | 10000 | |`
101-
assert.Equal(t, expectedOut, tw.RenderMarkdown())
96+
| | Total | 10000 | |`)
10297
})
10398

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

107-
expectedOut := `| # | Last Name | Salary | |
102+
compareOutput(t, tw.RenderMarkdown(), `| # | Last Name | Salary | |
108103
| ---:| --- | ---:| --- |
109104
| 307 | Lannister<< | 5013 | |
110105
| 8 | Stark<< | 3013 | |
111106
| 27 | Snow<< | 2013 | ~You know nothing, Jon Snow!~ |
112-
| | Total | 10000 | |`
113-
assert.Equal(t, expectedOut, tw.RenderMarkdown())
107+
| | Total | 10000 | |`)
114108
})
115109

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

119-
expectedOut := `| # | First Name | Last Name | Salary |
113+
compareOutput(t, tw.RenderMarkdown(), `| # | First Name | Last Name | Salary |
120114
| ---:| --- | --- | ---:|
121115
| 307 | >>Tyrion | Lannister<< | 5013 |
122116
| 8 | >>Arya | Stark<< | 3013 |
123117
| 27 | >>Jon | Snow<< | 2013 |
124-
| | | Total | 10000 |`
125-
assert.Equal(t, expectedOut, tw.RenderMarkdown())
118+
| | | Total | 10000 |`)
126119
})
127120
}
128121

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

137-
expectedOut := `| # | First Name | Last Name | Salary | |
130+
compareOutput(t, tw.RenderMarkdown(), `| # | First Name | Last Name | Salary | |
138131
| ---:| --- | --- | ---:| --- |
139132
| 300 | Tyrion | Lannister | 5000 | |
140133
| 20 | Jon | Snow | 2000 | You know nothing, Jon Snow! |
141134
| 1 | Arya | Stark | 3000 | |
142135
| 11 | Sansa | Stark | 6000 | |
143-
| | | Total | 10000 | |`
144-
assert.Equal(t, expectedOut, tw.RenderMarkdown())
136+
| | | Total | 10000 | |`)
145137
}

0 commit comments

Comments
 (0)