From e45b446b86a9dec12482568515d1f11b3c5b7e15 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Mon, 18 Oct 2021 14:35:45 +0100 Subject: [PATCH] Correct directory diffing test and algorithm Two steps: 1. TestDiffDirectories did not check if the expected only return value was correct; the intention was there to do so (judging by the comment "change in order"), but my eye for detail failed me. 2. Reversing the directory comparison in the test revealed bugs in the comparison code -- in general, it should skip any directory that is not a directory in the comparator. To make this easier, the code now keeps track of the expected files it saw. That means the check for whether an actual file has an expected counterpart only has two cases, yes or no (rather that trying to account for whether it's a directory and so on). If a directory was skipped while scanning the expected files, it won't be in the actual files anyway. Signed-off-by: Michael Bridgen --- pkg/test/files.go | 33 +++++++++++++++++++-------------- pkg/test/files_test.go | 12 ++++++------ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/pkg/test/files.go b/pkg/test/files.go index e58e11d9..fc133782 100644 --- a/pkg/test/files.go +++ b/pkg/test/files.go @@ -83,16 +83,21 @@ func (d dirfile) FailedExpectation(g *WithT) { // `foo.yaml~`). It panics if it encounters any error apart from a // file not found. func DiffDirectories(actual, expected string) (actualonly []string, expectedonly []string, different []Diff) { + seen := make(map[string]struct{}) + filepath.Walk(expected, func(expectedPath string, expectedInfo os.FileInfo, err error) error { if err != nil { panic(err) } + + relPath := expectedPath[len(expected):] + seen[relPath] = struct{}{} + // ignore emacs backups if strings.HasSuffix(expectedPath, "~") { return nil } - relPath := expectedPath[len(expected):] - actualPath := filepath.Join(actual, relPath) + // ignore dotfiles if strings.HasPrefix(filepath.Base(expectedPath), ".") { if expectedInfo.IsDir() { @@ -101,24 +106,30 @@ func DiffDirectories(actual, expected string) (actualonly []string, expectedonly return nil } + actualPath := filepath.Join(actual, relPath) actualInfo, err := os.Stat(actualPath) switch { case err == nil: break case os.IsNotExist(err): expectedonly = append(expectedonly, relPath) + if expectedInfo.IsDir() { + return filepath.SkipDir + } return nil default: panic(err) } // file exists in both places - switch { case actualInfo.IsDir() && expectedInfo.IsDir(): return nil // i.e., keep recursing case actualInfo.IsDir() || expectedInfo.IsDir(): different = append(different, dirfile{path: relPath, abspath: actualPath, expectedRegularFile: actualInfo.IsDir()}) + if expectedInfo.IsDir() { + return filepath.SkipDir + } return nil } @@ -152,18 +163,12 @@ func DiffDirectories(actual, expected string) (actualonly []string, expectedonly if actualInfo.IsDir() && strings.HasPrefix(filepath.Base(actualPath), ".") { return filepath.SkipDir } - // since I've already compared any file that exists in - // expected or both, I'm only concerned with files that appear - // in actual but not in expected. - expectedPath := filepath.Join(expected, relPath) - _, err = os.Stat(expectedPath) - switch { - case err == nil: - break - case os.IsNotExist(err): + + if _, ok := seen[relPath]; !ok { actualonly = append(actualonly, relPath) - default: - panic(err) + if actualInfo.IsDir() { + return filepath.SkipDir + } } return nil }) diff --git a/pkg/test/files_test.go b/pkg/test/files_test.go index 46ce50b2..b5e5f37d 100644 --- a/pkg/test/files_test.go +++ b/pkg/test/files_test.go @@ -51,13 +51,13 @@ func TestExpectMatchingDirectories(t *testing.T) { func TestDiffDirectories(t *testing.T) { g := NewWithT(t) - // Finds files in expected from a/ but not in actual b/. - aonly, _, _ := DiffDirectories("testdata/diff/a", "testdata/diff/b") - g.Expect(aonly).To(Equal([]string{"/only", "/only/here.yaml", "/onlyhere.yaml"})) - // Finds files in actual a/ that weren't expected from b/. - bonly, _, _ := DiffDirectories("testdata/diff/a", "testdata/diff/b") // change in order - g.Expect(bonly).To(Equal([]string{"/only", "/only/here.yaml", "/onlyhere.yaml"})) + actualonly, _, _ := DiffDirectories("testdata/diff/a", "testdata/diff/b") + g.Expect(actualonly).To(Equal([]string{"/only", "/onlyhere.yaml"})) + + // Finds files in expected from a/ but not in actual b/. + _, expectedonly, _ := DiffDirectories("testdata/diff/b", "testdata/diff/a") // NB change in order + g.Expect(expectedonly).To(Equal([]string{"/only", "/onlyhere.yaml"})) // Finds files that are different in a and b. _, _, diffs := DiffDirectories("testdata/diff/a", "testdata/diff/b")