]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm-remote/ainsl/ainsl_test.go
tests: use subtests
[safcm/safcm.git] / cmd / safcm-remote / ainsl / ainsl_test.go
1 // Copyright (C) 2021  Simon Ruderich
2 //
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package ainsl
17
18 import (
19         "fmt"
20         "io/fs"
21         "os"
22         "path/filepath"
23         "reflect"
24         "syscall"
25         "testing"
26
27         "github.com/google/go-cmp/cmp"
28
29         ft "ruderich.org/simon/safcm/cmd/safcm-remote/sync/filetest"
30 )
31
32 func TestHandle(t *testing.T) {
33         cwd, err := os.Getwd()
34         if err != nil {
35                 t.Fatal(err)
36         }
37         defer os.Chdir(cwd)
38
39         err = os.RemoveAll("testdata")
40         if err != nil {
41                 t.Fatal(err)
42         }
43         err = os.Mkdir("testdata", 0700)
44         if err != nil {
45                 t.Fatal(err)
46         }
47
48         // Set umask to test mode for new files
49         umask := syscall.Umask(027)
50         defer syscall.Umask(umask)
51
52         root := ft.File{
53                 Path: ".",
54                 Mode: fs.ModeDir | 0700,
55         }
56         _, uid, _, gid := ft.CurrentUserAndGroup()
57
58         tests := []struct {
59                 name       string
60                 path       string
61                 line       string
62                 create     bool
63                 prepare    func()
64                 expFiles   []ft.File
65                 expChanges []string
66                 expErr     error
67         }{
68
69                 // TODO: Add tests for chown and run them only as root
70
71                 {
72                         "missing",
73                         "file",
74                         "line",
75                         false,
76                         nil,
77                         []ft.File{
78                                 root,
79                         },
80                         nil,
81                         fmt.Errorf("\"file\": file does not exist, use -create"),
82                 },
83
84                 {
85                         "missing: create",
86                         "file",
87                         "line",
88                         true,
89                         nil,
90                         []ft.File{
91                                 root,
92                                 ft.File{
93                                         Path: "file",
94                                         Mode: 0640,
95                                         Data: []byte("line\n"),
96                                 },
97                         },
98                         []string{
99                                 fmt.Sprintf(`"file": created file (%d/%d -rw-r-----)`, uid, gid),
100                                 `"file": added line "line"`,
101                         },
102                         nil,
103                 },
104                 {
105                         "missing: create (empty line)",
106                         "file",
107                         "",
108                         true,
109                         nil,
110                         []ft.File{
111                                 root,
112                         },
113                         nil,
114                         fmt.Errorf("empty line"),
115                 },
116                 {
117                         "missing: create (newline)",
118                         "file",
119                         "line\n",
120                         true,
121                         nil,
122                         []ft.File{
123                                 root,
124                         },
125                         nil,
126                         fmt.Errorf("line must not contain newlines: \"line\\n\""),
127                 },
128
129                 {
130                         "exists: unchanged",
131                         "file",
132                         "line",
133                         true,
134                         func() {
135                                 ft.CreateFile("file", "line\n", 0641)
136                         },
137                         []ft.File{
138                                 root,
139                                 ft.File{
140                                         Path: "file",
141                                         Mode: 0641,
142                                         Data: []byte("line\n"),
143                                 },
144                         },
145                         nil,
146                         nil,
147                 },
148
149                 {
150                         "exists: append",
151                         "file",
152                         "line",
153                         true,
154                         func() {
155                                 ft.CreateFile("file", "existing\n", 0641)
156                         },
157                         []ft.File{
158                                 root,
159                                 ft.File{
160                                         Path: "file",
161                                         Mode: 0641,
162                                         Data: []byte("existing\nline\n"),
163                                 },
164                         },
165                         []string{
166                                 `"file": added line "line"`,
167                         },
168                         nil,
169                 },
170                 {
171                         "exists: append (no newline in file)",
172                         "file",
173                         "line",
174                         true,
175                         func() {
176                                 ft.CreateFile("file", "existing", 0641)
177                         },
178                         []ft.File{
179                                 root,
180                                 ft.File{
181                                         Path: "file",
182                                         Mode: 0641,
183                                         Data: []byte("existing\nline\n"),
184                                 },
185                         },
186                         []string{
187                                 `"file": added missing trailing newline`,
188                                 `"file": added line "line"`,
189                         },
190                         nil,
191                 },
192                 {
193                         "exists: append (only trailing newline I)",
194                         "file",
195                         "line",
196                         true,
197                         func() {
198                                 ft.CreateFile("file", "first\nline", 0641)
199                         },
200                         []ft.File{
201                                 root,
202                                 ft.File{
203                                         Path: "file",
204                                         Mode: 0641,
205                                         Data: []byte("first\nline\n"),
206                                 },
207                         },
208                         []string{
209                                 `"file": added missing trailing newline`,
210                         },
211                         nil,
212                 },
213                 {
214                         "exists: append (only trailing newline II)",
215                         "file",
216                         "first",
217                         true,
218                         func() {
219                                 ft.CreateFile("file", "first\nline", 0641)
220                         },
221                         []ft.File{
222                                 root,
223                                 ft.File{
224                                         Path: "file",
225                                         Mode: 0641,
226                                         Data: []byte("first\nline\n"),
227                                 },
228                         },
229                         []string{
230                                 `"file": added missing trailing newline`,
231                         },
232                         nil,
233                 },
234                 {
235                         "exists: append (partial line)",
236                         "file",
237                         "line with spaces",
238                         true,
239                         func() {
240                                 ft.CreateFile("file", "# line with spaces\n", 0641)
241                         },
242                         []ft.File{
243                                 root,
244                                 ft.File{
245                                         Path: "file",
246                                         Mode: 0641,
247                                         Data: []byte("# line with spaces\nline with spaces\n"),
248                                 },
249                         },
250                         []string{
251                                 `"file": added line "line with spaces"`,
252                         },
253                         nil,
254                 },
255
256                 {
257                         "exists: symlink",
258                         "file",
259                         "line",
260                         true,
261                         func() {
262                                 ft.CreateSymlink("file", "target")
263                         },
264                         []ft.File{
265                                 root,
266                                 ft.File{
267                                         Path: "file",
268                                         Mode: fs.ModeSymlink | 0777,
269                                         Data: []byte("target"),
270                                 },
271                         },
272                         nil,
273                         fmt.Errorf("open file: too many levels of symbolic links"),
274                 },
275                 {
276                         "exists: fifo",
277                         "file",
278                         "line",
279                         true,
280                         func() {
281                                 ft.CreateFifo("file", 0640)
282                         },
283                         []ft.File{
284                                 root,
285                                 ft.File{
286                                         Path: "file",
287                                         Mode: fs.ModeNamedPipe | 0640,
288                                 },
289                         },
290                         nil,
291                         fmt.Errorf("\"file\" is not a regular file but p---------"),
292                 },
293         }
294
295         for _, tc := range tests {
296                 t.Run(tc.name, func(t *testing.T) {
297                 // Create separate test directory for each test case
298                 path := filepath.Join(cwd, "testdata", tc.name)
299                 err = os.Mkdir(path, 0700)
300                 if err != nil {
301                         t.Fatal(err)
302                 }
303                 err = os.Chdir(path)
304                 if err != nil {
305                         t.Fatal(err)
306                 }
307
308                 if tc.prepare != nil {
309                         tc.prepare()
310                 }
311
312                 changes, err := handle(tc.path, tc.line, tc.create)
313                 if !reflect.DeepEqual(tc.expChanges, changes) {
314                         t.Errorf("changes: %s",
315                                 cmp.Diff(tc.expChanges, changes))
316                 }
317                 // Ugly but the simplest way to compare errors (including nil)
318                 if fmt.Sprintf("%s", err) != fmt.Sprintf("%s", tc.expErr) {
319                         t.Errorf("err = %#v, want %#v",
320                                 err, tc.expErr)
321                 }
322
323                 files, err := ft.WalkDir(path)
324                 if err != nil {
325                         t.Fatal(err)
326                 }
327                 if !reflect.DeepEqual(tc.expFiles, files) {
328                         t.Errorf("files: %s",
329                                 cmp.Diff(tc.expFiles, files))
330                 }
331                 })
332         }
333
334         if !t.Failed() {
335                 err = os.RemoveAll(filepath.Join(cwd, "testdata"))
336                 if err != nil {
337                         t.Fatal(err)
338                 }
339         }
340 }