// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2021-2024 Simon Ruderich package ainsl import ( "fmt" "io/fs" "os" "path/filepath" "runtime" "syscall" "testing" ft "ruderich.org/simon/safcm/remote/sync/filetest" "ruderich.org/simon/safcm/testutil" ) func TestHandle(t *testing.T) { cwd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(cwd) //nolint:errcheck err = os.RemoveAll("testdata") if err != nil { t.Fatal(err) } err = os.Mkdir("testdata", 0700) if err != nil { t.Fatal(err) } // Set umask to test mode for new files umask := syscall.Umask(027) defer syscall.Umask(umask) root := ft.File{ Path: ".", Mode: fs.ModeDir | 0700, } _, uid, _, gid := ft.CurrentUserAndGroup() symlinkExists := "\"file\": too many levels of symbolic links" if runtime.GOOS == "freebsd" { // EMLINK instead of ELOOP symlinkExists = "\"file\": too many links" } tests := []struct { name string path string line string create bool prepare func() expFiles []ft.File expChanges []string expErr error }{ // TODO: Add tests for chown and run them only as root { "missing", "file", "line", false, nil, []ft.File{ root, }, nil, fmt.Errorf("\"file\": file does not exist, use -create"), }, { "missing: create", "file", "line", true, nil, []ft.File{ root, { Path: "file", Mode: 0640, Data: []byte("line\n"), }, }, []string{ fmt.Sprintf(`"file": created file (%d/%d -rw-r-----)`, uid, gid), `"file": added line "line"`, }, nil, }, { "missing: create (empty line)", "file", "", true, nil, []ft.File{ root, }, nil, fmt.Errorf("empty line"), }, { "missing: create (newline)", "file", "line\n", true, nil, []ft.File{ root, }, nil, fmt.Errorf("line must not contain newlines: \"line\\n\""), }, { "exists: unchanged", "file", "line", true, func() { ft.CreateFile("file", "line\n", 0641) }, []ft.File{ root, { Path: "file", Mode: 0641, Data: []byte("line\n"), }, }, nil, nil, }, { "exists: append", "file", "line", true, func() { ft.CreateFile("file", "existing\n", 0641) }, []ft.File{ root, { Path: "file", Mode: 0641, Data: []byte("existing\nline\n"), }, }, []string{ `"file": added line "line"`, }, nil, }, { "exists: append (no newline in file)", "file", "line", true, func() { ft.CreateFile("file", "existing", 0641) }, []ft.File{ root, { Path: "file", Mode: 0641, Data: []byte("existing\nline\n"), }, }, []string{ `"file": added missing trailing newline`, `"file": added line "line"`, }, nil, }, { "exists: append (only trailing newline I)", "file", "line", true, func() { ft.CreateFile("file", "first\nline", 0641) }, []ft.File{ root, { Path: "file", Mode: 0641, Data: []byte("first\nline\n"), }, }, []string{ `"file": added missing trailing newline`, }, nil, }, { "exists: append (only trailing newline II)", "file", "first", true, func() { ft.CreateFile("file", "first\nline", 0641) }, []ft.File{ root, { Path: "file", Mode: 0641, Data: []byte("first\nline\n"), }, }, []string{ `"file": added missing trailing newline`, }, nil, }, { "exists: append (partial line)", "file", "line with spaces", true, func() { ft.CreateFile("file", "# line with spaces\n", 0641) }, []ft.File{ root, { Path: "file", Mode: 0641, Data: []byte("# line with spaces\nline with spaces\n"), }, }, []string{ `"file": added line "line with spaces"`, }, nil, }, { "exists: symlink", "file", "line", true, func() { ft.CreateSymlink("file", "target") }, []ft.File{ root, { Path: "file", Mode: fs.ModeSymlink | 0777, Data: []byte("target"), }, }, nil, fmt.Errorf(symlinkExists), }, { "exists: fifo", "file", "line", true, func() { ft.CreateFifo("file", 0640) }, []ft.File{ root, { Path: "file", Mode: fs.ModeNamedPipe | 0640, }, }, nil, fmt.Errorf("\"file\": not a regular file but p---------"), }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { // Create separate test directory for each test case path := filepath.Join(cwd, "testdata", tc.name) err = os.Mkdir(path, 0700) if err != nil { t.Fatal(err) } err = os.Chdir(path) if err != nil { t.Fatal(err) } if tc.prepare != nil { tc.prepare() } changes, err := handle(tc.path, tc.line, tc.create) testutil.AssertEqual(t, "changes", changes, tc.expChanges) testutil.AssertErrorEqual(t, "err", err, tc.expErr) files, err := ft.WalkDir(path) if err != nil { t.Fatal(err) } testutil.AssertEqual(t, "files", files, tc.expFiles) }) } if !t.Failed() { err = os.RemoveAll(filepath.Join(cwd, "testdata")) if err != nil { t.Fatal(err) } } }