1// Copyright 2015 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 5// No testdata on Android. 6 7// +build !android 8 9package main 10 11import ( 12 "bytes" 13 "log" 14 "os" 15 "path/filepath" 16 "runtime" 17 "strings" 18 "testing" 19 20 "golang.org/x/tools/internal/testenv" 21) 22 23// TODO(adonovan): 24// - test introduction of renaming imports. 25// - test induced failures of rewriteFile. 26 27// Guide to the test packages: 28// 29// new.com/one -- canonical name for old.com/one 30// old.com/one -- non-canonical; has import comment "new.com/one" 31// old.com/bad -- has a parse error 32// fruit.io/orange \ 33// fruit.io/banana } orange -> pear -> banana -> titanic.biz/bar 34// fruit.io/pear / 35// titanic.biz/bar -- domain is sinking; package has jumped ship to new.com/bar 36// titanic.biz/foo -- domain is sinking but package has no import comment yet 37 38var gopath = filepath.Join(cwd, "testdata") 39 40func init() { 41 if err := os.Setenv("GOPATH", gopath); err != nil { 42 log.Fatal(err) 43 } 44 45 // This test currently requires GOPATH mode. 46 // Explicitly disabling module mode should suffix, but 47 // we'll also turn off GOPROXY just for good measure. 48 if err := os.Setenv("GO111MODULE", "off"); err != nil { 49 log.Fatal(err) 50 } 51 if err := os.Setenv("GOPROXY", "off"); err != nil { 52 log.Fatal(err) 53 } 54} 55 56func TestFixImports(t *testing.T) { 57 testenv.NeedsTool(t, "go") 58 59 defer func() { 60 stderr = os.Stderr 61 *badDomains = "code.google.com" 62 *replaceFlag = "" 63 }() 64 65 for i, test := range []struct { 66 packages []string // packages to rewrite, "go list" syntax 67 badDomains string // -baddomains flag 68 replaceFlag string // -replace flag 69 wantOK bool 70 wantStderr string 71 wantRewrite map[string]string 72 }{ 73 // #0. No errors. 74 { 75 packages: []string{"all"}, 76 badDomains: "code.google.com", 77 wantOK: true, 78 wantStderr: ` 79testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF' 80fruit.io/banana 81 fixed: old.com/one -> new.com/one 82 fixed: titanic.biz/bar -> new.com/bar 83`, 84 wantRewrite: map[string]string{ 85 "$GOPATH/src/fruit.io/banana/banana.go": `package banana 86 87import ( 88 _ "new.com/bar" 89 _ "new.com/one" 90 _ "titanic.biz/foo" 91)`, 92 }, 93 }, 94 // #1. No packages needed rewriting. 95 { 96 packages: []string{"titanic.biz/...", "old.com/...", "new.com/..."}, 97 badDomains: "code.google.com", 98 wantOK: true, 99 wantStderr: ` 100testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF' 101`, 102 }, 103 // #2. Some packages without import comments matched bad domains. 104 { 105 packages: []string{"all"}, 106 badDomains: "titanic.biz", 107 wantOK: false, 108 wantStderr: ` 109testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF' 110fruit.io/banana 111 testdata/src/fruit.io/banana/banana.go:6: import "titanic.biz/foo" 112 fixed: old.com/one -> new.com/one 113 fixed: titanic.biz/bar -> new.com/bar 114 ERROR: titanic.biz/foo has no import comment 115 imported directly by: 116 fruit.io/pear 117 imported indirectly by: 118 fruit.io/orange 119`, 120 wantRewrite: map[string]string{ 121 "$GOPATH/src/fruit.io/banana/banana.go": `package banana 122 123import ( 124 _ "new.com/bar" 125 _ "new.com/one" 126 _ "titanic.biz/foo" 127)`, 128 }, 129 }, 130 // #3. The -replace flag lets user supply missing import comments. 131 { 132 packages: []string{"all"}, 133 replaceFlag: "titanic.biz/foo=new.com/foo", 134 wantOK: true, 135 wantStderr: ` 136testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF' 137fruit.io/banana 138 fixed: old.com/one -> new.com/one 139 fixed: titanic.biz/bar -> new.com/bar 140 fixed: titanic.biz/foo -> new.com/foo 141`, 142 wantRewrite: map[string]string{ 143 "$GOPATH/src/fruit.io/banana/banana.go": `package banana 144 145import ( 146 _ "new.com/bar" 147 _ "new.com/foo" 148 _ "new.com/one" 149)`, 150 }, 151 }, 152 // #4. The -replace flag supports wildcards. 153 // An explicit import comment takes precedence. 154 { 155 packages: []string{"all"}, 156 replaceFlag: "titanic.biz/...=new.com/...", 157 wantOK: true, 158 wantStderr: ` 159testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF' 160fruit.io/banana 161 fixed: old.com/one -> new.com/one 162 fixed: titanic.biz/bar -> new.com/bar 163 fixed: titanic.biz/foo -> new.com/foo 164`, 165 wantRewrite: map[string]string{ 166 "$GOPATH/src/fruit.io/banana/banana.go": `package banana 167 168import ( 169 _ "new.com/bar" 170 _ "new.com/foo" 171 _ "new.com/one" 172)`, 173 }, 174 }, 175 // #5. The -replace flag trumps -baddomains. 176 { 177 packages: []string{"all"}, 178 badDomains: "titanic.biz", 179 replaceFlag: "titanic.biz/foo=new.com/foo", 180 wantOK: true, 181 wantStderr: ` 182testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF' 183fruit.io/banana 184 fixed: old.com/one -> new.com/one 185 fixed: titanic.biz/bar -> new.com/bar 186 fixed: titanic.biz/foo -> new.com/foo 187`, 188 wantRewrite: map[string]string{ 189 "$GOPATH/src/fruit.io/banana/banana.go": `package banana 190 191import ( 192 _ "new.com/bar" 193 _ "new.com/foo" 194 _ "new.com/one" 195)`, 196 }, 197 }, 198 } { 199 *badDomains = test.badDomains 200 *replaceFlag = test.replaceFlag 201 202 stderr = new(bytes.Buffer) 203 gotRewrite := make(map[string]string) 204 writeFile = func(filename string, content []byte, mode os.FileMode) error { 205 filename = strings.Replace(filename, gopath, "$GOPATH", 1) 206 filename = filepath.ToSlash(filename) 207 gotRewrite[filename] = string(bytes.TrimSpace(content)) 208 return nil 209 } 210 211 if runtime.GOOS == "windows" { 212 test.wantStderr = strings.Replace(test.wantStderr, `testdata/src/old.com/bad/bad.go`, `testdata\src\old.com\bad\bad.go`, -1) 213 test.wantStderr = strings.Replace(test.wantStderr, `testdata/src/fruit.io/banana/banana.go`, `testdata\src\fruit.io\banana\banana.go`, -1) 214 } 215 216 // Check status code. 217 if fiximports(test.packages...) != test.wantOK { 218 t.Errorf("#%d. fiximports() = %t", i, !test.wantOK) 219 } 220 221 // Compare stderr output. 222 if got := stderr.(*bytes.Buffer).String(); got != test.wantStderr { 223 if strings.Contains(got, "vendor/golang_org/x/text/unicode/norm") { 224 t.Skip("skipping known-broken test; see golang.org/issue/17417") 225 } 226 t.Errorf("#%d. stderr: got <<%s>>, want <<%s>>", 227 i, stderr, test.wantStderr) 228 } 229 230 // Compare rewrites. 231 for k, v := range gotRewrite { 232 if test.wantRewrite[k] != v { 233 t.Errorf("#%d. rewrite[%s] = <<%s>>, want <<%s>>", 234 i, k, v, test.wantRewrite[k]) 235 } 236 delete(test.wantRewrite, k) 237 } 238 for k, v := range test.wantRewrite { 239 t.Errorf("#%d. rewrite[%s] missing, want <<%s>>", i, k, v) 240 } 241 } 242} 243 244// TestDryRun tests that the -n flag suppresses calls to writeFile. 245func TestDryRun(t *testing.T) { 246 testenv.NeedsTool(t, "go") 247 248 *dryrun = true 249 defer func() { *dryrun = false }() // restore 250 stderr = new(bytes.Buffer) 251 writeFile = func(filename string, content []byte, mode os.FileMode) error { 252 t.Fatalf("writeFile(%s) called in dryrun mode", filename) 253 return nil 254 } 255 256 if !fiximports("all") { 257 t.Fatalf("fiximports failed: %s", stderr) 258 } 259} 260