1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package gopathwalk 6 7import ( 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "reflect" 12 "runtime" 13 "strings" 14 "sync" 15 "testing" 16) 17 18func TestShouldTraverse(t *testing.T) { 19 switch runtime.GOOS { 20 case "windows", "plan9": 21 t.Skipf("skipping symlink-requiring test on %s", runtime.GOOS) 22 } 23 24 dir, err := ioutil.TempDir("", "goimports-") 25 if err != nil { 26 t.Fatal(err) 27 } 28 defer os.RemoveAll(dir) 29 30 // Note: mapToDir prepends "src" to each element, since 31 // mapToDir was made for creating GOPATHs. 32 if err := mapToDir(dir, map[string]string{ 33 "foo/foo2/file.txt": "", 34 "foo/foo2/link-to-src": "LINK:../../", 35 "foo/foo2/link-to-src-foo": "LINK:../../foo", 36 "foo/foo2/link-to-dot": "LINK:.", 37 "bar/bar2/file.txt": "", 38 "bar/bar2/link-to-src-foo": "LINK:../../foo", 39 40 "a/b/c": "LINK:../../a/d", 41 "a/d/e": "LINK:../../a/b", 42 }); err != nil { 43 t.Fatal(err) 44 } 45 tests := []struct { 46 dir string 47 file string 48 want bool 49 }{ 50 { 51 dir: "src/foo/foo2", 52 file: "link-to-src-foo", 53 want: false, // loop 54 }, 55 { 56 dir: "src/foo/foo2", 57 file: "link-to-src", 58 want: false, // loop 59 }, 60 { 61 dir: "src/foo/foo2", 62 file: "link-to-dot", 63 want: false, // loop 64 }, 65 { 66 dir: "src/bar/bar2", 67 file: "link-to-src-foo", 68 want: true, // not a loop 69 }, 70 { 71 dir: "src/a/b/c", 72 file: "e", 73 want: false, // loop: "e" is the same as "b". 74 }, 75 } 76 for i, tt := range tests { 77 fi, err := os.Stat(filepath.Join(dir, tt.dir, tt.file)) 78 if err != nil { 79 t.Errorf("%d. Stat = %v", i, err) 80 continue 81 } 82 var w walker 83 got := w.shouldTraverse(filepath.Join(dir, tt.dir), fi) 84 if got != tt.want { 85 t.Errorf("%d. shouldTraverse(%q, %q) = %v; want %v", i, tt.dir, tt.file, got, tt.want) 86 } 87 } 88} 89 90// TestSkip tests that various goimports rules are followed in non-modules mode. 91func TestSkip(t *testing.T) { 92 dir, err := ioutil.TempDir("", "goimports-") 93 if err != nil { 94 t.Fatal(err) 95 } 96 defer os.RemoveAll(dir) 97 98 if err := mapToDir(dir, map[string]string{ 99 "ignoreme/f.go": "package ignoreme", // ignored by .goimportsignore 100 "node_modules/f.go": "package nodemodules;", // ignored by hardcoded node_modules filter 101 "v/f.go": "package v;", // ignored by hardcoded vgo cache rule 102 "mod/f.go": "package mod;", // ignored by hardcoded vgo cache rule 103 "shouldfind/f.go": "package shouldfind;", // not ignored 104 105 ".goimportsignore": "ignoreme\n", 106 }); err != nil { 107 t.Fatal(err) 108 } 109 110 var found []string 111 var mu sync.Mutex 112 walkDir(Root{filepath.Join(dir, "src"), RootGOPATH}, 113 func(root Root, dir string) { 114 mu.Lock() 115 defer mu.Unlock() 116 found = append(found, dir[len(root.Path)+1:]) 117 }, func(root Root, dir string) bool { 118 return false 119 }, Options{ModulesEnabled: false, Debug: true}) 120 if want := []string{"shouldfind"}; !reflect.DeepEqual(found, want) { 121 t.Errorf("expected to find only %v, got %v", want, found) 122 } 123} 124 125// TestSkipFunction tests that scan successfully skips directories from user callback. 126func TestSkipFunction(t *testing.T) { 127 dir, err := ioutil.TempDir("", "goimports-") 128 if err != nil { 129 t.Fatal(err) 130 } 131 defer os.RemoveAll(dir) 132 133 if err := mapToDir(dir, map[string]string{ 134 "ignoreme/f.go": "package ignoreme", // ignored by skip 135 "ignoreme/subignore/f.go": "package subignore", // also ignored by skip 136 "shouldfind/f.go": "package shouldfind;", // not ignored 137 }); err != nil { 138 t.Fatal(err) 139 } 140 141 var found []string 142 var mu sync.Mutex 143 walkDir(Root{filepath.Join(dir, "src"), RootGOPATH}, 144 func(root Root, dir string) { 145 mu.Lock() 146 defer mu.Unlock() 147 found = append(found, dir[len(root.Path)+1:]) 148 }, func(root Root, dir string) bool { 149 return strings.HasSuffix(dir, "ignoreme") 150 }, 151 Options{ModulesEnabled: false}) 152 if want := []string{"shouldfind"}; !reflect.DeepEqual(found, want) { 153 t.Errorf("expected to find only %v, got %v", want, found) 154 } 155} 156 157func mapToDir(destDir string, files map[string]string) error { 158 for path, contents := range files { 159 file := filepath.Join(destDir, "src", path) 160 if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil { 161 return err 162 } 163 var err error 164 if strings.HasPrefix(contents, "LINK:") { 165 err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file) 166 } else { 167 err = ioutil.WriteFile(file, []byte(contents), 0644) 168 } 169 if err != nil { 170 return err 171 } 172 } 173 return nil 174} 175