1
0
mirror of https://github.com/golang/go synced 2024-10-01 01:18:32 -06:00
go/imports/fix_test.go

2288 lines
41 KiB
Go
Raw Normal View History

// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package imports
import (
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"
)
var tests = []struct {
name string
formatOnly bool
in, out string
}{
// Adding an import to an existing parenthesized import
{
name: "factored_imports_add",
in: `package foo
import (
"fmt"
)
func bar() {
var b bytes.Buffer
fmt.Println(b.String())
}
`,
out: `package foo
import (
"bytes"
"fmt"
)
func bar() {
var b bytes.Buffer
fmt.Println(b.String())
}
`,
},
// Adding an import to an existing parenthesized import,
// verifying it goes into the first section.
{
name: "factored_imports_add_first_sec",
in: `package foo
import (
"fmt"
"appengine"
)
func bar() {
var b bytes.Buffer
_ = appengine.IsDevServer
fmt.Println(b.String())
}
`,
out: `package foo
import (
"bytes"
"fmt"
"appengine"
)
func bar() {
var b bytes.Buffer
_ = appengine.IsDevServer
fmt.Println(b.String())
}
`,
},
// Adding an import to an existing parenthesized import,
// verifying it goes into the first section. (test 2)
{
name: "factored_imports_add_first_sec_2",
in: `package foo
import (
"fmt"
"appengine"
)
func bar() {
_ = math.NaN
_ = fmt.Sprintf
_ = appengine.IsDevServer
}
`,
out: `package foo
import (
"fmt"
"math"
"appengine"
)
func bar() {
_ = math.NaN
_ = fmt.Sprintf
_ = appengine.IsDevServer
}
`,
},
// Adding a new import line, without parens
{
name: "add_import_section",
in: `package foo
func bar() {
var b bytes.Buffer
}
`,
out: `package foo
import "bytes"
func bar() {
var b bytes.Buffer
}
`,
},
// Adding two new imports, which should make a parenthesized import decl.
{
name: "add_import_paren_section",
in: `package foo
func bar() {
_, _ := bytes.Buffer, zip.NewReader
}
`,
out: `package foo
import (
"archive/zip"
"bytes"
)
func bar() {
_, _ := bytes.Buffer, zip.NewReader
}
`,
},
// Make sure we don't add things twice
{
name: "no_double_add",
in: `package foo
func bar() {
_, _ := bytes.Buffer, bytes.NewReader
}
`,
out: `package foo
import "bytes"
func bar() {
_, _ := bytes.Buffer, bytes.NewReader
}
`,
},
// Make sure we don't add packages that don't have the right exports
{
name: "no_mismatched_add",
in: `package foo
func bar() {
_ := bytes.NonexistentSymbol
}
`,
out: `package foo
func bar() {
_ := bytes.NonexistentSymbol
}
`,
},
// Remove unused imports, 1 of a factored block
{
name: "remove_unused_1_of_2",
in: `package foo
import (
"bytes"
"fmt"
)
func bar() {
_, _ := bytes.Buffer, bytes.NewReader
}
`,
out: `package foo
import (
"bytes"
)
func bar() {
_, _ := bytes.Buffer, bytes.NewReader
}
`,
},
// Remove unused imports, 2 of 2
{
name: "remove_unused_2_of_2",
in: `package foo
import (
"bytes"
"fmt"
)
func bar() {
}
`,
out: `package foo
func bar() {
}
`,
},
// Remove unused imports, 1 of 1
{
name: "remove_unused_1_of_1",
in: `package foo
import "fmt"
func bar() {
}
`,
out: `package foo
func bar() {
}
`,
},
// Don't remove empty imports.
{
name: "dont_remove_empty_imports",
in: `package foo
import (
_ "image/png"
_ "image/jpeg"
)
`,
out: `package foo
import (
_ "image/jpeg"
_ "image/png"
)
`,
},
// Don't remove dot imports.
{
name: "dont_remove_dot_imports",
in: `package foo
import (
. "foo"
. "bar"
)
`,
out: `package foo
import (
. "bar"
. "foo"
)
`,
},
// Skip refs the parser can resolve.
{
name: "skip_resolved_refs",
in: `package foo
func f() {
type t struct{ Println func(string) }
fmt := t{Println: func(string) {}}
fmt.Println("foo")
}
`,
out: `package foo
func f() {
type t struct{ Println func(string) }
fmt := t{Println: func(string) {}}
fmt.Println("foo")
}
`,
},
// Do not add a package we already have a resolution for.
{
name: "skip_template",
in: `package foo
import "html/template"
func f() { t = template.New("sometemplate") }
`,
out: `package foo
import "html/template"
func f() { t = template.New("sometemplate") }
`,
},
// Don't touch cgo
{
name: "cgo",
in: `package foo
/*
#include <foo.h>
*/
import "C"
`,
out: `package foo
/*
#include <foo.h>
*/
import "C"
`,
},
// Put some things in their own section
{
name: "make_sections",
in: `package foo
import (
"os"
)
func foo () {
_, _ = os.Args, fmt.Println
_, _ = appengine.Main, datastore.ErrInvalidEntityType
}
`,
out: `package foo
import (
"fmt"
"os"
"appengine"
"appengine/datastore"
)
func foo() {
_, _ = os.Args, fmt.Println
_, _ = appengine.Main, datastore.ErrInvalidEntityType
}
`,
},
// Delete existing empty import block
{
name: "delete_empty_import_block",
in: `package foo
import ()
`,
out: `package foo
`,
},
// Use existing empty import block
{
name: "use_empty_import_block",
in: `package foo
import ()
func f() {
_ = fmt.Println
}
`,
out: `package foo
import "fmt"
func f() {
_ = fmt.Println
}
`,
},
// Blank line before adding new section.
{
name: "blank_line_before_new_group",
in: `package foo
import (
"fmt"
"net"
)
func f() {
_ = net.Dial
_ = fmt.Printf
_ = snappy.ErrCorrupt
}
`,
out: `package foo
import (
"fmt"
"net"
"code.google.com/p/snappy-go/snappy"
)
func f() {
_ = net.Dial
_ = fmt.Printf
_ = snappy.ErrCorrupt
}
`,
},
// Blank line between standard library and third-party stuff.
{
name: "blank_line_separating_std_and_third_party",
in: `package foo
import (
"code.google.com/p/snappy-go/snappy"
"fmt"
"net"
)
func f() {
_ = net.Dial
_ = fmt.Printf
_ = snappy.Foo
}
`,
out: `package foo
import (
"fmt"
"net"
"code.google.com/p/snappy-go/snappy"
)
func f() {
_ = net.Dial
_ = fmt.Printf
_ = snappy.Foo
}
`,
},
// golang.org/issue/6884
{
name: "new_imports_before_comment",
in: `package main
// A comment
func main() {
fmt.Println("Hello, world")
}
`,
out: `package main
import "fmt"
// A comment
func main() {
fmt.Println("Hello, world")
}
`,
},
// golang.org/issue/7132
{
name: "new_section_for_dotless_import",
in: `package main
import (
"fmt"
"gu"
"github.com/foo/bar"
)
var (
a = bar.a
b = gu.a
c = fmt.Printf
)
`,
out: `package main
import (
"fmt"
"gu"
"github.com/foo/bar"
)
var (
a = bar.a
b = gu.a
c = fmt.Printf
)
`,
},
{
name: "fragment_with_main",
in: `func main(){fmt.Println("Hello, world")}`,
out: `package main
import "fmt"
func main() { fmt.Println("Hello, world") }
`,
},
{
name: "fragment_without_main",
in: `func notmain(){fmt.Println("Hello, world")}`,
out: `import "fmt"
func notmain() { fmt.Println("Hello, world") }`,
},
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections. The issue occurs only when deleting an import that has a blank line immediately preceding, and other imports before that. Currently, DeleteImport assumes there's a blank line-sized hole left behind where the import was, and always deletes it. That blank line-sized hole is there in all cases except the above edge case. This fix checks for that edge case, and does not remove the blank line-sized hole. The CL also adds a previously failing test case that catches this scenario. After the change to DeleteImport, the new test passes (along with all other tests). Fixes golang/go#7679. Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly matching to what you would get if you printed the AST and parsed it back. This is how the rest of the package and the current tests work (i.e., they only check that printing the AST gives the correct output). Changing that is very hard, if not impossible, at least not without resorting to manipulating AST via printing, text manipulation and parsing. This is okay for most usages, but it does create potential problems. For example, astutil.Imports() currently only works correctly on freshly parsed AST. If that AST is manipulated via astutil funcs, then Imports() may not always generate correct output. However, thas is a separate issue and should be treated as such. LGTM=bradfitz R=golang-codereviews, gobot, adonovan, bradfitz CC=golang-codereviews https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
// Remove first import within in a 2nd/3rd/4th/etc. section.
// golang.org/issue/7679
{
name: "remove_first_import_in_section",
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections. The issue occurs only when deleting an import that has a blank line immediately preceding, and other imports before that. Currently, DeleteImport assumes there's a blank line-sized hole left behind where the import was, and always deletes it. That blank line-sized hole is there in all cases except the above edge case. This fix checks for that edge case, and does not remove the blank line-sized hole. The CL also adds a previously failing test case that catches this scenario. After the change to DeleteImport, the new test passes (along with all other tests). Fixes golang/go#7679. Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly matching to what you would get if you printed the AST and parsed it back. This is how the rest of the package and the current tests work (i.e., they only check that printing the AST gives the correct output). Changing that is very hard, if not impossible, at least not without resorting to manipulating AST via printing, text manipulation and parsing. This is okay for most usages, but it does create potential problems. For example, astutil.Imports() currently only works correctly on freshly parsed AST. If that AST is manipulated via astutil funcs, then Imports() may not always generate correct output. However, thas is a separate issue and should be treated as such. LGTM=bradfitz R=golang-codereviews, gobot, adonovan, bradfitz CC=golang-codereviews https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
in: `package main
import (
"fmt"
"github.com/foo/bar"
"github.com/foo/qux"
)
func main() {
var _ = fmt.Println
//var _ = bar.A
var _ = qux.B
}
`,
out: `package main
import (
"fmt"
"github.com/foo/qux"
)
func main() {
var _ = fmt.Println
//var _ = bar.A
var _ = qux.B
}
`,
},
// Blank line can be added before all types of import declarations.
// golang.org/issue/7866
{
name: "new_section_for_all_kinds_of_imports",
in: `package main
import (
"fmt"
renamed_bar "github.com/foo/bar"
. "github.com/foo/baz"
"io"
_ "github.com/foo/qux"
"strings"
)
var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B
`,
out: `package main
import (
"fmt"
"io"
"strings"
renamed_bar "github.com/foo/bar"
. "github.com/foo/baz"
_ "github.com/foo/qux"
)
var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B
`,
},
// Non-idempotent comment formatting
// golang.org/issue/8035
{
name: "comments_formatted",
in: `package main
import (
"fmt" // A
"go/ast" // B
_ "launchpad.net/gocheck" // C
)
func main() { _, _ = fmt.Print, ast.Walk }
`,
out: `package main
import (
"fmt" // A
"go/ast" // B
_ "launchpad.net/gocheck" // C
)
func main() { _, _ = fmt.Print, ast.Walk }
`,
},
// Failure to delete all duplicate imports
// golang.org/issue/8459
{
name: "remove_duplicates",
in: `package main
import (
"fmt"
"log"
"log"
"math"
)
func main() { fmt.Println("pi:", math.Pi) }
`,
out: `package main
import (
"fmt"
"math"
)
func main() { fmt.Println("pi:", math.Pi) }
`,
},
// Too aggressive prefix matching
// golang.org/issue/9961
{
name: "no_extra_groups",
in: `package p
import (
"zip"
"rsc.io/p"
)
var (
_ = fmt.Print
_ = zip.Store
_ p.P
_ = regexp.Compile
)
`,
out: `package p
import (
"fmt"
"regexp"
"zip"
"rsc.io/p"
)
var (
_ = fmt.Print
_ = zip.Store
_ p.P
_ = regexp.Compile
)
`,
},
// Unused named import is mistaken for unnamed import
// golang.org/issue/8149
{
name: "named_import_doesnt_provide_package_name",
in: `package main
import foo "fmt"
func main() { fmt.Println() }
`,
out: `package main
import "fmt"
func main() { fmt.Println() }
`,
},
// Unused named import is mistaken for unnamed import
// golang.org/issue/8149
{
name: "unused_named_import_removed",
in: `package main
import (
"fmt"
x "fmt"
)
func main() { fmt.Println() }
`,
out: `package main
import (
"fmt"
)
func main() { fmt.Println() }
`,
},
// FormatOnly
{
name: "formatonly_works",
formatOnly: true,
in: `package main
import (
"fmt"
"golang.org/x/foo"
)
func main() {}
`,
out: `package main
import (
"fmt"
"golang.org/x/foo"
)
func main() {}
`,
},
{
name: "preserve_import_group",
in: `package p
import (
"bytes"
"fmt"
)
var _ = fmt.Sprintf
`,
out: `package p
import (
"fmt"
)
var _ = fmt.Sprintf
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
`,
},
{
name: "import_grouping_not_path_dependent_no_groups",
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
in: `package main
import (
"time"
)
func main() {
_ = snappy.ErrCorrupt
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
_ = p.P
_ = time.Parse
}
`,
out: `package main
import (
"time"
"code.google.com/p/snappy-go/snappy"
"rsc.io/p"
)
func main() {
_ = snappy.ErrCorrupt
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
_ = p.P
_ = time.Parse
}
`,
},
{
name: "import_grouping_not_path_dependent_existing_group",
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
in: `package main
import (
"time"
"code.google.com/p/snappy-go/snappy"
)
func main() {
_ = snappy.ErrCorrupt
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
_ = p.P
_ = time.Parse
}
`,
out: `package main
import (
"time"
"code.google.com/p/snappy-go/snappy"
"rsc.io/p"
)
func main() {
_ = snappy.ErrCorrupt
go/ast/astutil: new third-party imports shouldn't go in the std group Before this change, astutil would only do a prefix match of a new import with all the existing ones, to try to place it in the correct group. If none was found, the new import would be placed at the beginning of the first import group. This works well for new std imports, but it doesn't work well for new third-party packages that don't share any prefix with any of the existing imports. Example: import ( "time" "github.com/golang/snappy" ) When adding "golang.org/x/sys/unix" with astutil.AddImport, the import is inserted as follows: import ( "golang.org/x/sys/unix" "time" "github.com/golang/snappy" ) And goimports reorganizes the imports to separate std and third-party packages: import ( "time" "golang.org/x/sys/unix" "github.com/golang/snappy" ) We usually don't want to introduce a new import group; in most cases, the desired behavior is separating std from third-party packages. With this CL, new imports that don't share prefix with any existing ones will be placed with the first group of third-party imports, if any exist. If no third-party import group exists, a new one will be added. In the case of our example above, this will be the new outcome: import ( "time" "github.com/golang/snappy" "golang.org/x/sys/unix" ) Fixes golang/go#19190. Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c Reviewed-on: https://go-review.googlesource.com/37552 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
_ = p.P
_ = time.Parse
}
`,
},
{
name: "issue #12097",
in: `// a
// b
// c
func main() {
_ = fmt.Println
}`,
out: `package main
import "fmt"
// a
// b
// c
func main() {
_ = fmt.Println
}
`,
},
{
name: "import_comment_stays_on_import",
in: `package main
import (
"math" // fun
)
func main() {
x := math.MaxInt64
fmt.Println(strings.Join(",", []string{"hi"}), x)
}`,
out: `package main
import (
"fmt"
"math" // fun
"strings"
)
func main() {
x := math.MaxInt64
fmt.Println(strings.Join(",", []string{"hi"}), x)
}
`,
},
{
name: "no_blank_after_comment",
in: `package main
import (
_ "io"
_ "net/http"
_ "net/http/pprof" // install the pprof http handlers
_ "strings"
)
func main() {
}
`,
out: `package main
import (
_ "io"
_ "net/http"
_ "net/http/pprof" // install the pprof http handlers
_ "strings"
)
func main() {
}
`,
},
{
name: "no_blank_after_comment_reordered",
in: `package main
import (
_ "io"
_ "net/http/pprof" // install the pprof http handlers
_ "net/http"
_ "strings"
)
func main() {
}
`,
out: `package main
import (
_ "io"
_ "net/http"
_ "net/http/pprof" // install the pprof http handlers
_ "strings"
)
func main() {
}
`,
},
{
name: "no_blank_after_comment_unnamed",
in: `package main
import (
"encoding/json"
"io"
"net/http"
_ "net/http/pprof" // install the pprof http handlers
"strings"
"github.com/pkg/errors"
)
func main() {
_ = strings.ToUpper("hello")
_ = io.EOF
var (
_ json.Number
_ *http.Request
_ errors.Frame
)
}
`,
out: `package main
import (
"encoding/json"
"io"
"net/http"
_ "net/http/pprof" // install the pprof http handlers
"strings"
"github.com/pkg/errors"
)
func main() {
_ = strings.ToUpper("hello")
_ = io.EOF
var (
_ json.Number
_ *http.Request
_ errors.Frame
)
}
`,
},
{
name: "blank_after_package_statement_with_comment",
in: `package p // comment
import "math"
var _ = fmt.Printf
`,
out: `package p // comment
import "fmt"
var _ = fmt.Printf
`,
},
{
name: "blank_after_package_statement_no_comment",
in: `package p
import "math"
var _ = fmt.Printf
`,
out: `package p
import "fmt"
var _ = fmt.Printf
`,
},
// golang.org/issue/20818
{
name: "sort_all_groups",
in: `package p
import (
"testing"
"github.com/Sirupsen/logrus"
"context"
)
var _, _, _ = testing.T, logrus.Entry, context.Context
`,
out: `package p
import (
"context"
"testing"
"github.com/Sirupsen/logrus"
)
var _, _, _ = testing.T, logrus.Entry, context.Context
`,
},
// golang.org/issue/20818
{
name: "sort_many_groups",
in: `package p
import (
"testing"
"k8s.io/apimachinery/pkg/api/meta"
"fmt"
"github.com/pkg/errors"
"golang.org/x/tools/cover"
"github.com/sirupsen/logrus"
"context"
)
var _, _, _, _, _, _ = testing.T, logrus.Entry, context.Context, meta.AnyGroup, fmt.Printf, errors.Frame
`,
out: `package p
import (
"context"
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/meta"
)
var _, _, _, _, _, _ = testing.T, logrus.Entry, context.Context, meta.AnyGroup, fmt.Printf, errors.Frame
`,
},
// golang.org/issue/20818
{
name: "sort_all_groups_with_blanks_and_comments",
in: `package p
import (
"testing"
"k8s.io/apimachinery/pkg/api/meta"
// a comment for the "fmt" package (#26921: they are broken, should be fixed)
"fmt"
"github.com/pkg/errors" // some comment
"golang.org/x/tools/cover"
"github.com/sirupsen/logrus"
"context"
)
var _, _, _, _, _, _ = testing.T, logrus.Entry, context.Context, meta.AnyGroup, fmt.Printf, errors.Frame
`,
out: `package p
import (
"context"
"fmt"
"testing"
"github.com/pkg/errors" // some comment
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/meta" // a comment for the "fmt" package (#26921: they are broken, should be fixed)
)
var _, _, _, _, _, _ = testing.T, logrus.Entry, context.Context, meta.AnyGroup, fmt.Printf, errors.Frame
`,
},
{
name: "sort_all_groups_with_local_packages",
in: `package p
import (
"local/foo"
"testing"
"k8s.io/apimachinery/pkg/api/meta"
"fmt"
"github.com/pkg/errors"
"github.com/local/bar"
"golang.org/x/tools/cover"
"github.com/sirupsen/logrus"
"context"
)
var _, _, _, _, _, _ = testing.T, logrus.Entry, context.Context, meta.AnyGroup, fmt.Printf, errors.Frame
var _, _ = foo.Foo, bar.Bar
`,
out: `package p
import (
"context"
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/meta"
"github.com/local/bar"
"local/foo"
)
var _, _, _, _, _, _ = testing.T, logrus.Entry, context.Context, meta.AnyGroup, fmt.Printf, errors.Frame
var _, _ = foo.Foo, bar.Bar
`,
},
{
name: "cryptorand_preferred_easy_possible",
in: `package p
var _ = rand.Read
`,
out: `package p
import "crypto/rand"
var _ = rand.Read
`,
},
{
name: "cryptorand_preferred_easy_impossible",
in: `package p
var _ = rand.NewZipf
`,
out: `package p
import "math/rand"
var _ = rand.NewZipf
`,
},
{
name: "cryptorand_preferred_complex_possible",
in: `package p
var _, _ = rand.Read, rand.Prime
`,
out: `package p
import "crypto/rand"
var _, _ = rand.Read, rand.Prime
`,
},
{
name: "cryptorand_preferred_complex_impossible",
in: `package p
var _, _ = rand.Read, rand.NewZipf
`,
out: `package p
import "math/rand"
var _, _ = rand.Read, rand.NewZipf
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections. The issue occurs only when deleting an import that has a blank line immediately preceding, and other imports before that. Currently, DeleteImport assumes there's a blank line-sized hole left behind where the import was, and always deletes it. That blank line-sized hole is there in all cases except the above edge case. This fix checks for that edge case, and does not remove the blank line-sized hole. The CL also adds a previously failing test case that catches this scenario. After the change to DeleteImport, the new test passes (along with all other tests). Fixes golang/go#7679. Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly matching to what you would get if you printed the AST and parsed it back. This is how the rest of the package and the current tests work (i.e., they only check that printing the AST gives the correct output). Changing that is very hard, if not impossible, at least not without resorting to manipulating AST via printing, text manipulation and parsing. This is okay for most usages, but it does create potential problems. For example, astutil.Imports() currently only works correctly on freshly parsed AST. If that AST is manipulated via astutil funcs, then Imports() may not always generate correct output. However, thas is a separate issue and should be treated as such. LGTM=bradfitz R=golang-codereviews, gobot, adonovan, bradfitz CC=golang-codereviews https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
`,
},
}
func TestSimpleCases(t *testing.T) {
defer func(lp string) { LocalPrefix = lp }(LocalPrefix)
LocalPrefix = "local,github.com/local"
testConfig{
// Skeleton non-stdlib packages for use during testing.
// Each includes one arbitrary symbol, e.g. the first declaration in the first file.
// Try not to add more without a good reason.
gopathFiles: map[string]string{
"appengine/x.go": "package appengine\nfunc Main(){}\n",
"appengine/datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
"rsc.io/p/x.go": "package p\nfunc P(){}\n",
"code.google.com/p/snappy-go/snappy/x.go": "package snappy\nvar ErrCorrupt error\n",
},
}.test(t, func(t *goimportTest) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
options := &Options{
TabWidth: 8,
TabIndent: true,
Comments: true,
Fragment: true,
FormatOnly: tt.formatOnly,
}
buf, err := Process(tt.name+".go", []byte(tt.in), options)
if err != nil {
t.Fatalf("Process(...) = %v", err)
}
if got := string(buf); got != tt.out {
t.Errorf("output differs:\nGOT:\n%s\nWANT:\n%s\n", got, tt.out)
}
})
}
})
}
func TestReadFromFilesystem(t *testing.T) {
tests := []struct {
name string
in, out string
}{
{
name: "works",
in: `package foo
func bar() {
fmt.Println("hi")
}
`,
out: `package foo
import "fmt"
func bar() {
fmt.Println("hi")
}
`,
},
{
name: "missing_package",
in: `
func bar() {
fmt.Println("hi")
}
`,
out: `
import "fmt"
func bar() {
fmt.Println("hi")
}
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"x.go": tt.in,
},
}.test(t, func(t *goimportTest) {
options := &Options{
TabWidth: 8,
TabIndent: true,
Comments: true,
Fragment: true,
}
buf, err := Process(filepath.Join(t.gopath, "/src/x.go"), nil, options)
if err != nil {
t.Errorf("Process(...) = %v", tt.name, err)
}
if got := string(buf); got != tt.out {
t.Errorf("output differs:\nGOT:\n%s\nWANT:\n%s\n", tt.name, got, tt.out)
}
})
})
}
}
// Test support for packages in GOPATH that are actually symlinks.
// Also test that a symlink loop does not block the process.
func TestImportSymlinks(t *testing.T) {
switch runtime.GOOS {
case "windows", "plan9":
t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
}
testConfig{
gopathFiles: map[string]string{
"../target/f.go": "package mypkg\nvar Foo = 123\n",
"x/mypkg": "LINK:../../target", // valid symlink
"x/apkg": "LINK:..", // symlink loop
},
}.test(t, func(t *goimportTest) {
build.Default.GOPATH = t.gopath
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
input := `package p
var (
_ = fmt.Print
_ = mypkg.Foo
)
`
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
output := `package p
import (
"fmt"
"x/mypkg"
)
var (
_ = fmt.Print
_ = mypkg.Foo
)
`
buf, err := Process(t.gopath+"/src/myotherpkg/toformat.go", []byte(input), &Options{})
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != output {
t.Fatalf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, output)
}
})
}
func TestImportSymlinksWithIgnore(t *testing.T) {
switch runtime.GOOS {
case "windows", "plan9":
t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
}
testConfig{
gopathFiles: map[string]string{
"../target/f.go": "package mypkg\nvar Foo = 123\n",
"x/mypkg": "LINK:../../target", // valid symlink
"x/apkg": "LINK:..", // symlink loop
".goimportsignore": "x/mypkg\n",
},
}.test(t, func(t *goimportTest) {
input := `package p
var (
_ = fmt.Print
_ = mypkg.Foo
)
`
output := `package p
import "fmt"
var (
_ = fmt.Print
_ = mypkg.Foo
)
`
buf, err := Process(t.gopath+"/src/myotherpkg/toformat.go", []byte(input), &Options{})
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != output {
t.Fatalf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, output)
}
})
}
// Test for x/y/v2 convention for package y.
func TestModuleVersion(t *testing.T) {
testConfig{}.test(t, func(t *goimportTest) {
input := `package p
import (
"fmt"
"github.com/foo/v2"
)
var (
_ = fmt.Print
_ = foo.Foo
)
`
buf, err := Process(filepath.Join(t.gopath, "src/mypkg.com/outpkg/toformat.go"), []byte(input), &Options{})
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != input {
t.Fatalf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, input)
}
})
}
// Test for correctly identifying the name of a vendored package when it
// differs from its directory name. In this test, the import line
// "mypkg.com/mypkg.v1" would be removed if goimports wasn't able to detect
// that the package name is "mypkg".
func TestVendorPackage(t *testing.T) {
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
testConfig{
gopathFiles: map[string]string{
"mypkg.com/outpkg/vendor/mypkg.com/mypkg.v1/f.go": "package mypkg\nvar Foo = 123\n",
},
}.test(t, func(t *goimportTest) {
input := `package p
import (
"fmt"
"mypkg.com/mypkg.v1"
)
var (
_ = fmt.Print
_ = mypkg.Foo
)
`
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
buf, err := Process(filepath.Join(t.gopath, "src/mypkg.com/outpkg/toformat.go"), []byte(input), &Options{})
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != input {
t.Fatalf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, input)
}
})
}
func withEmptyGoPath(fn func()) {
scanOnce = sync.Once{}
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
oldGOPATH := build.Default.GOPATH
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
oldGOROOT := build.Default.GOROOT
oldCompiler := build.Default.Compiler
build.Default.GOPATH = ""
build.Default.Compiler = "gc"
defer func() {
build.Default.GOPATH = oldGOPATH
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
build.Default.GOROOT = oldGOROOT
build.Default.Compiler = oldCompiler
}()
fn()
}
func TestInternal(t *testing.T) {
const input = `package bar
var _ = race.Acquire
`
const importAdded = `package bar
import "foo/internal/race"
var _ = race.Acquire
`
tc := testConfig{
gopathFiles: map[string]string{
"foo/internal/race/x.go": "package race\n func Acquire(){}\n",
},
}
// Packages under the same directory should be able to use internal packages.
tc.test(t, func(t *goimportTest) {
buf, err := Process(filepath.Join(t.gopath, "src/foo/bar/x.go"), []byte(input), &Options{})
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != importAdded {
t.Errorf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, importAdded)
}
})
// Packages outside the same directory should not.
tc.test(t, func(t *goimportTest) {
buf, err := Process(filepath.Join(t.gopath, "src/bar/x.go"), []byte(input), &Options{})
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != input {
t.Errorf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, input)
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
}
})
}
func TestProcessVendor(t *testing.T) {
const input = `package p
var _ = hpack.HuffmanDecode
`
const want = `package p
import "golang.org/x/net/http2/hpack"
var _ = hpack.HuffmanDecode
`
testConfig{
gopathFiles: map[string]string{
"vendor/golang.org/x/net/http2/hpack/huffman.go": "package hpack\nfunc HuffmanDecode() { }\n",
},
}.test(t, func(t *goimportTest) {
buf, err := Process(filepath.Join(t.gopath, "src/bar/x.go"), []byte(input), &Options{})
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t.Fatal(err)
}
if got := string(buf); got != want {
t.Errorf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, want)
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
}
})
}
func TestFindStdlib(t *testing.T) {
tests := []struct {
pkg string
symbols []string
want string
}{
{"http", []string{"Get"}, "net/http"},
{"http", []string{"Get", "Post"}, "net/http"},
{"http", []string{"Get", "Foo"}, ""},
{"bytes", []string{"Buffer"}, "bytes"},
{"ioutil", []string{"Discard"}, "io/ioutil"},
}
for _, tt := range tests {
input := "package p\n"
for _, sym := range tt.symbols {
input += fmt.Sprintf("var _ = %s.%s\n", tt.pkg, sym)
}
buf, err := Process("x.go", []byte(input), &Options{})
if err != nil {
t.Fatal(err)
}
if got := string(buf); !strings.Contains(got, tt.want) {
t.Errorf("Process(%q) = %q, wanted it to contain %q", input, buf, tt.want)
}
}
}
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
type testConfig struct {
// goroot and gopath optionally specifies the path on disk
// to use for the GOROOT and GOPATH. If empty, a temp directory
// is made if needed.
goroot, gopath string
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
// gorootFiles optionally specifies the complete contents of GOROOT to use,
// If nil, the normal current $GOROOT is used.
gorootFiles map[string]string // paths relative to $GOROOT/src to contents
// gopathFiles is like gorootFiles, but for $GOPATH.
// If nil, there is no GOPATH, though.
gopathFiles map[string]string // paths relative to $GOPATH/src to contents
}
func mustTempDir(t *testing.T, prefix string) string {
dir, err := ioutil.TempDir("", prefix)
if err != nil {
t.Fatal(err)
}
return dir
}
func mapToDir(destDir string, files map[string]string) error {
for path, contents := range files {
file := filepath.Join(destDir, "src", path)
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
return err
}
var err error
if strings.HasPrefix(contents, "LINK:") {
err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file)
} else {
err = ioutil.WriteFile(file, []byte(contents), 0644)
}
if err != nil {
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
return err
}
}
return nil
}
func (c testConfig) test(t *testing.T, fn func(*goimportTest)) {
goroot := c.goroot
gopath := c.gopath
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if c.gorootFiles != nil && goroot == "" {
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
goroot = mustTempDir(t, "goroot-")
defer os.RemoveAll(goroot)
}
if err := mapToDir(goroot, c.gorootFiles); err != nil {
t.Fatal(err)
}
if c.gopathFiles != nil && gopath == "" {
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
gopath = mustTempDir(t, "gopath-")
defer os.RemoveAll(gopath)
}
if err := mapToDir(gopath, c.gopathFiles); err != nil {
t.Fatal(err)
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
}
withEmptyGoPath(func() {
if goroot != "" {
build.Default.GOROOT = goroot
}
build.Default.GOPATH = gopath
it := &goimportTest{
T: t,
goroot: build.Default.GOROOT,
gopath: gopath,
ctx: &build.Default,
}
fn(it)
})
}
type goimportTest struct {
*testing.T
ctx *build.Context
goroot string
gopath string
}
// Tests that added imports are renamed when the import path's base doesn't
// match its package name. For example, we want to generate:
//
// import cloudbilling "google.golang.org/api/cloudbilling/v1"
func TestRenameWhenPackageNameMismatch(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"foo/bar/v1/x.go": "package bar \n const X = 1",
},
}.test(t, func(t *goimportTest) {
buf, err := Process(t.gopath+"/src/test/t.go", []byte("package main \n const Y = bar.X"), &Options{})
if err != nil {
t.Fatal(err)
}
const want = `package main
import bar "foo/bar/v1"
const Y = bar.X
`
if string(buf) != want {
t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
}
})
}
// Tests that the LocalPrefix option causes imports
// to be added into a later group (num=3).
func TestLocalPrefix(t *testing.T) {
tests := []struct {
config testConfig
localPrefix string
src string
want string
}{
{
config: testConfig{
gopathFiles: map[string]string{
"foo/bar/bar.go": "package bar \n const X = 1",
},
},
localPrefix: "foo/",
src: "package main \n const Y = bar.X \n const _ = runtime.GOOS",
want: `package main
import (
"runtime"
"foo/bar"
)
const Y = bar.X
const _ = runtime.GOOS
`,
},
{
config: testConfig{
gopathFiles: map[string]string{
"foo/foo.go": "package foo \n const X = 1",
"foo/bar/bar.go": "package bar \n const X = 1",
},
},
localPrefix: "foo/",
src: "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS",
want: `package main
import (
"runtime"
"foo"
"foo/bar"
)
const Y = bar.X
const Z = foo.X
const _ = runtime.GOOS
`,
},
{
config: testConfig{
gopathFiles: map[string]string{
"example.org/pkg/pkg.go": "package pkg \n const A = 1",
"foo/bar/bar.go": "package bar \n const B = 1",
"code.org/r/p/expproj/expproj.go": "package expproj \n const C = 1",
},
},
localPrefix: "example.org/pkg,foo/,code.org",
src: "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS",
want: `package main
import (
"runtime"
"code.org/r/p/expproj"
"example.org/pkg"
"foo/bar"
)
const X = pkg.A
const Y = bar.B
const Z = expproj.C
const _ = runtime.GOOS
`,
},
}
for _, tt := range tests {
tt.config.test(t, func(t *goimportTest) {
defer func(s string) { LocalPrefix = s }(LocalPrefix)
LocalPrefix = tt.localPrefix
buf, err := Process(t.gopath+"/src/test/t.go", []byte(tt.src), &Options{})
if err != nil {
t.Fatal(err)
}
if string(buf) != tt.want {
t.Errorf("Got:\n%s\nWant:\n%s", buf, tt.want)
}
})
}
}
cmd/goimports, imports: make goimports great again I felt the burn of my laptop on my legs, spinning away while processing goimports, and felt that it was time to make goimports great again. Over the past few years goimports fell into a slow state of disrepair with too many feature additions and no attention to the performance death by a thousand cuts. This was particularly terrible on OS X with its lackluster filesystem buffering. This CL makes goimports stronger, together with various optimizations and more visibility into what goimports is doing. * adds more internal documentation * avoids scanning $GOPATH for answers when running goimports on a file under $GOROOT (for Go core hackers) * don't read all $GOROOT & $GOPATH directories' Go code looking for their package names until much later. Require the package name of missing imports to be present in the last two directory path components. Then only try importing them in order from best to worst (shortest to longest, as before), so we can stop early. * when adding imports, add names to imports when the imported package name doesn't match the baes of its import path. For example: import foo "example.net/foo/v1" * don't read all *.go files in a package directory once the first file in a directory has revealed itself to be a package we're not looking for. For example, if we're looking for the right "client" for "client.Foo", we used to consider a directory "bar/client" as a candidate and read all 50 of its *.go files instead of stopping after its first *.go file had a "package main" line. * add some fast paths to remove allocations * add some fast paths to remove disk I/O when looking up the base package name of a standard library import (of existing imports in a file, which are very common) * adds a special case for import "C", to avoid some disk I/O. * add a -verbose flag to goimports for debugging On my Mac laptop with a huge $GOPATH, with a test file like: package foo import ( "fmt" "net/http" ) /* */ import "C" var _ = cloudbilling.New var _ = http.NewRequest var _ = client.New ... this took like 10 seconds before, and now 1.3 seconds. (Still slow; disk-based caching can come later) Updates golang/go#16367 (goimports is slow) Updates golang/go#16384 (refactor TestRename is broken on Windows) Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183 Reviewed-on: https://go-review.googlesource.com/24941 Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
// Tests that "package documentation" files are ignored.
func TestIgnoreDocumentationPackage(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"foo/foo.go": "package foo\nconst X = 1\n",
"foo/doc.go": "package documentation \n // just to confuse things\n",
},
}.test(t, func(t *goimportTest) {
const in = "package x\n\nconst Y = foo.X\n"
const want = "package x\n\nimport \"foo\"\n\nconst Y = foo.X\n"
buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != want {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", in, want)
}
})
}
// Tests importPathToNameGoPathParse and in particular that it stops
// after finding the first non-documentation package name, not
// reporting an error on inconsistent package names (since it should
// never make it that far).
func TestImportPathToNameGoPathParse(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"example.net/pkg/doc.go": "package documentation\n", // ignored
"example.net/pkg/gen.go": "package main\n", // also ignored
"example.net/pkg/pkg.go": "package the_pkg_name_to_find\n and this syntax error is ignored because of parser.PackageClauseOnly",
"example.net/pkg/z.go": "package inconsistent\n", // inconsistent but ignored
},
}.test(t, func(t *goimportTest) {
got, err := importPathToNameGoPathParse("example.net/pkg", filepath.Join(t.gopath, "src", "other.net"))
if err != nil {
t.Fatal(err)
}
const want = "the_pkg_name_to_find"
if got != want {
t.Errorf("importPathToNameGoPathParse(..) = %q; want %q", got, want)
}
})
}
func TestIgnoreConfiguration(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
".goimportsignore": "# comment line\n\n example.net", // tests comment, blank line, whitespace trimming
"example.net/pkg/pkg.go": "package pkg\nconst X = 1",
"otherwise-longer-so-worse.example.net/foo/pkg/pkg.go": "package pkg\nconst X = 1",
},
}.test(t, func(t *goimportTest) {
const in = "package x\n\nconst _ = pkg.X\n"
const want = "package x\n\nimport \"otherwise-longer-so-worse.example.net/foo/pkg\"\n\nconst _ = pkg.X\n"
buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != want {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want)
}
})
}
// Skip "node_modules" directory.
func TestSkipNodeModules(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"example.net/node_modules/pkg/a.go": "package pkg\nconst X = 1",
"otherwise-longer.net/not_modules/pkg/a.go": "package pkg\nconst X = 1",
},
}.test(t, func(t *goimportTest) {
const in = "package x\n\nconst _ = pkg.X\n"
const want = "package x\n\nimport \"otherwise-longer.net/not_modules/pkg\"\n\nconst _ = pkg.X\n"
buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != want {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want)
}
})
}
// golang.org/issue/16458 -- if GOROOT is a prefix of GOPATH, GOPATH is ignored.
func TestGoRootPrefixOfGoPath(t *testing.T) {
dir := mustTempDir(t, "importstest")
defer os.RemoveAll(dir)
testConfig{
goroot: filepath.Join(dir, "go"),
gopath: filepath.Join(dir, "gopath"),
gopathFiles: map[string]string{
"example.com/foo/pkg.go": "package foo\nconst X = 1",
},
}.test(t, func(t *goimportTest) {
const in = "package x\n\nconst _ = foo.X\n"
const want = "package x\n\nimport \"example.com/foo\"\n\nconst _ = foo.X\n"
buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != want {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want)
}
})
}
// Tests that package global variables with the same name and function name as
// a function in a separate package do not result in an import which masks
// the global variable
func TestGlobalImports(t *testing.T) {
const usesGlobal = `package pkg
func doSomething() {
t := time.Now()
}
`
const declaresGlobal = `package pkg
type Time struct{}
func (t Time) Now() Time {
return Time{}
}
var time Time
`
testConfig{
gopathFiles: map[string]string{
"pkg/global.go": declaresGlobal,
},
}.test(t, func(t *goimportTest) {
buf, err := Process(
filepath.Join(t.gopath, "src/pkg/uses.go"), []byte(usesGlobal), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != usesGlobal {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, usesGlobal)
}
})
}
// Tests that sibling files - other files in the same package - can provide an
// import that may not be the default one otherwise.
func TestSiblingImports(t *testing.T) {
// provide is the sibling file that provides the desired import.
const provide = `package siblingimporttest
import "local/log"
import "my/bytes"
func LogSomething() {
log.Print("Something")
bytes.SomeFunc()
}
`
// need is the file being tested that needs the import.
const need = `package siblingimporttest
var _ = bytes.Buffer{}
func LogSomethingElse() {
log.Print("Something else")
}
`
// want is the expected result file
const want = `package siblingimporttest
import (
"bytes"
"local/log"
)
var _ = bytes.Buffer{}
func LogSomethingElse() {
log.Print("Something else")
}
`
const pkg = "siblingimporttest"
const siblingFile = pkg + "/needs_import.go"
testConfig{
gopathFiles: map[string]string{
siblingFile: need,
pkg + "/provides_import.go": provide,
},
}.test(t, func(t *goimportTest) {
buf, err := Process(
t.gopath+"/src/"+siblingFile, []byte(need), nil)
if err != nil {
t.Fatal(err)
}
if string(buf) != want {
t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want)
}
})
}
func TestPkgIsCandidate(t *testing.T) {
tests := []struct {
name string
filename string
pkgIdent string
pkg *pkg
want bool
}{
{
name: "normal_match",
filename: "/gopath/src/my/pkg/pkg.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/client",
importPath: "client",
importPathShort: "client",
},
want: true,
},
{
name: "no_match",
filename: "/gopath/src/my/pkg/pkg.go",
pkgIdent: "zzz",
pkg: &pkg{
dir: "/gopath/src/client",
importPath: "client",
importPathShort: "client",
},
want: false,
},
{
name: "match_too_early",
filename: "/gopath/src/my/pkg/pkg.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/client/foo/foo/foo",
importPath: "client/foo/foo",
importPathShort: "client/foo/foo",
},
want: false,
},
{
name: "substring_match",
filename: "/gopath/src/my/pkg/pkg.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/foo/go-client",
importPath: "foo/go-client",
importPathShort: "foo/go-client",
},
want: true,
},
{
name: "hidden_internal",
filename: "/gopath/src/my/pkg/pkg.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/foo/internal/client",
importPath: "foo/internal/client",
importPathShort: "foo/internal/client",
},
want: false,
},
{
name: "visible_internal",
filename: "/gopath/src/foo/bar.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/foo/internal/client",
importPath: "foo/internal/client",
importPathShort: "foo/internal/client",
},
want: true,
},
{
name: "invisible_vendor",
filename: "/gopath/src/foo/bar.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/other/vendor/client",
importPath: "other/vendor/client",
importPathShort: "client",
},
want: false,
},
{
name: "visible_vendor",
filename: "/gopath/src/foo/bar.go",
pkgIdent: "client",
pkg: &pkg{
dir: "/gopath/src/foo/vendor/client",
importPath: "other/foo/client",
importPathShort: "client",
},
want: true,
},
{
name: "match_with_hyphens",
filename: "/gopath/src/foo/bar.go",
pkgIdent: "socketio",
pkg: &pkg{
dir: "/gopath/src/foo/socket-io",
importPath: "foo/socket-io",
importPathShort: "foo/socket-io",
},
want: true,
},
{
name: "match_with_mixed_case",
filename: "/gopath/src/foo/bar.go",
pkgIdent: "fooprod",
pkg: &pkg{
dir: "/gopath/src/foo/FooPROD",
importPath: "foo/FooPROD",
importPathShort: "foo/FooPROD",
},
want: true,
},
{
name: "matches_with_hyphen_and_caps",
filename: "/gopath/src/foo/bar.go",
pkgIdent: "fooprod",
pkg: &pkg{
dir: "/gopath/src/foo/Foo-PROD",
importPath: "foo/Foo-PROD",
importPathShort: "foo/Foo-PROD",
},
want: true,
},
}
for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := pkgIsCandidate(tt.filename, tt.pkgIdent, tt.pkg)
if got != tt.want {
t.Errorf("test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v",
i, tt.filename, tt.pkgIdent, *tt.pkg, got, tt.want)
}
})
}
}
// Issue 20941: this used to panic on Windows.
func TestProcessStdin(t *testing.T) {
got, err := Process("<standard input>", []byte("package main\nfunc main() {\n\tfmt.Println(123)\n}\n"), nil)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(got), `"fmt"`) {
t.Errorf("expected fmt import; got: %s", got)
}
}
// Tests LocalPackagePromotion when there is a local package that matches, it
// should be the closest match.
// https://golang.org/issues/17557
func TestLocalPackagePromotion(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"config.net/config/config.go": "package config\n type SystemConfig struct {}", // Will match but should not be first choice
"mycompany.net/config/config.go": "package config\n type SystemConfig struct {}", // Will match but should not be first choice
"mycompany.net/tool/config/config.go": "package config\n type SystemConfig struct {}", // Local package should be promoted over shorter package
},
}.test(t, func(t *goimportTest) {
const in = "package main\n var c = &config.SystemConfig{}"
const want = `package main
import "mycompany.net/tool/config"
var c = &config.SystemConfig{}
`
got, err := Process(filepath.Join(t.gopath, "src", "mycompany.net/tool/main.go"), []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(got) != want {
t.Errorf("Process = %q; want %q", got, want)
}
})
}
// Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the
// local directory, since the user is likely to import the same packages in the current
// Go file. If an import is found that satisfies the need, it should be used over the
// standard library.
// https://golang.org/issues/17557
func TestFindImportInLocalGoFiles(t *testing.T) {
testConfig{
gopathFiles: map[string]string{
"bytes.net/bytes/bytes.go": "package bytes\n type Buffer struct {}", // Should be selected over standard library
"mycompany.net/tool/io.go": "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored
"mycompany.net/tool/err.go": "package main\n import \"bogus.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains import which is not resolved, so it is ignored
},
}.test(t, func(t *goimportTest) {
const in = "package main\n var _ = &bytes.Buffer{}"
const want = `package main
import "bytes.net/bytes"
var _ = &bytes.Buffer{}
`
got, err := Process(filepath.Join(t.gopath, "src", "mycompany.net/tool/main.go"), []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(got) != want {
t.Errorf("Process = got %q; want %q", got, want)
}
})
}
func TestImportNoGoFiles(t *testing.T) {
testConfig{
gopathFiles: map[string]string{},
}.test(t, func(t *goimportTest) {
const in = "package main\n var _ = &bytes.Buffer{}"
const want = `package main
import "bytes"
var _ = &bytes.Buffer{}
`
got, err := Process(filepath.Join(t.gopath, "src", "mycompany.net/tool/main.go"), []byte(in), nil)
if err != nil {
t.Fatal(err)
}
if string(got) != want {
t.Errorf("Process = got %q; want %q", got, want)
}
})
}
// Ensures a token as large as 500000 bytes can be handled
// https://golang.org/issues/18201
func TestProcessLargeToken(t *testing.T) {
largeString := strings.Repeat("x", 500000)
in := `package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package")
// end
`
out, err := Process("foo", []byte(in), nil)
if err != nil {
t.Errorf("Process returned error.\n got:\n%v\nwant:\nnil", err)
}
want := `package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt.Sprintf("%s", "` + largeString + `")
const x = mypkg.Sprintf("%s", "my package")
// end
`
if got := string(out); got != want {
t.Errorf("Process returned unexpected result.\ngot:\n%.100v\nwant:\n%.100v", got, want)
}
}