GoPLS Viewer

Home|gopls/godoc/godoc_test.go
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
5package godoc
6
7import (
8    "bytes"
9    "go/parser"
10    "go/token"
11    "strings"
12    "testing"
13
14    "golang.org/x/tools/internal/typeparams"
15)
16
17func TestPkgLinkFunc(t *testing.T) {
18    for _tc := range []struct {
19        path string
20        want string
21    }{
22        {"/src/fmt""pkg/fmt"},
23        {"src/fmt""pkg/fmt"},
24        {"/fmt""pkg/fmt"},
25        {"fmt""pkg/fmt"},
26    } {
27        if got := pkgLinkFunc(tc.path); got != tc.want {
28            t.Errorf("pkgLinkFunc(%v) = %v; want %v"tc.pathgottc.want)
29        }
30    }
31}
32
33func TestSrcPosLinkFunc(t *testing.T) {
34    for _tc := range []struct {
35        src  string
36        line int
37        low  int
38        high int
39        want string
40    }{
41        {"/src/fmt/print.go"423050"/src/fmt/print.go?s=30:50#L32"},
42        {"/src/fmt/print.go"215"/src/fmt/print.go?s=1:5#L1"},
43        {"/src/fmt/print.go"200"/src/fmt/print.go#L2"},
44        {"/src/fmt/print.go"000"/src/fmt/print.go"},
45        {"/src/fmt/print.go"015"/src/fmt/print.go?s=1:5#L1"},
46        {"fmt/print.go"000"/src/fmt/print.go"},
47        {"fmt/print.go"015"/src/fmt/print.go?s=1:5#L1"},
48    } {
49        if got := srcPosLinkFunc(tc.srctc.linetc.lowtc.high); got != tc.want {
50            t.Errorf("srcLinkFunc(%v, %v, %v, %v) = %v; want %v"tc.srctc.linetc.lowtc.highgottc.want)
51        }
52    }
53}
54
55func TestSrcLinkFunc(t *testing.T) {
56    for _tc := range []struct {
57        src  string
58        want string
59    }{
60        {"/src/fmt/print.go""/src/fmt/print.go"},
61        {"src/fmt/print.go""/src/fmt/print.go"},
62        {"/fmt/print.go""/src/fmt/print.go"},
63        {"fmt/print.go""/src/fmt/print.go"},
64    } {
65        if got := srcLinkFunc(tc.src); got != tc.want {
66            t.Errorf("srcLinkFunc(%v) = %v; want %v"tc.srcgottc.want)
67        }
68    }
69}
70
71func TestQueryLinkFunc(t *testing.T) {
72    for _tc := range []struct {
73        src   string
74        query string
75        line  int
76        want  string
77    }{
78        {"/src/fmt/print.go""Sprintf"33"/src/fmt/print.go?h=Sprintf#L33"},
79        {"/src/fmt/print.go""Sprintf"0"/src/fmt/print.go?h=Sprintf"},
80        {"src/fmt/print.go""EOF"33"/src/fmt/print.go?h=EOF#L33"},
81        {"src/fmt/print.go""a%3f+%26b"1"/src/fmt/print.go?h=a%3f+%26b#L1"},
82    } {
83        if got := queryLinkFunc(tc.srctc.querytc.line); got != tc.want {
84            t.Errorf("queryLinkFunc(%v, %v, %v) = %v; want %v"tc.srctc.querytc.linegottc.want)
85        }
86    }
87}
88
89func TestDocLinkFunc(t *testing.T) {
90    for _tc := range []struct {
91        src   string
92        ident string
93        want  string
94    }{
95        {"fmt""Sprintf""/pkg/fmt/#Sprintf"},
96        {"fmt""EOF""/pkg/fmt/#EOF"},
97    } {
98        if got := docLinkFunc(tc.srctc.ident); got != tc.want {
99            t.Errorf("docLinkFunc(%v, %v) = %v; want %v"tc.srctc.identgottc.want)
100        }
101    }
102}
103
104func TestSanitizeFunc(t *testing.T) {
105    for _tc := range []struct {
106        src  string
107        want string
108    }{
109        {},
110        {"foo""foo"},
111        {"func   f()""func f()"},
112        {"func f(a int,)""func f(a int)"},
113        {"func f(a int,\n)""func f(a int)"},
114        {"func f(\n\ta int,\n\tb int,\n\tc int,\n)""func f(a int, b int, c int)"},
115        {"  (   a,   b,  c  )  ""(a, b, c)"},
116        {"(  a,  b, c    int, foo   bar  ,  )""(a, b, c int, foo bar)"},
117        {"{   a,   b}""{a, b}"},
118        {"[   a,   b]""[a, b]"},
119    } {
120        if got := sanitizeFunc(tc.src); got != tc.want {
121            t.Errorf("sanitizeFunc(%v) = %v; want %v"tc.srcgottc.want)
122        }
123    }
124}
125
126// Test that we add <span id="StructName.FieldName"> elements
127// to the HTML of struct fields.
128func TestStructFieldsIDAttributes(t *testing.T) {
129    got := linkifySource(t, []byte(`
130package foo
131
132type T struct {
133    NoDoc string
134
135    // Doc has a comment.
136    Doc string
137
138    // Opt, if non-nil, is an option.
139    Opt *int
140
141    // Опция - другое поле.
142    Опция bool
143}
144`))
145    want := `type T struct {
146<span id="T.NoDoc"></span>NoDoc <a href="/pkg/builtin/#string">string</a>
147
148<span id="T.Doc"></span><span class="comment">// Doc has a comment.</span>
149Doc <a href="/pkg/builtin/#string">string</a>
150
151<span id="T.Opt"></span><span class="comment">// Opt, if non-nil, is an option.</span>
152Opt *<a href="/pkg/builtin/#int">int</a>
153
154<span id="T.Опция"></span><span class="comment">// Опция - другое поле.</span>
155Опция <a href="/pkg/builtin/#bool">bool</a>
156}`
157    if got != want {
158        t.Errorf("got: %s\n\nwant: %s\n"gotwant)
159    }
160}
161
162// Test that we add <span id="ConstName"> elements to the HTML
163// of definitions in const and var specs.
164func TestValueSpecIDAttributes(t *testing.T) {
165    got := linkifySource(t, []byte(`
166package foo
167
168const (
169    NoDoc string = "NoDoc"
170
171    // Doc has a comment
172    Doc = "Doc"
173
174    NoVal
175)`))
176    want := `const (
177<span id="NoDoc">NoDoc</span> <a href="/pkg/builtin/#string">string</a> = &#34;NoDoc&#34;
178
179<span class="comment">// Doc has a comment</span>
180<span id="Doc">Doc</span> = &#34;Doc&#34;
181
182<span id="NoVal">NoVal</span>
183)`
184    if got != want {
185        t.Errorf("got: %s\n\nwant: %s\n"gotwant)
186    }
187}
188
189func TestCompositeLitLinkFields(t *testing.T) {
190    got := linkifySource(t, []byte(`
191package foo
192
193type T struct {
194    X int
195}
196
197var S T = T{X: 12}`))
198    want := `type T struct {
199<span id="T.X"></span>X <a href="/pkg/builtin/#int">int</a>
200}
201var <span id="S">S</span> <a href="#T">T</a> = <a href="#T">T</a>{<a href="#T.X">X</a>: 12}`
202    if got != want {
203        t.Errorf("got: %s\n\nwant: %s\n"gotwant)
204    }
205}
206
207func TestFuncDeclNotLink(t *testing.T) {
208    // Function.
209    got := linkifySource(t, []byte(`
210package http
211
212func Get(url string) (resp *Response, err error)`))
213    want := `func Get(url <a href="/pkg/builtin/#string">string</a>) (resp *<a href="#Response">Response</a>, err <a href="/pkg/builtin/#error">error</a>)`
214    if got != want {
215        t.Errorf("got: %s\n\nwant: %s\n"gotwant)
216    }
217
218    // Method.
219    got = linkifySource(t, []byte(`
220package http
221
222func (h Header) Get(key string) string`))
223    want = `func (h <a href="#Header">Header</a>) Get(key <a href="/pkg/builtin/#string">string</a>) <a href="/pkg/builtin/#string">string</a>`
224    if got != want {
225        t.Errorf("got: %s\n\nwant: %s\n"gotwant)
226    }
227}
228
229func linkifySource(t *testing.Tsrc []bytestring {
230    p := &Presentation{
231        DeclLinkstrue,
232    }
233    fset := token.NewFileSet()
234    aferr := parser.ParseFile(fset"foo.go"srcparser.ParseComments)
235    if err != nil {
236        t.Fatal(err)
237    }
238    var buf bytes.Buffer
239    pi := &PageInfo{
240        FSetfset,
241    }
242    sep := ""
243    for _decl := range af.Decls {
244        buf.WriteString(sep)
245        sep = "\n"
246        buf.WriteString(p.node_htmlFunc(pidecltrue))
247    }
248    return buf.String()
249}
250
251func TestScanIdentifier(t *testing.T) {
252    tests := []struct {
253        inwant string
254    }{
255        {"foo bar""foo"},
256        {"foo/bar""foo"},
257        {" foo"""},
258        {"фоо""фоо"},
259        {"f123""f123"},
260        {"123f"""},
261    }
262    for _tt := range tests {
263        got := scanIdentifier([]byte(tt.in))
264        if string(got) != tt.want {
265            t.Errorf("scanIdentifier(%q) = %q; want %q"tt.ingottt.want)
266        }
267    }
268}
269
270func TestReplaceLeadingIndentation(t *testing.T) {
271    oldIndent := strings.Repeat(" "2)
272    newIndent := strings.Repeat(" "4)
273    tests := []struct {
274        srcwant string
275    }{
276        {"  foo\n    bar\n  baz""    foo\n      bar\n    baz"},
277        {"  '`'\n  '`'\n""    '`'\n    '`'\n"},
278        {"  '\\''\n  '`'\n""    '\\''\n    '`'\n"},
279        {"  \"`\"\n  \"`\"\n""    \"`\"\n    \"`\"\n"},
280        {"  `foo\n  bar`""    `foo\n      bar`"},
281        {"  `foo\\`\n  bar""    `foo\\`\n    bar"},
282        {"  '\\`'`foo\n  bar""    '\\`'`foo\n      bar"},
283        {
284            "  if true {\n    foo := `One\n    \tTwo\nThree`\n  }\n",
285            "    if true {\n      foo := `One\n        \tTwo\n    Three`\n    }\n",
286        },
287    }
288    for _tc := range tests {
289        if got := replaceLeadingIndentation(tc.srcoldIndentnewIndent); got != tc.want {
290            t.Errorf("replaceLeadingIndentation:\n%v\n---\nhave:\n%v\n---\nwant:\n%v\n",
291                tc.srcgottc.want)
292        }
293    }
294}
295
296func TestSrcBreadcrumbFunc(t *testing.T) {
297    for _tc := range []struct {
298        path string
299        want string
300    }{
301        {"src/"`<span class="text-muted">src/</span>`},
302        {"src/fmt/"`<a href="/src">src</a>/<span class="text-muted">fmt/</span>`},
303        {"src/fmt/print.go"`<a href="/src">src</a>/<a href="/src/fmt">fmt</a>/<span class="text-muted">print.go</span>`},
304    } {
305        if got := srcBreadcrumbFunc(tc.path); got != tc.want {
306            t.Errorf("srcBreadcrumbFunc(%v) = %v; want %v"tc.pathgottc.want)
307        }
308    }
309}
310
311func TestSrcToPkgLinkFunc(t *testing.T) {
312    for _tc := range []struct {
313        path string
314        want string
315    }{
316        {"src/"`<a href="/pkg">Index</a>`},
317        {"src/fmt/"`<a href="/pkg/fmt">fmt</a>`},
318        {"pkg/"`<a href="/pkg">Index</a>`},
319        {"pkg/LICENSE"`<a href="/pkg">Index</a>`},
320    } {
321        if got := srcToPkgLinkFunc(tc.path); got != tc.want {
322            t.Errorf("srcToPkgLinkFunc(%v) = %v; want %v"tc.pathgottc.want)
323        }
324    }
325}
326
327func TestFilterOutBuildAnnotations(t *testing.T) {
328    // TODO: simplify this by using a multiline string once we stop
329    // using go vet from 1.10 on the build dashboard.
330    // https://golang.org/issue/26627
331    src := []byte("// +build !foo\n" +
332        "// +build !anothertag\n" +
333        "\n" +
334        "// non-tag comment\n" +
335        "\n" +
336        "package foo\n" +
337        "\n" +
338        "func bar() int {\n" +
339        "    return 42\n" +
340        "}\n")
341
342    fset := token.NewFileSet()
343    aferr := parser.ParseFile(fset"foo.go"srcparser.ParseComments)
344    if err != nil {
345        t.Fatal(err)
346    }
347
348    var found bool
349    for _cg := range af.Comments {
350        if strings.HasPrefix(cg.Text(), "+build ") {
351            found = true
352            break
353        }
354    }
355    if !found {
356        t.Errorf("TestFilterOutBuildAnnotations is broken: missing build tag in test input")
357    }
358
359    found = false
360    for _cg := range filterOutBuildAnnotations(af.Comments) {
361        if strings.HasPrefix(cg.Text(), "+build ") {
362            t.Errorf("filterOutBuildAnnotations failed to filter build tag")
363        }
364
365        if strings.Contains(cg.Text(), "non-tag comment") {
366            found = true
367        }
368    }
369    if !found {
370        t.Errorf("filterOutBuildAnnotations should not remove non-build tag comment")
371    }
372}
373
374func TestLinkifyGenerics(t *testing.T) {
375    if !typeparams.Enabled {
376        t.Skip("type params are not enabled at this Go version")
377    }
378
379    got := linkifySource(t, []byte(`
380package foo
381
382type T struct {
383    field *T
384}
385
386type ParametricStruct[T any] struct {
387    field *T
388}
389
390func F1[T any](arg T) { }
391
392func F2(arg T) { }
393
394func (*ParametricStruct[T]) M(arg T) { }
395
396func (*T) M(arg T) { }
397
398type ParametricStruct2[T1, T2 any] struct {
399    a T1
400    b T2
401}
402
403func (*ParametricStruct2[T1, T2]) M(a T1, b T2) { }
404
405
406`))
407
408    want := `type T struct {
409<span id="T.field"></span>field *<a href="#T">T</a>
410}
411type ParametricStruct[T <a href="/pkg/builtin/#any">any</a>] struct {
412<span id="ParametricStruct.field"></span>field *T
413}
414func F1[T <a href="/pkg/builtin/#any">any</a>](arg T) {}
415func F2(arg <a href="#T">T</a>) {}
416func (*<a href="#ParametricStruct">ParametricStruct</a>[T]) M(arg T) {}
417func (*<a href="#T">T</a>) M(arg <a href="#T">T</a>) {}
418type ParametricStruct2[T1, T2 <a href="/pkg/builtin/#any">any</a>] struct {
419<span id="ParametricStruct2.a"></span>a T1
420<span id="ParametricStruct2.b"></span>b T2
421}
422func (*<a href="#ParametricStruct2">ParametricStruct2</a>[T1, T2]) M(a T1, b T2) {}`
423
424    if got != want {
425        t.Errorf("got: %s\n\nwant: %s\n"gotwant)
426    }
427}
428
MembersX
TestSrcBreadcrumbFunc.t
TestFilterOutBuildAnnotations.fset
linkifySource.pi
TestReplaceLeadingIndentation.tests
TestReplaceLeadingIndentation.RangeStmt_7460.BlockStmt.got
linkifySource.af
TestReplaceLeadingIndentation
TestFilterOutBuildAnnotations.err
typeparams
TestSrcLinkFunc
TestValueSpecIDAttributes.want
TestSanitizeFunc
TestValueSpecIDAttributes.t
TestScanIdentifier
TestDocLinkFunc
TestCompositeLitLinkFields.got
TestFuncDeclNotLink.t
TestFuncDeclNotLink.got
TestReplaceLeadingIndentation.t
TestPkgLinkFunc.t
TestPkgLinkFunc.RangeStmt_325.tc
TestQueryLinkFunc.RangeStmt_1820.BlockStmt.got
TestFilterOutBuildAnnotations.found
TestSrcPosLinkFunc.RangeStmt_660.BlockStmt.got
linkifySource.RangeStmt_6262.decl
TestSrcBreadcrumbFunc
linkifySource.sep
TestScanIdentifier.tests
TestReplaceLeadingIndentation.RangeStmt_7460.tc
TestSanitizeFunc.RangeStmt_2770.tc
TestValueSpecIDAttributes.got
TestFilterOutBuildAnnotations.af
TestFilterOutBuildAnnotations.RangeStmt_9393.cg
TestSrcPosLinkFunc.RangeStmt_660.tc
TestSrcLinkFunc.RangeStmt_1412.BlockStmt.got
TestQueryLinkFunc.RangeStmt_1820.tc
linkifySource.t
linkifySource.src
TestScanIdentifier.t
TestLinkifyGenerics.t
TestLinkifyGenerics.got
TestSanitizeFunc.RangeStmt_2770.BlockStmt.got
TestStructFieldsIDAttributes.got
TestCompositeLitLinkFields
linkifySource.buf
TestScanIdentifier.RangeStmt_6615.BlockStmt.got
TestSrcToPkgLinkFunc
TestSrcToPkgLinkFunc.RangeStmt_8233.tc
TestFilterOutBuildAnnotations.src
TestDocLinkFunc.RangeStmt_2418.BlockStmt.got
TestStructFieldsIDAttributes.want
TestCompositeLitLinkFields.t
TestStructFieldsIDAttributes.t
linkifySource
TestFilterOutBuildAnnotations
TestLinkifyGenerics.want
TestPkgLinkFunc
TestQueryLinkFunc.t
TestSanitizeFunc.t
TestReplaceLeadingIndentation.newIndent
TestSrcBreadcrumbFunc.RangeStmt_7733.tc
linkifySource.p
linkifySource.fset
linkifySource.err
TestValueSpecIDAttributes
TestLinkifyGenerics
TestStructFieldsIDAttributes
TestReplaceLeadingIndentation.oldIndent
TestSrcBreadcrumbFunc.RangeStmt_7733.BlockStmt.got
TestFilterOutBuildAnnotations.t
TestFilterOutBuildAnnotations.RangeStmt_9161.cg
TestSrcPosLinkFunc
TestSrcPosLinkFunc.t
TestQueryLinkFunc
TestSrcToPkgLinkFunc.t
TestSrcLinkFunc.RangeStmt_1412.tc
TestFuncDeclNotLink
TestFuncDeclNotLink.want
TestCompositeLitLinkFields.want
TestPkgLinkFunc.RangeStmt_325.BlockStmt.got
TestSrcLinkFunc.t
TestDocLinkFunc.RangeStmt_2418.tc
TestDocLinkFunc.t
TestScanIdentifier.RangeStmt_6615.tt
TestSrcToPkgLinkFunc.RangeStmt_8233.BlockStmt.got
Members
X