Source file
src/cmd/api/goapi_test.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "go/build"
12 "os"
13 "path/filepath"
14 "sort"
15 "strings"
16 "sync"
17 "testing"
18 )
19
20 func TestMain(m *testing.M) {
21 flag.Parse()
22 for _, c := range contexts {
23 c.Compiler = build.Default.Compiler
24 }
25
26
27 var wg sync.WaitGroup
28 for _, context := range contexts {
29 context := context
30 wg.Add(1)
31 go func() {
32 defer wg.Done()
33 _ = NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
34 }()
35 }
36 wg.Wait()
37
38 os.Exit(m.Run())
39 }
40
41 var (
42 updateGolden = flag.Bool("updategolden", false, "update golden files")
43 )
44
45 func TestGolden(t *testing.T) {
46 td, err := os.Open("testdata/src/pkg")
47 if err != nil {
48 t.Fatal(err)
49 }
50 fis, err := td.Readdir(0)
51 if err != nil {
52 t.Fatal(err)
53 }
54 for _, fi := range fis {
55 if !fi.IsDir() {
56 continue
57 }
58
59
60 goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
61 w := NewWalker(nil, "testdata/src/pkg")
62 pkg, _ := w.Import(fi.Name())
63 w.export(pkg)
64
65 if *updateGolden {
66 os.Remove(goldenFile)
67 f, err := os.Create(goldenFile)
68 if err != nil {
69 t.Fatal(err)
70 }
71 for _, feat := range w.Features() {
72 fmt.Fprintf(f, "%s\n", feat)
73 }
74 f.Close()
75 }
76
77 bs, err := os.ReadFile(goldenFile)
78 if err != nil {
79 t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
80 }
81 wanted := strings.Split(string(bs), "\n")
82 sort.Strings(wanted)
83 for _, feature := range wanted {
84 if feature == "" {
85 continue
86 }
87 _, ok := w.features[feature]
88 if !ok {
89 t.Errorf("package %s: missing feature %q", fi.Name(), feature)
90 }
91 delete(w.features, feature)
92 }
93
94 for _, feature := range w.Features() {
95 t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
96 }
97 }
98 }
99
100 func TestCompareAPI(t *testing.T) {
101 tests := []struct {
102 name string
103 features, required, optional, exception []string
104 ok bool
105 out string
106 }{
107 {
108 name: "feature added",
109 features: []string{"A", "B", "C", "D", "E", "F"},
110 required: []string{"B", "D"},
111 ok: true,
112 out: "+A\n+C\n+E\n+F\n",
113 },
114 {
115 name: "feature removed",
116 features: []string{"C", "A"},
117 required: []string{"A", "B", "C"},
118 ok: false,
119 out: "-B\n",
120 },
121 {
122 name: "feature added then removed",
123 features: []string{"A", "C"},
124 optional: []string{"B"},
125 required: []string{"A", "C"},
126 ok: true,
127 out: "±B\n",
128 },
129 {
130 name: "exception removal",
131 required: []string{"A", "B", "C"},
132 features: []string{"A", "C"},
133 exception: []string{"B"},
134 ok: true,
135 out: "",
136 },
137 {
138
139 name: "contexts reconverging",
140 required: []string{
141 "A",
142 "pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
143 },
144 features: []string{
145 "A",
146 "pkg syscall, type RawSockaddrInet6 struct",
147 },
148 ok: true,
149 out: "+pkg syscall, type RawSockaddrInet6 struct\n",
150 },
151 }
152 for _, tt := range tests {
153 buf := new(bytes.Buffer)
154 gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
155 if gotok != tt.ok {
156 t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
157 }
158 if got := buf.String(); got != tt.out {
159 t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
160 }
161 }
162 }
163
164 func TestSkipInternal(t *testing.T) {
165 tests := []struct {
166 pkg string
167 want bool
168 }{
169 {"net/http", true},
170 {"net/http/internal-foo", true},
171 {"net/http/internal", false},
172 {"net/http/internal/bar", false},
173 {"internal/foo", false},
174 {"internal", false},
175 }
176 for _, tt := range tests {
177 got := !internalPkg.MatchString(tt.pkg)
178 if got != tt.want {
179 t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want)
180 }
181 }
182 }
183
184 func BenchmarkAll(b *testing.B) {
185 for i := 0; i < b.N; i++ {
186 for _, context := range contexts {
187 w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
188 for _, name := range w.stdPackages {
189 pkg, _ := w.Import(name)
190 w.export(pkg)
191 }
192 w.Features()
193 }
194 }
195 }
196
197 func TestIssue21181(t *testing.T) {
198 for _, context := range contexts {
199 w := NewWalker(context, "testdata/src/issue21181")
200 pkg, err := w.Import("p")
201 if err != nil {
202 t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH,
203 pkg.Name(), w.imported)
204 }
205 w.export(pkg)
206 }
207 }
208
209 func TestIssue29837(t *testing.T) {
210 for _, context := range contexts {
211 w := NewWalker(context, "testdata/src/issue29837")
212 _, err := w.Import("p")
213 if _, nogo := err.(*build.NoGoError); !nogo {
214 t.Errorf("expected *build.NoGoError, got %T", err)
215 }
216 }
217 }
218
219 func TestIssue41358(t *testing.T) {
220 context := new(build.Context)
221 *context = build.Default
222 context.Dir = filepath.Join(context.GOROOT, "src")
223
224 w := NewWalker(context, context.Dir)
225 for _, pkg := range w.stdPackages {
226 if strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "golang.org/x/") {
227 t.Fatalf("stdPackages contains unexpected package %s", pkg)
228 }
229 }
230 }
231
View as plain text