| // 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/drivertest" | |
| "golang.org/x/tools/internal/packagesinternal" | |
| "golang.org/x/tools/internal/testenv" | |
| "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) { | |
| testenv.NeedsExec(t) | |
| const workspace = ` | |
| -- go.mod -- | |
| module example.com/m | |
| go 1.20 | |
| -- m.go -- | |
| package m | |
| -- lib/lib.go -- | |
| package lib | |
| ` | |
| fs, err := txtar.FS(txtar.Parse([]byte(workspace))) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| dir := testfiles.CopyToTmp(t, fs) | |
| // 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.NeedForTest, | |
| } | |
| 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] | |
| edits := diff.Lines(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) | |
| } | |
| }) | |
| } | |
| } |