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