| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package gps |
| |
| import ( |
| "io/ioutil" |
| "os" |
| "testing" |
| |
| "github.com/golang/dep/internal/test" |
| ) |
| |
| func TestCascadingPruneOptions(t *testing.T) { |
| cases := []struct { |
| name string |
| co CascadingPruneOptions |
| results map[ProjectRoot]PruneOptions |
| }{ |
| { |
| name: "all empty values", |
| co: CascadingPruneOptions{ |
| DefaultOptions: PruneNestedVendorDirs, |
| PerProjectOptions: map[ProjectRoot]PruneOptionSet{ |
| ProjectRoot("github.com/golang/dep"): {}, |
| }, |
| }, |
| results: map[ProjectRoot]PruneOptions{ |
| ProjectRoot("github.com/golang/dep"): PruneNestedVendorDirs, |
| }, |
| }, |
| { |
| name: "all overridden", |
| co: CascadingPruneOptions{ |
| DefaultOptions: PruneNestedVendorDirs, |
| PerProjectOptions: map[ProjectRoot]PruneOptionSet{ |
| ProjectRoot("github.com/golang/dep"): { |
| NestedVendor: 2, |
| UnusedPackages: 1, |
| NonGoFiles: 1, |
| GoTests: 1, |
| }, |
| }, |
| }, |
| results: map[ProjectRoot]PruneOptions{ |
| ProjectRoot("github.com/golang/dep"): PruneUnusedPackages | PruneNonGoFiles | PruneGoTestFiles, |
| }, |
| }, |
| { |
| name: "all redundant", |
| co: CascadingPruneOptions{ |
| DefaultOptions: PruneNestedVendorDirs, |
| PerProjectOptions: map[ProjectRoot]PruneOptionSet{ |
| ProjectRoot("github.com/golang/dep"): { |
| NestedVendor: 1, |
| UnusedPackages: 2, |
| NonGoFiles: 2, |
| GoTests: 2, |
| }, |
| }, |
| }, |
| results: map[ProjectRoot]PruneOptions{ |
| ProjectRoot("github.com/golang/dep"): PruneNestedVendorDirs, |
| }, |
| }, |
| { |
| name: "multiple projects, all combos", |
| co: CascadingPruneOptions{ |
| DefaultOptions: PruneNestedVendorDirs, |
| PerProjectOptions: map[ProjectRoot]PruneOptionSet{ |
| ProjectRoot("github.com/golang/dep"): { |
| NestedVendor: 1, |
| UnusedPackages: 2, |
| NonGoFiles: 2, |
| GoTests: 2, |
| }, |
| ProjectRoot("github.com/other/one"): { |
| NestedVendor: 2, |
| UnusedPackages: 1, |
| NonGoFiles: 1, |
| GoTests: 1, |
| }, |
| }, |
| }, |
| results: map[ProjectRoot]PruneOptions{ |
| ProjectRoot("github.com/golang/dep"): PruneNestedVendorDirs, |
| ProjectRoot("github.com/other/one"): PruneUnusedPackages | PruneNonGoFiles | PruneGoTestFiles, |
| ProjectRoot("not/there"): PruneNestedVendorDirs, |
| }, |
| }, |
| } |
| |
| for _, c := range cases { |
| t.Run(c.name, func(t *testing.T) { |
| for pr, wanted := range c.results { |
| if c.co.PruneOptionsFor(pr) != wanted { |
| t.Fatalf("did not get expected final PruneOptions value from cascade:\n\t(GOT): %d\n\t(WNT): %d", c.co.PruneOptionsFor(pr), wanted) |
| } |
| |
| } |
| }) |
| } |
| } |
| |
| func TestPruneProject(t *testing.T) { |
| h := test.NewHelper(t) |
| defer h.Cleanup() |
| |
| pr := "github.com/project/repository" |
| h.TempDir(pr) |
| |
| baseDir := h.Path(".") |
| lp := lockedProject{ |
| pi: ProjectIdentifier{ |
| ProjectRoot: ProjectRoot(pr), |
| }, |
| pkgs: []string{}, |
| } |
| |
| options := PruneNestedVendorDirs | PruneNonGoFiles | PruneGoTestFiles | PruneUnusedPackages |
| |
| err := PruneProject(baseDir, lp, options) |
| if err != nil { |
| t.Fatal(err) |
| } |
| } |
| |
| func TestPruneUnusedPackages(t *testing.T) { |
| h := test.NewHelper(t) |
| defer h.Cleanup() |
| |
| h.TempDir(".") |
| |
| pr := "github.com/sample/repository" |
| pi := ProjectIdentifier{ProjectRoot: ProjectRoot(pr)} |
| |
| testcases := []struct { |
| name string |
| lp LockedProject |
| fs fsTestCase |
| err bool |
| }{ |
| { |
| "one-package", |
| lockedProject{ |
| pi: pi, |
| pkgs: []string{ |
| ".", |
| }, |
| }, |
| fsTestCase{ |
| before: filesystemState{ |
| files: []string{ |
| "main.go", |
| }, |
| }, |
| after: filesystemState{ |
| files: []string{ |
| "main.go", |
| }, |
| }, |
| }, |
| false, |
| }, |
| { |
| "nested-package", |
| lockedProject{ |
| pi: pi, |
| pkgs: []string{ |
| "pkg", |
| }, |
| }, |
| fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "pkg", |
| }, |
| files: []string{ |
| "main.go", |
| "pkg/main.go", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "pkg", |
| }, |
| files: []string{ |
| "pkg/main.go", |
| }, |
| }, |
| }, |
| false, |
| }, |
| { |
| "complex-project", |
| lockedProject{ |
| pi: pi, |
| pkgs: []string{ |
| "pkg", |
| "pkg/nestedpkg/otherpkg", |
| }, |
| }, |
| fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "pkg", |
| "pkg/nestedpkg", |
| "pkg/nestedpkg/otherpkg", |
| }, |
| files: []string{ |
| "main.go", |
| "COPYING", |
| "pkg/main.go", |
| "pkg/nestedpkg/main.go", |
| "pkg/nestedpkg/legal.go", |
| "pkg/nestedpkg/PATENT.md", |
| "pkg/nestedpkg/otherpkg/main.go", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "pkg", |
| "pkg/nestedpkg", |
| "pkg/nestedpkg/otherpkg", |
| }, |
| files: []string{ |
| "COPYING", |
| "pkg/main.go", |
| "pkg/nestedpkg/PATENT.md", |
| "pkg/nestedpkg/otherpkg/main.go", |
| }, |
| }, |
| }, |
| false, |
| }, |
| } |
| |
| for _, tc := range testcases { |
| t.Run(tc.name, func(t *testing.T) { |
| h.TempDir(pr) |
| baseDir := h.Path(pr) |
| tc.fs.before.root = baseDir |
| tc.fs.after.root = baseDir |
| tc.fs.setup(t) |
| |
| fs, err := deriveFilesystemState(baseDir) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| _, err = pruneUnusedPackages(tc.lp, fs) |
| if tc.err && err == nil { |
| t.Fatalf("expected an error, got nil") |
| } else if !tc.err && err != nil { |
| t.Fatalf("unexpected error: %s", err) |
| } |
| |
| tc.fs.assert(t) |
| }) |
| } |
| } |
| |
| func TestPruneNonGoFiles(t *testing.T) { |
| h := test.NewHelper(t) |
| defer h.Cleanup() |
| |
| h.TempDir(".") |
| |
| testcases := []struct { |
| name string |
| fs fsTestCase |
| err bool |
| }{ |
| { |
| "one-file", |
| fsTestCase{ |
| before: filesystemState{ |
| files: []string{ |
| "README.md", |
| }, |
| }, |
| after: filesystemState{}, |
| }, |
| false, |
| }, |
| { |
| "multiple-files", |
| fsTestCase{ |
| before: filesystemState{ |
| files: []string{ |
| "main.go", |
| "main_test.go", |
| "README", |
| }, |
| }, |
| after: filesystemState{ |
| files: []string{ |
| "main.go", |
| "main_test.go", |
| }, |
| }, |
| }, |
| false, |
| }, |
| { |
| "mixed-files", |
| fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "dir", |
| }, |
| files: []string{ |
| "dir/main.go", |
| "dir/main_test.go", |
| "dir/db.sqlite", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "dir", |
| }, |
| files: []string{ |
| "dir/main.go", |
| "dir/main_test.go", |
| }, |
| }, |
| }, |
| false, |
| }, |
| } |
| |
| for _, tc := range testcases { |
| t.Run(tc.name, func(t *testing.T) { |
| h.TempDir(tc.name) |
| baseDir := h.Path(tc.name) |
| tc.fs.before.root = baseDir |
| tc.fs.after.root = baseDir |
| |
| tc.fs.setup(t) |
| |
| fs, err := deriveFilesystemState(baseDir) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| err = pruneNonGoFiles(fs) |
| if tc.err && err == nil { |
| t.Errorf("expected an error, got nil") |
| } else if !tc.err && err != nil { |
| t.Errorf("unexpected error: %s", err) |
| } |
| |
| tc.fs.assert(t) |
| }) |
| } |
| } |
| |
| func TestPruneGoTestFiles(t *testing.T) { |
| h := test.NewHelper(t) |
| defer h.Cleanup() |
| |
| h.TempDir(".") |
| |
| testcases := []struct { |
| name string |
| fs fsTestCase |
| err bool |
| }{ |
| { |
| "one-test-file", |
| fsTestCase{ |
| before: filesystemState{ |
| files: []string{ |
| "main_test.go", |
| }, |
| }, |
| after: filesystemState{}, |
| }, |
| false, |
| }, |
| { |
| "multiple-files", |
| fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "dir", |
| }, |
| files: []string{ |
| "dir/main_test.go", |
| "dir/main2_test.go", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "dir", |
| }, |
| }, |
| }, |
| false, |
| }, |
| { |
| "mixed-files", |
| fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "dir", |
| }, |
| files: []string{ |
| "dir/main.go", |
| "dir/main2.go", |
| "dir/main_test.go", |
| "dir/main2_test.go", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "dir", |
| }, |
| files: []string{ |
| "dir/main.go", |
| "dir/main2.go", |
| }, |
| }, |
| }, |
| false, |
| }, |
| } |
| |
| for _, tc := range testcases { |
| t.Run(tc.name, func(t *testing.T) { |
| h.TempDir(tc.name) |
| baseDir := h.Path(tc.name) |
| tc.fs.before.root = baseDir |
| tc.fs.after.root = baseDir |
| |
| tc.fs.setup(t) |
| |
| fs, err := deriveFilesystemState(baseDir) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| err = pruneGoTestFiles(fs) |
| if tc.err && err == nil { |
| t.Fatalf("expected an error, got nil") |
| } else if !tc.err && err != nil { |
| t.Fatalf("unexpected error: %s", err) |
| } |
| |
| tc.fs.assert(t) |
| }) |
| } |
| } |
| |
| func TestPruneVendorDirs(t *testing.T) { |
| tests := []struct { |
| name string |
| test fsTestCase |
| }{ |
| { |
| name: "vendor directory", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "package", |
| "package/vendor", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "vendor file", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| files: []string{ |
| "package/vendor", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| files: []string{ |
| "package/vendor", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "vendor symlink", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "package", |
| "package/_vendor", |
| }, |
| links: []fsLink{ |
| { |
| path: "package/vendor", |
| to: "_vendor", |
| }, |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "package", |
| "package/_vendor", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "nonvendor symlink", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "package", |
| "package/_vendor", |
| }, |
| links: []fsLink{ |
| { |
| path: "package/link", |
| to: "_vendor", |
| }, |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "package", |
| "package/_vendor", |
| }, |
| links: []fsLink{ |
| { |
| path: "package/link", |
| to: "_vendor", |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "vendor symlink to file", |
| test: fsTestCase{ |
| before: filesystemState{ |
| files: []string{ |
| "file", |
| }, |
| links: []fsLink{ |
| { |
| path: "vendor", |
| to: "file", |
| }, |
| }, |
| }, |
| after: filesystemState{ |
| files: []string{ |
| "file", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "broken vendor symlink", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| links: []fsLink{ |
| { |
| path: "package/vendor", |
| to: "nonexistence", |
| }, |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| links: []fsLink{}, |
| }, |
| }, |
| }, |
| { |
| name: "chained symlinks", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "_vendor", |
| }, |
| links: []fsLink{ |
| { |
| path: "vendor", |
| to: "vendor2", |
| }, |
| { |
| path: "vendor2", |
| to: "_vendor", |
| }, |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "_vendor", |
| }, |
| links: []fsLink{ |
| { |
| path: "vendor2", |
| to: "_vendor", |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "circular symlinks", |
| test: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| links: []fsLink{ |
| { |
| path: "package/link1", |
| to: "link2", |
| }, |
| { |
| path: "package/link2", |
| to: "link1", |
| }, |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "package", |
| }, |
| links: []fsLink{ |
| { |
| path: "package/link1", |
| to: "link2", |
| }, |
| { |
| path: "package/link2", |
| to: "link1", |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run(test.name, pruneVendorDirsTestCase(test.test)) |
| } |
| } |
| |
| func pruneVendorDirsTestCase(tc fsTestCase) func(*testing.T) { |
| return func(t *testing.T) { |
| tempDir, err := ioutil.TempDir("", "pruneVendorDirsTestCase") |
| if err != nil { |
| t.Fatalf("ioutil.TempDir err=%q", err) |
| } |
| defer func() { |
| if err := os.RemoveAll(tempDir); err != nil { |
| t.Errorf("os.RemoveAll(%q) err=%q", tempDir, err) |
| } |
| }() |
| |
| tc.before.root = tempDir |
| tc.after.root = tempDir |
| |
| tc.setup(t) |
| |
| fs, err := deriveFilesystemState(tempDir) |
| if err != nil { |
| t.Fatalf("deriveFilesystemState failed: %s", err) |
| } |
| |
| if err := pruneVendorDirs(fs); err != nil { |
| t.Errorf("pruneVendorDirs err=%q", err) |
| } |
| |
| tc.assert(t) |
| } |
| } |
| |
| func TestDeleteEmptyDirs(t *testing.T) { |
| testcases := []struct { |
| name string |
| fs fsTestCase |
| }{ |
| { |
| name: "empty-dir", |
| fs: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "pkg1", |
| }, |
| }, |
| after: filesystemState{}, |
| }, |
| }, |
| { |
| name: "nested-empty-dirs", |
| fs: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "pkg1", |
| "pkg1/pkg2", |
| }, |
| }, |
| after: filesystemState{}, |
| }, |
| }, |
| { |
| name: "non-empty-dir", |
| fs: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "pkg1", |
| }, |
| files: []string{ |
| "pkg1/file1", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "pkg1", |
| }, |
| files: []string{ |
| "pkg1/file1", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "mixed-dirs", |
| fs: fsTestCase{ |
| before: filesystemState{ |
| dirs: []string{ |
| "pkg1", |
| "pkg1/pkg2", |
| }, |
| files: []string{ |
| "pkg1/file1", |
| }, |
| }, |
| after: filesystemState{ |
| dirs: []string{ |
| "pkg1", |
| }, |
| files: []string{ |
| "pkg1/file1", |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testcases { |
| t.Run(tc.name, func(t *testing.T) { |
| h := test.NewHelper(t) |
| h.Cleanup() |
| h.TempDir(".") |
| |
| tc.fs.before.root = h.Path(".") |
| tc.fs.after.root = h.Path(".") |
| |
| if err := tc.fs.before.setup(); err != nil { |
| t.Fatal("unexpected error in fs setup: ", err) |
| } |
| |
| if err := deleteEmptyDirs(tc.fs.before); err != nil { |
| t.Fatal("unexpected error in deleteEmptyDirs: ", err) |
| } |
| |
| tc.fs.assert(t) |
| }) |
| } |
| } |