| package main |
| |
| import ( |
| "io/fs" |
| "io/ioutil" |
| "path/filepath" |
| "os" |
| "reflect" |
| "testing" |
| ) |
| |
| func TestFileExists(t *testing.T) { |
| tmpd := t.TempDir() |
| existsFile := filepath.Join(tmpd, "exists.txt") |
| ioutil.WriteFile(existsFile, []byte("\n"), 0644) |
| if !fileExists(existsFile) { |
| t.Errorf("%s should exist, but does not", existsFile) |
| } |
| |
| notExistsFile := filepath.Join(tmpd, "not_exists.txt") |
| if fileExists(notExistsFile) { |
| t.Errorf("%s should not exist, but does", notExistsFile) |
| } |
| |
| if fileExists(tmpd) { |
| t.Errorf("%s should not exist as a file, it is a dir", tmpd) |
| } |
| } |
| |
| func TestFilesMatchByLine(t *testing.T) { |
| tmpd := t.TempDir() |
| |
| type fileSpec struct { |
| name string |
| contents string |
| } |
| |
| aFileSpec := fileSpec { |
| name: "a.txt", |
| contents: "a\n", |
| } |
| bFileSpec := fileSpec{ |
| name: "b.txt", |
| contents: "b\n", |
| } |
| abFileSpec := fileSpec{ |
| name: "ab.txt", |
| contents: "a\nb\n", |
| } |
| acFileSpec := fileSpec{ |
| name: "ac.txt", |
| contents: "a\nc\n", |
| } |
| |
| files := []fileSpec{ |
| aFileSpec, bFileSpec, abFileSpec, acFileSpec, |
| } |
| |
| for _, f := range files { |
| file := filepath.Join(tmpd, f.name) |
| ioutil.WriteFile(file, []byte(f.contents), 0644) |
| } |
| |
| match := func(fs1 fileSpec, fs2 fileSpec) bool { |
| return filesMatchByLine( |
| filepath.Join(tmpd, fs1.name), |
| filepath.Join(tmpd, fs2.name), |
| ) |
| } |
| |
| testCases := []struct{ |
| left fileSpec |
| right fileSpec |
| expectMatch bool |
| }{ |
| |
| { |
| left: aFileSpec, |
| right: aFileSpec, |
| expectMatch: true, |
| }, |
| { |
| left: bFileSpec, |
| right: bFileSpec, |
| expectMatch: true, |
| }, |
| { |
| left: abFileSpec, |
| right: abFileSpec, |
| expectMatch: true, |
| }, |
| { |
| left: acFileSpec, |
| right: acFileSpec, |
| expectMatch: true, |
| }, |
| { |
| left: aFileSpec, |
| right: bFileSpec, |
| expectMatch: false, |
| }, |
| { |
| left: bFileSpec, |
| right: aFileSpec, |
| expectMatch: false, |
| }, |
| { |
| left: aFileSpec, |
| right: abFileSpec, |
| expectMatch: false, |
| }, |
| { |
| left: abFileSpec, |
| right: aFileSpec, |
| expectMatch: false, |
| }, |
| { |
| left: aFileSpec, |
| right: acFileSpec, |
| expectMatch: false, |
| }, |
| { |
| left: acFileSpec, |
| right: aFileSpec, |
| expectMatch: false, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| actual := match(tc.left, tc.right) |
| if actual != tc.expectMatch { |
| t.Errorf("Matching %s vs. %s should have been %v, but got %v", tc.left.name, tc.right.name, tc.expectMatch, actual) |
| } |
| } |
| } |
| |
| func TestCopyFileWithMode(t *testing.T) { |
| tmpd := t.TempDir() |
| |
| var mode fs.FileMode = 0600 |
| testFile := filepath.Join(tmpd, "private.txt") |
| ioutil.WriteFile(testFile, []byte("\n"), mode) |
| |
| copyFile := filepath.Join(tmpd, "copy.txt") |
| err := copyFileWithMode(copyFile, testFile) |
| if err != nil { |
| t.Fatalf("Error copying file: %s", copyFile) |
| } |
| |
| copyF, err := os.Open(copyFile) |
| if err != nil { |
| t.Fatalf("Failed to read the file that was just written, %s", copyFile) |
| } |
| info, err := copyF.Stat() |
| if err != nil { |
| t.Fatalf("Failed to stat the written file, %s", copyFile) |
| } |
| if info.Mode() != mode { |
| t.Errorf("File modes mismatched. Want: %o, Got: %o", mode, info.Mode()) |
| } |
| } |
| |
| func TestRemoveIfAbsentRootDoesNotExist(t *testing.T) { |
| tmpdDst := t.TempDir() |
| |
| var mode fs.FileMode = 0644 |
| ioutil.WriteFile(filepath.Join(tmpdDst, "b.txt"), []byte("z\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "c.txt"), []byte("w\n"), mode) |
| |
| keepers := map[string]bool{} // value doesn't matter |
| removed, err := removeIfAbsent(filepath.Join(tmpdDst, "subdir_not_exist"), keepers) |
| if err != nil { |
| t.Errorf("Expected no error, but got: %v", err) |
| } |
| if removed { |
| t.Errorf("Expected that nothing was removed, but got: %v", removed) |
| } |
| } |
| |
| func TestRemoveIfAbsentPartialRemove(t *testing.T) { |
| tmpdSrc := t.TempDir() |
| tmpdDst := t.TempDir() |
| |
| var mode fs.FileMode = 0644 |
| ioutil.WriteFile(filepath.Join(tmpdSrc, "a.txt"), []byte("x\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdSrc, "b.txt"), []byte("y\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "b.txt"), []byte("z\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "c.txt"), []byte("w\n"), mode) |
| |
| keepers := listFilesDirsRecursively(tmpdSrc) |
| removed, err := removeIfAbsent(tmpdDst, keepers) |
| if err != nil { |
| t.Fatalf("Expected no error, but got: %v", err) |
| } |
| actualRemainder := listFilesDirsRecursively(tmpdDst) |
| expectedRemainder := map[string]bool{ |
| "b.txt": false, |
| } |
| if !removed { |
| t.Errorf("Expected that something was removed, but got: %v", removed) |
| } |
| |
| if !reflect.DeepEqual(actualRemainder, expectedRemainder) { |
| t.Errorf("Expected dir contents %v, but got %v", expectedRemainder, actualRemainder) |
| } |
| } |
| |
| func TestRemoveIfAbsentRemoveNothing(t *testing.T) { |
| tmpdDst := t.TempDir() |
| |
| var mode fs.FileMode = 0644 |
| ioutil.WriteFile(filepath.Join(tmpdDst, "j.txt"), []byte("z\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "k.txt"), []byte("w\n"), mode) |
| |
| keepers := map[string]bool{ |
| "j.txt": false, |
| "k.txt": false, |
| } |
| removed, err := removeIfAbsent(tmpdDst, keepers) |
| if err != nil { |
| t.Fatalf("Expected no error, but got: %v", err) |
| } |
| actualRemainder := listFilesDirsRecursively(tmpdDst) |
| |
| if removed { |
| t.Errorf("Expected that nothing was removed, but got: %v", removed) |
| } |
| if !reflect.DeepEqual(actualRemainder, keepers) { |
| t.Errorf("Expected dir contents %v, but got %v", keepers, actualRemainder) |
| } |
| } |
| |
| func TestRemoveIfAbsentRemoveEverything(t *testing.T) { |
| tmpdDst := t.TempDir() |
| |
| var mode fs.FileMode = 0644 |
| ioutil.WriteFile(filepath.Join(tmpdDst, "p.txt"), []byte("z\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "q.txt"), []byte("w\n"), mode) |
| |
| keepers := map[string]bool{} |
| removed, err := removeIfAbsent(tmpdDst, keepers) |
| if err != nil { |
| t.Fatalf("Expected no error, but got: %v", err) |
| } |
| actualRemainder := listFilesDirsRecursively(tmpdDst) |
| |
| if !removed { |
| t.Errorf("Expected that something was removed, but got: %v", removed) |
| } |
| if !reflect.DeepEqual(actualRemainder, keepers) { |
| t.Errorf("Expected dir contents %v, but got %v", keepers, actualRemainder) |
| } |
| } |
| |
| func TestRemoveIfAbsentPartialRemoveInSubdirs(t *testing.T) { |
| tmpdSrc := t.TempDir() |
| tmpdDst := t.TempDir() |
| |
| var mode fs.FileMode = 0644 |
| |
| if err := os.Mkdir(filepath.Join(tmpdSrc, "sub"), os.ModePerm); err != nil { |
| t.Fatalf("Error creating dir: %v", err) |
| } |
| if err := os.Mkdir(filepath.Join(tmpdDst, "sub"), os.ModePerm); err != nil { |
| t.Fatalf("Error creating dir: %v", err) |
| } |
| |
| ioutil.WriteFile(filepath.Join(tmpdSrc, "sub", "a.txt"), []byte("x\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdSrc, "sub", "b.txt"), []byte("y\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "sub", "b.txt"), []byte("z\n"), mode) |
| ioutil.WriteFile(filepath.Join(tmpdDst, "sub", "c.txt"), []byte("w\n"), mode) |
| |
| keepers := listFilesDirsRecursively(tmpdSrc) |
| removed, err := removeIfAbsent(tmpdDst, keepers) |
| if err != nil { |
| t.Fatalf("Expected no error, but got: %v", err) |
| } |
| actualRemainder := listFilesDirsRecursively(tmpdDst) |
| expectedRemainder := map[string]bool{ |
| "sub": true, |
| "sub/b.txt": false, |
| } |
| |
| if !removed { |
| t.Errorf("Expected that something was removed, but got: %v", removed) |
| } |
| if !reflect.DeepEqual(actualRemainder, expectedRemainder) { |
| t.Errorf("Expected dir contents %v, but got %v", expectedRemainder, actualRemainder) |
| } |
| } |
| |
| |