mirror of https://github.com/golang/go.git
189 lines
4.8 KiB
Go
189 lines
4.8 KiB
Go
// Copyright 2015 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.
|
|
|
|
// Incomplete std lib sources on Android.
|
|
|
|
//go:build !android
|
|
// +build !android
|
|
|
|
package importgraph_test
|
|
|
|
import (
|
|
"fmt"
|
|
"go/build"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/tools/go/packages/packagestest"
|
|
"golang.org/x/tools/refactor/importgraph"
|
|
|
|
_ "crypto/hmac" // just for test, below
|
|
)
|
|
|
|
const this = "golang.org/x/tools/refactor/importgraph"
|
|
|
|
func TestBuild(t *testing.T) {
|
|
exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{
|
|
{Name: "golang.org/x/tools/refactor/importgraph", Files: packagestest.MustCopyFileTree(".")}})
|
|
defer exported.Cleanup()
|
|
|
|
var gopath string
|
|
for _, env := range exported.Config.Env {
|
|
eq := strings.Index(env, "=")
|
|
if eq == 0 {
|
|
// We sometimes see keys with a single leading "=" in the environment on Windows.
|
|
// TODO(#49886): What is the correct way to parse them in general?
|
|
eq = strings.Index(env[1:], "=") + 1
|
|
}
|
|
if eq < 0 {
|
|
t.Fatalf("invalid variable in exported.Config.Env: %q", env)
|
|
}
|
|
k := env[:eq]
|
|
v := env[eq+1:]
|
|
if k == "GOPATH" {
|
|
gopath = v
|
|
}
|
|
|
|
if os.Getenv(k) == v {
|
|
continue
|
|
}
|
|
defer func(prev string, prevOK bool) {
|
|
if !prevOK {
|
|
if err := os.Unsetenv(k); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
} else {
|
|
if err := os.Setenv(k, prev); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}(os.LookupEnv(k))
|
|
|
|
if err := os.Setenv(k, v); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Logf("%s=%s", k, v)
|
|
}
|
|
if gopath == "" {
|
|
t.Fatal("Failed to fish GOPATH out of env: ", exported.Config.Env)
|
|
}
|
|
|
|
var buildContext = build.Default
|
|
buildContext.GOPATH = gopath
|
|
buildContext.Dir = exported.Config.Dir
|
|
|
|
forward, reverse, errs := importgraph.Build(&buildContext)
|
|
for path, err := range errs {
|
|
t.Errorf("%s: %s", path, err)
|
|
}
|
|
if t.Failed() {
|
|
return
|
|
}
|
|
|
|
// Log the complete graph before the errors, so that the errors are near the
|
|
// end of the log (where we expect them to be).
|
|
nodePrinted := map[string]bool{}
|
|
printNode := func(direction string, from string) {
|
|
key := fmt.Sprintf("%s[%q]", direction, from)
|
|
if nodePrinted[key] {
|
|
return
|
|
}
|
|
nodePrinted[key] = true
|
|
|
|
var g importgraph.Graph
|
|
switch direction {
|
|
case "forward":
|
|
g = forward
|
|
case "reverse":
|
|
g = reverse
|
|
default:
|
|
t.Helper()
|
|
t.Fatalf("bad direction: %q", direction)
|
|
}
|
|
|
|
t.Log(key)
|
|
var pkgs []string
|
|
for pkg := range g[from] {
|
|
pkgs = append(pkgs, pkg)
|
|
}
|
|
sort.Strings(pkgs)
|
|
for _, pkg := range pkgs {
|
|
t.Logf("\t%s", pkg)
|
|
}
|
|
}
|
|
|
|
if testing.Verbose() {
|
|
printNode("forward", this)
|
|
printNode("reverse", this)
|
|
}
|
|
|
|
// Test direct edges.
|
|
// We throw in crypto/hmac to prove that external test files
|
|
// (such as this one) are inspected.
|
|
for _, p := range []string{"go/build", "testing", "crypto/hmac"} {
|
|
if !forward[this][p] {
|
|
printNode("forward", this)
|
|
t.Errorf("forward[%q][%q] not found", this, p)
|
|
}
|
|
if !reverse[p][this] {
|
|
printNode("reverse", p)
|
|
t.Errorf("reverse[%q][%q] not found", p, this)
|
|
}
|
|
}
|
|
|
|
// Test non-existent direct edges
|
|
for _, p := range []string{"errors", "reflect"} {
|
|
if forward[this][p] {
|
|
printNode("forward", this)
|
|
t.Errorf("unexpected: forward[%q][%q] found", this, p)
|
|
}
|
|
if reverse[p][this] {
|
|
printNode("reverse", p)
|
|
t.Errorf("unexpected: reverse[%q][%q] found", p, this)
|
|
}
|
|
}
|
|
|
|
// Test Search is reflexive.
|
|
if !forward.Search(this)[this] {
|
|
printNode("forward", this)
|
|
t.Errorf("irreflexive: forward.Search(importgraph)[importgraph] not found")
|
|
}
|
|
if !reverse.Search(this)[this] {
|
|
printNode("reverse", this)
|
|
t.Errorf("irrefexive: reverse.Search(importgraph)[importgraph] not found")
|
|
}
|
|
|
|
// Test Search is transitive. (There is no direct edge to these packages.)
|
|
for _, p := range []string{"errors", "reflect", "unsafe"} {
|
|
if !forward.Search(this)[p] {
|
|
printNode("forward", this)
|
|
t.Errorf("intransitive: forward.Search(importgraph)[%s] not found", p)
|
|
}
|
|
if !reverse.Search(p)[this] {
|
|
printNode("reverse", p)
|
|
t.Errorf("intransitive: reverse.Search(%s)[importgraph] not found", p)
|
|
}
|
|
}
|
|
|
|
// Test strongly-connected components. Because A's external
|
|
// test package can depend on B, and vice versa, most of the
|
|
// standard libraries are mutually dependent when their external
|
|
// tests are considered.
|
|
//
|
|
// For any nodes x, y in the same SCC, y appears in the results
|
|
// of both forward and reverse searches starting from x
|
|
if !forward.Search("fmt")["io"] ||
|
|
!forward.Search("io")["fmt"] ||
|
|
!reverse.Search("fmt")["io"] ||
|
|
!reverse.Search("io")["fmt"] {
|
|
printNode("forward", "fmt")
|
|
printNode("forward", "io")
|
|
printNode("reverse", "fmt")
|
|
printNode("reverse", "io")
|
|
t.Errorf("fmt and io are not mutually reachable despite being in the same SCC")
|
|
}
|
|
}
|