toolsgolang.org/x/tools/go/analysis/analysistest Index | Files

package analysistest

import "golang.org/x/tools/go/analysis/analysistest"

Package analysistest provides utilities for testing analyzers.

Index

Variables

var TestData = func() string {
	testdata, err := filepath.Abs("testdata")
	if err != nil {
		log.Fatal(err)
	}
	return testdata
}

TestData returns the effective filename of the program's "testdata" directory. This function may be overridden by projects using an alternative build system (such as Blaze) that does not run a test in its package directory.

Functions

func WriteFiles

func WriteFiles(filemap map[string]string) (dir string, cleanup func(), err error)

WriteFiles is a helper function that creates a temporary directory and populates it with a GOPATH-style project using filemap (which maps file names to contents). On success it returns the name of the directory and a cleanup function to delete it.

TODO(adonovan): provide a newer version that accepts a testing.T, calls T.TempDir, and calls T.Fatal on any error, avoiding the need to return cleanup or err:

func WriteFilesToTmp(t *testing.T filemap map[string]string) string

Types

type Result

type Result struct {
	Action *checker.Action

	// legacy fields
	Facts       map[types.Object][]analysis.Fact // nil key => package fact
	Pass        *analysis.Pass
	Diagnostics []analysis.Diagnostic // see Action.Diagnostics
	Result      any                   // see Action.Result
	Err         error                 // see Action.Err
}

A Result holds the result of applying an analyzer to a package.

Facts contains only facts associated with the package and its objects.

This internal type was inadvertently and regrettably exposed through a public type alias. It is essentially redundant with checker.Action, but must be retained for compatibility. Clients may access the public fields of the Pass but must not invoke any of its "verbs", since the pass is already complete.

func Run

func Run(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Result

Run applies an analysis to the packages denoted by the "go list" patterns.

It loads the packages from the specified 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. It treats a comment of the form "//...// want..." or "/*...// want... */" as if it starts at 'want'.

If the directory contains a go.mod file, Run treats it as the root of the Go module in which to work. Otherwise, Run treats it as the root of a GOPATH-style tree, with package contained in the src subdirectory.

An expectation of a Diagnostic is specified by a string literal containing a regular expression that must match the diagnostic message. For example:

fmt.Printf("%s", 1) // want `cannot provide int 1 to %s`

An expectation of a Fact associated with an object is specified by 'name:"pattern"', where name is the name of the object, which must be declared on the same line as the comment, and pattern is a regular expression that must match the string representation of the fact, fmt.Sprint(fact). For example:

func panicf(format string, args interface{}) { // want panicf:"printfWrapper"

Package facts are specified by the name "package" and appear on line 1 of the first source file of the package.

A single 'want' comment may contain a mixture of diagnostic and fact expectations, including multiple facts about the same object:

// want "diag" "diag2" x:"fact1" x:"fact2" y:"fact3"

Unexpected diagnostics and facts, and unmatched expectations, are reported as errors to the Testing.

Run reports an error to the Testing if loading or analysis failed. Run also returns a Result for each package for which analysis was 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 RunWithSuggestedFixes

func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Result

RunWithSuggestedFixes behaves like Run, but additionally applies suggested fixes and verifies their output.

It uses golden files, placed alongside each source file, to express the desired output: the expected transformation of file example.go is specified in file example.go.golden.

Golden files may be of two forms: a plain Go source file, or a txtar archive.

A plain Go source file indicates the expected result of applying all suggested fixes to the original file.

A txtar archive specifies, in each section, the expected result of applying all suggested fixes of a given message to the original file; the name of the archive section is the fix's message. In this way, the various alternative fixes offered by a single diagnostic can be tested independently. Here's an example:

-- turn into single negation --
package pkg

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()
	}
}

Conflicts

Regardless of the form of the golden file, it is possible for multiple fixes to conflict, either because they overlap, or are close enough together that the particular diff algorithm cannot separate them.

RunWithSuggestedFixes uses a simple three-way merge to accumulate fixes, similar to a git merge. The merge algorithm may be able to coalesce identical edits, for example duplicate imports of the same package. (Bear in mind that this is an editorial decision. In general, coalescing identical edits may not be correct: consider two statements that increment the same counter.)

If there are conflicts, the test fails. In any case, the non-conflicting edits will be compared against the expected output. In this situation, we recommend that you increase the textual separation between conflicting parts or, if that fails, split your tests into smaller parts.

If a diagnostic offers multiple fixes for the same problem, they are almost certain to conflict, so in this case you should define the expected output using a multi-section txtar file as described above.

type Testing

type Testing interface {
	Errorf(format string, args ...any)
}

Testing is an abstraction of a *testing.T.

Source Files

analysistest.go

Version
v0.31.0 (latest)
Published
Mar 5, 2025
Platform
linux/amd64
Imports
24 packages
Last checked
6 hours ago

Tools for package owners.