1
2
3
4
5
6
7
8
9
10 package importgraph_test
11
12 import (
13 "fmt"
14 "go/build"
15 "os"
16 "sort"
17 "strings"
18 "testing"
19
20 "golang.org/x/tools/go/packages/packagestest"
21 "golang.org/x/tools/refactor/importgraph"
22
23 _ "crypto/hmac"
24 )
25
26 const this = "golang.org/x/tools/refactor/importgraph"
27
28 func TestBuild(t *testing.T) {
29 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{
30 {Name: "golang.org/x/tools/refactor/importgraph", Files: packagestest.MustCopyFileTree(".")}})
31 defer exported.Cleanup()
32
33 var gopath string
34 for _, env := range exported.Config.Env {
35 eq := strings.Index(env, "=")
36 if eq == 0 {
37
38
39 eq = strings.Index(env[1:], "=") + 1
40 }
41 if eq < 0 {
42 t.Fatalf("invalid variable in exported.Config.Env: %q", env)
43 }
44 k := env[:eq]
45 v := env[eq+1:]
46 if k == "GOPATH" {
47 gopath = v
48 }
49
50 if os.Getenv(k) == v {
51 continue
52 }
53 defer func(prev string, prevOK bool) {
54 if !prevOK {
55 if err := os.Unsetenv(k); err != nil {
56 t.Fatal(err)
57 }
58 } else {
59 if err := os.Setenv(k, prev); err != nil {
60 t.Fatal(err)
61 }
62 }
63 }(os.LookupEnv(k))
64
65 if err := os.Setenv(k, v); err != nil {
66 t.Fatal(err)
67 }
68 t.Logf("%s=%s", k, v)
69 }
70 if gopath == "" {
71 t.Fatal("Failed to fish GOPATH out of env: ", exported.Config.Env)
72 }
73
74 var buildContext = build.Default
75 buildContext.GOPATH = gopath
76 buildContext.Dir = exported.Config.Dir
77
78 forward, reverse, errs := importgraph.Build(&buildContext)
79 for path, err := range errs {
80 t.Errorf("%s: %s", path, err)
81 }
82 if t.Failed() {
83 return
84 }
85
86
87
88 nodePrinted := map[string]bool{}
89 printNode := func(direction string, from string) {
90 key := fmt.Sprintf("%s[%q]", direction, from)
91 if nodePrinted[key] {
92 return
93 }
94 nodePrinted[key] = true
95
96 var g importgraph.Graph
97 switch direction {
98 case "forward":
99 g = forward
100 case "reverse":
101 g = reverse
102 default:
103 t.Helper()
104 t.Fatalf("bad direction: %q", direction)
105 }
106
107 t.Log(key)
108 var pkgs []string
109 for pkg := range g[from] {
110 pkgs = append(pkgs, pkg)
111 }
112 sort.Strings(pkgs)
113 for _, pkg := range pkgs {
114 t.Logf("\t%s", pkg)
115 }
116 }
117
118 if testing.Verbose() {
119 printNode("forward", this)
120 printNode("reverse", this)
121 }
122
123
124
125
126 for _, p := range []string{"go/build", "testing", "crypto/hmac"} {
127 if !forward[this][p] {
128 printNode("forward", this)
129 t.Errorf("forward[%q][%q] not found", this, p)
130 }
131 if !reverse[p][this] {
132 printNode("reverse", p)
133 t.Errorf("reverse[%q][%q] not found", p, this)
134 }
135 }
136
137
138 for _, p := range []string{"errors", "reflect"} {
139 if forward[this][p] {
140 printNode("forward", this)
141 t.Errorf("unexpected: forward[%q][%q] found", this, p)
142 }
143 if reverse[p][this] {
144 printNode("reverse", p)
145 t.Errorf("unexpected: reverse[%q][%q] found", p, this)
146 }
147 }
148
149
150 if !forward.Search(this)[this] {
151 printNode("forward", this)
152 t.Errorf("irreflexive: forward.Search(importgraph)[importgraph] not found")
153 }
154 if !reverse.Search(this)[this] {
155 printNode("reverse", this)
156 t.Errorf("irrefexive: reverse.Search(importgraph)[importgraph] not found")
157 }
158
159
160 for _, p := range []string{"errors", "reflect", "unsafe"} {
161 if !forward.Search(this)[p] {
162 printNode("forward", this)
163 t.Errorf("intransitive: forward.Search(importgraph)[%s] not found", p)
164 }
165 if !reverse.Search(p)[this] {
166 printNode("reverse", p)
167 t.Errorf("intransitive: reverse.Search(%s)[importgraph] not found", p)
168 }
169 }
170
171
172
173
174
175
176
177
178 if !forward.Search("fmt")["io"] ||
179 !forward.Search("io")["fmt"] ||
180 !reverse.Search("fmt")["io"] ||
181 !reverse.Search("io")["fmt"] {
182 printNode("forward", "fmt")
183 printNode("forward", "io")
184 printNode("reverse", "fmt")
185 printNode("reverse", "io")
186 t.Errorf("fmt and io are not mutually reachable despite being in the same SCC")
187 }
188 }
189
View as plain text