1// Copyright 2021 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package gitdiff
5
6import (
7 "encoding/csv"
8 "strings"
9 "testing"
10
11 "forgejo.org/models/db"
12 csv_module "forgejo.org/modules/csv"
13 "forgejo.org/modules/setting"
14
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17)
18
19func TestCSVDiff(t *testing.T) {
20 cases := []struct {
21 diff string
22 base string
23 head string
24 cells [][]TableDiffCellType
25 }{
26 // case 0 - initial commit of a csv
27 {
28 diff: `diff --git a/unittest.csv b/unittest.csv
29--- a/unittest.csv
30+++ b/unittest.csv
31@@ -0,0 +1,2 @@
32+col1,col2
33+a,a`,
34 base: "",
35 head: `col1,col2
36a,a`,
37 cells: [][]TableDiffCellType{
38 {TableDiffCellAdd, TableDiffCellAdd},
39 {TableDiffCellAdd, TableDiffCellAdd},
40 },
41 },
42 // case 1 - adding 1 row at end
43 {
44 diff: `diff --git a/unittest.csv b/unittest.csv
45--- a/unittest.csv
46+++ b/unittest.csv
47@@ -1,2 +1,3 @@
48 col1,col2
49-a,a
50+a,a
51+b,b`,
52 base: `col1,col2
53a,a`,
54 head: `col1,col2
55a,a
56b,b`,
57 cells: [][]TableDiffCellType{
58 {TableDiffCellUnchanged, TableDiffCellUnchanged},
59 {TableDiffCellUnchanged, TableDiffCellUnchanged},
60 {TableDiffCellAdd, TableDiffCellAdd},
61 },
62 },
63 // case 2 - row deleted
64 {
65 diff: `diff --git a/unittest.csv b/unittest.csv
66--- a/unittest.csv
67+++ b/unittest.csv
68@@ -1,3 +1,2 @@
69 col1,col2
70-a,a
71 b,b`,
72 base: `col1,col2
73a,a
74b,b`,
75 head: `col1,col2
76b,b`,
77 cells: [][]TableDiffCellType{
78 {TableDiffCellUnchanged, TableDiffCellUnchanged},
79 {TableDiffCellDel, TableDiffCellDel},
80 {TableDiffCellUnchanged, TableDiffCellUnchanged},
81 },
82 },
83 // case 3 - row changed
84 {
85 diff: `diff --git a/unittest.csv b/unittest.csv
86--- a/unittest.csv
87+++ b/unittest.csv
88@@ -1,2 +1,2 @@
89 col1,col2
90-b,b
91+b,c`,
92 base: `col1,col2
93b,b`,
94 head: `col1,col2
95b,c`,
96 cells: [][]TableDiffCellType{
97 {TableDiffCellUnchanged, TableDiffCellUnchanged},
98 {TableDiffCellUnchanged, TableDiffCellChanged},
99 },
100 },
101 // case 4 - all deleted
102 {
103 diff: `diff --git a/unittest.csv b/unittest.csv
104--- a/unittest.csv
105+++ b/unittest.csv
106@@ -1,2 +0,0 @@
107-col1,col2
108-b,c`,
109 base: `col1,col2
110b,c`,
111 head: "",
112 cells: [][]TableDiffCellType{
113 {TableDiffCellDel, TableDiffCellDel},
114 {TableDiffCellDel, TableDiffCellDel},
115 },
116 },
117 // case 5 - renames first column
118 {
119 diff: `diff --git a/unittest.csv b/unittest.csv
120--- a/unittest.csv
121+++ b/unittest.csv
122@@ -1,3 +1,3 @@
123-col1,col2,col3
124+cola,col2,col3
125 a,b,c`,
126 base: `col1,col2,col3
127a,b,c`,
128 head: `cola,col2,col3
129a,b,c`,
130 cells: [][]TableDiffCellType{
131 {TableDiffCellDel, TableDiffCellAdd, TableDiffCellUnchanged, TableDiffCellUnchanged},
132 {TableDiffCellDel, TableDiffCellAdd, TableDiffCellUnchanged, TableDiffCellUnchanged},
133 },
134 },
135 // case 6 - inserts a column after first, deletes last column
136 {
137 diff: `diff --git a/unittest.csv b/unittest.csv
138--- a/unittest.csv
139+++ b/unittest.csv
140@@ -1,2 +1,2 @@
141-col1,col2,col3
142-a,b,c
143+col1,col1a,col2
144+a,d,b`,
145 base: `col1,col2,col3
146a,b,c`,
147 head: `col1,col1a,col2
148a,d,b`,
149 cells: [][]TableDiffCellType{
150 {TableDiffCellUnchanged, TableDiffCellAdd, TableDiffCellDel, TableDiffCellMovedUnchanged},
151 {TableDiffCellUnchanged, TableDiffCellAdd, TableDiffCellDel, TableDiffCellMovedUnchanged},
152 },
153 },
154 // case 7 - deletes first column, inserts column after last
155 {
156 diff: `diff --git a/unittest.csv b/unittest.csv
157--- a/unittest.csv
158+++ b/unittest.csv
159@@ -1,2 +1,2 @@
160-col1,col2,col3
161-a,b,c
162+col2,col3,col4
163+b,c,d`,
164 base: `col1,col2,col3
165a,b,c`,
166 head: `col2,col3,col4
167b,c,d`,
168 cells: [][]TableDiffCellType{
169 {TableDiffCellDel, TableDiffCellUnchanged, TableDiffCellUnchanged, TableDiffCellAdd},
170 {TableDiffCellDel, TableDiffCellUnchanged, TableDiffCellUnchanged, TableDiffCellAdd},
171 },
172 },
173 // case 8 - two columns deleted, 2 added
174 {
175 diff: `diff --git a/unittest.csv b/unittest.csv
176--- a/unittest.csv
177+++ b/unittest.csv
178@@ -1,2 +1,2 @@
179-col1,col2,col
180-a,b,c
181+col3,col4,col5
182+c,d,e`,
183 base: `col1,col2,col3
184a,b,c`,
185 head: `col3,col4,col5
186c,d,e`,
187 cells: [][]TableDiffCellType{
188 {TableDiffCellDel, TableDiffCellMovedUnchanged, TableDiffCellDel, TableDiffCellAdd, TableDiffCellAdd},
189 {TableDiffCellDel, TableDiffCellMovedUnchanged, TableDiffCellDel, TableDiffCellAdd, TableDiffCellAdd},
190 },
191 },
192 }
193
194 for n, c := range cases {
195 diff, err := ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.diff), "")
196 if err != nil {
197 t.Errorf("ParsePatch failed: %s", err)
198 }
199
200 var baseReader *csv.Reader
201 if len(c.base) > 0 {
202 baseReader, err = csv_module.CreateReaderAndDetermineDelimiter(nil, strings.NewReader(c.base))
203 if err != nil {
204 t.Errorf("CreateReaderAndDetermineDelimiter failed: %s", err)
205 }
206 }
207 var headReader *csv.Reader
208 if len(c.head) > 0 {
209 headReader, err = csv_module.CreateReaderAndDetermineDelimiter(nil, strings.NewReader(c.head))
210 if err != nil {
211 t.Errorf("CreateReaderAndDetermineDelimiter failed: %s", err)
212 }
213 }
214
215 result, err := CreateCsvDiff(diff.Files[0], baseReader, headReader)
216 require.NoError(t, err)
217 assert.Len(t, result, 1, "case %d: should be one section", n)
218
219 section := result[0]
220 assert.Len(t, section.Rows, len(c.cells), "case %d: should be %d rows", n, len(c.cells))
221
222 for i, row := range section.Rows {
223 assert.Len(t, row.Cells, len(c.cells[i]), "case %d: row %d should have %d cells", n, i, len(c.cells[i]))
224 for j, cell := range row.Cells {
225 assert.Equal(t, c.cells[i][j], cell.Type, "case %d: row %d cell %d should be equal", n, i, j)
226 }
227 }
228 }
229}