diff options
Diffstat (limited to 'go/analysis/analysistest/analysistest.go')
-rw-r--r-- | go/analysis/analysistest/analysistest.go | 96 |
1 files changed, 49 insertions, 47 deletions
diff --git a/go/analysis/analysistest/analysistest.go b/go/analysis/analysistest/analysistest.go index df79a4419..be016e7e9 100644 --- a/go/analysis/analysistest/analysistest.go +++ b/go/analysis/analysistest/analysistest.go @@ -19,14 +19,13 @@ import ( "sort" "strconv" "strings" + "testing" "text/scanner" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/internal/checker" "golang.org/x/tools/go/packages" - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/diff/myers" - "golang.org/x/tools/internal/span" + "golang.org/x/tools/internal/diff" "golang.org/x/tools/internal/testenv" "golang.org/x/tools/txtar" ) @@ -81,23 +80,24 @@ type Testing interface { // Each section in the archive corresponds to a single message. // // A golden file using txtar may look like this: -// -- turn into single negation -- -// package pkg // -// func fn(b1, b2 bool) { -// if !b1 { // want `negating a boolean twice` -// println() -// } -// } +// -- turn into single negation -- +// package pkg // -// -- remove double negation -- -// package pkg +// func fn(b1, b2 bool) { +// if !b1 { // want `negating a boolean twice` +// println() +// } +// } // -// func fn(b1, b2 bool) { -// if b1 { // want `negating a boolean twice` -// println() -// } -// } +// -- remove double negation -- +// package pkg +// +// func fn(b1, b2 bool) { +// if b1 { // want `negating a boolean twice` +// println() +// } +// } func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Result { r := Run(t, dir, a, patterns...) @@ -113,7 +113,7 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns // should match up. for _, act := range r { // file -> message -> edits - fileEdits := make(map[*token.File]map[string][]diff.TextEdit) + fileEdits := make(map[*token.File]map[string][]diff.Edit) fileContents := make(map[*token.File][]byte) // Validate edits, prepare the fileEdits map and read the file contents. @@ -141,17 +141,13 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns } fileContents[file] = contents } - spn, err := span.NewRange(act.Pass.Fset, edit.Pos, edit.End).Span() - if err != nil { - t.Errorf("error converting edit to span %s: %v", file.Name(), err) - } - if _, ok := fileEdits[file]; !ok { - fileEdits[file] = make(map[string][]diff.TextEdit) + fileEdits[file] = make(map[string][]diff.Edit) } - fileEdits[file][sf.Message] = append(fileEdits[file][sf.Message], diff.TextEdit{ - Span: spn, - NewText: string(edit.NewText), + fileEdits[file][sf.Message] = append(fileEdits[file][sf.Message], diff.Edit{ + Start: file.Offset(edit.Pos), + End: file.Offset(edit.End), + New: string(edit.NewText), }) } } @@ -188,23 +184,24 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns for _, vf := range ar.Files { if vf.Name == sf { found = true - out := diff.ApplyEdits(string(orig), edits) + out, err := diff.ApplyBytes(orig, edits) + if err != nil { + t.Errorf("%s: error applying fixes: %v", file.Name(), err) + continue + } // the file may contain multiple trailing // newlines if the user places empty lines // between files in the archive. normalize // this to a single newline. want := string(bytes.TrimRight(vf.Data, "\n")) + "\n" - formatted, err := format.Source([]byte(out)) + formatted, err := format.Source(out) if err != nil { t.Errorf("%s: error formatting edited source: %v\n%s", file.Name(), err, out) continue } - if want != string(formatted) { - d, err := myers.ComputeEdits("", want, string(formatted)) - if err != nil { - t.Errorf("failed to compute suggested fix diff: %v", err) - } - t.Errorf("suggested fixes failed for %s:\n%s", file.Name(), diff.ToUnified(fmt.Sprintf("%s.golden [%s]", file.Name(), sf), "actual", want, d)) + if got := string(formatted); got != want { + unified := diff.Unified(fmt.Sprintf("%s.golden [%s]", file.Name(), sf), "actual", want, got) + t.Errorf("suggested fixes failed for %s:\n%s", file.Name(), unified) } break } @@ -216,25 +213,26 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns } else { // all suggested fixes are represented by a single file - var catchallEdits []diff.TextEdit + var catchallEdits []diff.Edit for _, edits := range fixes { catchallEdits = append(catchallEdits, edits...) } - out := diff.ApplyEdits(string(orig), catchallEdits) + out, err := diff.ApplyBytes(orig, catchallEdits) + if err != nil { + t.Errorf("%s: error applying fixes: %v", file.Name(), err) + continue + } want := string(ar.Comment) - formatted, err := format.Source([]byte(out)) + formatted, err := format.Source(out) if err != nil { t.Errorf("%s: error formatting resulting source: %v\n%s", file.Name(), err, out) continue } - if want != string(formatted) { - d, err := myers.ComputeEdits("", want, string(formatted)) - if err != nil { - t.Errorf("%s: failed to compute suggested fix diff: %s", file.Name(), err) - } - t.Errorf("suggested fixes failed for %s:\n%s", file.Name(), diff.ToUnified(file.Name()+".golden", "actual", want, d)) + if got := string(formatted); got != want { + unified := diff.Unified(file.Name()+".golden", "actual", want, got) + t.Errorf("suggested fixes failed for %s:\n%s", file.Name(), unified) } } } @@ -248,7 +246,8 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns // directory using golang.org/x/tools/go/packages, runs the analysis on // them, and checks that each analysis emits the expected diagnostics // and facts specified by the contents of '// want ...' comments in the -// package's source files. +// package's source files. It treats a comment of the form +// "//...// want..." or "/*...// want... */" as if it starts at 'want' // // An expectation of a Diagnostic is specified by a string literal // containing a regular expression that must match the diagnostic @@ -280,7 +279,7 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns // attempted, even if unsuccessful. It is safe for a test to ignore all // the results, but a test may use it to perform additional checks. func Run(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Result { - if t, ok := t.(testenv.Testing); ok { + if t, ok := t.(testing.TB); ok { testenv.NeedsGoPackages(t) } @@ -316,8 +315,11 @@ func loadPackages(a *analysis.Analyzer, dir string, patterns ...string) ([]*pack // a list of packages we generate and then do the parsing and // typechecking, though this feature seems to be a recurring need. + mode := packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | + packages.NeedTypes | packages.NeedTypesSizes | packages.NeedSyntax | packages.NeedTypesInfo | + packages.NeedDeps cfg := &packages.Config{ - Mode: packages.LoadAllSyntax, + Mode: mode, Dir: dir, Tests: true, Env: append(os.Environ(), "GOPATH="+dir, "GO111MODULE=off", "GOPROXY=off"), |