whatcanGOwrong

This commit is contained in:
2024-09-19 21:38:24 -04:00
commit d0ae4d841d
17908 changed files with 4096831 additions and 0 deletions
@@ -0,0 +1,92 @@
// Copyright 2024 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.
// The drivertest package provides a fake implementation of the go/packages
// driver protocol that delegates to the go list driver. It may be used to test
// programs such as gopls that specialize behavior when a go/packages driver is
// in use.
//
// The driver is run as a child of the current process, by calling [RunIfChild]
// at process start, and running go/packages with the environment variables set
// by [Env].
package drivertest
import (
"encoding/json"
"flag"
"log"
"os"
"golang.org/x/tools/go/packages"
)
const runAsDriverEnv = "DRIVERTEST_RUN_AS_DRIVER"
// RunIfChild runs the current process as a go/packages driver, if configured
// to do so by the current environment (see [Env]).
//
// Otherwise, RunIfChild is a no op.
func RunIfChild() {
if os.Getenv(runAsDriverEnv) != "" {
main()
os.Exit(0)
}
}
// Env returns additional environment variables for use in [packages.Config]
// to enable the use of drivertest as the driver.
//
// t abstracts a *testing.T or log.Default().
func Env(t interface{ Fatal(...any) }) []string {
exe, err := os.Executable()
if err != nil {
t.Fatal(err)
}
return []string{"GOPACKAGESDRIVER=" + exe, runAsDriverEnv + "=1"}
}
func main() {
flag.Parse()
dec := json.NewDecoder(os.Stdin)
var request packages.DriverRequest
if err := dec.Decode(&request); err != nil {
log.Fatalf("decoding request: %v", err)
}
config := packages.Config{
Mode: request.Mode,
Env: append(request.Env, "GOPACKAGESDRIVER=off"), // avoid recursive invocation
BuildFlags: request.BuildFlags,
Tests: request.Tests,
Overlay: request.Overlay,
}
pkgs, err := packages.Load(&config, flag.Args()...)
if err != nil {
log.Fatalf("load failed: %v", err)
}
var roots []string
for _, pkg := range pkgs {
roots = append(roots, pkg.ID)
}
var allPackages []*packages.Package
packages.Visit(pkgs, nil, func(pkg *packages.Package) {
newImports := make(map[string]*packages.Package)
for path, imp := range pkg.Imports {
newImports[path] = &packages.Package{ID: imp.ID}
}
pkg.Imports = newImports
allPackages = append(allPackages, pkg)
})
enc := json.NewEncoder(os.Stdout)
response := packages.DriverResponse{
Roots: roots,
Packages: allPackages,
}
if err := enc.Encode(response); err != nil {
log.Fatalf("encoding response: %v", err)
}
}
@@ -0,0 +1,146 @@
// Copyright 2024 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 drivertest_test
// This file is both a test of drivertest and an example of how to use it in your own tests.
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/diff"
"golang.org/x/tools/internal/diff/myers"
"golang.org/x/tools/internal/drivertest"
"golang.org/x/tools/internal/packagesinternal"
"golang.org/x/tools/internal/testfiles"
"golang.org/x/tools/txtar"
)
func TestMain(m *testing.M) {
drivertest.RunIfChild()
os.Exit(m.Run())
}
func TestDriverConformance(t *testing.T) {
const workspace = `
-- go.mod --
module example.com/m
go 1.20
-- m.go --
package m
-- lib/lib.go --
package lib
`
dir := testfiles.ExtractTxtarToTmp(t, txtar.Parse([]byte(workspace)))
// TODO(rfindley): on mac, this is required to fix symlink path mismatches.
// But why? Where is the symlink being evaluated in go/packages?
dir, err := filepath.EvalSymlinks(dir)
if err != nil {
t.Fatal(err)
}
baseConfig := packages.Config{
Dir: dir,
Mode: packages.NeedName |
packages.NeedFiles |
packages.NeedCompiledGoFiles |
packages.NeedImports |
packages.NeedDeps |
packages.NeedTypesSizes |
packages.NeedModule |
packages.NeedEmbedFiles |
packages.LoadMode(packagesinternal.DepsErrors) |
packages.LoadMode(packagesinternal.ForTest),
}
tests := []struct {
name string
query string
overlay string
}{
{
name: "load all",
query: "./...",
},
{
name: "overlays",
query: "./...",
overlay: `
-- m.go --
package m
import . "lib"
-- a/a.go --
package a
`,
},
{
name: "std",
query: "std",
},
{
name: "builtin",
query: "builtin",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cfg := baseConfig
if test.overlay != "" {
cfg.Overlay = make(map[string][]byte)
for _, file := range txtar.Parse([]byte(test.overlay)).Files {
name := filepath.Join(dir, filepath.FromSlash(file.Name))
cfg.Overlay[name] = file.Data
}
}
// Compare JSON-encoded packages with and without GOPACKAGESDRIVER.
//
// Note that this does not guarantee that the go/packages results
// themselves are equivalent, only that their encoded JSON is equivalent.
// Certain fields such as Module are intentionally omitted from external
// drivers, because they don't make sense for an arbitrary build system.
var jsons []string
for _, env := range [][]string{
{"GOPACKAGESDRIVER=off"},
drivertest.Env(t),
} {
cfg.Env = append(os.Environ(), env...)
pkgs, err := packages.Load(&cfg, test.query)
if err != nil {
t.Fatalf("failed to load (env: %v): %v", env, err)
}
data, err := json.MarshalIndent(pkgs, "", "\t")
if err != nil {
t.Fatalf("failed to marshal (env: %v): %v", env, err)
}
jsons = append(jsons, string(data))
}
listJSON := jsons[0]
driverJSON := jsons[1]
// Use the myers package for better line diffs.
edits := myers.ComputeEdits(listJSON, driverJSON)
d, err := diff.ToUnified("go list", "driver", listJSON, edits, 0)
if err != nil {
t.Fatal(err)
}
if d != "" {
t.Errorf("mismatching JSON:\n%s", d)
}
})
}
}