.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / go / ast / astutil / imports_test.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/ast/astutil/imports_test.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/ast/astutil/imports_test.go
new file mode 100644 (file)
index 0000000..68f05ab
--- /dev/null
@@ -0,0 +1,2100 @@
+// 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 astutil
+
+import (
+       "bytes"
+       "go/ast"
+       "go/format"
+       "go/parser"
+       "go/token"
+       "reflect"
+       "strconv"
+       "testing"
+)
+
+var fset = token.NewFileSet()
+
+func parse(t *testing.T, name, in string) *ast.File {
+       file, err := parser.ParseFile(fset, name, in, parser.ParseComments)
+       if err != nil {
+               t.Fatalf("%s parse: %v", name, err)
+       }
+       return file
+}
+
+func print(t *testing.T, name string, f *ast.File) string {
+       var buf bytes.Buffer
+       if err := format.Node(&buf, fset, f); err != nil {
+               t.Fatalf("%s gofmt: %v", name, err)
+       }
+       return buf.String()
+}
+
+type test struct {
+       name       string
+       renamedPkg string
+       pkg        string
+       in         string
+       out        string
+       unchanged  bool // Expect added/deleted return value to be false.
+}
+
+var addTests = []test{
+       {
+               name: "leave os alone",
+               pkg:  "os",
+               in: `package main
+
+import (
+       "os"
+)
+`,
+               out: `package main
+
+import (
+       "os"
+)
+`,
+               unchanged: true,
+       },
+       {
+               name: "import.1",
+               pkg:  "os",
+               in: `package main
+`,
+               out: `package main
+
+import "os"
+`,
+       },
+       {
+               name: "import.2",
+               pkg:  "os",
+               in: `package main
+
+// Comment
+import "C"
+`,
+               out: `package main
+
+// Comment
+import "C"
+import "os"
+`,
+       },
+       {
+               name: "import.3",
+               pkg:  "os",
+               in: `package main
+
+// Comment
+import "C"
+
+import (
+       "io"
+       "utf8"
+)
+`,
+               out: `package main
+
+// Comment
+import "C"
+
+import (
+       "io"
+       "os"
+       "utf8"
+)
+`,
+       },
+       {
+               name: "import.17",
+               pkg:  "x/y/z",
+               in: `package main
+
+// Comment
+import "C"
+
+import (
+       "a"
+       "b"
+
+       "x/w"
+
+       "d/f"
+)
+`,
+               out: `package main
+
+// Comment
+import "C"
+
+import (
+       "a"
+       "b"
+
+       "x/w"
+       "x/y/z"
+
+       "d/f"
+)
+`,
+       },
+       {
+               name: "issue #19190",
+               pkg:  "x.org/y/z",
+               in: `package main
+
+// Comment
+import "C"
+
+import (
+       "bytes"
+       "os"
+
+       "d.com/f"
+)
+`,
+               out: `package main
+
+// Comment
+import "C"
+
+import (
+       "bytes"
+       "os"
+
+       "d.com/f"
+       "x.org/y/z"
+)
+`,
+       },
+       {
+               name: "issue #19190 with existing grouped import packages",
+               pkg:  "x.org/y/z",
+               in: `package main
+
+// Comment
+import "C"
+
+import (
+       "bytes"
+       "os"
+
+       "c.com/f"
+       "d.com/f"
+
+       "y.com/a"
+       "y.com/b"
+       "y.com/c"
+)
+`,
+               out: `package main
+
+// Comment
+import "C"
+
+import (
+       "bytes"
+       "os"
+
+       "c.com/f"
+       "d.com/f"
+       "x.org/y/z"
+
+       "y.com/a"
+       "y.com/b"
+       "y.com/c"
+)
+`,
+       },
+       {
+               name: "issue #19190 - match score is still respected",
+               pkg:  "y.org/c",
+               in: `package main
+
+import (
+       "x.org/a"
+
+       "y.org/b"
+)
+`,
+               out: `package main
+
+import (
+       "x.org/a"
+
+       "y.org/b"
+       "y.org/c"
+)
+`,
+       },
+       {
+               name: "import into singular group",
+               pkg:  "bytes",
+               in: `package main
+
+import "os"
+
+`,
+               out: `package main
+
+import (
+       "bytes"
+       "os"
+)
+`,
+       },
+       {
+               name: "import into singular group with comment",
+               pkg:  "bytes",
+               in: `package main
+
+import /* why */ /* comment here? */ "os"
+
+`,
+               out: `package main
+
+import /* why */ /* comment here? */ (
+       "bytes"
+       "os"
+)
+`,
+       },
+       {
+               name: "import into group with leading comment",
+               pkg:  "strings",
+               in: `package main
+
+import (
+       // comment before bytes
+       "bytes"
+       "os"
+)
+
+`,
+               out: `package main
+
+import (
+       // comment before bytes
+       "bytes"
+       "os"
+       "strings"
+)
+`,
+       },
+       {
+               name:       "",
+               renamedPkg: "fmtpkg",
+               pkg:        "fmt",
+               in: `package main
+
+import "os"
+
+`,
+               out: `package main
+
+import (
+       fmtpkg "fmt"
+       "os"
+)
+`,
+       },
+       {
+               name: "struct comment",
+               pkg:  "time",
+               in: `package main
+
+// This is a comment before a struct.
+type T struct {
+       t  time.Time
+}
+`,
+               out: `package main
+
+import "time"
+
+// This is a comment before a struct.
+type T struct {
+       t time.Time
+}
+`,
+       },
+       {
+               name: "issue 8729 import C",
+               pkg:  "time",
+               in: `package main
+
+import "C"
+
+// comment
+type T time.Time
+`,
+               out: `package main
+
+import "C"
+import "time"
+
+// comment
+type T time.Time
+`,
+       },
+       {
+               name: "issue 8729 empty import",
+               pkg:  "time",
+               in: `package main
+
+import ()
+
+// comment
+type T time.Time
+`,
+               out: `package main
+
+import "time"
+
+// comment
+type T time.Time
+`,
+       },
+       {
+               name: "issue 8729 comment on package line",
+               pkg:  "time",
+               in: `package main // comment
+
+type T time.Time
+`,
+               out: `package main // comment
+
+import "time"
+
+type T time.Time
+`,
+       },
+       {
+               name: "issue 8729 comment after package",
+               pkg:  "time",
+               in: `package main
+// comment
+
+type T time.Time
+`,
+               out: `package main
+
+import "time"
+
+// comment
+
+type T time.Time
+`,
+       },
+       {
+               name: "issue 8729 comment before and on package line",
+               pkg:  "time",
+               in: `// comment before
+package main // comment on
+
+type T time.Time
+`,
+               out: `// comment before
+package main // comment on
+
+import "time"
+
+type T time.Time
+`,
+       },
+
+       // Issue 9961: Match prefixes using path segments rather than bytes
+       {
+               name: "issue 9961",
+               pkg:  "regexp",
+               in: `package main
+
+import (
+       "flag"
+       "testing"
+
+       "rsc.io/p"
+)
+`,
+               out: `package main
+
+import (
+       "flag"
+       "regexp"
+       "testing"
+
+       "rsc.io/p"
+)
+`,
+       },
+       // Issue 10337: Preserve comment position
+       {
+               name: "issue 10337",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "bytes" // a
+       "log" // c
+)
+`,
+               out: `package main
+
+import (
+       "bytes" // a
+       "fmt"
+       "log" // c
+)
+`,
+       },
+       {
+               name: "issue 10337 new import at the start",
+               pkg:  "bytes",
+               in: `package main
+
+import (
+       "fmt" // b
+       "log" // c
+)
+`,
+               out: `package main
+
+import (
+       "bytes"
+       "fmt" // b
+       "log" // c
+)
+`,
+       },
+       {
+               name: "issue 10337 new import at the end",
+               pkg:  "log",
+               in: `package main
+
+import (
+       "bytes" // a
+       "fmt" // b
+)
+`,
+               out: `package main
+
+import (
+       "bytes" // a
+       "fmt"   // b
+       "log"
+)
+`,
+       },
+       // Issue 14075: Merge import declarations
+       {
+               name: "issue 14075",
+               pkg:  "bufio",
+               in: `package main
+
+import "bytes"
+import "fmt"
+`,
+               out: `package main
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+)
+`,
+       },
+       {
+               name: "issue 14075 update position",
+               pkg:  "bufio",
+               in: `package main
+
+import "bytes"
+import (
+       "fmt"
+)
+`,
+               out: `package main
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+)
+`,
+       },
+       {
+               name: `issue 14075 ignore import "C"`,
+               pkg:  "bufio",
+               in: `package main
+
+// Comment
+import "C"
+
+import "bytes"
+import "fmt"
+`,
+               out: `package main
+
+// Comment
+import "C"
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+)
+`,
+       },
+       {
+               name: `issue 14075 ignore adjacent import "C"`,
+               pkg:  "bufio",
+               in: `package main
+
+// Comment
+import "C"
+import "fmt"
+`,
+               out: `package main
+
+// Comment
+import "C"
+import (
+       "bufio"
+       "fmt"
+)
+`,
+       },
+       {
+               name: `issue 14075 ignore adjacent import "C" (without factored import)`,
+               pkg:  "bufio",
+               in: `package main
+
+// Comment
+import "C"
+import "fmt"
+`,
+               out: `package main
+
+// Comment
+import "C"
+import (
+       "bufio"
+       "fmt"
+)
+`,
+       },
+       {
+               name: `issue 14075 ignore single import "C"`,
+               pkg:  "bufio",
+               in: `package main
+
+// Comment
+import "C"
+`,
+               out: `package main
+
+// Comment
+import "C"
+import "bufio"
+`,
+       },
+       {
+               name: `issue 17212 several single-import lines with shared prefix ending in a slash`,
+               pkg:  "net/http",
+               in: `package main
+
+import "bufio"
+import "net/url"
+`,
+               out: `package main
+
+import (
+       "bufio"
+       "net/http"
+       "net/url"
+)
+`,
+       },
+       {
+               name: `issue 17212 block imports lines with shared prefix ending in a slash`,
+               pkg:  "net/http",
+               in: `package main
+
+import (
+       "bufio"
+       "net/url"
+)
+`,
+               out: `package main
+
+import (
+       "bufio"
+       "net/http"
+       "net/url"
+)
+`,
+       },
+       {
+               name: `issue 17213 many single-import lines`,
+               pkg:  "fmt",
+               in: `package main
+
+import "bufio"
+import "bytes"
+import "errors"
+`,
+               out: `package main
+
+import (
+       "bufio"
+       "bytes"
+       "errors"
+       "fmt"
+)
+`,
+       },
+
+       // Issue 28605: Add specified import, even if that import path is imported under another name
+       {
+               name:       "issue 28605 add unnamed path",
+               renamedPkg: "",
+               pkg:        "path",
+               in: `package main
+
+import (
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+       },
+       {
+               name:       "issue 28605 add pathpkg-renamed path",
+               renamedPkg: "pathpkg",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+       },
+       {
+               name:       "issue 28605 add blank identifier path",
+               renamedPkg: "_",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       . "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+       },
+       {
+               name:       "issue 28605 add dot import path",
+               renamedPkg: ".",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+       },
+
+       {
+               name:       "duplicate import declarations, add existing one",
+               renamedPkg: "f",
+               pkg:        "fmt",
+               in: `package main
+
+import "fmt"
+import "fmt"
+import f "fmt"
+import f "fmt"
+`,
+               out: `package main
+
+import "fmt"
+import "fmt"
+import f "fmt"
+import f "fmt"
+`,
+               unchanged: true,
+       },
+}
+
+func TestAddImport(t *testing.T) {
+       for _, test := range addTests {
+               file := parse(t, test.name, test.in)
+               var before bytes.Buffer
+               ast.Fprint(&before, fset, file, nil)
+               added := AddNamedImport(fset, file, test.renamedPkg, test.pkg)
+               if got := print(t, test.name, file); got != test.out {
+                       t.Errorf("first run: %s:\ngot: %s\nwant: %s", test.name, got, test.out)
+                       var after bytes.Buffer
+                       ast.Fprint(&after, fset, file, nil)
+                       t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String())
+               }
+               if got, want := added, !test.unchanged; got != want {
+                       t.Errorf("first run: %s: added = %v, want %v", test.name, got, want)
+               }
+
+               // AddNamedImport should be idempotent. Verify that by calling it again,
+               // expecting no change to the AST, and the returned added value to always be false.
+               added = AddNamedImport(fset, file, test.renamedPkg, test.pkg)
+               if got := print(t, test.name, file); got != test.out {
+                       t.Errorf("second run: %s:\ngot: %s\nwant: %s", test.name, got, test.out)
+               }
+               if got, want := added, false; got != want {
+                       t.Errorf("second run: %s: added = %v, want %v", test.name, got, want)
+               }
+       }
+}
+
+func TestDoubleAddImport(t *testing.T) {
+       file := parse(t, "doubleimport", "package main\n")
+       AddImport(fset, file, "os")
+       AddImport(fset, file, "bytes")
+       want := `package main
+
+import (
+       "bytes"
+       "os"
+)
+`
+       if got := print(t, "doubleimport", file); got != want {
+               t.Errorf("got: %s\nwant: %s", got, want)
+       }
+}
+
+func TestDoubleAddNamedImport(t *testing.T) {
+       file := parse(t, "doublenamedimport", "package main\n")
+       AddNamedImport(fset, file, "o", "os")
+       AddNamedImport(fset, file, "i", "io")
+       want := `package main
+
+import (
+       i "io"
+       o "os"
+)
+`
+       if got := print(t, "doublenamedimport", file); got != want {
+               t.Errorf("got: %s\nwant: %s", got, want)
+       }
+}
+
+// Part of issue 8729.
+func TestDoubleAddImportWithDeclComment(t *testing.T) {
+       file := parse(t, "doubleimport", `package main
+
+import (
+)
+
+// comment
+type I int
+`)
+       // The AddImport order here matters.
+       AddImport(fset, file, "golang.org/x/tools/go/ast/astutil")
+       AddImport(fset, file, "os")
+       want := `package main
+
+import (
+       "golang.org/x/tools/go/ast/astutil"
+       "os"
+)
+
+// comment
+type I int
+`
+       if got := print(t, "doubleimport_with_decl_comment", file); got != want {
+               t.Errorf("got: %s\nwant: %s", got, want)
+       }
+}
+
+var deleteTests = []test{
+       {
+               name: "import.4",
+               pkg:  "os",
+               in: `package main
+
+import (
+       "os"
+)
+`,
+               out: `package main
+`,
+       },
+       {
+               name: "import.5",
+               pkg:  "os",
+               in: `package main
+
+// Comment
+import "C"
+import "os"
+`,
+               out: `package main
+
+// Comment
+import "C"
+`,
+       },
+       {
+               name: "import.6",
+               pkg:  "os",
+               in: `package main
+
+// Comment
+import "C"
+
+import (
+       "io"
+       "os"
+       "utf8"
+)
+`,
+               out: `package main
+
+// Comment
+import "C"
+
+import (
+       "io"
+       "utf8"
+)
+`,
+       },
+       {
+               name: "import.7",
+               pkg:  "io",
+               in: `package main
+
+import (
+       "io"   // a
+       "os"   // b
+       "utf8" // c
+)
+`,
+               out: `package main
+
+import (
+       // a
+       "os"   // b
+       "utf8" // c
+)
+`,
+       },
+       {
+               name: "import.8",
+               pkg:  "os",
+               in: `package main
+
+import (
+       "io"   // a
+       "os"   // b
+       "utf8" // c
+)
+`,
+               out: `package main
+
+import (
+       "io" // a
+       // b
+       "utf8" // c
+)
+`,
+       },
+       {
+               name: "import.9",
+               pkg:  "utf8",
+               in: `package main
+
+import (
+       "io"   // a
+       "os"   // b
+       "utf8" // c
+)
+`,
+               out: `package main
+
+import (
+       "io" // a
+       "os" // b
+       // c
+)
+`,
+       },
+       {
+               name: "import.10",
+               pkg:  "io",
+               in: `package main
+
+import (
+       "io"
+       "os"
+       "utf8"
+)
+`,
+               out: `package main
+
+import (
+       "os"
+       "utf8"
+)
+`,
+       },
+       {
+               name: "import.11",
+               pkg:  "os",
+               in: `package main
+
+import (
+       "io"
+       "os"
+       "utf8"
+)
+`,
+               out: `package main
+
+import (
+       "io"
+       "utf8"
+)
+`,
+       },
+       {
+               name: "import.12",
+               pkg:  "utf8",
+               in: `package main
+
+import (
+       "io"
+       "os"
+       "utf8"
+)
+`,
+               out: `package main
+
+import (
+       "io"
+       "os"
+)
+`,
+       },
+       {
+               name: "handle.raw.quote.imports",
+               pkg:  "os",
+               in:   "package main\n\nimport `os`",
+               out: `package main
+`,
+       },
+       {
+               name: "import.13",
+               pkg:  "io",
+               in: `package main
+
+import (
+       "fmt"
+
+       "io"
+       "os"
+       "utf8"
+
+       "go/format"
+)
+`,
+               out: `package main
+
+import (
+       "fmt"
+
+       "os"
+       "utf8"
+
+       "go/format"
+)
+`,
+       },
+       {
+               name: "import.14",
+               pkg:  "io",
+               in: `package main
+
+import (
+       "fmt" // a
+
+       "io"   // b
+       "os"   // c
+       "utf8" // d
+
+       "go/format" // e
+)
+`,
+               out: `package main
+
+import (
+       "fmt" // a
+
+       // b
+       "os"   // c
+       "utf8" // d
+
+       "go/format" // e
+)
+`,
+       },
+       {
+               name: "import.15",
+               pkg:  "double",
+               in: `package main
+
+import (
+       "double"
+       "double"
+)
+`,
+               out: `package main
+`,
+       },
+       {
+               name: "import.16",
+               pkg:  "bubble",
+               in: `package main
+
+import (
+       "toil"
+       "bubble"
+       "bubble"
+       "trouble"
+)
+`,
+               out: `package main
+
+import (
+       "toil"
+       "trouble"
+)
+`,
+       },
+       {
+               name: "import.17",
+               pkg:  "quad",
+               in: `package main
+
+import (
+       "quad"
+       "quad"
+)
+
+import (
+       "quad"
+       "quad"
+)
+`,
+               out: `package main
+`,
+       },
+       {
+               name:       "import.18",
+               renamedPkg: "x",
+               pkg:        "fmt",
+               in: `package main
+
+import (
+       "fmt"
+       x "fmt"
+)
+`,
+               out: `package main
+
+import (
+       "fmt"
+)
+`,
+       },
+       {
+               name:       "import.18",
+               renamedPkg: "x",
+               pkg:        "fmt",
+               in: `package main
+
+import x "fmt"
+import y "fmt"
+`,
+               out: `package main
+
+import y "fmt"
+`,
+       },
+       // Issue #15432, #18051
+       {
+               name: "import.19",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt"
+
+       // Some comment.
+       "io"
+)`,
+               out: `package main
+
+import (
+       // Some comment.
+       "io"
+)
+`,
+       },
+       {
+               name: "import.20",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt"
+
+       // Some
+       // comment.
+       "io"
+)`,
+               out: `package main
+
+import (
+       // Some
+       // comment.
+       "io"
+)
+`,
+       },
+       {
+               name: "import.21",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt"
+
+       /*
+               Some
+               comment.
+       */
+       "io"
+)`,
+               out: `package main
+
+import (
+       /*
+               Some
+               comment.
+       */
+       "io"
+)
+`,
+       },
+       {
+               name: "import.22",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       /* Some */
+       // comment.
+       "io"
+       "fmt"
+)`,
+               out: `package main
+
+import (
+       /* Some */
+       // comment.
+       "io"
+)
+`,
+       },
+       {
+               name: "import.23",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       // comment 1
+       "fmt"
+       // comment 2
+       "io"
+)`,
+               out: `package main
+
+import (
+       // comment 2
+       "io"
+)
+`,
+       },
+       {
+               name: "import.24",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt" // comment 1
+       "io" // comment 2
+)`,
+               out: `package main
+
+import (
+       "io" // comment 2
+)
+`,
+       },
+       {
+               name: "import.25",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt"
+       /* comment */ "io"
+)`,
+               out: `package main
+
+import (
+       /* comment */ "io"
+)
+`,
+       },
+       {
+               name: "import.26",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt"
+       "io" /* comment */
+)`,
+               out: `package main
+
+import (
+       "io" /* comment */
+)
+`,
+       },
+       {
+               name: "import.27",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       "fmt" /* comment */
+       "io"
+)`,
+               out: `package main
+
+import (
+       "io"
+)
+`,
+       },
+       {
+               name: "import.28",
+               pkg:  "fmt",
+               in: `package main
+
+import (
+       /* comment */  "fmt"
+       "io"
+)`,
+               out: `package main
+
+import (
+       "io"
+)
+`,
+       },
+       {
+               name: "import.29",
+               pkg:  "fmt",
+               in: `package main
+
+// comment 1
+import (
+       "fmt"
+       "io" // comment 2
+)`,
+               out: `package main
+
+// comment 1
+import (
+       "io" // comment 2
+)
+`,
+       },
+       {
+               name: "import.30",
+               pkg:  "fmt",
+               in: `package main
+
+// comment 1
+import (
+       "fmt" // comment 2
+       "io"
+)`,
+               out: `package main
+
+// comment 1
+import (
+       "io"
+)
+`,
+       },
+       {
+               name: "import.31",
+               pkg:  "fmt",
+               in: `package main
+
+// comment 1
+import (
+       "fmt"
+       /* comment 2 */ "io"
+)`,
+               out: `package main
+
+// comment 1
+import (
+       /* comment 2 */ "io"
+)
+`,
+       },
+       {
+               name:       "import.32",
+               pkg:        "fmt",
+               renamedPkg: "f",
+               in: `package main
+
+// comment 1
+import (
+       f "fmt"
+       /* comment 2 */ i "io"
+)`,
+               out: `package main
+
+// comment 1
+import (
+       /* comment 2 */ i "io"
+)
+`,
+       },
+       {
+               name:       "import.33",
+               pkg:        "fmt",
+               renamedPkg: "f",
+               in: `package main
+
+// comment 1
+import (
+       /* comment 2 */ f "fmt"
+       i "io"
+)`,
+               out: `package main
+
+// comment 1
+import (
+       i "io"
+)
+`,
+       },
+       {
+               name:       "import.34",
+               pkg:        "fmt",
+               renamedPkg: "f",
+               in: `package main
+
+// comment 1
+import (
+       f "fmt" /* comment 2 */
+       i "io"
+)`,
+               out: `package main
+
+// comment 1
+import (
+       i "io"
+)
+`,
+       },
+       {
+               name: "import.35",
+               pkg:  "fmt",
+               in: `package main
+
+// comment 1
+import (
+       "fmt"
+       // comment 2
+       "io"
+)`,
+               out: `package main
+
+// comment 1
+import (
+       // comment 2
+       "io"
+)
+`,
+       },
+       {
+               name: "import.36",
+               pkg:  "fmt",
+               in: `package main
+
+/* comment 1 */
+import (
+       "fmt"
+       /* comment 2 */
+       "io"
+)`,
+               out: `package main
+
+/* comment 1 */
+import (
+       /* comment 2 */
+       "io"
+)
+`,
+       },
+
+       // Issue 20229: MergeLine panic on weird input
+       {
+               name: "import.37",
+               pkg:  "io",
+               in: `package main
+import("_"
+"io")`,
+               out: `package main
+
+import (
+       "_"
+)
+`,
+       },
+
+       // Issue 28605: Delete specified import, even if that import path is imported under another name
+       {
+               name:       "import.38",
+               renamedPkg: "",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+       },
+       {
+               name:       "import.39",
+               renamedPkg: "pathpkg",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+)
+`,
+       },
+       {
+               name:       "import.40",
+               renamedPkg: "_",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       . "path"
+       pathpkg "path"
+)
+`,
+       },
+       {
+               name:       "import.41",
+               renamedPkg: ".",
+               pkg:        "path",
+               in: `package main
+
+import (
+       "path"
+       . "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+               out: `package main
+
+import (
+       "path"
+       _ "path"
+       pathpkg "path"
+)
+`,
+       },
+
+       // Duplicate import declarations, all matching ones are deleted.
+       {
+               name:       "import.42",
+               renamedPkg: "f",
+               pkg:        "fmt",
+               in: `package main
+
+import "fmt"
+import "fmt"
+import f "fmt"
+import f "fmt"
+`,
+               out: `package main
+
+import "fmt"
+import "fmt"
+`,
+       },
+       {
+               name:       "import.43",
+               renamedPkg: "x",
+               pkg:        "fmt",
+               in: `package main
+
+import "fmt"
+import "fmt"
+import f "fmt"
+import f "fmt"
+`,
+               out: `package main
+
+import "fmt"
+import "fmt"
+import f "fmt"
+import f "fmt"
+`,
+               unchanged: true,
+       },
+}
+
+func TestDeleteImport(t *testing.T) {
+       for _, test := range deleteTests {
+               file := parse(t, test.name, test.in)
+               var before bytes.Buffer
+               ast.Fprint(&before, fset, file, nil)
+               deleted := DeleteNamedImport(fset, file, test.renamedPkg, test.pkg)
+               if got := print(t, test.name, file); got != test.out {
+                       t.Errorf("first run: %s:\ngot: %s\nwant: %s", test.name, got, test.out)
+                       var after bytes.Buffer
+                       ast.Fprint(&after, fset, file, nil)
+                       t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String())
+               }
+               if got, want := deleted, !test.unchanged; got != want {
+                       t.Errorf("first run: %s: deleted = %v, want %v", test.name, got, want)
+               }
+
+               // DeleteNamedImport should be idempotent. Verify that by calling it again,
+               // expecting no change to the AST, and the returned deleted value to always be false.
+               deleted = DeleteNamedImport(fset, file, test.renamedPkg, test.pkg)
+               if got := print(t, test.name, file); got != test.out {
+                       t.Errorf("second run: %s:\ngot: %s\nwant: %s", test.name, got, test.out)
+               }
+               if got, want := deleted, false; got != want {
+                       t.Errorf("second run: %s: deleted = %v, want %v", test.name, got, want)
+               }
+       }
+}
+
+func TestDeleteImportAfterAddImport(t *testing.T) {
+       file := parse(t, "test", `package main
+
+import "os"
+`)
+       if got, want := AddImport(fset, file, "fmt"), true; got != want {
+               t.Errorf("AddImport: got: %v, want: %v", got, want)
+       }
+       if got, want := DeleteImport(fset, file, "fmt"), true; got != want {
+               t.Errorf("DeleteImport: got: %v, want: %v", got, want)
+       }
+}
+
+type rewriteTest struct {
+       name   string
+       srcPkg string
+       dstPkg string
+       in     string
+       out    string
+}
+
+var rewriteTests = []rewriteTest{
+       {
+               name:   "import.13",
+               srcPkg: "utf8",
+               dstPkg: "encoding/utf8",
+               in: `package main
+
+import (
+       "io"
+       "os"
+       "utf8" // thanks ken
+)
+`,
+               out: `package main
+
+import (
+       "encoding/utf8" // thanks ken
+       "io"
+       "os"
+)
+`,
+       },
+       {
+               name:   "import.14",
+               srcPkg: "asn1",
+               dstPkg: "encoding/asn1",
+               in: `package main
+
+import (
+       "asn1"
+       "crypto"
+       "crypto/rsa"
+       _ "crypto/sha1"
+       "crypto/x509"
+       "crypto/x509/pkix"
+       "time"
+)
+
+var x = 1
+`,
+               out: `package main
+
+import (
+       "crypto"
+       "crypto/rsa"
+       _ "crypto/sha1"
+       "crypto/x509"
+       "crypto/x509/pkix"
+       "encoding/asn1"
+       "time"
+)
+
+var x = 1
+`,
+       },
+       {
+               name:   "import.15",
+               srcPkg: "url",
+               dstPkg: "net/url",
+               in: `package main
+
+import (
+       "bufio"
+       "net"
+       "path"
+       "url"
+)
+
+var x = 1 // comment on x, not on url
+`,
+               out: `package main
+
+import (
+       "bufio"
+       "net"
+       "net/url"
+       "path"
+)
+
+var x = 1 // comment on x, not on url
+`,
+       },
+       {
+               name:   "import.16",
+               srcPkg: "http",
+               dstPkg: "net/http",
+               in: `package main
+
+import (
+       "flag"
+       "http"
+       "log"
+       "text/template"
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+`,
+               out: `package main
+
+import (
+       "flag"
+       "log"
+       "net/http"
+       "text/template"
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+`,
+       },
+}
+
+func TestRewriteImport(t *testing.T) {
+       for _, test := range rewriteTests {
+               file := parse(t, test.name, test.in)
+               RewriteImport(fset, file, test.srcPkg, test.dstPkg)
+               if got := print(t, test.name, file); got != test.out {
+                       t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)
+               }
+       }
+}
+
+var importsTests = []struct {
+       name string
+       in   string
+       want [][]string
+}{
+       {
+               name: "no packages",
+               in: `package foo
+`,
+               want: nil,
+       },
+       {
+               name: "one group",
+               in: `package foo
+
+import (
+       "fmt"
+       "testing"
+)
+`,
+               want: [][]string{{"fmt", "testing"}},
+       },
+       {
+               name: "four groups",
+               in: `package foo
+
+import "C"
+import (
+       "fmt"
+       "testing"
+
+       "appengine"
+
+       "myproject/mylib1"
+       "myproject/mylib2"
+)
+`,
+               want: [][]string{
+                       {"C"},
+                       {"fmt", "testing"},
+                       {"appengine"},
+                       {"myproject/mylib1", "myproject/mylib2"},
+               },
+       },
+       {
+               name: "multiple factored groups",
+               in: `package foo
+
+import (
+       "fmt"
+       "testing"
+
+       "appengine"
+)
+import (
+       "reflect"
+
+       "bytes"
+)
+`,
+               want: [][]string{
+                       {"fmt", "testing"},
+                       {"appengine"},
+                       {"reflect"},
+                       {"bytes"},
+               },
+       },
+}
+
+func unquote(s string) string {
+       res, err := strconv.Unquote(s)
+       if err != nil {
+               return "could_not_unquote"
+       }
+       return res
+}
+
+func TestImports(t *testing.T) {
+       fset := token.NewFileSet()
+       for _, test := range importsTests {
+               f, err := parser.ParseFile(fset, "test.go", test.in, 0)
+               if err != nil {
+                       t.Errorf("%s: %v", test.name, err)
+                       continue
+               }
+               var got [][]string
+               for _, group := range Imports(fset, f) {
+                       var b []string
+                       for _, spec := range group {
+                               b = append(b, unquote(spec.Path.Value))
+                       }
+                       got = append(got, b)
+               }
+               if !reflect.DeepEqual(got, test.want) {
+                       t.Errorf("Imports(%s)=%v, want %v", test.name, got, test.want)
+               }
+       }
+}
+
+var usesImportTests = []struct {
+       name string
+       path string
+       in   string
+       want bool
+}{
+       {
+               name: "no packages",
+               path: "io",
+               in: `package foo
+`,
+               want: false,
+       },
+       {
+               name: "import.1",
+               path: "io",
+               in: `package foo
+
+import "io"
+
+var _ io.Writer
+`,
+               want: true,
+       },
+       {
+               name: "import.2",
+               path: "io",
+               in: `package foo
+
+import "io"
+`,
+               want: false,
+       },
+       {
+               name: "import.3",
+               path: "io",
+               in: `package foo
+
+import "io"
+
+var io = 42
+`,
+               want: false,
+       },
+       {
+               name: "import.4",
+               path: "io",
+               in: `package foo
+
+import i "io"
+
+var _ i.Writer
+`,
+               want: true,
+       },
+       {
+               name: "import.5",
+               path: "io",
+               in: `package foo
+
+import i "io"
+`,
+               want: false,
+       },
+       {
+               name: "import.6",
+               path: "io",
+               in: `package foo
+
+import i "io"
+
+var i = 42
+var io = 42
+`,
+               want: false,
+       },
+       {
+               name: "import.7",
+               path: "encoding/json",
+               in: `package foo
+
+import "encoding/json"
+
+var _ json.Encoder
+`,
+               want: true,
+       },
+       {
+               name: "import.8",
+               path: "encoding/json",
+               in: `package foo
+
+import "encoding/json"
+`,
+               want: false,
+       },
+       {
+               name: "import.9",
+               path: "encoding/json",
+               in: `package foo
+
+import "encoding/json"
+
+var json = 42
+`,
+               want: false,
+       },
+       {
+               name: "import.10",
+               path: "encoding/json",
+               in: `package foo
+
+import j "encoding/json"
+
+var _ j.Encoder
+`,
+               want: true,
+       },
+       {
+               name: "import.11",
+               path: "encoding/json",
+               in: `package foo
+
+import j "encoding/json"
+`,
+               want: false,
+       },
+       {
+               name: "import.12",
+               path: "encoding/json",
+               in: `package foo
+
+import j "encoding/json"
+
+var j = 42
+var json = 42
+`,
+               want: false,
+       },
+       {
+               name: "import.13",
+               path: "io",
+               in: `package foo
+
+import _ "io"
+`,
+               want: true,
+       },
+       {
+               name: "import.14",
+               path: "io",
+               in: `package foo
+
+import . "io"
+`,
+               want: true,
+       },
+}
+
+func TestUsesImport(t *testing.T) {
+       fset := token.NewFileSet()
+       for _, test := range usesImportTests {
+               f, err := parser.ParseFile(fset, "test.go", test.in, 0)
+               if err != nil {
+                       t.Errorf("%s: %v", test.name, err)
+                       continue
+               }
+               got := UsesImport(f, test.path)
+               if got != test.want {
+                       t.Errorf("UsesImport(%s)=%v, want %v", test.name, got, test.want)
+               }
+       }
+}