github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/imports/fix_test.go (about)

     1  // Copyright 2013 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  package imports
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"go/build"
    12  	"io/ioutil"
    13  	"log"
    14  	"path/filepath"
    15  	"reflect"
    16  	"sort"
    17  	"strings"
    18  	"sync"
    19  	"testing"
    20  
    21  	"github.com/powerman/golang-tools/go/packages/packagestest"
    22  	"github.com/powerman/golang-tools/internal/gocommand"
    23  )
    24  
    25  var testDebug = flag.Bool("debug", false, "enable debug output")
    26  
    27  var tests = []struct {
    28  	name       string
    29  	formatOnly bool
    30  	in, out    string
    31  }{
    32  	// Adding an import to an existing parenthesized import
    33  	{
    34  		name: "factored_imports_add",
    35  		in: `package foo
    36  import (
    37    "fmt"
    38  )
    39  func bar() {
    40  var b bytes.Buffer
    41  fmt.Println(b.String())
    42  }
    43  `,
    44  		out: `package foo
    45  
    46  import (
    47  	"bytes"
    48  	"fmt"
    49  )
    50  
    51  func bar() {
    52  	var b bytes.Buffer
    53  	fmt.Println(b.String())
    54  }
    55  `,
    56  	},
    57  
    58  	// Adding an import to an existing parenthesized import,
    59  	// verifying it goes into the first section.
    60  	{
    61  		name: "factored_imports_add_first_sec",
    62  		in: `package foo
    63  import (
    64    "fmt"
    65  
    66    "github.com/golang/snappy"
    67  )
    68  func bar() {
    69  var b bytes.Buffer
    70  _ = snappy.ErrCorrupt
    71  fmt.Println(b.String())
    72  }
    73  `,
    74  		out: `package foo
    75  
    76  import (
    77  	"bytes"
    78  	"fmt"
    79  
    80  	"github.com/golang/snappy"
    81  )
    82  
    83  func bar() {
    84  	var b bytes.Buffer
    85  	_ = snappy.ErrCorrupt
    86  	fmt.Println(b.String())
    87  }
    88  `,
    89  	},
    90  
    91  	// Adding an import to an existing parenthesized import,
    92  	// verifying it goes into the first section. (test 2)
    93  	{
    94  		name: "factored_imports_add_first_sec_2",
    95  		in: `package foo
    96  import (
    97    "fmt"
    98  
    99    "github.com/golang/snappy"
   100  )
   101  func bar() {
   102  _ = math.NaN
   103  _ = fmt.Sprintf
   104  _ = snappy.ErrCorrupt
   105  }
   106  `,
   107  		out: `package foo
   108  
   109  import (
   110  	"fmt"
   111  	"math"
   112  
   113  	"github.com/golang/snappy"
   114  )
   115  
   116  func bar() {
   117  	_ = math.NaN
   118  	_ = fmt.Sprintf
   119  	_ = snappy.ErrCorrupt
   120  }
   121  `,
   122  	},
   123  
   124  	// Adding a new import line, without parens
   125  	{
   126  		name: "add_import_section",
   127  		in: `package foo
   128  func bar() {
   129  var b bytes.Buffer
   130  }
   131  `,
   132  		out: `package foo
   133  
   134  import "bytes"
   135  
   136  func bar() {
   137  	var b bytes.Buffer
   138  }
   139  `,
   140  	},
   141  
   142  	// Adding two new imports, which should make a parenthesized import decl.
   143  	{
   144  		name: "add_import_paren_section",
   145  		in: `package foo
   146  func bar() {
   147  _, _ := bytes.Buffer, zip.NewReader
   148  }
   149  `,
   150  		out: `package foo
   151  
   152  import (
   153  	"archive/zip"
   154  	"bytes"
   155  )
   156  
   157  func bar() {
   158  	_, _ := bytes.Buffer, zip.NewReader
   159  }
   160  `,
   161  	},
   162  
   163  	// Make sure we don't add things twice
   164  	{
   165  		name: "no_double_add",
   166  		in: `package foo
   167  func bar() {
   168  _, _ := bytes.Buffer, bytes.NewReader
   169  }
   170  `,
   171  		out: `package foo
   172  
   173  import "bytes"
   174  
   175  func bar() {
   176  	_, _ := bytes.Buffer, bytes.NewReader
   177  }
   178  `,
   179  	},
   180  
   181  	// Make sure we don't add packages that don't have the right exports
   182  	{
   183  		name: "no_mismatched_add",
   184  		in: `package foo
   185  
   186  func bar() {
   187  	_ := bytes.NonexistentSymbol
   188  }
   189  `,
   190  		out: `package foo
   191  
   192  func bar() {
   193  	_ := bytes.NonexistentSymbol
   194  }
   195  `,
   196  	},
   197  
   198  	// Remove unused imports, 1 of a factored block
   199  	{
   200  		name: "remove_unused_1_of_2",
   201  		in: `package foo
   202  import (
   203  "bytes"
   204  "fmt"
   205  )
   206  
   207  func bar() {
   208  _, _ := bytes.Buffer, bytes.NewReader
   209  }
   210  `,
   211  		out: `package foo
   212  
   213  import (
   214  	"bytes"
   215  )
   216  
   217  func bar() {
   218  	_, _ := bytes.Buffer, bytes.NewReader
   219  }
   220  `,
   221  	},
   222  
   223  	// Remove unused imports, 2 of 2
   224  	{
   225  		name: "remove_unused_2_of_2",
   226  		in: `package foo
   227  import (
   228  "bytes"
   229  "fmt"
   230  )
   231  
   232  func bar() {
   233  }
   234  `,
   235  		out: `package foo
   236  
   237  func bar() {
   238  }
   239  `,
   240  	},
   241  
   242  	// Remove unused imports, 1 of 1
   243  	{
   244  		name: "remove_unused_1_of_1",
   245  		in: `package foo
   246  
   247  import "fmt"
   248  
   249  func bar() {
   250  }
   251  `,
   252  		out: `package foo
   253  
   254  func bar() {
   255  }
   256  `,
   257  	},
   258  
   259  	// Don't remove empty imports.
   260  	{
   261  		name: "dont_remove_empty_imports",
   262  		in: `package foo
   263  import (
   264  _ "image/png"
   265  _ "image/jpeg"
   266  )
   267  `,
   268  		out: `package foo
   269  
   270  import (
   271  	_ "image/jpeg"
   272  	_ "image/png"
   273  )
   274  `,
   275  	},
   276  
   277  	// Don't remove dot imports.
   278  	{
   279  		name: "dont_remove_dot_imports",
   280  		in: `package foo
   281  import (
   282  . "foo"
   283  . "bar"
   284  )
   285  `,
   286  		out: `package foo
   287  
   288  import (
   289  	. "bar"
   290  	. "foo"
   291  )
   292  `,
   293  	},
   294  
   295  	// Skip refs the parser can resolve.
   296  	{
   297  		name: "skip_resolved_refs",
   298  		in: `package foo
   299  
   300  func f() {
   301  	type t struct{ Println func(string) }
   302  	fmt := t{Println: func(string) {}}
   303  	fmt.Println("foo")
   304  }
   305  `,
   306  		out: `package foo
   307  
   308  func f() {
   309  	type t struct{ Println func(string) }
   310  	fmt := t{Println: func(string) {}}
   311  	fmt.Println("foo")
   312  }
   313  `,
   314  	},
   315  
   316  	// Do not add a package we already have a resolution for.
   317  	{
   318  		name: "skip_template",
   319  		in: `package foo
   320  
   321  import "html/template"
   322  
   323  func f() { t = template.New("sometemplate") }
   324  `,
   325  		out: `package foo
   326  
   327  import "html/template"
   328  
   329  func f() { t = template.New("sometemplate") }
   330  `,
   331  	},
   332  
   333  	// Don't touch cgo
   334  	{
   335  		name: "cgo",
   336  		in: `package foo
   337  
   338  /*
   339  #include <foo.h>
   340  */
   341  import "C"
   342  `,
   343  		out: `package foo
   344  
   345  /*
   346  #include <foo.h>
   347  */
   348  import "C"
   349  `,
   350  	},
   351  
   352  	// Put some things in their own section
   353  	{
   354  		name: "make_sections",
   355  		in: `package foo
   356  
   357  import (
   358  "os"
   359  )
   360  
   361  func foo () {
   362  _, _ = os.Args, fmt.Println
   363  _, _ = snappy.ErrCorrupt, p.P
   364  }
   365  `,
   366  		out: `package foo
   367  
   368  import (
   369  	"fmt"
   370  	"os"
   371  
   372  	"github.com/golang/snappy"
   373  	"rsc.io/p"
   374  )
   375  
   376  func foo() {
   377  	_, _ = os.Args, fmt.Println
   378  	_, _ = snappy.ErrCorrupt, p.P
   379  }
   380  `,
   381  	},
   382  	// Merge import blocks, even when no additions are required.
   383  	{
   384  		name: "merge_import_blocks_no_fix",
   385  		in: `package foo
   386  
   387  import (
   388  	"fmt"
   389  )
   390  import "os"
   391  
   392  import (
   393  	"rsc.io/p"
   394  )
   395  
   396  var _, _ = os.Args, fmt.Println
   397  var _, _ = snappy.ErrCorrupt, p.P
   398  `,
   399  		out: `package foo
   400  
   401  import (
   402  	"fmt"
   403  	"os"
   404  
   405  	"github.com/golang/snappy"
   406  	"rsc.io/p"
   407  )
   408  
   409  var _, _ = os.Args, fmt.Println
   410  var _, _ = snappy.ErrCorrupt, p.P
   411  `,
   412  	},
   413  	// Delete existing empty import block
   414  	{
   415  		name: "delete_empty_import_block",
   416  		in: `package foo
   417  
   418  import ()
   419  `,
   420  		out: `package foo
   421  `,
   422  	},
   423  
   424  	// Use existing empty import block
   425  	{
   426  		name: "use_empty_import_block",
   427  		in: `package foo
   428  
   429  import ()
   430  
   431  func f() {
   432  	_ = fmt.Println
   433  }
   434  `,
   435  		out: `package foo
   436  
   437  import "fmt"
   438  
   439  func f() {
   440  	_ = fmt.Println
   441  }
   442  `,
   443  	},
   444  
   445  	// Blank line before adding new section.
   446  	{
   447  		name: "blank_line_before_new_group",
   448  		in: `package foo
   449  
   450  import (
   451  	"fmt"
   452  	"net"
   453  )
   454  
   455  func f() {
   456  	_ = net.Dial
   457  	_ = fmt.Printf
   458  	_ = snappy.ErrCorrupt
   459  }
   460  `,
   461  		out: `package foo
   462  
   463  import (
   464  	"fmt"
   465  	"net"
   466  
   467  	"github.com/golang/snappy"
   468  )
   469  
   470  func f() {
   471  	_ = net.Dial
   472  	_ = fmt.Printf
   473  	_ = snappy.ErrCorrupt
   474  }
   475  `,
   476  	},
   477  
   478  	// Blank line between standard library and third-party stuff.
   479  	{
   480  		name: "blank_line_separating_std_and_third_party",
   481  		in: `package foo
   482  
   483  import (
   484  	"github.com/golang/snappy"
   485  	"fmt"
   486  	"net"
   487  )
   488  
   489  func f() {
   490  	_ = net.Dial
   491  	_ = fmt.Printf
   492  	_ = snappy.Foo
   493  }
   494  `,
   495  		out: `package foo
   496  
   497  import (
   498  	"fmt"
   499  	"net"
   500  
   501  	"github.com/golang/snappy"
   502  )
   503  
   504  func f() {
   505  	_ = net.Dial
   506  	_ = fmt.Printf
   507  	_ = snappy.Foo
   508  }
   509  `,
   510  	},
   511  
   512  	// golang.org/issue/6884
   513  	{
   514  		name: "new_imports_before_comment",
   515  		in: `package main
   516  
   517  // A comment
   518  func main() {
   519  	fmt.Println("Hello, world")
   520  }
   521  `,
   522  		out: `package main
   523  
   524  import "fmt"
   525  
   526  // A comment
   527  func main() {
   528  	fmt.Println("Hello, world")
   529  }
   530  `,
   531  	},
   532  
   533  	// golang.org/issue/7132
   534  	{
   535  		name: "new_section_for_dotless_import",
   536  		in: `package main
   537  
   538  import (
   539  "fmt"
   540  
   541  "gu"
   542  "manypackages.com/packagea"
   543  )
   544  
   545  var (
   546  a = packagea.A
   547  b = gu.A
   548  c = fmt.Printf
   549  )
   550  `,
   551  		out: `package main
   552  
   553  import (
   554  	"fmt"
   555  
   556  	"gu"
   557  
   558  	"manypackages.com/packagea"
   559  )
   560  
   561  var (
   562  	a = packagea.A
   563  	b = gu.A
   564  	c = fmt.Printf
   565  )
   566  `,
   567  	},
   568  
   569  	{
   570  		name: "fragment_with_main",
   571  		in:   `func main(){fmt.Println("Hello, world")}`,
   572  		out: `package main
   573  
   574  import "fmt"
   575  
   576  func main() { fmt.Println("Hello, world") }
   577  `,
   578  	},
   579  
   580  	{
   581  		name: "fragment_without_main",
   582  		in:   `func notmain(){fmt.Println("Hello, world")}`,
   583  		out: `import "fmt"
   584  
   585  func notmain() { fmt.Println("Hello, world") }`,
   586  	},
   587  
   588  	// Remove first import within in a 2nd/3rd/4th/etc. section.
   589  	// golang.org/issue/7679
   590  	{
   591  		name: "remove_first_import_in_section",
   592  		in: `package main
   593  
   594  import (
   595  	"fmt"
   596  
   597  	"manypackages.com/packagea"
   598  	"manypackages.com/packageb"
   599  )
   600  
   601  func main() {
   602  	var _ = fmt.Println
   603  	//var _ = packagea.A
   604  	var _ = packageb.B
   605  }
   606  `,
   607  		out: `package main
   608  
   609  import (
   610  	"fmt"
   611  
   612  	"manypackages.com/packageb"
   613  )
   614  
   615  func main() {
   616  	var _ = fmt.Println
   617  	//var _ = packagea.A
   618  	var _ = packageb.B
   619  }
   620  `,
   621  	},
   622  
   623  	// Blank line can be added before all types of import declarations.
   624  	// golang.org/issue/7866
   625  	{
   626  		name: "new_section_for_all_kinds_of_imports",
   627  		in: `package main
   628  
   629  import (
   630  	"fmt"
   631  	renamed_packagea "manypackages.com/packagea"
   632  
   633  	. "manypackages.com/packageb"
   634  	"io"
   635  
   636  	_ "manypackages.com/packagec"
   637  	"strings"
   638  )
   639  
   640  var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
   641  `,
   642  		out: `package main
   643  
   644  import (
   645  	"fmt"
   646  
   647  	renamed_packagea "manypackages.com/packagea"
   648  
   649  	"io"
   650  
   651  	. "manypackages.com/packageb"
   652  
   653  	"strings"
   654  
   655  	_ "manypackages.com/packagec"
   656  )
   657  
   658  var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
   659  `,
   660  	},
   661  
   662  	// Blank line can be added even when first import of group has comment with quote
   663  	{
   664  		name: "new_section_where_trailing_comment_has_quote",
   665  		in: `package main
   666  
   667  import (
   668  	"context"
   669  	bar "local.com/bar"
   670  	baz "local.com/baz"
   671  	buzz "local.com/buzz"
   672  	"github.com/golang/snappy" // this is a "typical" import
   673  )
   674  
   675  var _, _, _, _, _ = context.Background, bar.B, baz.B, buzz.B, snappy.ErrCorrupt
   676  `,
   677  		out: `package main
   678  
   679  import (
   680  	"context"
   681  
   682  	"github.com/golang/snappy" // this is a "typical" import
   683  
   684  	bar "local.com/bar"
   685  	baz "local.com/baz"
   686  	buzz "local.com/buzz"
   687  )
   688  
   689  var _, _, _, _, _ = context.Background, bar.B, baz.B, buzz.B, snappy.ErrCorrupt
   690  `,
   691  	},
   692  
   693  	// Non-idempotent comment formatting
   694  	// golang.org/issue/8035
   695  	{
   696  		name: "comments_formatted",
   697  		in: `package main
   698  
   699  import (
   700  	"fmt"                     // A
   701  	"go/ast"                  // B
   702  	_ "manypackages.com/packagec"    // C
   703  )
   704  
   705  func main() { _, _ = fmt.Print, ast.Walk }
   706  `,
   707  		out: `package main
   708  
   709  import (
   710  	"fmt"    // A
   711  	"go/ast" // B
   712  
   713  	_ "manypackages.com/packagec" // C
   714  )
   715  
   716  func main() { _, _ = fmt.Print, ast.Walk }
   717  `,
   718  	},
   719  
   720  	// Failure to delete all duplicate imports
   721  	// golang.org/issue/8459
   722  	{
   723  		name: "remove_duplicates",
   724  		in: `package main
   725  
   726  import (
   727  	"fmt"
   728  	"log"
   729  	"log"
   730  	"math"
   731  )
   732  
   733  func main() { fmt.Println("pi:", math.Pi) }
   734  `,
   735  		out: `package main
   736  
   737  import (
   738  	"fmt"
   739  	"math"
   740  )
   741  
   742  func main() { fmt.Println("pi:", math.Pi) }
   743  `,
   744  	},
   745  
   746  	// Too aggressive prefix matching
   747  	// golang.org/issue/9961
   748  	{
   749  		name: "no_extra_groups",
   750  		in: `package p
   751  
   752  import (
   753  	"zip"
   754  
   755  	"rsc.io/p"
   756  )
   757  
   758  var (
   759  	_ = fmt.Print
   760  	_ = zip.Store
   761  	_ p.P
   762  	_ = regexp.Compile
   763  )
   764  `,
   765  		out: `package p
   766  
   767  import (
   768  	"fmt"
   769  	"regexp"
   770  	"zip"
   771  
   772  	"rsc.io/p"
   773  )
   774  
   775  var (
   776  	_ = fmt.Print
   777  	_ = zip.Store
   778  	_ p.P
   779  	_ = regexp.Compile
   780  )
   781  `,
   782  	},
   783  
   784  	// Unused named import is mistaken for unnamed import
   785  	// golang.org/issue/8149
   786  	{
   787  		name: "named_import_doesnt_provide_package_name",
   788  		in: `package main
   789  
   790  import foo "fmt"
   791  
   792  func main() { fmt.Println() }
   793  `,
   794  		out: `package main
   795  
   796  import "fmt"
   797  
   798  func main() { fmt.Println() }
   799  `,
   800  	},
   801  
   802  	// Unused named import is mistaken for unnamed import
   803  	// golang.org/issue/8149
   804  	{
   805  		name: "unused_named_import_removed",
   806  		in: `package main
   807  
   808  import (
   809  	"fmt"
   810  	x "fmt"
   811  )
   812  
   813  func main() { fmt.Println() }
   814  `,
   815  		out: `package main
   816  
   817  import (
   818  	"fmt"
   819  )
   820  
   821  func main() { fmt.Println() }
   822  `,
   823  	},
   824  
   825  	{
   826  		name: "ignore_unexported_identifier",
   827  		in: `package main
   828  var _ = fmt.unexported`,
   829  		out: `package main
   830  
   831  var _ = fmt.unexported
   832  `,
   833  	},
   834  
   835  	// FormatOnly
   836  	{
   837  		name:       "formatonly_works",
   838  		formatOnly: true,
   839  		in: `package main
   840  
   841  import (
   842  "fmt"
   843  "manypackages.com/packagea"
   844  )
   845  
   846  func main() {}
   847  `,
   848  		out: `package main
   849  
   850  import (
   851  	"fmt"
   852  
   853  	"manypackages.com/packagea"
   854  )
   855  
   856  func main() {}
   857  `,
   858  	},
   859  
   860  	{
   861  		name: "preserve_import_group",
   862  		in: `package p
   863  
   864  import (
   865  	"bytes"
   866  	"fmt"
   867  )
   868  
   869  var _ = fmt.Sprintf
   870  `,
   871  		out: `package p
   872  
   873  import (
   874  	"fmt"
   875  )
   876  
   877  var _ = fmt.Sprintf
   878  `,
   879  	},
   880  	{
   881  		name: "import_grouping_not_path_dependent_no_groups",
   882  		in: `package main
   883  
   884  import (
   885  	"time"
   886  )
   887  
   888  func main() {
   889  	_ = snappy.ErrCorrupt
   890  	_ = p.P
   891  	_ = time.Parse
   892  }
   893  `,
   894  		out: `package main
   895  
   896  import (
   897  	"time"
   898  
   899  	"github.com/golang/snappy"
   900  	"rsc.io/p"
   901  )
   902  
   903  func main() {
   904  	_ = snappy.ErrCorrupt
   905  	_ = p.P
   906  	_ = time.Parse
   907  }
   908  `,
   909  	},
   910  
   911  	{
   912  		name: "import_grouping_not_path_dependent_existing_group",
   913  		in: `package main
   914  
   915  import (
   916  	"time"
   917  
   918  	"github.com/golang/snappy"
   919  )
   920  
   921  func main() {
   922  	_ = snappy.ErrCorrupt
   923  	_ = p.P
   924  	_ = time.Parse
   925  }
   926  `,
   927  		out: `package main
   928  
   929  import (
   930  	"time"
   931  
   932  	"github.com/golang/snappy"
   933  	"rsc.io/p"
   934  )
   935  
   936  func main() {
   937  	_ = snappy.ErrCorrupt
   938  	_ = p.P
   939  	_ = time.Parse
   940  }
   941  `,
   942  	},
   943  
   944  	// golang.org/issue/12097
   945  	{
   946  		name: "package_statement_insertion_preserves_comments",
   947  		in: `// a
   948  // b
   949  // c
   950  
   951  func main() {
   952      _ = fmt.Println
   953  }`,
   954  		out: `package main
   955  
   956  import "fmt"
   957  
   958  // a
   959  // b
   960  // c
   961  
   962  func main() {
   963  	_ = fmt.Println
   964  }
   965  `,
   966  	},
   967  
   968  	{
   969  		name: "import_comment_stays_on_import",
   970  		in: `package main
   971  
   972  import (
   973  	"math" // fun
   974  )
   975  
   976  func main() {
   977  	x := math.MaxInt64
   978  	fmt.Println(strings.Join(",", []string{"hi"}), x)
   979  }`,
   980  		out: `package main
   981  
   982  import (
   983  	"fmt"
   984  	"math" // fun
   985  	"strings"
   986  )
   987  
   988  func main() {
   989  	x := math.MaxInt64
   990  	fmt.Println(strings.Join(",", []string{"hi"}), x)
   991  }
   992  `,
   993  	},
   994  
   995  	{
   996  		name: "no_blank_after_comment",
   997  		in: `package main
   998  
   999  import (
  1000  	_ "io"
  1001  	_ "net/http"
  1002  	_ "net/http/pprof" // install the pprof http handlers
  1003  	_ "strings"
  1004  )
  1005  
  1006  func main() {
  1007  }
  1008  `,
  1009  		out: `package main
  1010  
  1011  import (
  1012  	_ "io"
  1013  	_ "net/http"
  1014  	_ "net/http/pprof" // install the pprof http handlers
  1015  	_ "strings"
  1016  )
  1017  
  1018  func main() {
  1019  }
  1020  `,
  1021  	},
  1022  
  1023  	{
  1024  		name: "no_blank_after_comment_reordered",
  1025  		in: `package main
  1026  
  1027  import (
  1028  	_ "io"
  1029  	_ "net/http/pprof" // install the pprof http handlers
  1030  	_ "net/http"
  1031  	_ "strings"
  1032  )
  1033  
  1034  func main() {
  1035  }
  1036  `,
  1037  		out: `package main
  1038  
  1039  import (
  1040  	_ "io"
  1041  	_ "net/http"
  1042  	_ "net/http/pprof" // install the pprof http handlers
  1043  	_ "strings"
  1044  )
  1045  
  1046  func main() {
  1047  }
  1048  `,
  1049  	},
  1050  
  1051  	{
  1052  		name: "no_blank_after_comment_unnamed",
  1053  		in: `package main
  1054  
  1055  import (
  1056  	"encoding/json"
  1057  	"io"
  1058  	"net/http"
  1059  	_ "net/http/pprof" // install the pprof http handlers
  1060  	"strings"
  1061  
  1062  	"manypackages.com/packagea"
  1063  )
  1064  
  1065  func main() {
  1066  	_ = strings.ToUpper("hello")
  1067  	_ = io.EOF
  1068  	var (
  1069  		_ json.Number
  1070  		_ *http.Request
  1071  		_ packagea.A
  1072  	)
  1073  }
  1074  `,
  1075  		out: `package main
  1076  
  1077  import (
  1078  	"encoding/json"
  1079  	"io"
  1080  	"net/http"
  1081  	_ "net/http/pprof" // install the pprof http handlers
  1082  	"strings"
  1083  
  1084  	"manypackages.com/packagea"
  1085  )
  1086  
  1087  func main() {
  1088  	_ = strings.ToUpper("hello")
  1089  	_ = io.EOF
  1090  	var (
  1091  		_ json.Number
  1092  		_ *http.Request
  1093  		_ packagea.A
  1094  	)
  1095  }
  1096  `,
  1097  	},
  1098  
  1099  	{
  1100  		name: "blank_after_package_statement_with_comment",
  1101  		in: `package p // comment
  1102  
  1103  import "math"
  1104  
  1105  var _ = fmt.Printf
  1106  `,
  1107  		out: `package p // comment
  1108  
  1109  import "fmt"
  1110  
  1111  var _ = fmt.Printf
  1112  `,
  1113  	},
  1114  
  1115  	{
  1116  		name: "blank_after_package_statement_no_comment",
  1117  		in: `package p
  1118  
  1119  import "math"
  1120  
  1121  var _ = fmt.Printf
  1122  `,
  1123  		out: `package p
  1124  
  1125  import "fmt"
  1126  
  1127  var _ = fmt.Printf
  1128  `,
  1129  	},
  1130  
  1131  	{
  1132  		name: "cryptorand_preferred_easy_possible",
  1133  		in: `package p
  1134  
  1135  var _ = rand.Read
  1136  `,
  1137  		out: `package p
  1138  
  1139  import "crypto/rand"
  1140  
  1141  var _ = rand.Read
  1142  `,
  1143  	},
  1144  
  1145  	{
  1146  		name: "cryptorand_preferred_easy_impossible",
  1147  		in: `package p
  1148  
  1149  var _ = rand.NewZipf
  1150  `,
  1151  		out: `package p
  1152  
  1153  import "math/rand"
  1154  
  1155  var _ = rand.NewZipf
  1156  `,
  1157  	},
  1158  
  1159  	{
  1160  		name: "cryptorand_preferred_complex_possible",
  1161  		in: `package p
  1162  
  1163  var _, _ = rand.Read, rand.Prime
  1164  `,
  1165  		out: `package p
  1166  
  1167  import "crypto/rand"
  1168  
  1169  var _, _ = rand.Read, rand.Prime
  1170  `,
  1171  	},
  1172  
  1173  	{
  1174  		name: "cryptorand_preferred_complex_impossible",
  1175  		in: `package p
  1176  
  1177  var _, _ = rand.Read, rand.NewZipf
  1178  `,
  1179  		out: `package p
  1180  
  1181  import "math/rand"
  1182  
  1183  var _, _ = rand.Read, rand.NewZipf
  1184  `,
  1185  	},
  1186  }
  1187  
  1188  func TestSimpleCases(t *testing.T) {
  1189  	const localPrefix = "local.com,github.com/local"
  1190  	for _, tt := range tests {
  1191  		t.Run(tt.name, func(t *testing.T) {
  1192  			testConfig{
  1193  				modules: []packagestest.Module{
  1194  					{
  1195  						Name:  "golang.org/fake",
  1196  						Files: fm{"x.go": tt.in},
  1197  					},
  1198  					// Skeleton non-stdlib packages for use during testing.
  1199  					// Each includes one arbitrary symbol, e.g. the first declaration in the first file.
  1200  					// Try not to add more without a good reason.
  1201  					// DO NOT USE PACKAGES NOT LISTED HERE -- they will be downloaded!
  1202  					{
  1203  						Name:  "rsc.io",
  1204  						Files: fm{"p/x.go": "package p\nfunc P(){}\n"},
  1205  					},
  1206  					{
  1207  						Name:  "github.com/golang/snappy",
  1208  						Files: fm{"x.go": "package snappy\nvar ErrCorrupt error\n"},
  1209  					},
  1210  					{
  1211  						Name: "manypackages.com",
  1212  						Files: fm{
  1213  							"packagea/x.go": "package packagea\nfunc A(){}\n",
  1214  							"packageb/x.go": "package packageb\nfunc B(){}\n",
  1215  							"packagec/x.go": "package packagec\nfunc C(){}\n",
  1216  							"packaged/x.go": "package packaged\nfunc D(){}\n",
  1217  						},
  1218  					},
  1219  					{
  1220  						Name:  "local.com",
  1221  						Files: fm{"foo/x.go": "package foo\nfunc Foo(){}\n"},
  1222  					},
  1223  					{
  1224  						Name:  "github.com/local",
  1225  						Files: fm{"bar/x.go": "package bar\nfunc Bar(){}\n"},
  1226  					},
  1227  				},
  1228  			}.test(t, func(t *goimportTest) {
  1229  				options := &Options{
  1230  					LocalPrefix: localPrefix,
  1231  					TabWidth:    8,
  1232  					TabIndent:   true,
  1233  					Comments:    true,
  1234  					Fragment:    true,
  1235  					FormatOnly:  tt.formatOnly,
  1236  				}
  1237  				t.assertProcessEquals("golang.org/fake", "x.go", nil, options, tt.out)
  1238  			})
  1239  
  1240  		})
  1241  	}
  1242  }
  1243  
  1244  func TestAppengine(t *testing.T) {
  1245  	const input = `package p
  1246  
  1247  var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
  1248  `
  1249  
  1250  	const want = `package p
  1251  
  1252  import (
  1253  	"fmt"
  1254  
  1255  	"appengine"
  1256  	"appengine/datastore"
  1257  )
  1258  
  1259  var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
  1260  `
  1261  
  1262  	testConfig{
  1263  		gopathOnly: true, // can't create a module named appengine, so no module tests.
  1264  		modules: []packagestest.Module{
  1265  			{
  1266  				Name:  "golang.org/fake",
  1267  				Files: fm{"x.go": input},
  1268  			},
  1269  			{
  1270  				Name: "appengine",
  1271  				Files: fm{
  1272  					"x.go":           "package appengine\nfunc Main(){}\n",
  1273  					"datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
  1274  				},
  1275  			},
  1276  		},
  1277  	}.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
  1278  }
  1279  
  1280  func TestReadFromFilesystem(t *testing.T) {
  1281  	tests := []struct {
  1282  		name    string
  1283  		in, out string
  1284  	}{
  1285  		{
  1286  			name: "works",
  1287  			in: `package foo
  1288  func bar() {
  1289  fmt.Println("hi")
  1290  }
  1291  `,
  1292  			out: `package foo
  1293  
  1294  import "fmt"
  1295  
  1296  func bar() {
  1297  	fmt.Println("hi")
  1298  }
  1299  `,
  1300  		},
  1301  		{
  1302  			name: "missing_package",
  1303  			in: `
  1304  func bar() {
  1305  fmt.Println("hi")
  1306  }
  1307  `,
  1308  			out: `
  1309  import "fmt"
  1310  
  1311  func bar() {
  1312  	fmt.Println("hi")
  1313  }
  1314  `,
  1315  		},
  1316  	}
  1317  
  1318  	for _, tt := range tests {
  1319  		t.Run(tt.name, func(t *testing.T) {
  1320  			options := &Options{
  1321  				TabWidth:  8,
  1322  				TabIndent: true,
  1323  				Comments:  true,
  1324  				Fragment:  true,
  1325  			}
  1326  			testConfig{
  1327  				module: packagestest.Module{
  1328  					Name:  "golang.org/fake",
  1329  					Files: fm{"x.go": tt.in},
  1330  				},
  1331  			}.processTest(t, "golang.org/fake", "x.go", nil, options, tt.out)
  1332  		})
  1333  	}
  1334  
  1335  }
  1336  
  1337  // Test support for packages in GOPATH that are actually symlinks.
  1338  // Also test that a symlink loop does not block the process.
  1339  func TestImportSymlinks(t *testing.T) {
  1340  	const input = `package p
  1341  
  1342  var (
  1343  	_ = fmt.Print
  1344  	_ = mypkg.Foo
  1345  )
  1346  `
  1347  	const want = `package p
  1348  
  1349  import (
  1350  	"fmt"
  1351  
  1352  	"golang.org/fake/x/y/mypkg"
  1353  )
  1354  
  1355  var (
  1356  	_ = fmt.Print
  1357  	_ = mypkg.Foo
  1358  )
  1359  `
  1360  
  1361  	testConfig{
  1362  		module: packagestest.Module{
  1363  			Name: "golang.org/fake",
  1364  			Files: fm{
  1365  				"target/f.go":                "package mypkg\nvar Foo = 123\n",
  1366  				"x/y/mypkg":                  packagestest.Symlink("../../target"), // valid symlink
  1367  				"x/y/apkg":                   packagestest.Symlink(".."),           // symlink loop
  1368  				"myotherpackage/toformat.go": input,
  1369  			},
  1370  		},
  1371  	}.processTest(t, "golang.org/fake", "myotherpackage/toformat.go", nil, nil, want)
  1372  }
  1373  
  1374  func TestImportSymlinksWithIgnore(t *testing.T) {
  1375  	const input = `package p
  1376  
  1377  var (
  1378  	_ = fmt.Print
  1379  	_ = mypkg.Foo
  1380  )
  1381  `
  1382  	const want = `package p
  1383  
  1384  import "fmt"
  1385  
  1386  var (
  1387  	_ = fmt.Print
  1388  	_ = mypkg.Foo
  1389  )
  1390  `
  1391  
  1392  	testConfig{
  1393  		gopathOnly: true,
  1394  		module: packagestest.Module{
  1395  			Name: "golang.org/fake",
  1396  			Files: fm{
  1397  				"target/f.go":            "package mypkg\nvar Foo = 123\n",
  1398  				"x/y/mypkg":              packagestest.Symlink("../../target"), // valid symlink
  1399  				"x/y/apkg":               packagestest.Symlink(".."),           // symlink loop
  1400  				"myotherpkg/toformat.go": input,
  1401  				"../../.goimportsignore": "golang.org/fake/x/y/mypkg\n",
  1402  			},
  1403  		},
  1404  	}.processTest(t, "golang.org/fake", "myotherpkg/toformat.go", nil, nil, want)
  1405  }
  1406  
  1407  // Test for x/y/v2 convention for package y.
  1408  func TestModuleVersion(t *testing.T) {
  1409  	const input = `package p
  1410  
  1411  import (
  1412  	"fmt"
  1413  
  1414  	"github.com/foo/v2"
  1415  )
  1416  
  1417  var (
  1418  	_ = fmt.Print
  1419  	_ = foo.Foo
  1420  )
  1421  `
  1422  
  1423  	testConfig{
  1424  		modules: []packagestest.Module{
  1425  			{
  1426  				Name:  "mypkg.com/outpkg",
  1427  				Files: fm{"toformat.go": input},
  1428  			},
  1429  			{
  1430  				Name:  "github.com/foo/v2",
  1431  				Files: fm{"x.go": "package foo\n func Foo(){}\n"},
  1432  			},
  1433  		},
  1434  	}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, input)
  1435  }
  1436  
  1437  // Test for correctly identifying the name of a vendored package when it
  1438  // differs from its directory name. In this test, the import line
  1439  // "mypkg.com/mypkg_v1" would be removed if goimports wasn't able to detect
  1440  // that the package name is "mypkg".
  1441  func TestVendorPackage(t *testing.T) {
  1442  	const input = `package p
  1443  import (
  1444  	"fmt"
  1445  	"mypkg.com/mypkg_v1"
  1446  )
  1447  var _, _ = fmt.Print, mypkg.Foo
  1448  `
  1449  
  1450  	const want = `package p
  1451  
  1452  import (
  1453  	"fmt"
  1454  
  1455  	mypkg "mypkg.com/mypkg_v1"
  1456  )
  1457  
  1458  var _, _ = fmt.Print, mypkg.Foo
  1459  `
  1460  
  1461  	testConfig{
  1462  		gopathOnly: true,
  1463  		module: packagestest.Module{
  1464  			Name: "mypkg.com/outpkg",
  1465  			Files: fm{
  1466  				"vendor/mypkg.com/mypkg_v1/f.go": "package mypkg\nvar Foo = 123\n",
  1467  				"toformat.go":                    input,
  1468  			},
  1469  		},
  1470  	}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, want)
  1471  }
  1472  
  1473  func TestInternal(t *testing.T) {
  1474  	const input = `package bar
  1475  
  1476  var _ = race.Acquire
  1477  `
  1478  	const importAdded = `package bar
  1479  
  1480  import "foo.com/internal/race"
  1481  
  1482  var _ = race.Acquire
  1483  `
  1484  
  1485  	// Packages under the same directory should be able to use internal packages.
  1486  	testConfig{
  1487  		module: packagestest.Module{
  1488  			Name: "foo.com",
  1489  			Files: fm{
  1490  				"internal/race/x.go": "package race\n func Acquire(){}\n",
  1491  				"bar/x.go":           input,
  1492  			},
  1493  		},
  1494  	}.processTest(t, "foo.com", "bar/x.go", nil, nil, importAdded)
  1495  
  1496  	// Packages outside the same directory should not.
  1497  	testConfig{
  1498  		modules: []packagestest.Module{
  1499  			{
  1500  				Name:  "foo.com",
  1501  				Files: fm{"internal/race/x.go": "package race\n func Acquire(){}\n"},
  1502  			},
  1503  			{
  1504  				Name:  "bar.com",
  1505  				Files: fm{"x.go": input},
  1506  			},
  1507  		},
  1508  	}.processTest(t, "bar.com", "x.go", nil, nil, input)
  1509  }
  1510  
  1511  func TestProcessVendor(t *testing.T) {
  1512  	const input = `package p
  1513  
  1514  var _ = hpack.HuffmanDecode
  1515  `
  1516  	const want = `package p
  1517  
  1518  import "golang.org/x/net/http2/hpack"
  1519  
  1520  var _ = hpack.HuffmanDecode
  1521  `
  1522  	testConfig{
  1523  		gopathOnly: true,
  1524  		module: packagestest.Module{
  1525  			Name: "foo.com",
  1526  			Files: fm{
  1527  				"vendor/golang.org/x/net/http2/hpack/huffman.go": "package hpack\nfunc HuffmanDecode() { }\n",
  1528  				"bar/x.go": input,
  1529  			},
  1530  		},
  1531  	}.processTest(t, "foo.com", "bar/x.go", nil, nil, want)
  1532  }
  1533  
  1534  func TestFindStdlib(t *testing.T) {
  1535  	tests := []struct {
  1536  		pkg     string
  1537  		symbols []string
  1538  		want    string
  1539  	}{
  1540  		{"http", []string{"Get"}, "net/http"},
  1541  		{"http", []string{"Get", "Post"}, "net/http"},
  1542  		{"http", []string{"Get", "Foo"}, ""},
  1543  		{"bytes", []string{"Buffer"}, "bytes"},
  1544  		{"ioutil", []string{"Discard"}, "io/ioutil"},
  1545  	}
  1546  	for _, tt := range tests {
  1547  		input := "package p\n"
  1548  		for _, sym := range tt.symbols {
  1549  			input += fmt.Sprintf("var _ = %s.%s\n", tt.pkg, sym)
  1550  		}
  1551  		testConfig{
  1552  			module: packagestest.Module{
  1553  				Name:  "foo.com",
  1554  				Files: fm{"x.go": input},
  1555  			},
  1556  		}.test(t, func(t *goimportTest) {
  1557  			buf, err := t.process("foo.com", "x.go", nil, nil)
  1558  			if err != nil {
  1559  				t.Fatal(err)
  1560  			}
  1561  			if got := string(buf); !strings.Contains(got, tt.want) {
  1562  				t.Errorf("Process(%q) = %q, wanted it to contain %q", input, buf, tt.want)
  1563  			}
  1564  		})
  1565  	}
  1566  }
  1567  
  1568  // https://golang.org/issue/31814
  1569  func TestStdlibNotPrefixed(t *testing.T) {
  1570  	const input = `package p
  1571  var _ = bytes.Buffer
  1572  `
  1573  	const want = `package p
  1574  
  1575  import "bytes"
  1576  
  1577  var _ = bytes.Buffer
  1578  `
  1579  	// Force a scan of the stdlib.
  1580  	savedStdlib := stdlib
  1581  	defer func() { stdlib = savedStdlib }()
  1582  	stdlib = map[string][]string{}
  1583  
  1584  	testConfig{
  1585  		module: packagestest.Module{
  1586  			Name:  "ignored.com",
  1587  			Files: fm{"x.go": "package x"},
  1588  		},
  1589  	}.test(t, func(t *goimportTest) {
  1590  		// Run in GOROOT/src so that the std module shows up in go list -m all.
  1591  		t.env.WorkingDir = filepath.Join(t.goroot, "src")
  1592  		got, err := t.processNonModule(filepath.Join(t.goroot, "src/x.go"), []byte(input), nil)
  1593  		if err != nil {
  1594  			t.Fatalf("Process() = %v", err)
  1595  		}
  1596  		if string(got) != want {
  1597  			t.Errorf("Got:\n%s\nWant:\n%s", got, want)
  1598  		}
  1599  	})
  1600  }
  1601  
  1602  func TestStdlibSelfImports(t *testing.T) {
  1603  	const input = `package ecdsa
  1604  
  1605  var _ = ecdsa.GenerateKey
  1606  `
  1607  
  1608  	testConfig{
  1609  		module: packagestest.Module{
  1610  			Name:  "ignored.com",
  1611  			Files: fm{"x.go": "package x"},
  1612  		},
  1613  	}.test(t, func(t *goimportTest) {
  1614  		got, err := t.processNonModule(filepath.Join(t.goroot, "src/crypto/ecdsa/foo.go"), []byte(input), nil)
  1615  		if err != nil {
  1616  			t.Fatalf("Process() = %v", err)
  1617  		}
  1618  		if string(got) != input {
  1619  			t.Errorf("Got:\n%s\nWant:\n%s", got, input)
  1620  		}
  1621  	})
  1622  }
  1623  
  1624  type testConfig struct {
  1625  	gopathOnly bool
  1626  	module     packagestest.Module
  1627  	modules    []packagestest.Module
  1628  }
  1629  
  1630  // fm is the type for a packagestest.Module's Files, abbreviated for shorter lines.
  1631  type fm map[string]interface{}
  1632  
  1633  func (c testConfig) test(t *testing.T, fn func(*goimportTest)) {
  1634  	t.Helper()
  1635  
  1636  	if c.module.Name != "" {
  1637  		c.modules = []packagestest.Module{c.module}
  1638  	}
  1639  
  1640  	for _, exporter := range packagestest.All {
  1641  		t.Run(exporter.Name(), func(t *testing.T) {
  1642  			t.Helper()
  1643  			if c.gopathOnly && exporter.Name() == "Modules" {
  1644  				t.Skip("test marked GOPATH-only")
  1645  			}
  1646  			exported := packagestest.Export(t, exporter, c.modules)
  1647  			defer exported.Cleanup()
  1648  
  1649  			env := map[string]string{}
  1650  			for _, kv := range exported.Config.Env {
  1651  				split := strings.SplitN(kv, "=", 2)
  1652  				env[split[0]] = split[1]
  1653  			}
  1654  			it := &goimportTest{
  1655  				T: t,
  1656  				env: &ProcessEnv{
  1657  					Env:         env,
  1658  					WorkingDir:  exported.Config.Dir,
  1659  					GocmdRunner: &gocommand.Runner{},
  1660  				},
  1661  				exported: exported,
  1662  			}
  1663  			if *testDebug {
  1664  				it.env.Logf = log.Printf
  1665  			}
  1666  			// packagestest clears out GOROOT to work around golang/go#32849,
  1667  			// which isn't relevant here. Fill it back in so we can find the standard library.
  1668  			it.env.Env["GOROOT"] = build.Default.GOROOT
  1669  			it.goroot = build.Default.GOROOT
  1670  
  1671  			fn(it)
  1672  		})
  1673  	}
  1674  }
  1675  
  1676  func (c testConfig) processTest(t *testing.T, module, file string, contents []byte, opts *Options, want string) {
  1677  	t.Helper()
  1678  	c.test(t, func(t *goimportTest) {
  1679  		t.Helper()
  1680  		t.assertProcessEquals(module, file, contents, opts, want)
  1681  	})
  1682  }
  1683  
  1684  type goimportTest struct {
  1685  	*testing.T
  1686  	goroot   string
  1687  	env      *ProcessEnv
  1688  	exported *packagestest.Exported
  1689  }
  1690  
  1691  func (t *goimportTest) process(module, file string, contents []byte, opts *Options) ([]byte, error) {
  1692  	t.Helper()
  1693  	f := t.exported.File(module, file)
  1694  	if f == "" {
  1695  		t.Fatalf("%v not found in exported files (typo in filename?)", file)
  1696  	}
  1697  	return t.processNonModule(f, contents, opts)
  1698  }
  1699  
  1700  func (t *goimportTest) processNonModule(file string, contents []byte, opts *Options) ([]byte, error) {
  1701  	if contents == nil {
  1702  		var err error
  1703  		contents, err = ioutil.ReadFile(file)
  1704  		if err != nil {
  1705  			return nil, err
  1706  		}
  1707  	}
  1708  	if opts == nil {
  1709  		opts = &Options{Comments: true, TabIndent: true, TabWidth: 8}
  1710  	}
  1711  	// ProcessEnv is not safe for concurrent use. Make a copy.
  1712  	opts.Env = t.env.CopyConfig()
  1713  	return Process(file, contents, opts)
  1714  }
  1715  
  1716  func (t *goimportTest) assertProcessEquals(module, file string, contents []byte, opts *Options, want string) {
  1717  	buf, err := t.process(module, file, contents, opts)
  1718  	if err != nil {
  1719  		t.Fatalf("Process() = %v", err)
  1720  	}
  1721  	if string(buf) != want {
  1722  		t.Errorf("Got:\n'%s'\nWant:\n'%s'", buf, want) // 's show empty lines
  1723  	}
  1724  }
  1725  
  1726  // Tests that added imports are renamed when the import path's base doesn't
  1727  // match its package name.
  1728  func TestRenameWhenPackageNameMismatch(t *testing.T) {
  1729  	const input = `package main
  1730   const Y = bar.X`
  1731  
  1732  	const want = `package main
  1733  
  1734  import bar "foo.com/foo/bar/baz"
  1735  
  1736  const Y = bar.X
  1737  `
  1738  	testConfig{
  1739  		module: packagestest.Module{
  1740  			Name: "foo.com",
  1741  			Files: fm{
  1742  				"foo/bar/baz/x.go": "package bar \n const X = 1",
  1743  				"test/t.go":        input,
  1744  			},
  1745  		},
  1746  	}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
  1747  }
  1748  
  1749  func TestPanicAstutils(t *testing.T) {
  1750  	t.Skip("panic in ast/astutil/imports.go, should be PostionFor(,false) at lines 273, 274, at least")
  1751  	const input = `package main
  1752  //line mah.go:600
  1753  
  1754  import (
  1755  "foo.com/a.thing"
  1756  "foo.com/surprise"
  1757  "foo.com/v1"
  1758  "foo.com/other/v2"
  1759  "foo.com/other/v3"
  1760  )
  1761  `
  1762  
  1763  	const want = `package main
  1764  
  1765  //line mah.go:600
  1766  
  1767  import (
  1768  	"foo.com/a.thing"
  1769  	"foo.com/go-thing"
  1770  	gow "foo.com/go-wrong"
  1771  	v2 "foo.com/other/v2"
  1772  	"foo.com/other/v3"
  1773  	bar "foo.com/surprise"
  1774  	v1 "foo.com/v1"
  1775  )
  1776  
  1777  `
  1778  
  1779  	testConfig{
  1780  		module: packagestest.Module{
  1781  			Name: "foo.com",
  1782  			Files: fm{
  1783  				"test/t.go": input,
  1784  			},
  1785  		},
  1786  	}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
  1787  }
  1788  
  1789  // without PositionFor in sortImports this test panics
  1790  func TestPanic51916(t *testing.T) {
  1791  	const input = `package main
  1792  //line mah.go:600
  1793  
  1794  import (
  1795  "foo.com/a.thing"
  1796  "foo.com/surprise"
  1797  "foo.com/v1"
  1798  "foo.com/other/v2"
  1799  "foo.com/other/v3"
  1800  "foo.com/go-thing"
  1801  "foo.com/go-wrong"
  1802  )
  1803  
  1804  var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}`
  1805  
  1806  	const want = `package main
  1807  
  1808  //line mah.go:600
  1809  
  1810  import (
  1811  	"foo.com/a.thing"
  1812  	"foo.com/go-thing"
  1813  	gow "foo.com/go-wrong"
  1814  	v2 "foo.com/other/v2"
  1815  	"foo.com/other/v3"
  1816  	bar "foo.com/surprise"
  1817  	v1 "foo.com/v1"
  1818  )
  1819  
  1820  var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}
  1821  `
  1822  
  1823  	testConfig{
  1824  		module: packagestest.Module{
  1825  			Name: "foo.com",
  1826  			Files: fm{
  1827  				"a.thing/a.go":  "package a \n const A = 1",
  1828  				"surprise/x.go": "package bar \n const X = 1",
  1829  				"v1/x.go":       "package v1 \n const Y = 1",
  1830  				"other/v2/y.go": "package v2 \n const V2 = 1",
  1831  				"other/v3/z.go": "package other \n const V3 = 1",
  1832  				"go-thing/b.go": "package thing \n const Thing = 1",
  1833  				"go-wrong/b.go": "package gow \n const Wrong = 1",
  1834  				"test/t.go":     input,
  1835  			},
  1836  		},
  1837  	}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
  1838  }
  1839  
  1840  // Tests that an existing import with badly mismatched path/name has its name
  1841  // correctly added. See #28645 and #29041.
  1842  // and check that //line directives are ignored (#51916)
  1843  func TestAddNameToMismatchedImport(t *testing.T) {
  1844  	const input = `package main
  1845  
  1846  import (
  1847  "foo.com/a.thing"
  1848  "foo.com/surprise"
  1849  "foo.com/v1"
  1850  "foo.com/other/v2"
  1851  "foo.com/other/v3"
  1852  "foo.com/go-thing"
  1853  "foo.com/go-wrong"
  1854  )
  1855  
  1856  var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}`
  1857  
  1858  	const want = `package main
  1859  
  1860  import (
  1861  	"foo.com/a.thing"
  1862  	"foo.com/go-thing"
  1863  	gow "foo.com/go-wrong"
  1864  	v2 "foo.com/other/v2"
  1865  	"foo.com/other/v3"
  1866  	bar "foo.com/surprise"
  1867  	v1 "foo.com/v1"
  1868  )
  1869  
  1870  var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}
  1871  `
  1872  
  1873  	testConfig{
  1874  		module: packagestest.Module{
  1875  			Name: "foo.com",
  1876  			Files: fm{
  1877  				"a.thing/a.go":  "package a \n const A = 1",
  1878  				"surprise/x.go": "package bar \n const X = 1",
  1879  				"v1/x.go":       "package v1 \n const Y = 1",
  1880  				"other/v2/y.go": "package v2 \n const V2 = 1",
  1881  				"other/v3/z.go": "package other \n const V3 = 1",
  1882  				"go-thing/b.go": "package thing \n const Thing = 1",
  1883  				"go-wrong/b.go": "package gow \n const Wrong = 1",
  1884  				"test/t.go":     input,
  1885  			},
  1886  		},
  1887  	}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
  1888  }
  1889  
  1890  // Tests that the LocalPrefix option causes imports
  1891  // to be added into a later group (num=3).
  1892  func TestLocalPrefix(t *testing.T) {
  1893  	tests := []struct {
  1894  		name        string
  1895  		modules     []packagestest.Module
  1896  		localPrefix string
  1897  		src         string
  1898  		want        string
  1899  	}{
  1900  		{
  1901  			name: "one_local",
  1902  			modules: []packagestest.Module{
  1903  				{
  1904  					Name: "foo.com",
  1905  					Files: fm{
  1906  						"bar/bar.go": "package bar \n const X = 1",
  1907  					},
  1908  				},
  1909  			},
  1910  			localPrefix: "foo.com/",
  1911  			src:         "package main \n const Y = bar.X \n const _ = runtime.GOOS",
  1912  			want: `package main
  1913  
  1914  import (
  1915  	"runtime"
  1916  
  1917  	"foo.com/bar"
  1918  )
  1919  
  1920  const Y = bar.X
  1921  const _ = runtime.GOOS
  1922  `,
  1923  		},
  1924  		{
  1925  			name: "two_local",
  1926  			modules: []packagestest.Module{
  1927  				{
  1928  					Name: "foo.com",
  1929  					Files: fm{
  1930  						"foo/foo.go":     "package foo \n const X = 1",
  1931  						"foo/bar/bar.go": "package bar \n const X = 1",
  1932  					},
  1933  				},
  1934  			},
  1935  			localPrefix: "foo.com/foo",
  1936  			src:         "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS",
  1937  			want: `package main
  1938  
  1939  import (
  1940  	"runtime"
  1941  
  1942  	"foo.com/foo"
  1943  	"foo.com/foo/bar"
  1944  )
  1945  
  1946  const Y = bar.X
  1947  const Z = foo.X
  1948  const _ = runtime.GOOS
  1949  `,
  1950  		},
  1951  		{
  1952  			name: "three_prefixes",
  1953  			modules: []packagestest.Module{
  1954  				{
  1955  					Name:  "example.org/pkg",
  1956  					Files: fm{"pkg.go": "package pkg \n const A = 1"},
  1957  				},
  1958  				{
  1959  					Name:  "foo.com",
  1960  					Files: fm{"bar/bar.go": "package bar \n const B = 1"},
  1961  				},
  1962  				{
  1963  					Name:  "code.org/r/p",
  1964  					Files: fm{"expproj/expproj.go": "package expproj \n const C = 1"},
  1965  				},
  1966  			},
  1967  			localPrefix: "example.org/pkg,foo.com/,code.org",
  1968  			src:         "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS",
  1969  			want: `package main
  1970  
  1971  import (
  1972  	"runtime"
  1973  
  1974  	"code.org/r/p/expproj"
  1975  	"example.org/pkg"
  1976  	"foo.com/bar"
  1977  )
  1978  
  1979  const X = pkg.A
  1980  const Y = bar.B
  1981  const Z = expproj.C
  1982  const _ = runtime.GOOS
  1983  `,
  1984  		},
  1985  	}
  1986  
  1987  	for _, tt := range tests {
  1988  		t.Run(tt.name, func(t *testing.T) {
  1989  			testConfig{
  1990  				// The module being processed has to be first so it's the primary module.
  1991  				modules: append([]packagestest.Module{{
  1992  					Name:  "test.com",
  1993  					Files: fm{"t.go": tt.src},
  1994  				}}, tt.modules...),
  1995  			}.test(t, func(t *goimportTest) {
  1996  				options := &Options{
  1997  					LocalPrefix: tt.localPrefix,
  1998  					TabWidth:    8,
  1999  					TabIndent:   true,
  2000  					Comments:    true,
  2001  					Fragment:    true,
  2002  				}
  2003  				t.assertProcessEquals("test.com", "t.go", nil, options, tt.want)
  2004  			})
  2005  		})
  2006  	}
  2007  }
  2008  
  2009  // Tests that "package documentation" files are ignored.
  2010  func TestIgnoreDocumentationPackage(t *testing.T) {
  2011  	const input = `package x
  2012  
  2013  const Y = foo.X
  2014  `
  2015  	const want = `package x
  2016  
  2017  import "foo.com/foo"
  2018  
  2019  const Y = foo.X
  2020  `
  2021  
  2022  	testConfig{
  2023  		module: packagestest.Module{
  2024  			Name: "foo.com",
  2025  			Files: fm{
  2026  				"foo/foo.go": "package foo\nconst X = 1\n",
  2027  				"foo/doc.go": "package documentation \n // just to confuse things\n",
  2028  				"x/x.go":     input,
  2029  			},
  2030  		},
  2031  	}.processTest(t, "foo.com", "x/x.go", nil, nil, want)
  2032  }
  2033  
  2034  // Tests importPathToNameGoPathParse and in particular that it stops
  2035  // after finding the first non-documentation package name, not
  2036  // reporting an error on inconsistent package names (since it should
  2037  // never make it that far).
  2038  func TestImportPathToNameGoPathParse(t *testing.T) {
  2039  	testConfig{
  2040  		module: packagestest.Module{
  2041  			Name: "example.net/pkg",
  2042  			Files: fm{
  2043  				"doc.go": "package documentation\n", // ignored
  2044  				"gen.go": "package main\n",          // also ignored
  2045  				"pkg.go": "package the_pkg_name_to_find\n  and this syntax error is ignored because of parser.PackageClauseOnly",
  2046  				"z.go":   "package inconsistent\n", // inconsistent but ignored
  2047  			},
  2048  		},
  2049  	}.test(t, func(t *goimportTest) {
  2050  		if strings.Contains(t.Name(), "GoPackages") {
  2051  			t.Skip("go/packages does not ignore package main")
  2052  		}
  2053  		r, err := t.env.GetResolver()
  2054  		if err != nil {
  2055  			t.Fatal(err)
  2056  		}
  2057  		srcDir := filepath.Dir(t.exported.File("example.net/pkg", "z.go"))
  2058  		names, err := r.loadPackageNames([]string{"example.net/pkg"}, srcDir)
  2059  		if err != nil {
  2060  			t.Fatal(err)
  2061  		}
  2062  		const want = "the_pkg_name_to_find"
  2063  		if got := names["example.net/pkg"]; got != want {
  2064  			t.Errorf("loadPackageNames(..) = %q; want %q", got, want)
  2065  		}
  2066  	})
  2067  }
  2068  
  2069  func TestIgnoreConfiguration(t *testing.T) {
  2070  	const input = `package x
  2071  
  2072  const _ = pkg.X
  2073  `
  2074  	const want = `package x
  2075  
  2076  import "foo.com/otherwise-longer-so-worse-example/foo/pkg"
  2077  
  2078  const _ = pkg.X
  2079  `
  2080  
  2081  	testConfig{
  2082  		gopathOnly: true,
  2083  		module: packagestest.Module{
  2084  			Name: "foo.com",
  2085  			Files: fm{
  2086  				"../.goimportsignore":                              "# comment line\n\n foo.com/example", // tests comment, blank line, whitespace trimming
  2087  				"example/pkg/pkg.go":                               "package pkg\nconst X = 1",
  2088  				"otherwise-longer-so-worse-example/foo/pkg/pkg.go": "package pkg\nconst X = 1",
  2089  				"x/x.go": input,
  2090  			},
  2091  		},
  2092  	}.processTest(t, "foo.com", "x/x.go", nil, nil, want)
  2093  }
  2094  
  2095  // Skip "node_modules" directory.
  2096  func TestSkipNodeModules(t *testing.T) {
  2097  	const input = `package x
  2098  
  2099  const _ = pkg.X
  2100  `
  2101  	const want = `package x
  2102  
  2103  import "foo.com/otherwise-longer/not_modules/pkg"
  2104  
  2105  const _ = pkg.X
  2106  `
  2107  
  2108  	testConfig{
  2109  		gopathOnly: true,
  2110  		module: packagestest.Module{
  2111  			Name: "foo.com",
  2112  			Files: fm{
  2113  				"example/node_modules/pkg/a.go":         "package pkg\nconst X = 1",
  2114  				"otherwise-longer/not_modules/pkg/a.go": "package pkg\nconst X = 1",
  2115  				"x/x.go":                                input,
  2116  			},
  2117  		},
  2118  	}.processTest(t, "foo.com", "x/x.go", nil, nil, want)
  2119  }
  2120  
  2121  // Tests that package global variables with the same name and function name as
  2122  // a function in a separate package do not result in an import which masks
  2123  // the global variable
  2124  func TestGlobalImports(t *testing.T) {
  2125  	const usesGlobal = `package pkg
  2126  
  2127  func doSomething() {
  2128  	t := time.Now()
  2129  }
  2130  `
  2131  
  2132  	const declaresGlobal = `package pkg
  2133  
  2134  type Time struct{}
  2135  
  2136  func (t Time) Now() Time {
  2137  	return Time{}
  2138  }
  2139  
  2140  var time Time
  2141  `
  2142  
  2143  	testConfig{
  2144  		module: packagestest.Module{
  2145  			Name: "foo.com",
  2146  			Files: fm{
  2147  				"pkg/uses.go":   usesGlobal,
  2148  				"pkg/global.go": declaresGlobal,
  2149  			},
  2150  		},
  2151  	}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, usesGlobal)
  2152  }
  2153  
  2154  // Some people put multiple packages' files in the same directory. Globals
  2155  // declared in other packages should be ignored.
  2156  func TestGlobalImports_DifferentPackage(t *testing.T) {
  2157  	const declaresGlobal = `package main
  2158  var fmt int
  2159  `
  2160  	const input = `package pkg
  2161  var _ = fmt.Printf
  2162  `
  2163  	const want = `package pkg
  2164  
  2165  import "fmt"
  2166  
  2167  var _ = fmt.Printf
  2168  `
  2169  
  2170  	testConfig{
  2171  		module: packagestest.Module{
  2172  			Name: "foo.com",
  2173  			Files: fm{
  2174  				"pkg/main.go": declaresGlobal,
  2175  				"pkg/uses.go": input,
  2176  			},
  2177  		},
  2178  	}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
  2179  }
  2180  
  2181  func TestGlobalImports_MultipleMains(t *testing.T) {
  2182  	const declaresGlobal = `package main
  2183  var fmt int
  2184  `
  2185  	const input = `package main
  2186  import "fmt"
  2187  var _, _ = fmt.Printf, bytes.Equal
  2188  `
  2189  	const want = `package main
  2190  
  2191  import (
  2192  	"bytes"
  2193  	"fmt"
  2194  )
  2195  
  2196  var _, _ = fmt.Printf, bytes.Equal
  2197  `
  2198  
  2199  	testConfig{
  2200  		module: packagestest.Module{
  2201  			Name: "foo.com",
  2202  			Files: fm{
  2203  				"pkg/main.go": declaresGlobal,
  2204  				"pkg/uses.go": input,
  2205  			},
  2206  		},
  2207  	}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
  2208  }
  2209  
  2210  // Tests that sibling files - other files in the same package - can provide an
  2211  // import that may not be the default one otherwise.
  2212  func TestSiblingImports(t *testing.T) {
  2213  
  2214  	// provide is the sibling file that provides the desired import.
  2215  	const provide = `package siblingimporttest
  2216  
  2217  import "local/log"
  2218  import "my/bytes"
  2219  import renamed "fmt"
  2220  
  2221  func LogSomething() {
  2222  	log.Print("Something")
  2223  	bytes.SomeFunc()
  2224  	renamed.Println("Something")
  2225  }
  2226  `
  2227  
  2228  	// need is the file being tested that needs the import.
  2229  	const need = `package siblingimporttest
  2230  
  2231  var _ = bytes.Buffer{}
  2232  
  2233  func LogSomethingElse() {
  2234  	log.Print("Something else")
  2235  	renamed.Println("Yet another")
  2236  }
  2237  `
  2238  
  2239  	// want is the expected result file
  2240  	const want = `package siblingimporttest
  2241  
  2242  import (
  2243  	"bytes"
  2244  	renamed "fmt"
  2245  	"local/log"
  2246  )
  2247  
  2248  var _ = bytes.Buffer{}
  2249  
  2250  func LogSomethingElse() {
  2251  	log.Print("Something else")
  2252  	renamed.Println("Yet another")
  2253  }
  2254  `
  2255  
  2256  	testConfig{
  2257  		module: packagestest.Module{
  2258  			Name: "foo.com",
  2259  			Files: fm{
  2260  				"p/needs_import.go":    need,
  2261  				"p/provides_import.go": provide,
  2262  			},
  2263  		},
  2264  	}.processTest(t, "foo.com", "p/needs_import.go", nil, nil, want)
  2265  }
  2266  
  2267  // Tests #29180: a sibling import of the right package with the wrong name is used.
  2268  func TestSiblingImport_Misnamed(t *testing.T) {
  2269  	const sibling = `package main
  2270  import renamed "fmt"
  2271  var _ = renamed.Printf
  2272  `
  2273  	const input = `package pkg
  2274  var _ = fmt.Printf
  2275  `
  2276  	const want = `package pkg
  2277  
  2278  import "fmt"
  2279  
  2280  var _ = fmt.Printf
  2281  `
  2282  
  2283  	testConfig{
  2284  		module: packagestest.Module{
  2285  			Name: "foo.com",
  2286  			Files: fm{
  2287  				"pkg/main.go": sibling,
  2288  				"pkg/uses.go": input,
  2289  			},
  2290  		},
  2291  	}.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
  2292  
  2293  }
  2294  
  2295  // Tests that an input file's own package is ignored.
  2296  func TestIgnoreOwnPackage(t *testing.T) {
  2297  	const input = `package pkg
  2298  
  2299  const _ = pkg.X
  2300  `
  2301  	const want = `package pkg
  2302  
  2303  const _ = pkg.X
  2304  `
  2305  
  2306  	testConfig{
  2307  		module: packagestest.Module{
  2308  			Name: "foo.com",
  2309  			Files: fm{
  2310  				"pkg/a.go": "package pkg\nconst X = 1",
  2311  				"pkg/b.go": input,
  2312  			},
  2313  		},
  2314  	}.processTest(t, "foo.com", "pkg/b.go", nil, nil, want)
  2315  }
  2316  
  2317  func TestExternalTestImportsPackageUnderTest(t *testing.T) {
  2318  	const provide = `package pkg
  2319  func DoIt(){}
  2320  `
  2321  	const input = `package pkg_test
  2322  
  2323  var _ = pkg.DoIt`
  2324  
  2325  	const want = `package pkg_test
  2326  
  2327  import "foo.com/pkg"
  2328  
  2329  var _ = pkg.DoIt
  2330  `
  2331  
  2332  	testConfig{
  2333  		module: packagestest.Module{
  2334  			Name: "foo.com",
  2335  			Files: fm{
  2336  				"pkg/provide.go": provide,
  2337  				"pkg/x_test.go":  input,
  2338  			},
  2339  		},
  2340  	}.processTest(t, "foo.com", "pkg/x_test.go", nil, nil, want)
  2341  }
  2342  
  2343  func TestPkgIsCandidate(t *testing.T) {
  2344  	tests := []struct {
  2345  		name     string
  2346  		filename string
  2347  		pkgIdent string
  2348  		pkg      *pkg
  2349  		want     bool
  2350  	}{
  2351  		{
  2352  			name:     "normal_match",
  2353  			filename: "/gopath/src/my/pkg/pkg.go",
  2354  			pkgIdent: "client",
  2355  			pkg: &pkg{
  2356  				dir:             "/gopath/src/client",
  2357  				importPathShort: "client",
  2358  			},
  2359  			want: true,
  2360  		},
  2361  		{
  2362  			name:     "no_match",
  2363  			filename: "/gopath/src/my/pkg/pkg.go",
  2364  			pkgIdent: "zzz",
  2365  			pkg: &pkg{
  2366  				dir:             "/gopath/src/client",
  2367  				importPathShort: "client",
  2368  			},
  2369  			want: false,
  2370  		},
  2371  		{
  2372  			name:     "match_too_early",
  2373  			filename: "/gopath/src/my/pkg/pkg.go",
  2374  			pkgIdent: "client",
  2375  			pkg: &pkg{
  2376  				dir:             "/gopath/src/client/foo/foo/foo",
  2377  				importPathShort: "client/foo/foo",
  2378  			},
  2379  			want: false,
  2380  		},
  2381  		{
  2382  			name:     "substring_match",
  2383  			filename: "/gopath/src/my/pkg/pkg.go",
  2384  			pkgIdent: "client",
  2385  			pkg: &pkg{
  2386  				dir:             "/gopath/src/foo/go-client",
  2387  				importPathShort: "foo/go-client",
  2388  			},
  2389  			want: true,
  2390  		},
  2391  		{
  2392  			name:     "hidden_internal",
  2393  			filename: "/gopath/src/my/pkg/pkg.go",
  2394  			pkgIdent: "client",
  2395  			pkg: &pkg{
  2396  				dir:             "/gopath/src/foo/internal/client",
  2397  				importPathShort: "foo/internal/client",
  2398  			},
  2399  			want: false,
  2400  		},
  2401  		{
  2402  			name:     "visible_internal",
  2403  			filename: "/gopath/src/foo/bar.go",
  2404  			pkgIdent: "client",
  2405  			pkg: &pkg{
  2406  				dir:             "/gopath/src/foo/internal/client",
  2407  				importPathShort: "foo/internal/client",
  2408  			},
  2409  			want: true,
  2410  		},
  2411  		{
  2412  			name:     "invisible_vendor",
  2413  			filename: "/gopath/src/foo/bar.go",
  2414  			pkgIdent: "client",
  2415  			pkg: &pkg{
  2416  				dir:             "/gopath/src/other/vendor/client",
  2417  				importPathShort: "client",
  2418  			},
  2419  			want: false,
  2420  		},
  2421  		{
  2422  			name:     "visible_vendor",
  2423  			filename: "/gopath/src/foo/bar.go",
  2424  			pkgIdent: "client",
  2425  			pkg: &pkg{
  2426  				dir:             "/gopath/src/foo/vendor/client",
  2427  				importPathShort: "client",
  2428  			},
  2429  			want: true,
  2430  		},
  2431  		{
  2432  			name:     "match_with_hyphens",
  2433  			filename: "/gopath/src/foo/bar.go",
  2434  			pkgIdent: "socketio",
  2435  			pkg: &pkg{
  2436  				dir:             "/gopath/src/foo/socket-io",
  2437  				importPathShort: "foo/socket-io",
  2438  			},
  2439  			want: true,
  2440  		},
  2441  		{
  2442  			name:     "match_with_mixed_case",
  2443  			filename: "/gopath/src/foo/bar.go",
  2444  			pkgIdent: "fooprod",
  2445  			pkg: &pkg{
  2446  				dir:             "/gopath/src/foo/FooPROD",
  2447  				importPathShort: "foo/FooPROD",
  2448  			},
  2449  			want: true,
  2450  		},
  2451  		{
  2452  			name:     "matches_with_hyphen_and_caps",
  2453  			filename: "/gopath/src/foo/bar.go",
  2454  			pkgIdent: "fooprod",
  2455  			pkg: &pkg{
  2456  				dir:             "/gopath/src/foo/Foo-PROD",
  2457  				importPathShort: "foo/Foo-PROD",
  2458  			},
  2459  			want: true,
  2460  		},
  2461  	}
  2462  	for i, tt := range tests {
  2463  		t.Run(tt.name, func(t *testing.T) {
  2464  			refs := references{tt.pkgIdent: nil}
  2465  			got := pkgIsCandidate(tt.filename, refs, tt.pkg)
  2466  			if got != tt.want {
  2467  				t.Errorf("test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v",
  2468  					i, tt.filename, tt.pkgIdent, *tt.pkg, got, tt.want)
  2469  			}
  2470  		})
  2471  	}
  2472  }
  2473  
  2474  // Issue 20941: this used to panic on Windows.
  2475  func TestProcessStdin(t *testing.T) {
  2476  	testConfig{
  2477  		module: packagestest.Module{
  2478  			Name: "foo.com",
  2479  		},
  2480  	}.test(t, func(t *goimportTest) {
  2481  		got, err := t.processNonModule("<standard input>", []byte("package main\nfunc main() {\n\tfmt.Println(123)\n}\n"), nil)
  2482  		if err != nil {
  2483  			t.Fatal(err)
  2484  		}
  2485  		if !strings.Contains(string(got), `"fmt"`) {
  2486  			t.Errorf("expected fmt import; got: %s", got)
  2487  		}
  2488  	})
  2489  }
  2490  
  2491  // Tests LocalPackagePromotion when there is a local package that matches, it
  2492  // should be the closest match.
  2493  // https://golang.org/issues/17557
  2494  func TestLocalPackagePromotion(t *testing.T) {
  2495  	const input = `package main
  2496  var c = &config.SystemConfig{}
  2497  `
  2498  	const want = `package main
  2499  
  2500  import "mycompany.net/tool/config"
  2501  
  2502  var c = &config.SystemConfig{}
  2503  `
  2504  
  2505  	testConfig{
  2506  		modules: []packagestest.Module{
  2507  			{
  2508  				Name:  "config.net/config",
  2509  				Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
  2510  			},
  2511  			{
  2512  				Name:  "mycompany.net/config",
  2513  				Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
  2514  			},
  2515  			{
  2516  				Name: "mycompany.net/tool",
  2517  				Files: fm{
  2518  					"config/config.go": "package config\n type SystemConfig struct {}", // Local package should be promoted over shorter package
  2519  					"main.go":          input,
  2520  				},
  2521  			},
  2522  		},
  2523  	}.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
  2524  }
  2525  
  2526  // Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the
  2527  // local directory, since the user is likely to import the same packages in the current
  2528  // Go file.  If an import is found that satisfies the need, it should be used over the
  2529  // standard library.
  2530  // https://golang.org/issues/17557
  2531  func TestFindImportInLocalGoFiles(t *testing.T) {
  2532  	const input = `package main
  2533   var _ = &bytes.Buffer{}`
  2534  
  2535  	const want = `package main
  2536  
  2537  import "bytes.net/bytes"
  2538  
  2539  var _ = &bytes.Buffer{}
  2540  `
  2541  	testConfig{
  2542  		modules: []packagestest.Module{
  2543  			{
  2544  				Name: "mycompany.net/tool",
  2545  				Files: fm{
  2546  					"io.go":   "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored
  2547  					"main.go": input,
  2548  				},
  2549  			},
  2550  			{
  2551  				Name:  "bytes.net/bytes",
  2552  				Files: fm{"bytes.go": "package bytes\n type Buffer struct {}"}, // Should be selected over standard library
  2553  			},
  2554  		},
  2555  	}.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
  2556  }
  2557  
  2558  func TestInMemoryFile(t *testing.T) {
  2559  	const input = `package main
  2560   var _ = &bytes.Buffer{}`
  2561  
  2562  	const want = `package main
  2563  
  2564  import "bytes"
  2565  
  2566  var _ = &bytes.Buffer{}
  2567  `
  2568  	testConfig{
  2569  		module: packagestest.Module{
  2570  			Name:  "foo.com",
  2571  			Files: fm{"x.go": "package x\n"},
  2572  		},
  2573  	}.processTest(t, "foo.com", "x.go", []byte(input), nil, want)
  2574  }
  2575  
  2576  func TestImportNoGoFiles(t *testing.T) {
  2577  	const input = `package main
  2578   var _ = &bytes.Buffer{}`
  2579  
  2580  	const want = `package main
  2581  
  2582  import "bytes"
  2583  
  2584  var _ = &bytes.Buffer{}
  2585  `
  2586  	testConfig{
  2587  		module: packagestest.Module{
  2588  			Name: "mycompany.net",
  2589  		},
  2590  	}.test(t, func(t *goimportTest) {
  2591  		buf, err := t.processNonModule("mycompany.net/tool/main.go", []byte(input), nil)
  2592  		if err != nil {
  2593  			t.Fatalf("Process() = %v", err)
  2594  		}
  2595  		if string(buf) != want {
  2596  			t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
  2597  		}
  2598  	})
  2599  
  2600  }
  2601  
  2602  // Ensures a token as large as 500000 bytes can be handled
  2603  // https://golang.org/issues/18201
  2604  func TestProcessLargeToken(t *testing.T) {
  2605  	largeString := strings.Repeat("x", 500000)
  2606  
  2607  	input := `package testimports
  2608  
  2609  import (
  2610  	"bytes"
  2611  )
  2612  
  2613  const s = fmt.Sprintf("%s", "` + largeString + `")
  2614  var _ = bytes.Buffer{}
  2615  
  2616  // end
  2617  `
  2618  
  2619  	want := `package testimports
  2620  
  2621  import (
  2622  	"bytes"
  2623  	"fmt"
  2624  )
  2625  
  2626  const s = fmt.Sprintf("%s", "` + largeString + `")
  2627  
  2628  var _ = bytes.Buffer{}
  2629  
  2630  // end
  2631  `
  2632  
  2633  	testConfig{
  2634  		module: packagestest.Module{
  2635  			Name:  "foo.com",
  2636  			Files: fm{"foo.go": input},
  2637  		},
  2638  	}.processTest(t, "foo.com", "foo.go", nil, nil, want)
  2639  }
  2640  
  2641  // Tests that an external test package will import the package under test if it
  2642  // also uses symbols exported only in test files.
  2643  // https://golang.org/issues/29979
  2644  func TestExternalTest(t *testing.T) {
  2645  	const input = `package a_test
  2646  func TestX() {
  2647  	a.X()
  2648  	a.Y()
  2649  }
  2650  `
  2651  	const want = `package a_test
  2652  
  2653  import "foo.com/a"
  2654  
  2655  func TestX() {
  2656  	a.X()
  2657  	a.Y()
  2658  }
  2659  `
  2660  
  2661  	testConfig{
  2662  		modules: []packagestest.Module{
  2663  			{
  2664  				Name: "foo.com/a",
  2665  				Files: fm{
  2666  					"a.go":           "package a\n func X() {}",
  2667  					"export_test.go": "package a\n func Y() {}",
  2668  					"a_test.go":      input,
  2669  				},
  2670  			},
  2671  		},
  2672  	}.processTest(t, "foo.com/a", "a_test.go", nil, nil, want)
  2673  }
  2674  
  2675  // TestGetCandidates tests that get packages finds packages
  2676  // with correct priorities.
  2677  func TestGetCandidates(t *testing.T) {
  2678  	type res struct {
  2679  		relevance  float64
  2680  		name, path string
  2681  	}
  2682  	want := []res{
  2683  		{0, "bytes", "bytes"},
  2684  		{0, "http", "net/http"},
  2685  		{0, "rand", "crypto/rand"},
  2686  		{0, "bar", "bar.com/bar"},
  2687  		{0, "foo", "foo.com/foo"},
  2688  	}
  2689  
  2690  	testConfig{
  2691  		modules: []packagestest.Module{
  2692  			{
  2693  				Name:  "bar.com",
  2694  				Files: fm{"bar/bar.go": "package bar\n"},
  2695  			},
  2696  			{
  2697  				Name:  "foo.com",
  2698  				Files: fm{"foo/foo.go": "package foo\n"},
  2699  			},
  2700  		},
  2701  	}.test(t, func(t *goimportTest) {
  2702  		var mu sync.Mutex
  2703  		var got []res
  2704  		add := func(c ImportFix) {
  2705  			mu.Lock()
  2706  			defer mu.Unlock()
  2707  			for _, w := range want {
  2708  				if c.StmtInfo.ImportPath == w.path {
  2709  					got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
  2710  				}
  2711  			}
  2712  		}
  2713  		if err := GetAllCandidates(context.Background(), add, "", "x.go", "x", t.env); err != nil {
  2714  			t.Fatalf("GetAllCandidates() = %v", err)
  2715  		}
  2716  		// Sort, then clear out relevance so it doesn't mess up the DeepEqual.
  2717  		sort.Slice(got, func(i, j int) bool {
  2718  			ri, rj := got[i], got[j]
  2719  			if ri.relevance != rj.relevance {
  2720  				return ri.relevance > rj.relevance // Highest first.
  2721  			}
  2722  			return ri.name < rj.name
  2723  		})
  2724  		for i := range got {
  2725  			got[i].relevance = 0
  2726  		}
  2727  		if !reflect.DeepEqual(want, got) {
  2728  			t.Errorf("wanted results in order %v, got %v", want, got)
  2729  		}
  2730  	})
  2731  }
  2732  
  2733  func TestGetImportPaths(t *testing.T) {
  2734  	type res struct {
  2735  		relevance  float64
  2736  		name, path string
  2737  	}
  2738  	want := []res{
  2739  		{0, "http", "net/http"},
  2740  		{0, "net", "net"},
  2741  		{0, "neta", "neta.com/neta"},
  2742  	}
  2743  
  2744  	testConfig{
  2745  		modules: []packagestest.Module{
  2746  			{
  2747  				Name:  "neta.com",
  2748  				Files: fm{"neta/neta.go": "package neta\n"},
  2749  			},
  2750  		},
  2751  	}.test(t, func(t *goimportTest) {
  2752  		var mu sync.Mutex
  2753  		var got []res
  2754  		add := func(c ImportFix) {
  2755  			mu.Lock()
  2756  			defer mu.Unlock()
  2757  			for _, w := range want {
  2758  				if c.StmtInfo.ImportPath == w.path {
  2759  					got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
  2760  				}
  2761  			}
  2762  		}
  2763  		if err := GetImportPaths(context.Background(), add, "ne", "x.go", "x", t.env); err != nil {
  2764  			t.Fatalf("GetImportPaths() = %v", err)
  2765  		}
  2766  		// Sort, then clear out relevance so it doesn't mess up the DeepEqual.
  2767  		sort.Slice(got, func(i, j int) bool {
  2768  			ri, rj := got[i], got[j]
  2769  			if ri.relevance != rj.relevance {
  2770  				return ri.relevance > rj.relevance // Highest first.
  2771  			}
  2772  			return ri.name < rj.name
  2773  		})
  2774  		for i := range got {
  2775  			got[i].relevance = 0
  2776  		}
  2777  		if !reflect.DeepEqual(want, got) {
  2778  			t.Errorf("wanted results in order %v, got %v", want, got)
  2779  		}
  2780  	})
  2781  }
  2782  
  2783  func TestGetPackageCompletions(t *testing.T) {
  2784  	type res struct {
  2785  		relevance          float64
  2786  		name, path, symbol string
  2787  	}
  2788  	want := []res{
  2789  		{0, "rand", "math/rand", "Seed"},
  2790  		{0, "rand", "bar.com/rand", "Bar"},
  2791  	}
  2792  
  2793  	testConfig{
  2794  		modules: []packagestest.Module{
  2795  			{
  2796  				Name:  "bar.com",
  2797  				Files: fm{"rand/bar.go": "package rand\nvar Bar int\n"},
  2798  			},
  2799  		},
  2800  	}.test(t, func(t *goimportTest) {
  2801  		var mu sync.Mutex
  2802  		var got []res
  2803  		add := func(c PackageExport) {
  2804  			mu.Lock()
  2805  			defer mu.Unlock()
  2806  			for _, csym := range c.Exports {
  2807  				for _, w := range want {
  2808  					if c.Fix.StmtInfo.ImportPath == w.path && csym == w.symbol {
  2809  						got = append(got, res{c.Fix.Relevance, c.Fix.IdentName, c.Fix.StmtInfo.ImportPath, csym})
  2810  					}
  2811  				}
  2812  			}
  2813  		}
  2814  		if err := GetPackageExports(context.Background(), add, "rand", "x.go", "x", t.env); err != nil {
  2815  			t.Fatalf("getPackageCompletions() = %v", err)
  2816  		}
  2817  		// Sort, then clear out relevance so it doesn't mess up the DeepEqual.
  2818  		sort.Slice(got, func(i, j int) bool {
  2819  			ri, rj := got[i], got[j]
  2820  			if ri.relevance != rj.relevance {
  2821  				return ri.relevance > rj.relevance // Highest first.
  2822  			}
  2823  			return ri.name < rj.name
  2824  		})
  2825  		for i := range got {
  2826  			got[i].relevance = 0
  2827  		}
  2828  		if !reflect.DeepEqual(want, got) {
  2829  			t.Errorf("wanted results in order %v, got %v", want, got)
  2830  		}
  2831  	})
  2832  }
  2833  
  2834  // Tests #34895: process should not panic on concurrent calls.
  2835  func TestConcurrentProcess(t *testing.T) {
  2836  	testConfig{
  2837  		module: packagestest.Module{
  2838  			Name: "foo.com",
  2839  			Files: fm{
  2840  				"p/first.go": `package foo
  2841  
  2842  func _() {
  2843  	fmt.Println()
  2844  }
  2845  `,
  2846  				"p/second.go": `package foo
  2847  
  2848  import "fmt"
  2849  
  2850  func _() {
  2851  	fmt.Println()
  2852  	imports.Bar() // not imported.
  2853  }
  2854  `,
  2855  			},
  2856  		},
  2857  	}.test(t, func(t *goimportTest) {
  2858  		var (
  2859  			n  = 10
  2860  			wg sync.WaitGroup
  2861  		)
  2862  		wg.Add(n)
  2863  		for i := 0; i < n; i++ {
  2864  			go func() {
  2865  				defer wg.Done()
  2866  				_, err := t.process("foo.com", "p/first.go", nil, nil)
  2867  				if err != nil {
  2868  					t.Error(err)
  2869  				}
  2870  			}()
  2871  		}
  2872  		wg.Wait()
  2873  	})
  2874  }
  2875  
  2876  func TestNonlocalDot(t *testing.T) {
  2877  	const input = `package main
  2878  import (
  2879  	"fmt"
  2880  )
  2881  var _, _ = fmt.Sprintf, dot.Dot
  2882  `
  2883  	const want = `package main
  2884  
  2885  import (
  2886  	"fmt"
  2887  	"noninternet/dot.v1/dot"
  2888  )
  2889  
  2890  var _, _ = fmt.Sprintf, dot.Dot
  2891  `
  2892  	testConfig{
  2893  		modules: []packagestest.Module{
  2894  			{
  2895  				Name:  "golang.org/fake",
  2896  				Files: fm{"x.go": input},
  2897  			},
  2898  			{
  2899  				Name: "noninternet/dot.v1",
  2900  				Files: fm{
  2901  					"dot/dot.go": "package dot\nfunc Dot(){}\n",
  2902  				},
  2903  			},
  2904  		},
  2905  		gopathOnly: true, // our modules testing setup doesn't allow modules without dots.
  2906  	}.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
  2907  }