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