]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm/sync_changes_test.go
9326dbbf3e6638120d9cdbcfc5237a5e241265e0
[safcm/safcm.git] / cmd / safcm / sync_changes_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 main
17
18 import (
19         "io/fs"
20         "testing"
21
22         "ruderich.org/simon/safcm"
23         "ruderich.org/simon/safcm/cmd/safcm/config"
24         "ruderich.org/simon/safcm/testutil"
25 )
26
27 func TestFormatChanges(t *testing.T) {
28         tests := []struct {
29                 name   string
30                 dryRun bool
31                 isTTY  bool
32                 resp   safcm.MsgSyncResp
33                 exp    string
34         }{
35
36                 // Just a few basic tests and border cases; see the other
37                 // tests for more detailed tests of each format function
38
39                 {
40                         "no changes",
41                         false,
42                         false,
43                         safcm.MsgSyncResp{},
44                         "",
45                 },
46
47                 {
48                         "changes",
49                         false,
50                         false,
51                         safcm.MsgSyncResp{
52                                 FileChanges: []safcm.FileChange{
53                                         {
54                                                 Path:    "created",
55                                                 Created: true,
56                                                 New: safcm.FileChangeInfo{
57                                                         Mode:  0644,
58                                                         User:  "user",
59                                                         Uid:   1000,
60                                                         Group: "group",
61                                                         Gid:   2000,
62                                                 },
63                                         },
64                                 },
65                                 PackageChanges: []safcm.PackageChange{
66                                         {
67                                                 Name: "package-one",
68                                         },
69                                         {
70                                                 Name: "package-two",
71                                         },
72                                 },
73                                 ServiceChanges: []safcm.ServiceChange{
74                                         {
75                                                 Name:    "service-one",
76                                                 Started: true,
77                                         },
78                                         {
79                                                 Name:    "service-two",
80                                                 Enabled: true,
81                                         },
82                                         {
83                                                 Name:    "service-three",
84                                                 Started: true,
85                                                 Enabled: true,
86                                         },
87                                 },
88                                 CommandChanges: []safcm.CommandChange{
89                                         {
90                                                 Command: "fake command",
91                                                 Output:  "fake output",
92                                         },
93                                         {
94                                                 Command: "fake command with no output",
95                                         },
96                                 },
97                         },
98                         "\nchanged 1 file(s):\n\"created\": created, file, user(1000) group(2000), 0644\n\ninstalled 2 package(s):\n\"package-one\"\n\"package-two\"\n\nmodified 3 service(s):\n\"service-one\": started\n\"service-two\": enabled\n\"service-three\": started, enabled\n\nexecuted 2 command(s):\n\"fake command\":\n   > fake output\n   > \\ No newline at end of file\n\"fake command with no output\"\n",
99                 },
100         }
101
102         for _, tc := range tests {
103                 t.Run(tc.name, func(t *testing.T) {
104                         s := &Sync{
105                                 config: &config.Config{
106                                         DryRun: tc.dryRun,
107                                 },
108                                 isTTY: tc.isTTY,
109                         }
110
111                         res := s.formatChanges(tc.resp)
112                         testutil.AssertEqual(t, "res", res, tc.exp)
113                 })
114         }
115 }
116
117 func TestFormatFileChanges(t *testing.T) {
118         tests := []struct {
119                 name    string
120                 dryRun  bool
121                 isTTY   bool
122                 changes []safcm.FileChange
123                 exp     string
124         }{
125
126                 {
127                         "regular",
128                         false,
129                         false,
130                         []safcm.FileChange{
131                                 {
132                                         Path:    "created: file",
133                                         Created: true,
134                                         New: safcm.FileChangeInfo{
135                                                 Mode:  0644,
136                                                 User:  "user",
137                                                 Uid:   1000,
138                                                 Group: "group",
139                                                 Gid:   2000,
140                                         },
141                                 },
142                                 {
143                                         Path:    "created: link",
144                                         Created: true,
145                                         New: safcm.FileChangeInfo{
146                                                 Mode:  fs.ModeSymlink | 0777,
147                                                 User:  "user",
148                                                 Uid:   1000,
149                                                 Group: "group",
150                                                 Gid:   2000,
151                                         },
152                                 },
153                                 {
154                                         Path: "type change: file -> dir",
155                                         Old: safcm.FileChangeInfo{
156                                                 Mode:  0751,
157                                                 User:  "user",
158                                                 Uid:   1000,
159                                                 Group: "group",
160                                                 Gid:   2000,
161                                         },
162                                         New: safcm.FileChangeInfo{
163                                                 Mode:  fs.ModeDir | 0751,
164                                                 User:  "user",
165                                                 Uid:   1000,
166                                                 Group: "group",
167                                                 Gid:   2000,
168                                         },
169                                         DataDiff: `@@ -1,2 +1 @@
170 -content
171  
172 `,
173                                 },
174                                 {
175                                         Path: "user change",
176                                         Old: safcm.FileChangeInfo{
177                                                 Mode:  0755,
178                                                 User:  "user",
179                                                 Uid:   1000,
180                                                 Group: "group",
181                                                 Gid:   2000,
182                                         },
183                                         New: safcm.FileChangeInfo{
184                                                 Mode:  0755,
185                                                 User:  "user2",
186                                                 Uid:   1001,
187                                                 Group: "group",
188                                                 Gid:   2000,
189                                         },
190                                 },
191                                 {
192                                         Path: "group change",
193                                         Old: safcm.FileChangeInfo{
194                                                 Mode:  0755,
195                                                 User:  "user",
196                                                 Uid:   1000,
197                                                 Group: "group",
198                                                 Gid:   2000,
199                                         },
200                                         New: safcm.FileChangeInfo{
201                                                 Mode:  0755,
202                                                 User:  "user",
203                                                 Uid:   1000,
204                                                 Group: "group2",
205                                                 Gid:   2001,
206                                         },
207                                 },
208                                 {
209                                         Path: "mode change",
210                                         Old: safcm.FileChangeInfo{
211                                                 Mode:  0755,
212                                                 User:  "user",
213                                                 Uid:   1000,
214                                                 Group: "group",
215                                                 Gid:   2000,
216                                         },
217                                         New: safcm.FileChangeInfo{
218                                                 Mode:  0750,
219                                                 User:  "user",
220                                                 Uid:   1000,
221                                                 Group: "group",
222                                                 Gid:   2000,
223                                         },
224                                 },
225                                 {
226                                         Path: "mode change (setuid)",
227                                         Old: safcm.FileChangeInfo{
228                                                 Mode:  0755,
229                                                 User:  "user",
230                                                 Uid:   1000,
231                                                 Group: "group",
232                                                 Gid:   2000,
233                                         },
234                                         New: safcm.FileChangeInfo{
235                                                 Mode:  0755 | fs.ModeSetuid,
236                                                 User:  "user",
237                                                 Uid:   1000,
238                                                 Group: "group",
239                                                 Gid:   2000,
240                                         },
241                                 },
242                                 {
243                                         Path: "content change",
244                                         Old: safcm.FileChangeInfo{
245                                                 Mode:  0644,
246                                                 User:  "user",
247                                                 Uid:   1000,
248                                                 Group: "group",
249                                                 Gid:   2000,
250                                         },
251                                         New: safcm.FileChangeInfo{
252                                                 Mode:  0644,
253                                                 User:  "user",
254                                                 Uid:   1000,
255                                                 Group: "group",
256                                                 Gid:   2000,
257                                         },
258                                         DataDiff: `@@ -1,2 +1,2 @@
259 -old content
260 +content
261  
262 `,
263                                 },
264                                 {
265                                         Path: "multiple changes",
266                                         Old: safcm.FileChangeInfo{
267                                                 Mode:  0644,
268                                                 User:  "user",
269                                                 Uid:   1000,
270                                                 Group: "group",
271                                                 Gid:   2000,
272                                         },
273                                         New: safcm.FileChangeInfo{
274                                                 Mode:  fs.ModeDir | 0755,
275                                                 User:  "user2",
276                                                 Uid:   1001,
277                                                 Group: "group2",
278                                                 Gid:   2001,
279                                         },
280                                         DataDiff: `@@ -1,2 +1 @@
281 -content
282  
283 `,
284                                 },
285                         },
286                         `changed 9 file(s):
287 "created: file": created, file, user(1000) group(2000), 0644
288 "created: link": created, symlink, user(1000) group(2000), 0777
289 "type change: file -> dir": file -> dir
290    @@ -1,2 +1 @@
291    -content
292     
293 "user change": user(1000) group(2000) -> user2(1001) group(2000)
294 "group change": user(1000) group(2000) -> user(1000) group2(2001)
295 "mode change": 0755 -> 0750
296 "mode change (setuid)": 0755 -> 04755
297 "content change":
298    @@ -1,2 +1,2 @@
299    -old content
300    +content
301     
302 "multiple changes": file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755
303    @@ -1,2 +1 @@
304    -content
305     
306 `,
307                 },
308
309                 {
310                         "regular (tty)",
311                         false,
312                         true,
313                         []safcm.FileChange{
314                                 {
315                                         Path:    "created: file",
316                                         Created: true,
317                                         New: safcm.FileChangeInfo{
318                                                 Mode:  0644,
319                                                 User:  "user",
320                                                 Uid:   1000,
321                                                 Group: "group",
322                                                 Gid:   2000,
323                                         },
324                                 },
325                                 {
326                                         Path:    "created: link",
327                                         Created: true,
328                                         New: safcm.FileChangeInfo{
329                                                 Mode:  fs.ModeSymlink | 0777,
330                                                 User:  "user",
331                                                 Uid:   1000,
332                                                 Group: "group",
333                                                 Gid:   2000,
334                                         },
335                                 },
336                                 {
337                                         Path: "type change: file -> dir",
338                                         Old: safcm.FileChangeInfo{
339                                                 Mode:  0751,
340                                                 User:  "user",
341                                                 Uid:   1000,
342                                                 Group: "group",
343                                                 Gid:   2000,
344                                         },
345                                         New: safcm.FileChangeInfo{
346                                                 Mode:  fs.ModeDir | 0751,
347                                                 User:  "user",
348                                                 Uid:   1000,
349                                                 Group: "group",
350                                                 Gid:   2000,
351                                         },
352                                         DataDiff: `@@ -1,2 +1 @@
353 -content
354  
355 `,
356                                 },
357                                 {
358                                         Path: "user change",
359                                         Old: safcm.FileChangeInfo{
360                                                 Mode:  0755,
361                                                 User:  "user",
362                                                 Uid:   1000,
363                                                 Group: "group",
364                                                 Gid:   2000,
365                                         },
366                                         New: safcm.FileChangeInfo{
367                                                 Mode:  0755,
368                                                 User:  "user2",
369                                                 Uid:   1001,
370                                                 Group: "group",
371                                                 Gid:   2000,
372                                         },
373                                 },
374                                 {
375                                         Path: "group change",
376                                         Old: safcm.FileChangeInfo{
377                                                 Mode:  0755,
378                                                 User:  "user",
379                                                 Uid:   1000,
380                                                 Group: "group",
381                                                 Gid:   2000,
382                                         },
383                                         New: safcm.FileChangeInfo{
384                                                 Mode:  0755,
385                                                 User:  "user",
386                                                 Uid:   1000,
387                                                 Group: "group2",
388                                                 Gid:   2001,
389                                         },
390                                 },
391                                 {
392                                         Path: "mode change",
393                                         Old: safcm.FileChangeInfo{
394                                                 Mode:  0755,
395                                                 User:  "user",
396                                                 Uid:   1000,
397                                                 Group: "group",
398                                                 Gid:   2000,
399                                         },
400                                         New: safcm.FileChangeInfo{
401                                                 Mode:  0750,
402                                                 User:  "user",
403                                                 Uid:   1000,
404                                                 Group: "group",
405                                                 Gid:   2000,
406                                         },
407                                 },
408                                 {
409                                         Path: "mode change (setuid)",
410                                         Old: safcm.FileChangeInfo{
411                                                 Mode:  0755,
412                                                 User:  "user",
413                                                 Uid:   1000,
414                                                 Group: "group",
415                                                 Gid:   2000,
416                                         },
417                                         New: safcm.FileChangeInfo{
418                                                 Mode:  0755 | fs.ModeSetuid,
419                                                 User:  "user",
420                                                 Uid:   1000,
421                                                 Group: "group",
422                                                 Gid:   2000,
423                                         },
424                                 },
425                                 {
426                                         Path: "content change",
427                                         Old: safcm.FileChangeInfo{
428                                                 Mode:  0644,
429                                                 User:  "user",
430                                                 Uid:   1000,
431                                                 Group: "group",
432                                                 Gid:   2000,
433                                         },
434                                         New: safcm.FileChangeInfo{
435                                                 Mode:  0644,
436                                                 User:  "user",
437                                                 Uid:   1000,
438                                                 Group: "group",
439                                                 Gid:   2000,
440                                         },
441                                         DataDiff: `@@ -1,2 +1,2 @@
442 -old content
443 +content
444  
445 `,
446                                 },
447                                 {
448                                         Path: "multiple changes",
449                                         Old: safcm.FileChangeInfo{
450                                                 Mode:  0644,
451                                                 User:  "user",
452                                                 Uid:   1000,
453                                                 Group: "group",
454                                                 Gid:   2000,
455                                         },
456                                         New: safcm.FileChangeInfo{
457                                                 Mode:  fs.ModeDir | 0755,
458                                                 User:  "user2",
459                                                 Uid:   1001,
460                                                 Group: "group2",
461                                                 Gid:   2001,
462                                         },
463                                         DataDiff: `@@ -1,2 +1 @@
464 -content
465  
466 `,
467                                 },
468                         },
469                         "changed 9 file(s):\n\x1b[36m\"created: file\"\x1b[0m: \x1b[32mcreated\x1b[0m, file, user(1000) group(2000), 0644\n\x1b[36m\"created: link\"\x1b[0m: \x1b[32mcreated\x1b[0m, symlink, user(1000) group(2000), 0777\n\x1b[36m\"type change: file -> dir\"\x1b[0m: file -> dir\n   @@ -1,2 +1 @@\n\x1b[31m   -content\x1b[0m\n    \n\x1b[36m\"user change\"\x1b[0m: user(1000) group(2000) -> user2(1001) group(2000)\n\x1b[36m\"group change\"\x1b[0m: user(1000) group(2000) -> user(1000) group2(2001)\n\x1b[36m\"mode change\"\x1b[0m: 0755 -> 0750\n\x1b[36m\"mode change (setuid)\"\x1b[0m: 0755 -> 04755\n\x1b[36m\"content change\"\x1b[0m:\n   @@ -1,2 +1,2 @@\n\x1b[31m   -old content\x1b[0m\n\x1b[32m   +content\x1b[0m\n    \n\x1b[36m\"multiple changes\"\x1b[0m: file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755\n   @@ -1,2 +1 @@\n\x1b[31m   -content\x1b[0m\n    \n",
470                 },
471
472                 {
473                         "dry-run",
474                         true,
475                         false,
476                         []safcm.FileChange{
477                                 {
478                                         Path:    "file",
479                                         Created: true,
480                                         New: safcm.FileChangeInfo{
481                                                 Mode:  0644,
482                                                 User:  "user",
483                                                 Uid:   1000,
484                                                 Group: "group",
485                                                 Gid:   2000,
486                                         },
487                                 },
488                         },
489                         `changed 1 file(s): (dry-run)
490 "file": created, file, user(1000) group(2000), 0644
491 `,
492                 },
493
494                 {
495                         "dry-run (tty)",
496                         true,
497                         true,
498                         []safcm.FileChange{
499                                 {
500                                         Path:    "file",
501                                         Created: true,
502                                         New: safcm.FileChangeInfo{
503                                                 Mode:  0644,
504                                                 User:  "user",
505                                                 Uid:   1000,
506                                                 Group: "group",
507                                                 Gid:   2000,
508                                         },
509                                 },
510                         },
511                         "changed 1 file(s): (dry-run)\n\x1B[36m\"file\"\x1B[0m: \x1B[32mcreated\x1B[0m, file, user(1000) group(2000), 0644\n",
512                 },
513
514                 {
515                         "escaping",
516                         false,
517                         false,
518                         []safcm.FileChange{
519                                 {
520                                         Path:    "\x00",
521                                         Created: true,
522                                         New: safcm.FileChangeInfo{
523                                                 Mode:  0xFFFFFFFF,
524                                                 User:  "\x01",
525                                                 Uid:   -1,
526                                                 Group: "\x02",
527                                                 Gid:   -2,
528                                         },
529                                         DataDiff: "\x03",
530                                 },
531                                 {
532                                         Path: "\x00",
533                                         Old: safcm.FileChangeInfo{
534                                                 Mode:  0x00000000,
535                                                 User:  "\x01",
536                                                 Uid:   -1,
537                                                 Group: "\x02",
538                                                 Gid:   -2,
539                                         },
540                                         New: safcm.FileChangeInfo{
541                                                 Mode:  0xFFFFFFFF,
542                                                 User:  "\x03",
543                                                 Uid:   -3,
544                                                 Group: "\x04",
545                                                 Gid:   -4,
546                                         },
547                                         DataDiff: "\x05",
548                                 },
549                         },
550                         `changed 2 file(s):
551 "\x00": created, invalid type dLDpSc?---------, \x01(-1) \x02(-2), 07777
552    \x03
553    \ No newline at end of file
554 "\x00": file -> invalid type dLDpSc?---------, \x01(-1) \x02(-2) -> \x03(-3) \x04(-4), 0 -> 07777
555    \x05
556    \ No newline at end of file
557 `,
558                 },
559
560                 {
561                         "escaping (tty)",
562                         false,
563                         true,
564                         []safcm.FileChange{
565                                 {
566                                         Path:    "\x00",
567                                         Created: true,
568                                         New: safcm.FileChangeInfo{
569                                                 Mode:  0xFFFFFFFF,
570                                                 User:  "\x01",
571                                                 Uid:   -1,
572                                                 Group: "\x02",
573                                                 Gid:   -2,
574                                         },
575                                         DataDiff: "\x03",
576                                 },
577                                 {
578                                         Path: "\x00",
579                                         Old: safcm.FileChangeInfo{
580                                                 Mode:  0x00000000,
581                                                 User:  "\x01",
582                                                 Uid:   -1,
583                                                 Group: "\x02",
584                                                 Gid:   -2,
585                                         },
586                                         New: safcm.FileChangeInfo{
587                                                 Mode:  0xFFFFFFFF,
588                                                 User:  "\x03",
589                                                 Uid:   -3,
590                                                 Group: "\x04",
591                                                 Gid:   -4,
592                                         },
593                                         DataDiff: "\x05",
594                                 },
595                         },
596                         "changed 2 file(s):\n\x1b[36m\"\\x00\"\x1b[0m: \x1b[32mcreated\x1b[0m, invalid type dLDpSc?---------, \\x01(-1) \\x02(-2), 07777\n   \\x03\n   \\ No newline at end of file\n\x1b[36m\"\\x00\"\x1b[0m: file -> invalid type dLDpSc?---------, \\x01(-1) \\x02(-2) -> \\x03(-3) \\x04(-4), 0 -> 07777\n   \\x05\n   \\ No newline at end of file\n",
597                 },
598         }
599
600         for _, tc := range tests {
601                 t.Run(tc.name, func(t *testing.T) {
602                         s := &Sync{
603                                 config: &config.Config{
604                                         DryRun: tc.dryRun,
605                                 },
606                                 isTTY: tc.isTTY,
607                         }
608
609                         res := s.formatFileChanges(tc.changes)
610                         testutil.AssertEqual(t, "res", res, tc.exp)
611                 })
612         }
613 }
614
615 func TestFormatPackageChanges(t *testing.T) {
616         tests := []struct {
617                 name    string
618                 dryRun  bool
619                 isTTY   bool
620                 changes []safcm.PackageChange
621                 exp     string
622         }{
623
624                 {
625                         "regular",
626                         false,
627                         false,
628                         []safcm.PackageChange{
629                                 {
630                                         Name: "package-one",
631                                 },
632                                 {
633                                         Name: "package-two",
634                                 },
635                         },
636                         `installed 2 package(s):
637 "package-one"
638 "package-two"
639 `,
640                 },
641
642                 {
643                         "regular (tty)",
644                         false,
645                         true,
646                         []safcm.PackageChange{
647                                 {
648                                         Name: "package-one",
649                                 },
650                                 {
651                                         Name: "package-two",
652                                 },
653                         },
654                         "installed 2 package(s):\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
655                 },
656
657                 {
658                         "dry-run",
659                         true,
660                         false,
661                         []safcm.PackageChange{
662                                 {
663                                         Name: "package-one",
664                                 },
665                                 {
666                                         Name: "package-two",
667                                 },
668                         },
669                         `installed 2 package(s): (dry-run)
670 "package-one"
671 "package-two"
672 `,
673                 },
674
675                 {
676                         "dry-run (tty)",
677                         true,
678                         true,
679                         []safcm.PackageChange{
680                                 {
681                                         Name: "package-one",
682                                 },
683                                 {
684                                         Name: "package-two",
685                                 },
686                         },
687                         "installed 2 package(s): (dry-run)\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
688                 },
689
690                 {
691                         "escaping",
692                         false,
693                         false,
694                         []safcm.PackageChange{
695                                 {
696                                         Name: "\x00",
697                                 },
698                         },
699                         `installed 1 package(s):
700 "\x00"
701 `,
702                 },
703
704                 {
705                         "escaping (tty)",
706                         false,
707                         true,
708                         []safcm.PackageChange{
709                                 {
710                                         Name: "\x00",
711                                 },
712                         },
713                         "installed 1 package(s):\n\x1b[36m\"\\x00\"\x1b[0m\n",
714                 },
715         }
716
717         for _, tc := range tests {
718                 t.Run(tc.name, func(t *testing.T) {
719                         s := &Sync{
720                                 config: &config.Config{
721                                         DryRun: tc.dryRun,
722                                 },
723                                 isTTY: tc.isTTY,
724                         }
725
726                         res := s.formatPackageChanges(tc.changes)
727                         testutil.AssertEqual(t, "res", res, tc.exp)
728                 })
729         }
730 }
731
732 func TestFormatServiceChanges(t *testing.T) {
733         tests := []struct {
734                 name    string
735                 dryRun  bool
736                 isTTY   bool
737                 changes []safcm.ServiceChange
738                 exp     string
739         }{
740
741                 {
742                         "regular",
743                         false,
744                         false,
745                         []safcm.ServiceChange{
746                                 {
747                                         Name:    "service-one",
748                                         Started: true,
749                                 },
750                                 {
751                                         Name:    "service-two",
752                                         Enabled: true,
753                                 },
754                                 {
755                                         Name:    "service-three",
756                                         Started: true,
757                                         Enabled: true,
758                                 },
759                         },
760                         `modified 3 service(s):
761 "service-one": started
762 "service-two": enabled
763 "service-three": started, enabled
764 `,
765                 },
766
767                 {
768                         "regular (tty)",
769                         false,
770                         true,
771                         []safcm.ServiceChange{
772                                 {
773                                         Name:    "service-one",
774                                         Started: true,
775                                 },
776                                 {
777                                         Name:    "service-two",
778                                         Enabled: true,
779                                 },
780                                 {
781                                         Name:    "service-three",
782                                         Started: true,
783                                         Enabled: true,
784                                 },
785                         },
786                         "modified 3 service(s):\n\x1b[36m\"service-one\"\x1b[0m: started\n\x1b[36m\"service-two\"\x1b[0m: enabled\n\x1b[36m\"service-three\"\x1b[0m: started, enabled\n",
787                 },
788
789                 {
790                         "dry-run",
791                         true,
792                         false,
793                         []safcm.ServiceChange{
794                                 {
795                                         Name:    "service-one",
796                                         Started: true,
797                                 },
798                                 {
799                                         Name:    "service-two",
800                                         Enabled: true,
801                                 },
802                                 {
803                                         Name:    "service-three",
804                                         Started: true,
805                                         Enabled: true,
806                                 },
807                         },
808                         `modified 3 service(s): (dry-run)
809 "service-one": started
810 "service-two": enabled
811 "service-three": started, enabled
812 `,
813                 },
814
815                 {
816                         "dry-run (tty)",
817                         true,
818                         true,
819                         []safcm.ServiceChange{
820                                 {
821                                         Name:    "service-one",
822                                         Started: true,
823                                 },
824                                 {
825                                         Name:    "service-two",
826                                         Enabled: true,
827                                 },
828                                 {
829                                         Name:    "service-three",
830                                         Started: true,
831                                         Enabled: true,
832                                 },
833                         },
834                         "modified 3 service(s): (dry-run)\n\x1b[36m\"service-one\"\x1b[0m: started\n\x1b[36m\"service-two\"\x1b[0m: enabled\n\x1b[36m\"service-three\"\x1b[0m: started, enabled\n",
835                 },
836
837                 {
838                         "escaping",
839                         false,
840                         false,
841                         []safcm.ServiceChange{
842                                 {
843                                         Name: "\x00",
844                                 },
845                                 {
846                                         Name:    "\x01",
847                                         Started: true,
848                                         Enabled: true,
849                                 },
850                         },
851                         `modified 2 service(s):
852 "\x00": 
853 "\x01": started, enabled
854 `,
855                 },
856
857                 {
858                         "escaping (tty)",
859                         false,
860                         true,
861                         []safcm.ServiceChange{
862                                 {
863                                         Name: "\x00",
864                                 },
865                                 {
866                                         Name:    "\x01",
867                                         Started: true,
868                                         Enabled: true,
869                                 },
870                         },
871                         "modified 2 service(s):\n\x1b[36m\"\\x00\"\x1b[0m: \n\x1b[36m\"\\x01\"\x1b[0m: started, enabled\n",
872                 },
873         }
874
875         for _, tc := range tests {
876                 t.Run(tc.name, func(t *testing.T) {
877                         s := &Sync{
878                                 config: &config.Config{
879                                         DryRun: tc.dryRun,
880                                 },
881                                 isTTY: tc.isTTY,
882                         }
883
884                         res := s.formatServiceChanges(tc.changes)
885                         testutil.AssertEqual(t, "res", res, tc.exp)
886                 })
887         }
888 }
889
890 func TestFormatCommandChanges(t *testing.T) {
891         tests := []struct {
892                 name    string
893                 dryRun  bool
894                 quiet   bool
895                 isTTY   bool
896                 changes []safcm.CommandChange
897                 exp     string
898         }{
899
900                 {
901                         "regular",
902                         false,
903                         false,
904                         false,
905                         []safcm.CommandChange{
906                                 {
907                                         Command: "fake command",
908                                         Output:  "fake output",
909                                 },
910                                 {
911                                         Command: "fake command with no output",
912                                 },
913                                 {
914                                         Command: "fake command with newline",
915                                         Output:  "fake output\n",
916                                 },
917                                 {
918                                         Command: "fake command with more output",
919                                         Output:  "fake out\nfake put\nfake\n",
920                                 },
921                                 {
922                                         Command: "fake failed command",
923                                         Output:  "fake output",
924                                         Error:   "fake error",
925                                 },
926                         },
927                         `executed 5 command(s):
928 "fake command":
929    > fake output
930    > \ No newline at end of file
931 "fake command with no output"
932 "fake command with newline":
933    > fake output
934 "fake command with more output":
935    > fake out
936    > fake put
937    > fake
938 "fake failed command", failed: "fake error":
939    > fake output
940    > \ No newline at end of file
941 `,
942                 },
943
944                 {
945                         "regular (tty)",
946                         false,
947                         false,
948                         true,
949                         []safcm.CommandChange{
950                                 {
951                                         Command: "fake command",
952                                         Output:  "fake output",
953                                 },
954                                 {
955                                         Command: "fake command with no output",
956                                 },
957                                 {
958                                         Command: "fake command with newline",
959                                         Output:  "fake output\n",
960                                 },
961                                 {
962                                         Command: "fake command with more output",
963                                         Output:  "fake out\nfake put\nfake\n",
964                                 },
965                                 {
966                                         Command: "fake failed command",
967                                         Output:  "fake output",
968                                         Error:   "fake error",
969                                 },
970                         },
971                         "executed 5 command(s):\n\x1b[36m\"fake command\"\x1b[0m:\n   > fake output\n   > \\ No newline at end of file\n\x1b[36m\"fake command with no output\"\x1b[0m\n\x1b[36m\"fake command with newline\"\x1b[0m:\n   > fake output\n\x1b[36m\"fake command with more output\"\x1b[0m:\n   > fake out\n   > fake put\n   > fake\n\x1b[36m\"fake failed command\"\x1b[0m, failed: \"fake error\":\n   > fake output\n   > \\ No newline at end of file\n",
972                 },
973
974                 {
975                         "dry-run",
976                         true,
977                         false,
978                         false,
979                         []safcm.CommandChange{
980                                 {
981                                         Command: "fake command",
982                                         Output:  "fake output",
983                                 },
984                         },
985                         `executed 1 command(s): (dry-run)
986 "fake command":
987    > fake output
988    > \ No newline at end of file
989 `,
990                 },
991
992                 {
993                         "dry-run (tty)",
994                         true,
995                         false,
996                         true,
997                         []safcm.CommandChange{
998                                 {
999                                         Command: "fake command",
1000                                         Output:  "fake output",
1001                                 },
1002                         },
1003                         "executed 1 command(s): (dry-run)\n\x1b[36m\"fake command\"\x1b[0m:\n   > fake output\n   > \\ No newline at end of file\n",
1004                 },
1005
1006                 {
1007                         "quiet",
1008                         false,
1009                         true,
1010                         false,
1011                         []safcm.CommandChange{
1012                                 {
1013                                         Command: "fake command",
1014                                         Output:  "fake output",
1015                                 },
1016                                 {
1017                                         Command: "fake command with no output",
1018                                 },
1019                                 {
1020                                         Command: "fake command with newline",
1021                                         Output:  "fake output\n",
1022                                 },
1023                                 {
1024                                         Command: "fake command with more output",
1025                                         Output:  "fake out\nfake put\nfake\n",
1026                                 },
1027                                 {
1028                                         Command: "fake failed command",
1029                                         Output:  "fake output",
1030                                         Error:   "fake error",
1031                                 },
1032                         },
1033                         `executed 5 command(s), 1 with no output:
1034 "fake command":
1035    > fake output
1036    > \ No newline at end of file
1037 "fake command with newline":
1038    > fake output
1039 "fake command with more output":
1040    > fake out
1041    > fake put
1042    > fake
1043 "fake failed command", failed: "fake error":
1044    > fake output
1045    > \ No newline at end of file
1046 `,
1047                 },
1048
1049                 {
1050                         "quiet (tty)",
1051                         false,
1052                         true,
1053                         true,
1054                         []safcm.CommandChange{
1055                                 {
1056                                         Command: "fake command",
1057                                         Output:  "fake output",
1058                                 },
1059                                 {
1060                                         Command: "fake command with no output",
1061                                 },
1062                                 {
1063                                         Command: "fake command with newline",
1064                                         Output:  "fake output\n",
1065                                 },
1066                                 {
1067                                         Command: "fake command with more output",
1068                                         Output:  "fake out\nfake put\nfake\n",
1069                                 },
1070                                 {
1071                                         Command: "fake failed command",
1072                                         Output:  "fake output",
1073                                         Error:   "fake error",
1074                                 },
1075                         },
1076                         "executed 5 command(s), 1 with no output:\n\x1b[36m\"fake command\"\x1b[0m:\n   > fake output\n   > \\ No newline at end of file\n\x1b[36m\"fake command with newline\"\x1b[0m:\n   > fake output\n\x1b[36m\"fake command with more output\"\x1b[0m:\n   > fake out\n   > fake put\n   > fake\n\x1b[36m\"fake failed command\"\x1b[0m, failed: \"fake error\":\n   > fake output\n   > \\ No newline at end of file\n",
1077                 },
1078
1079                 {
1080                         "quiet (only quiet commands)",
1081                         false,
1082                         true,
1083                         false,
1084                         []safcm.CommandChange{
1085                                 {
1086                                         Command: "fake command with no output",
1087                                 },
1088                                 {
1089                                         Command: "fake command with no output",
1090                                 },
1091                         },
1092                         `executed 2 command(s), 2 with no output
1093 `,
1094                 },
1095
1096                 {
1097                         "quiet (quiet with errors)",
1098                         false,
1099                         true,
1100                         false,
1101                         []safcm.CommandChange{
1102                                 {
1103                                         Command: "fake command with no output but error",
1104                                         Error:   "fake error",
1105                                 },
1106                                 {
1107                                         Command: "fake command with no output",
1108                                 },
1109                         },
1110                         `executed 2 command(s), 1 with no output:
1111 "fake command with no output but error", failed: "fake error"
1112 `,
1113                 },
1114
1115                 {
1116                         "quiet & dry-run",
1117                         true,
1118                         true,
1119                         false,
1120                         []safcm.CommandChange{
1121                                 {
1122                                         Command: "fake command",
1123                                 },
1124                                 {
1125                                         Command: "fake command with no output",
1126                                 },
1127                                 {
1128                                         Command: "fake command with newline",
1129                                 },
1130                                 {
1131                                         Command: "fake command with more output",
1132                                 },
1133                                 {
1134                                         Command: "fake failed command",
1135                                 },
1136                         },
1137                         `executed 5 command(s): (dry-run)
1138 "fake command"
1139 "fake command with no output"
1140 "fake command with newline"
1141 "fake command with more output"
1142 "fake failed command"
1143 `,
1144                 },
1145
1146                 {
1147                         "escaping",
1148                         false,
1149                         false,
1150                         false,
1151                         []safcm.CommandChange{
1152                                 {
1153                                         Command: "\x00",
1154                                         Trigger: "\x01",
1155                                         Output:  "\x02",
1156                                         Error:   "\x03",
1157                                 },
1158                         },
1159                         `executed 1 command(s):
1160 "\x00", trigger for "\x01", failed: "\x03":
1161    > \x02
1162    > \ No newline at end of file
1163 `,
1164                 },
1165
1166                 {
1167                         "escaping (tty)",
1168                         false,
1169                         false,
1170                         true,
1171                         []safcm.CommandChange{
1172                                 {
1173                                         Command: "\x00",
1174                                         Trigger: "\x01",
1175                                         Output:  "\x02",
1176                                         Error:   "\x03",
1177                                 },
1178                         },
1179                         "executed 1 command(s):\n\x1b[36m\"\\x00\"\x1b[0m, trigger for \"\\x01\", failed: \"\\x03\":\n   > \x1b[35m\\x02\x1b[0m\n   > \\ No newline at end of file\n",
1180                 },
1181         }
1182
1183         for _, tc := range tests {
1184                 t.Run(tc.name, func(t *testing.T) {
1185                         s := &Sync{
1186                                 config: &config.Config{
1187                                         DryRun: tc.dryRun,
1188                                         Quiet:  tc.quiet,
1189                                 },
1190                                 isTTY: tc.isTTY,
1191                         }
1192
1193                         res := s.formatCommandChanges(tc.changes)
1194                         testutil.AssertEqual(t, "res", res, tc.exp)
1195                 })
1196         }
1197 }