1
2
3
4
5 package godoc
6
7 import (
8 "bytes"
9 "reflect"
10 "sort"
11 "strings"
12 "testing"
13
14 "golang.org/x/tools/godoc/vfs/mapfs"
15 )
16
17 func newCorpus(t *testing.T) *Corpus {
18 c := NewCorpus(mapfs.New(map[string]string{
19 "src/foo/foo.go": `// Package foo is an example.
20 package foo
21
22 import "bar"
23
24 const Pi = 3.1415
25
26 var Foos []Foo
27
28 // Foo is stuff.
29 type Foo struct{}
30
31 func New() *Foo {
32 return new(Foo)
33 }
34 `,
35 "src/bar/bar.go": `// Package bar is another example to test races.
36 package bar
37 `,
38 "src/other/bar/bar.go": `// Package bar is another bar package.
39 package bar
40 func X() {}
41 `,
42 "src/skip/skip.go": `// Package skip should be skipped.
43 package skip
44 func Skip() {}
45 `,
46 "src/bar/readme.txt": `Whitelisted text file.
47 `,
48 "src/bar/baz.zzz": `Text file not whitelisted.
49 `,
50 }))
51 c.IndexEnabled = true
52 c.IndexDirectory = func(dir string) bool {
53 return !strings.Contains(dir, "skip")
54 }
55
56 if err := c.Init(); err != nil {
57 t.Fatal(err)
58 }
59 return c
60 }
61
62 func TestIndex(t *testing.T) {
63 for _, docs := range []bool{true, false} {
64 for _, goCode := range []bool{true, false} {
65 for _, fullText := range []bool{true, false} {
66 c := newCorpus(t)
67 c.IndexDocs = docs
68 c.IndexGoCode = goCode
69 c.IndexFullText = fullText
70 c.UpdateIndex()
71 ix, _ := c.CurrentIndex()
72 if ix == nil {
73 t.Fatal("no index")
74 }
75 t.Logf("docs, goCode, fullText = %v,%v,%v", docs, goCode, fullText)
76 testIndex(t, c, ix)
77 }
78 }
79 }
80 }
81
82 func TestIndexWriteRead(t *testing.T) {
83 type key struct {
84 docs, goCode, fullText bool
85 }
86 type val struct {
87 buf *bytes.Buffer
88 c *Corpus
89 }
90 m := map[key]val{}
91
92 for _, docs := range []bool{true, false} {
93 for _, goCode := range []bool{true, false} {
94 for _, fullText := range []bool{true, false} {
95 k := key{docs, goCode, fullText}
96 c := newCorpus(t)
97 c.IndexDocs = docs
98 c.IndexGoCode = goCode
99 c.IndexFullText = fullText
100 c.UpdateIndex()
101 ix, _ := c.CurrentIndex()
102 if ix == nil {
103 t.Fatal("no index")
104 }
105 var buf bytes.Buffer
106 nw, err := ix.WriteTo(&buf)
107 if err != nil {
108 t.Fatalf("Index.WriteTo: %v", err)
109 }
110 m[k] = val{bytes.NewBuffer(buf.Bytes()), c}
111 ix2 := new(Index)
112 nr, err := ix2.ReadFrom(&buf)
113 if err != nil {
114 t.Fatalf("Index.ReadFrom: %v", err)
115 }
116 if nr != nw {
117 t.Errorf("Wrote %d bytes to index but read %d", nw, nr)
118 }
119 testIndex(t, c, ix)
120 }
121 }
122 }
123
124 for k1, v1 := range m {
125 ix := new(Index)
126 if _, err := ix.ReadFrom(v1.buf); err != nil {
127 t.Fatalf("Index.ReadFrom: %v", err)
128 }
129 for k2, v2 := range m {
130 if got, want := ix.CompatibleWith(v2.c), k1 == k2; got != want {
131 t.Errorf("CompatibleWith = %v; want %v for %v, %v", got, want, k1, k2)
132 }
133 }
134 }
135 }
136
137 func testIndex(t *testing.T, c *Corpus, ix *Index) {
138 if _, ok := ix.words["Skip"]; ok {
139 t.Errorf("the word Skip was found; expected it to be skipped")
140 }
141 checkStats(t, c, ix)
142 checkImportCount(t, c, ix)
143 checkPackagePath(t, c, ix)
144 checkExports(t, c, ix)
145 checkIdents(t, c, ix)
146 }
147
148
149
150 func checkStats(t *testing.T, c *Corpus, ix *Index) {
151 want := Statistics{}
152 if c.IndexFullText {
153 want.Bytes = 314
154 want.Files = 4
155 want.Lines = 21
156 } else if c.IndexDocs || c.IndexGoCode {
157 want.Bytes = 291
158 want.Files = 3
159 want.Lines = 20
160 }
161 if c.IndexGoCode {
162 want.Words = 8
163 want.Spots = 12
164 }
165 if got := ix.Stats(); !reflect.DeepEqual(got, want) {
166 t.Errorf("Stats = %#v; want %#v", got, want)
167 }
168 }
169
170
171
172 func checkImportCount(t *testing.T, c *Corpus, ix *Index) {
173 want := map[string]int{}
174 if c.IndexGoCode {
175 want = map[string]int{
176 "bar": 1,
177 }
178 }
179 if got := ix.ImportCount(); !reflect.DeepEqual(got, want) {
180 t.Errorf("ImportCount = %v; want %v", got, want)
181 }
182 }
183
184
185
186 func checkPackagePath(t *testing.T, c *Corpus, ix *Index) {
187 want := map[string]map[string]bool{}
188 if c.IndexDocs || c.IndexGoCode || c.IndexFullText {
189 want = map[string]map[string]bool{
190 "foo": {
191 "foo": true,
192 },
193 "bar": {
194 "bar": true,
195 "other/bar": true,
196 },
197 }
198 }
199 if got := ix.PackagePath(); !reflect.DeepEqual(got, want) {
200 t.Errorf("PackagePath = %v; want %v", got, want)
201 }
202 }
203
204
205
206 func checkExports(t *testing.T, c *Corpus, ix *Index) {
207 want := map[string]map[string]SpotKind{}
208 if c.IndexGoCode {
209 want = map[string]map[string]SpotKind{
210 "foo": {
211 "Pi": ConstDecl,
212 "Foos": VarDecl,
213 "Foo": TypeDecl,
214 "New": FuncDecl,
215 },
216 "other/bar": {
217 "X": FuncDecl,
218 },
219 }
220 }
221 if got := ix.Exports(); !reflect.DeepEqual(got, want) {
222 t.Errorf("Exports = %v; want %v", got, want)
223 }
224 }
225
226
227
228 func checkIdents(t *testing.T, c *Corpus, ix *Index) {
229 want := map[SpotKind]map[string][]Ident{}
230 if c.IndexDocs {
231 want = map[SpotKind]map[string][]Ident{
232 PackageClause: {
233 "bar": {
234 {"bar", "bar", "bar", "Package bar is another example to test races."},
235 {"other/bar", "bar", "bar", "Package bar is another bar package."},
236 },
237 "foo": {{"foo", "foo", "foo", "Package foo is an example."}},
238 "other": {{"other/bar", "bar", "bar", "Package bar is another bar package."}},
239 },
240 ConstDecl: {
241 "Pi": {{"foo", "foo", "Pi", ""}},
242 },
243 VarDecl: {
244 "Foos": {{"foo", "foo", "Foos", ""}},
245 },
246 TypeDecl: {
247 "Foo": {{"foo", "foo", "Foo", "Foo is stuff."}},
248 },
249 FuncDecl: {
250 "New": {{"foo", "foo", "New", ""}},
251 "X": {{"other/bar", "bar", "X", ""}},
252 },
253 }
254 }
255 if got := ix.Idents(); !reflect.DeepEqual(got, want) {
256 t.Errorf("Idents = %v; want %v", got, want)
257 }
258 }
259
260 func TestIdentResultSort(t *testing.T) {
261 ic := map[string]int{
262 "/a/b/pkg1": 10,
263 "/a/b/pkg2": 2,
264 "/b/d/pkg3": 20,
265 }
266 for _, tc := range []struct {
267 ir []Ident
268 exp []Ident
269 }{
270 {
271 ir: []Ident{
272 {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
273 {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
274 {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
275 },
276 exp: []Ident{
277 {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
278 {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
279 {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
280 },
281 },
282 {
283 ir: []Ident{
284 {"/a/a/pkg1", "pkg1", "MyFunc1", ""},
285 {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
286 },
287 exp: []Ident{
288 {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
289 {"/a/a/pkg1", "pkg1", "MyFunc1", ""},
290 },
291 },
292 } {
293 if sort.Sort(byImportCount{tc.ir, ic}); !reflect.DeepEqual(tc.ir, tc.exp) {
294 t.Errorf("got: %v, want %v", tc.ir, tc.exp)
295 }
296 }
297 }
298
299 func TestIdentFilter(t *testing.T) {
300 ic := map[string]int{}
301 for _, tc := range []struct {
302 ir []Ident
303 pak string
304 exp []Ident
305 }{
306 {
307 ir: []Ident{
308 {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
309 {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
310 {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
311 },
312 pak: "pkg2",
313 exp: []Ident{
314 {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
315 },
316 },
317 } {
318 res := byImportCount{tc.ir, ic}.filter(tc.pak)
319 if !reflect.DeepEqual(res, tc.exp) {
320 t.Errorf("got: %v, want %v", res, tc.exp)
321 }
322 }
323 }
324
View as plain text