github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/cmd/fiximports/main_test.go (about)

     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  
    10  package main
    11  
    12  import (
    13  	"bytes"
    14  	"log"
    15  	"os"
    16  	"path/filepath"
    17  	"runtime"
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/jhump/golang-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  
    39  var gopath = filepath.Join(cwd, "testdata")
    40  
    41  func 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  
    57  func 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: `
    80  testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
    81  fruit.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  
    88  import (
    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: `
   101  testdata/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: `
   110  testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
   111  fruit.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  
   124  import (
   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: `
   137  testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
   138  fruit.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  
   146  import (
   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: `
   160  testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
   161  fruit.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  
   169  import (
   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: `
   183  testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
   184  fruit.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  
   192  import (
   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.
   247  func TestDryRun(t *testing.T) {
   248  	if os.Getenv("GO_BUILDER_NAME") == "plan9-arm" {
   249  		t.Skipf("skipping test that times out on plan9-arm; see https://go.dev/issue/50775")
   250  	}
   251  	testenv.NeedsTool(t, "go")
   252  
   253  	*dryrun = true
   254  	defer func() { *dryrun = false }() // restore
   255  	stderr = new(bytes.Buffer)
   256  	writeFile = func(filename string, content []byte, mode os.FileMode) error {
   257  		t.Fatalf("writeFile(%s) called in dryrun mode", filename)
   258  		return nil
   259  	}
   260  
   261  	if !fiximports("all") {
   262  		t.Fatalf("fiximports failed: %s", stderr)
   263  	}
   264  }