blob: 97f31e71b7880a98c4c41174535afa456d378ce8 [file] [log] [blame]
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -05001// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package godoc
6
7import (
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -08008 "bytes"
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -05009 "reflect"
Brad Garciaf3faf8b2013-11-21 11:55:42 -050010 "sort"
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050011 "strings"
12 "testing"
13
Andrew Gerrand5ebbcd12014-11-10 08:50:40 +110014 "golang.org/x/tools/godoc/vfs/mapfs"
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050015)
16
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -080017func newCorpus(t *testing.T) *Corpus {
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050018 c := NewCorpus(mapfs.New(map[string]string{
Alan Donovan6c93dbf2014-09-10 09:02:54 -040019 "src/foo/foo.go": `// Package foo is an example.
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050020package foo
21
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -050022import "bar"
23
Marko Mikulicicae3dd782013-11-15 11:03:25 -080024const Pi = 3.1415
25
26var Foos []Foo
27
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050028// Foo is stuff.
29type Foo struct{}
30
31func New() *Foo {
32 return new(Foo)
33}
34`,
Alan Donovan6c93dbf2014-09-10 09:02:54 -040035 "src/bar/bar.go": `// Package bar is another example to test races.
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050036package bar
37`,
Alan Donovan6c93dbf2014-09-10 09:02:54 -040038 "src/other/bar/bar.go": `// Package bar is another bar package.
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -050039package bar
40func X() {}
41`,
Alan Donovan6c93dbf2014-09-10 09:02:54 -040042 "src/skip/skip.go": `// Package skip should be skipped.
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050043package skip
44func Skip() {}
45`,
Alan Donovan6c93dbf2014-09-10 09:02:54 -040046 "src/bar/readme.txt": `Whitelisted text file.
Brad Garcia8880e2e2013-11-25 14:23:36 -050047`,
Alan Donovan6c93dbf2014-09-10 09:02:54 -040048 "src/bar/baz.zzz": `Text file not whitelisted.
Brad Garcia8880e2e2013-11-25 14:23:36 -050049`,
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050050 }))
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 }
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -080059 return c
60}
61
62func TestIndex(t *testing.T) {
Brad Garcia8880e2e2013-11-25 14:23:36 -050063 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 }
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -050079 }
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -080080}
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -050081
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -080082func TestIndexWriteRead(t *testing.T) {
Brad Garcia8880e2e2013-11-25 14:23:36 -050083 type key struct {
84 docs, goCode, fullText bool
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -080085 }
Brad Garcia8880e2e2013-11-25 14:23:36 -050086 type val struct {
87 buf *bytes.Buffer
88 c *Corpus
89 }
90 m := map[key]val{}
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -080091
Brad Garcia8880e2e2013-11-25 14:23:36 -050092 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 }
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -0800122 }
Brad Garcia8880e2e2013-11-25 14:23:36 -0500123 // Test CompatibleWith
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 }
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -0800134 }
Brad Fitzpatrick515bcdc2013-11-12 14:58:47 -0800135}
136
Brad Garcia8880e2e2013-11-25 14:23:36 -0500137func testIndex(t *testing.T, c *Corpus, ix *Index) {
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -0500138 if _, ok := ix.words["Skip"]; ok {
139 t.Errorf("the word Skip was found; expected it to be skipped")
140 }
Brad Garcia8880e2e2013-11-25 14:23:36 -0500141 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}
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -0500147
Brad Garcia8880e2e2013-11-25 14:23:36 -0500148// checkStats checks the Index's statistics.
149// Some statistics are only set when we're indexing Go code.
150func 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// checkImportCount checks the Index's import count map.
171// It is only set when we're indexing Go code.
172func 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) {
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -0500180 t.Errorf("ImportCount = %v; want %v", got, want)
181 }
Brad Garcia8880e2e2013-11-25 14:23:36 -0500182}
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -0500183
Brad Garcia8880e2e2013-11-25 14:23:36 -0500184// checkPackagePath checks the Index's package path map.
185// It is set if at least one of the indexing options is enabled.
186func 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{
David R. Jenni59847712016-11-04 19:52:17 +0100190 "foo": {
Brad Garcia8880e2e2013-11-25 14:23:36 -0500191 "foo": true,
192 },
David R. Jenni59847712016-11-04 19:52:17 +0100193 "bar": {
Brad Garcia8880e2e2013-11-25 14:23:36 -0500194 "bar": true,
195 "other/bar": true,
196 },
197 }
198 }
199 if got := ix.PackagePath(); !reflect.DeepEqual(got, want) {
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -0500200 t.Errorf("PackagePath = %v; want %v", got, want)
201 }
Brad Garcia8880e2e2013-11-25 14:23:36 -0500202}
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -0500203
Brad Garcia8880e2e2013-11-25 14:23:36 -0500204// checkExports checks the Index's exports map.
205// It is only set when we're indexing Go code.
206func 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{
David R. Jenni59847712016-11-04 19:52:17 +0100210 "foo": {
Brad Garcia8880e2e2013-11-25 14:23:36 -0500211 "Pi": ConstDecl,
212 "Foos": VarDecl,
213 "Foo": TypeDecl,
214 "New": FuncDecl,
215 },
David R. Jenni59847712016-11-04 19:52:17 +0100216 "other/bar": {
Brad Garcia8880e2e2013-11-25 14:23:36 -0500217 "X": FuncDecl,
218 },
219 }
220 }
221 if got := ix.Exports(); !reflect.DeepEqual(got, want) {
Brad Fitzpatrick56a1b4d2013-11-06 15:00:26 -0500222 t.Errorf("Exports = %v; want %v", got, want)
223 }
Brad Garcia8880e2e2013-11-25 14:23:36 -0500224}
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500225
Brad Garcia8880e2e2013-11-25 14:23:36 -0500226// checkIdents checks the Index's indents map.
227// It is only set when we're indexing documentation.
228func 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{
David R. Jenni59847712016-11-04 19:52:17 +0100232 PackageClause: {
233 "bar": {
Brad Garcia936715c2014-06-27 10:25:57 -0400234 {"bar", "bar", "bar", "Package bar is another example to test races."},
235 {"other/bar", "bar", "bar", "Package bar is another bar package."},
Brad Garcia26542a82014-01-06 14:53:03 -0500236 },
David R. Jenni59847712016-11-04 19:52:17 +0100237 "foo": {{"foo", "foo", "foo", "Package foo is an example."}},
238 "other": {{"other/bar", "bar", "bar", "Package bar is another bar package."}},
Brad Garcia26542a82014-01-06 14:53:03 -0500239 },
David R. Jenni59847712016-11-04 19:52:17 +0100240 ConstDecl: {
241 "Pi": {{"foo", "foo", "Pi", ""}},
Brad Garcia8880e2e2013-11-25 14:23:36 -0500242 },
David R. Jenni59847712016-11-04 19:52:17 +0100243 VarDecl: {
244 "Foos": {{"foo", "foo", "Foos", ""}},
Brad Garcia8880e2e2013-11-25 14:23:36 -0500245 },
David R. Jenni59847712016-11-04 19:52:17 +0100246 TypeDecl: {
247 "Foo": {{"foo", "foo", "Foo", "Foo is stuff."}},
Brad Garcia8880e2e2013-11-25 14:23:36 -0500248 },
David R. Jenni59847712016-11-04 19:52:17 +0100249 FuncDecl: {
250 "New": {{"foo", "foo", "New", ""}},
251 "X": {{"other/bar", "bar", "X", ""}},
Brad Garcia8880e2e2013-11-25 14:23:36 -0500252 },
253 }
254 }
255 if got := ix.Idents(); !reflect.DeepEqual(got, want) {
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500256 t.Errorf("Idents = %v; want %v", got, want)
257 }
258}
259
260func TestIdentResultSort(t *testing.T) {
Brad Garcia345b6432014-06-27 12:47:39 -0400261 ic := map[string]int{
262 "/a/b/pkg1": 10,
263 "/a/b/pkg2": 2,
264 "/b/d/pkg3": 20,
265 }
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500266 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{
Brad Garcia345b6432014-06-27 12:47:39 -0400277 {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500278 {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
279 {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
Brad Garcia345b6432014-06-27 12:47:39 -0400280 },
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", ""},
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500290 },
291 },
292 } {
Brad Garcia345b6432014-06-27 12:47:39 -0400293 if sort.Sort(byImportCount{tc.ir, ic}); !reflect.DeepEqual(tc.ir, tc.exp) {
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500294 t.Errorf("got: %v, want %v", tc.ir, tc.exp)
295 }
296 }
297}
298
Brad Garcia345b6432014-06-27 12:47:39 -0400299func TestIdentFilter(t *testing.T) {
300 ic := map[string]int{}
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500301 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 } {
Brad Garcia345b6432014-06-27 12:47:39 -0400318 res := byImportCount{tc.ir, ic}.filter(tc.pak)
319 if !reflect.DeepEqual(res, tc.exp) {
Brad Garciaf3faf8b2013-11-21 11:55:42 -0500320 t.Errorf("got: %v, want %v", res, tc.exp)
321 }
322 }
Brad Fitzpatrick964f0f52013-11-05 09:35:58 -0500323}