Source file
src/cmd/api/api_test.go
1
2
3
4
5 package main
6
7 import (
8 "flag"
9 "fmt"
10 "go/build"
11 "internal/testenv"
12 "os"
13 "path/filepath"
14 "sort"
15 "strings"
16 "sync"
17 "testing"
18 )
19
20 var flagCheck = flag.Bool("check", false, "run API checks")
21
22 func TestMain(m *testing.M) {
23 flag.Parse()
24 for _, c := range contexts {
25 c.Compiler = build.Default.Compiler
26 }
27 build.Default.GOROOT = testenv.GOROOT(nil)
28
29 os.Exit(m.Run())
30 }
31
32 var (
33 updateGolden = flag.Bool("updategolden", false, "update golden files")
34 )
35
36 func TestGolden(t *testing.T) {
37 if *flagCheck {
38
39 t.Skip("skipping with -check set")
40 }
41
42 testenv.MustHaveGoBuild(t)
43
44 td, err := os.Open("testdata/src/pkg")
45 if err != nil {
46 t.Fatal(err)
47 }
48 fis, err := td.Readdir(0)
49 if err != nil {
50 t.Fatal(err)
51 }
52 for _, fi := range fis {
53 if !fi.IsDir() {
54 continue
55 }
56
57
58 goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
59 w := NewWalker(nil, "testdata/src/pkg")
60 pkg, _ := w.import_(fi.Name())
61 w.export(pkg)
62
63 if *updateGolden {
64 os.Remove(goldenFile)
65 f, err := os.Create(goldenFile)
66 if err != nil {
67 t.Fatal(err)
68 }
69 for _, feat := range w.Features() {
70 fmt.Fprintf(f, "%s\n", feat)
71 }
72 f.Close()
73 }
74
75 bs, err := os.ReadFile(goldenFile)
76 if err != nil {
77 t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
78 }
79 wanted := strings.Split(string(bs), "\n")
80 sort.Strings(wanted)
81 for _, feature := range wanted {
82 if feature == "" {
83 continue
84 }
85 _, ok := w.features[feature]
86 if !ok {
87 t.Errorf("package %s: missing feature %q", fi.Name(), feature)
88 }
89 delete(w.features, feature)
90 }
91
92 for _, feature := range w.Features() {
93 t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
94 }
95 }
96 }
97
98 func TestCompareAPI(t *testing.T) {
99 tests := []struct {
100 name string
101 features, required, exception []string
102 ok bool
103 out string
104 }{
105 {
106 name: "equal",
107 features: []string{"A", "B", "C"},
108 required: []string{"A", "B", "C"},
109 ok: true,
110 out: "",
111 },
112 {
113 name: "feature added",
114 features: []string{"A", "B", "C", "D", "E", "F"},
115 required: []string{"B", "D"},
116 ok: false,
117 out: "+A\n+C\n+E\n+F\n",
118 },
119 {
120 name: "feature removed",
121 features: []string{"C", "A"},
122 required: []string{"A", "B", "C"},
123 ok: false,
124 out: "-B\n",
125 },
126 {
127 name: "exception removal",
128 features: []string{"A", "C"},
129 required: []string{"A", "B", "C"},
130 exception: []string{"B"},
131 ok: true,
132 out: "",
133 },
134
135
136
137
138
139 {
140 name: "contexts reconverging after api/next/* update",
141 features: []string{
142 "A",
143 "pkg syscall, type RawSockaddrInet6 struct",
144 },
145 required: []string{
146 "A",
147 "pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
148 "pkg syscall, type RawSockaddrInet6 struct",
149 },
150 ok: true,
151 out: "",
152 },
153 {
154 name: "contexts reconverging before api/next/* update",
155 features: []string{
156 "A",
157 "pkg syscall, type RawSockaddrInet6 struct",
158 },
159 required: []string{
160 "A",
161 "pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
162 },
163 ok: false,
164 out: "+pkg syscall, type RawSockaddrInet6 struct\n",
165 },
166 }
167 for _, tt := range tests {
168 buf := new(strings.Builder)
169 gotOK := compareAPI(buf, tt.features, tt.required, tt.exception)
170 if gotOK != tt.ok {
171 t.Errorf("%s: ok = %v; want %v", tt.name, gotOK, tt.ok)
172 }
173 if got := buf.String(); got != tt.out {
174 t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
175 }
176 }
177 }
178
179 func TestSkipInternal(t *testing.T) {
180 tests := []struct {
181 pkg string
182 want bool
183 }{
184 {"net/http", true},
185 {"net/http/internal-foo", true},
186 {"net/http/internal", false},
187 {"net/http/internal/bar", false},
188 {"internal/foo", false},
189 {"internal", false},
190 }
191 for _, tt := range tests {
192 got := !internalPkg.MatchString(tt.pkg)
193 if got != tt.want {
194 t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want)
195 }
196 }
197 }
198
199 func BenchmarkAll(b *testing.B) {
200 for i := 0; i < b.N; i++ {
201 for _, context := range contexts {
202 w := NewWalker(context, filepath.Join(testenv.GOROOT(b), "src"))
203 for _, name := range w.stdPackages {
204 pkg, _ := w.import_(name)
205 w.export(pkg)
206 }
207 w.Features()
208 }
209 }
210 }
211
212 var warmupCache = sync.OnceFunc(func() {
213
214 var wg sync.WaitGroup
215 for _, context := range contexts {
216 context := context
217 wg.Add(1)
218 go func() {
219 defer wg.Done()
220 _ = NewWalker(context, filepath.Join(testenv.GOROOT(nil), "src"))
221 }()
222 }
223 wg.Wait()
224 })
225
226 func TestIssue21181(t *testing.T) {
227 if testing.Short() {
228 t.Skip("skipping with -short")
229 }
230 if *flagCheck {
231
232 t.Skip("skipping with -check set")
233 }
234 testenv.MustHaveGoBuild(t)
235
236 warmupCache()
237
238 for _, context := range contexts {
239 w := NewWalker(context, "testdata/src/issue21181")
240 pkg, err := w.import_("p")
241 if err != nil {
242 t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH,
243 pkg.Name(), w.imported)
244 }
245 w.export(pkg)
246 }
247 }
248
249 func TestIssue29837(t *testing.T) {
250 if testing.Short() {
251 t.Skip("skipping with -short")
252 }
253 if *flagCheck {
254
255 t.Skip("skipping with -check set")
256 }
257 testenv.MustHaveGoBuild(t)
258
259 warmupCache()
260
261 for _, context := range contexts {
262 w := NewWalker(context, "testdata/src/issue29837")
263 _, err := w.ImportFrom("p", "", 0)
264 if _, nogo := err.(*build.NoGoError); !nogo {
265 t.Errorf("expected *build.NoGoError, got %T", err)
266 }
267 }
268 }
269
270 func TestIssue41358(t *testing.T) {
271 if *flagCheck {
272
273 t.Skip("skipping with -check set")
274 }
275 testenv.MustHaveGoBuild(t)
276 context := new(build.Context)
277 *context = build.Default
278 context.Dir = filepath.Join(testenv.GOROOT(t), "src")
279
280 w := NewWalker(context, context.Dir)
281 for _, pkg := range w.stdPackages {
282 if strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "golang.org/x/") {
283 t.Fatalf("stdPackages contains unexpected package %s", pkg)
284 }
285 }
286 }
287
288 func TestIssue64958(t *testing.T) {
289 defer func() {
290 if x := recover(); x != nil {
291 t.Errorf("expected no panic; recovered %v", x)
292 }
293 }()
294
295 testenv.MustHaveGoBuild(t)
296
297 for _, context := range contexts {
298 w := NewWalker(context, "testdata/src/issue64958")
299 pkg, err := w.importFrom("p", "", 0)
300 if err != nil {
301 t.Errorf("expected no error importing; got %T", err)
302 }
303 w.export(pkg)
304 }
305 }
306
307 func TestCheck(t *testing.T) {
308 if !*flagCheck {
309 t.Skip("-check not specified")
310 }
311 testenv.MustHaveGoBuild(t)
312 Check(t)
313 }
314
View as plain text