You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

323 lines
7.4 KiB

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