blob: 2a383e467b77856525f1ace42fd83fb6df21e140 [file] [log] [blame]
// 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,
},
// this test panics without PositionFor in DeleteNamedImport
{
name: "import.44",
pkg: "foo.com/other/v3",
renamedPkg: "",
in: `package main
//line mah.go:600
import (
"foo.com/a.thing"
"foo.com/surprise"
"foo.com/v1"
"foo.com/other/v2"
"foo.com/other/v3"
)
`,
out: `package main
//line mah.go:600
import (
"foo.com/a.thing"
"foo.com/other/v2"
"foo.com/surprise"
"foo.com/v1"
)
`,
},
}
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)
}
}
}