github.com/v2fly/tools@v0.100.0/godoc/index_test.go (about) 1 // 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 5 package godoc 6 7 import ( 8 "bytes" 9 "reflect" 10 "sort" 11 "strings" 12 "testing" 13 14 "github.com/v2fly/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 // 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 } 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 // checkStats checks the Index's statistics. 149 // Some statistics are only set when we're indexing Go code. 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 // checkImportCount checks the Index's import count map. 171 // It is only set when we're indexing Go code. 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 // checkPackagePath checks the Index's package path map. 185 // It is set if at least one of the indexing options is enabled. 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 // checkExports checks the Index's exports map. 205 // It is only set when we're indexing Go code. 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 // checkIdents checks the Index's indents map. 227 // It is only set when we're indexing documentation. 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 }