GoPLS Viewer

Home|gopls/godoc/server_test.go
1// Copyright 2018 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    "go/doc"
9    "net/http"
10    "net/http/httptest"
11    "net/url"
12    "sort"
13    "strings"
14    "testing"
15    "text/template"
16
17    "golang.org/x/tools/godoc/vfs/mapfs"
18    "golang.org/x/tools/internal/typeparams"
19)
20
21// TestIgnoredGoFiles tests the scenario where a folder has no .go or .c files,
22// but has an ignored go file.
23func TestIgnoredGoFiles(t *testing.T) {
24    packagePath := "github.com/package"
25    packageComment := "main is documented in an ignored .go file"
26
27    c := NewCorpus(mapfs.New(map[string]string{
28        "src/" + packagePath + "/ignored.go"`// +build ignore
29
30// ` + packageComment + `
31package main`}))
32    srv := &handlerServer{
33        p: &Presentation{
34            Corpusc,
35        },
36        cc,
37    }
38    pInfo := srv.GetPageInfo("/src/"+packagePathpackagePathNoFiltering"linux""amd64")
39
40    if pInfo.PDoc == nil {
41        t.Error("pInfo.PDoc = nil; want non-nil.")
42    } else {
43        if gotwant := pInfo.PDoc.DocpackageComment+"\n"got != want {
44            t.Errorf("pInfo.PDoc.Doc = %q; want %q."gotwant)
45        }
46        if gotwant := pInfo.PDoc.Name"main"got != want {
47            t.Errorf("pInfo.PDoc.Name = %q; want %q."gotwant)
48        }
49        if gotwant := pInfo.PDoc.ImportPathpackagePathgot != want {
50            t.Errorf("pInfo.PDoc.ImportPath = %q; want %q."gotwant)
51        }
52    }
53    if pInfo.FSet == nil {
54        t.Error("pInfo.FSet = nil; want non-nil.")
55    }
56}
57
58func TestIssue5247(t *testing.T) {
59    const packagePath = "example.com/p"
60    c := NewCorpus(mapfs.New(map[string]string{
61        "src/" + packagePath + "/p.go"`package p
62
63//line notgen.go:3
64// F doc //line 1 should appear
65// line 2 should appear
66func F()
67//line foo.go:100`})) // No newline at end to check corner cases.
68
69    srv := &handlerServer{
70        p: &Presentation{Corpusc},
71        cc,
72    }
73    pInfo := srv.GetPageInfo("/src/"+packagePathpackagePath0"linux""amd64")
74    if gotwant := pInfo.PDoc.Funcs[0].Doc"F doc //line 1 should appear\nline 2 should appear\n"got != want {
75        t.Errorf("pInfo.PDoc.Funcs[0].Doc = %q; want %q"gotwant)
76    }
77}
78
79func testServeBody(t *testing.Tp *Presentationpathbody string) {
80    t.Helper()
81    r := &http.Request{URL: &url.URL{Pathpath}}
82    rw := httptest.NewRecorder()
83    p.ServeFile(rwr)
84    if rw.Code != 200 || !strings.Contains(rw.Body.String(), body) {
85        t.Fatalf("GET %s: expected 200 w/ %q: got %d w/ body:\n%s",
86            pathbodyrw.Coderw.Body)
87    }
88}
89
90func TestRedirectAndMetadata(t *testing.T) {
91    c := NewCorpus(mapfs.New(map[string]string{
92        "doc/y/index.html""Hello, y.",
93        "doc/x/index.html"`<!--{
94        "Path": "/doc/x/"
95}-->
96
97Hello, x.
98`}))
99    c.updateMetadata()
100    p := &Presentation{
101        Corpus:    c,
102        GodocHTMLtemplate.Must(template.New("").Parse(`{{printf "%s" .Body}}`)),
103    }
104
105    // Test that redirect is sent back correctly.
106    // Used to panic. See golang.org/issue/40665.
107    for _elem := range []string{"x""y"} {
108        dir := "/doc/" + elem + "/"
109
110        r := &http.Request{URL: &url.URL{Pathdir + "index.html"}}
111        rw := httptest.NewRecorder()
112        p.ServeFile(rwr)
113        loc := rw.Result().Header.Get("Location")
114        if rw.Code != 301 || loc != dir {
115            t.Errorf("GET %s: expected 301 -> %q, got %d -> %q"r.URL.Pathdirrw.Codeloc)
116        }
117
118        testServeBody(tpdir"Hello, "+elem)
119    }
120}
121
122func TestMarkdown(t *testing.T) {
123    p := &Presentation{
124        CorpusNewCorpus(mapfs.New(map[string]string{
125            "doc/test.md":  "**bold**",
126            "doc/test2.md"`{{"*template*"}}`,
127        })),
128        GodocHTMLtemplate.Must(template.New("").Parse(`{{printf "%s" .Body}}`)),
129    }
130
131    testServeBody(tp"/doc/test.html""<strong>bold</strong>")
132    testServeBody(tp"/doc/test2.html""<em>template</em>")
133}
134
135func TestGenerics(t *testing.T) {
136    if !typeparams.Enabled {
137        t.Skip("type params are not enabled at this Go version")
138    }
139
140    c := NewCorpus(mapfs.New(map[string]string{
141        "blah/blah.go"`package blah
142
143var A AStruct[int]
144
145type AStruct[T any] struct {
146    A string
147    X T
148}
149
150func (a *AStruct[T]) Method() T {
151    return a.X
152}
153
154func (a AStruct[T]) NonPointerMethod() T {
155    return a.X
156}
157
158func NewAStruct[T any](arg T) *AStruct[T] {
159    return &AStruct[T]{ X: arg }
160}
161
162type NonGenericStruct struct {
163    B int
164}
165
166func (b *NonGenericStruct) NonGenericMethod() int {
167    return b.B
168}
169
170func NewNonGenericStruct(arg int) *NonGenericStruct {
171    return &NonGenericStruct{arg}
172}
173
174type Pair[K, V any] struct {
175    K K
176    V V
177}
178
179func (p Pair[K, V]) Apply(kf func(K) K, vf func(V) V) Pair[K, V] {
180    return &Pair{ K: kf(p.K), V: vf(p.V) }
181}
182
183func (p *Pair[K, V]) Set(k K, v V) {
184    p.K = k
185    p.V = v
186}
187
188func NewPair[K, V any](k K, v V) Pair[K, V] {
189    return Pair[K, V]{ k, v }
190}
191`}))
192
193    srv := &handlerServer{
194        p: &Presentation{
195            Corpusc,
196        },
197        cc,
198    }
199    pInfo := srv.GetPageInfo("/blah/"""NoFiltering"linux""amd64")
200    t.Logf("%v\n"pInfo)
201
202    findType := func(name string) *doc.Type {
203        for _typ := range pInfo.PDoc.Types {
204            if typ.Name == name {
205                return typ
206            }
207        }
208        return nil
209    }
210
211    assertFuncs := func(typ *doc.TypetypFuncs []*doc.Funcfuncs ...string) {
212        typfuncs := make([]stringlen(typFuncs))
213        for i := range typFuncs {
214            typfuncs[i] = typFuncs[i].Name
215        }
216        sort.Strings(typfuncs)
217        sort.Strings(funcs)
218        if len(typfuncs) != len(funcs) {
219            t.Errorf("function mismatch for type %q, got: %q, want: %q"typ.Nametypfuncsfuncs)
220            return
221        }
222        for i := range funcs {
223            if funcs[i] != typfuncs[i] {
224                t.Errorf("function mismatch for type %q: got: %q, want: %q"typ.Nametypfuncsfuncs)
225                return
226            }
227        }
228    }
229
230    aStructType := findType("AStruct")
231    assertFuncs(aStructTypeaStructType.Funcs"NewAStruct")
232    assertFuncs(aStructTypeaStructType.Methods"Method""NonPointerMethod")
233
234    nonGenericStructType := findType("NonGenericStruct")
235    assertFuncs(nonGenericStructTypenonGenericStructType.Funcs"NewNonGenericStruct")
236    assertFuncs(nonGenericStructTypenonGenericStructType.Methods"NonGenericMethod")
237
238    pairType := findType("Pair")
239    assertFuncs(pairTypepairType.Funcs"NewPair")
240    assertFuncs(pairTypepairType.Methods"Apply""Set")
241
242    if len(pInfo.PDoc.Funcs) > 0 {
243        t.Errorf("unexpected functions in package documentation")
244    }
245}
246
MembersX
TestIgnoredGoFiles.c
testServeBody.p
TestRedirectAndMetadata.RangeStmt_2891.BlockStmt.rw
TestMarkdown.p
TestGenerics.BlockStmt.RangeStmt_4842.typ
TestGenerics.nonGenericStructType
TestIgnoredGoFiles.packagePath
TestIgnoredGoFiles.srv
testServeBody.rw
TestRedirectAndMetadata.c
TestGenerics.pInfo
TestGenerics.aStructType
TestIssue5247.c
TestIssue5247.srv
TestIssue5247.got
testServeBody.t
TestGenerics
TestGenerics.BlockStmt.RangeStmt_5070.i
TestGenerics.pairType
TestIgnoredGoFiles.pInfo
TestIssue5247.pInfo
TestIssue5247.want
testServeBody.path
TestRedirectAndMetadata.RangeStmt_2891.BlockStmt.loc
TestMarkdown
TestGenerics.t
TestIgnoredGoFiles
TestIgnoredGoFiles.BlockStmt.got
TestRedirectAndMetadata.t
TestRedirectAndMetadata.RangeStmt_2891.elem
TestMarkdown.t
TestGenerics.srv
TestGenerics.BlockStmt.RangeStmt_5323.i
httptest
TestIgnoredGoFiles.t
TestIgnoredGoFiles.packageComment
TestIssue5247.t
TestIssue5247.packagePath
TestRedirectAndMetadata.p
TestGenerics.c
TestIgnoredGoFiles.BlockStmt.want
TestIssue5247
testServeBody.body
TestRedirectAndMetadata.RangeStmt_2891.BlockStmt.r
url
testServeBody
testServeBody.r
TestRedirectAndMetadata
TestGenerics.BlockStmt.typfuncs
Members
X