mirror of
https://github.com/golang/go
synced 2024-11-18 16:44:43 -07:00
faa8a71ab5
After moving the filepath.Walk example to a standalone example file in CL 122237 (so it could use a standalone function), godoc includes the build tag annotation ("// +build !windows,!plan9" in this case) in the runnable example. The example runs correctly, but the annotation might be confusing for new users. With this change, godoc skips these annotations when displaying examples. Fixes golang/go#26490. Change-Id: Ice3d6a2ce4db5b5176c9c6fcabc01b69c323016d GitHub-Last-Rev: 52beabd3d2a9cb9a556bfa3bd998a2e31ac96960 GitHub-Pull-Request: golang/tools#40 Reviewed-on: https://go-review.googlesource.com/125040 Reviewed-by: Andrew Bonventre <andybons@golang.org>
369 lines
9.3 KiB
Go
369 lines
9.3 KiB
Go
// Copyright 2013 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package godoc
|
|
|
|
import (
|
|
"bytes"
|
|
"go/parser"
|
|
"go/token"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestPkgLinkFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
path string
|
|
want string
|
|
}{
|
|
{"/src/fmt", "pkg/fmt"},
|
|
{"src/fmt", "pkg/fmt"},
|
|
{"/fmt", "pkg/fmt"},
|
|
{"fmt", "pkg/fmt"},
|
|
} {
|
|
if got := pkgLinkFunc(tc.path); got != tc.want {
|
|
t.Errorf("pkgLinkFunc(%v) = %v; want %v", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSrcPosLinkFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
src string
|
|
line int
|
|
low int
|
|
high int
|
|
want string
|
|
}{
|
|
{"/src/fmt/print.go", 42, 30, 50, "/src/fmt/print.go?s=30:50#L32"},
|
|
{"/src/fmt/print.go", 2, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
|
|
{"/src/fmt/print.go", 2, 0, 0, "/src/fmt/print.go#L2"},
|
|
{"/src/fmt/print.go", 0, 0, 0, "/src/fmt/print.go"},
|
|
{"/src/fmt/print.go", 0, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
|
|
{"fmt/print.go", 0, 0, 0, "/src/fmt/print.go"},
|
|
{"fmt/print.go", 0, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
|
|
} {
|
|
if got := srcPosLinkFunc(tc.src, tc.line, tc.low, tc.high); got != tc.want {
|
|
t.Errorf("srcLinkFunc(%v, %v, %v, %v) = %v; want %v", tc.src, tc.line, tc.low, tc.high, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSrcLinkFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
src string
|
|
want string
|
|
}{
|
|
{"/src/fmt/print.go", "/src/fmt/print.go"},
|
|
{"src/fmt/print.go", "/src/fmt/print.go"},
|
|
{"/fmt/print.go", "/src/fmt/print.go"},
|
|
{"fmt/print.go", "/src/fmt/print.go"},
|
|
} {
|
|
if got := srcLinkFunc(tc.src); got != tc.want {
|
|
t.Errorf("srcLinkFunc(%v) = %v; want %v", tc.src, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestQueryLinkFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
src string
|
|
query string
|
|
line int
|
|
want string
|
|
}{
|
|
{"/src/fmt/print.go", "Sprintf", 33, "/src/fmt/print.go?h=Sprintf#L33"},
|
|
{"/src/fmt/print.go", "Sprintf", 0, "/src/fmt/print.go?h=Sprintf"},
|
|
{"src/fmt/print.go", "EOF", 33, "/src/fmt/print.go?h=EOF#L33"},
|
|
{"src/fmt/print.go", "a%3f+%26b", 1, "/src/fmt/print.go?h=a%3f+%26b#L1"},
|
|
} {
|
|
if got := queryLinkFunc(tc.src, tc.query, tc.line); got != tc.want {
|
|
t.Errorf("queryLinkFunc(%v, %v, %v) = %v; want %v", tc.src, tc.query, tc.line, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDocLinkFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
src string
|
|
ident string
|
|
want string
|
|
}{
|
|
{"fmt", "Sprintf", "/pkg/fmt/#Sprintf"},
|
|
{"fmt", "EOF", "/pkg/fmt/#EOF"},
|
|
} {
|
|
if got := docLinkFunc(tc.src, tc.ident); got != tc.want {
|
|
t.Errorf("docLinkFunc(%v, %v) = %v; want %v", tc.src, tc.ident, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSanitizeFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
src string
|
|
want string
|
|
}{
|
|
{},
|
|
{"foo", "foo"},
|
|
{"func f()", "func f()"},
|
|
{"func f(a int,)", "func f(a int)"},
|
|
{"func f(a int,\n)", "func f(a int)"},
|
|
{"func f(\n\ta int,\n\tb int,\n\tc int,\n)", "func f(a int, b int, c int)"},
|
|
{" ( a, b, c ) ", "(a, b, c)"},
|
|
{"( a, b, c int, foo bar , )", "(a, b, c int, foo bar)"},
|
|
{"{ a, b}", "{a, b}"},
|
|
{"[ a, b]", "[a, b]"},
|
|
} {
|
|
if got := sanitizeFunc(tc.src); got != tc.want {
|
|
t.Errorf("sanitizeFunc(%v) = %v; want %v", tc.src, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test that we add <span id="StructName.FieldName"> elements
|
|
// to the HTML of struct fields.
|
|
func TestStructFieldsIDAttributes(t *testing.T) {
|
|
got := linkifySource(t, []byte(`
|
|
package foo
|
|
|
|
type T struct {
|
|
NoDoc string
|
|
|
|
// Doc has a comment.
|
|
Doc string
|
|
|
|
// Opt, if non-nil, is an option.
|
|
Opt *int
|
|
|
|
// Опция - другое поле.
|
|
Опция bool
|
|
}
|
|
`))
|
|
want := `type T struct {
|
|
<span id="T.NoDoc"></span>NoDoc <a href="/pkg/builtin/#string">string</a>
|
|
|
|
<span id="T.Doc"></span><span class="comment">// Doc has a comment.</span>
|
|
Doc <a href="/pkg/builtin/#string">string</a>
|
|
|
|
<span id="T.Opt"></span><span class="comment">// Opt, if non-nil, is an option.</span>
|
|
Opt *<a href="/pkg/builtin/#int">int</a>
|
|
|
|
<span id="T.Опция"></span><span class="comment">// Опция - другое поле.</span>
|
|
Опция <a href="/pkg/builtin/#bool">bool</a>
|
|
}`
|
|
if got != want {
|
|
t.Errorf("got: %s\n\nwant: %s\n", got, want)
|
|
}
|
|
}
|
|
|
|
// Test that we add <span id="ConstName"> elements to the HTML
|
|
// of definitions in const and var specs.
|
|
func TestValueSpecIDAttributes(t *testing.T) {
|
|
got := linkifySource(t, []byte(`
|
|
package foo
|
|
|
|
const (
|
|
NoDoc string = "NoDoc"
|
|
|
|
// Doc has a comment
|
|
Doc = "Doc"
|
|
|
|
NoVal
|
|
)`))
|
|
want := `const (
|
|
<span id="NoDoc">NoDoc</span> <a href="/pkg/builtin/#string">string</a> = "NoDoc"
|
|
|
|
<span class="comment">// Doc has a comment</span>
|
|
<span id="Doc">Doc</span> = "Doc"
|
|
|
|
<span id="NoVal">NoVal</span>
|
|
)`
|
|
if got != want {
|
|
t.Errorf("got: %s\n\nwant: %s\n", got, want)
|
|
}
|
|
}
|
|
|
|
func TestCompositeLitLinkFields(t *testing.T) {
|
|
got := linkifySource(t, []byte(`
|
|
package foo
|
|
|
|
type T struct {
|
|
X int
|
|
}
|
|
|
|
var S T = T{X: 12}`))
|
|
want := `type T struct {
|
|
<span id="T.X"></span>X <a href="/pkg/builtin/#int">int</a>
|
|
}
|
|
var <span id="S">S</span> <a href="#T">T</a> = <a href="#T">T</a>{<a href="#T.X">X</a>: 12}`
|
|
if got != want {
|
|
t.Errorf("got: %s\n\nwant: %s\n", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFuncDeclNotLink(t *testing.T) {
|
|
// Function.
|
|
got := linkifySource(t, []byte(`
|
|
package http
|
|
|
|
func Get(url string) (resp *Response, err error)`))
|
|
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>)`
|
|
if got != want {
|
|
t.Errorf("got: %s\n\nwant: %s\n", got, want)
|
|
}
|
|
|
|
// Method.
|
|
got = linkifySource(t, []byte(`
|
|
package http
|
|
|
|
func (h Header) Get(key string) string`))
|
|
want = `func (h <a href="#Header">Header</a>) Get(key <a href="/pkg/builtin/#string">string</a>) <a href="/pkg/builtin/#string">string</a>`
|
|
if got != want {
|
|
t.Errorf("got: %s\n\nwant: %s\n", got, want)
|
|
}
|
|
}
|
|
|
|
func linkifySource(t *testing.T, src []byte) string {
|
|
p := &Presentation{
|
|
DeclLinks: true,
|
|
}
|
|
fset := token.NewFileSet()
|
|
af, err := parser.ParseFile(fset, "foo.go", src, parser.ParseComments)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var buf bytes.Buffer
|
|
pi := &PageInfo{
|
|
FSet: fset,
|
|
}
|
|
sep := ""
|
|
for _, decl := range af.Decls {
|
|
buf.WriteString(sep)
|
|
sep = "\n"
|
|
buf.WriteString(p.node_htmlFunc(pi, decl, true))
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
func TestScanIdentifier(t *testing.T) {
|
|
tests := []struct {
|
|
in, want string
|
|
}{
|
|
{"foo bar", "foo"},
|
|
{"foo/bar", "foo"},
|
|
{" foo", ""},
|
|
{"фоо", "фоо"},
|
|
{"f123", "f123"},
|
|
{"123f", ""},
|
|
}
|
|
for _, tt := range tests {
|
|
got := scanIdentifier([]byte(tt.in))
|
|
if string(got) != tt.want {
|
|
t.Errorf("scanIdentifier(%q) = %q; want %q", tt.in, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReplaceLeadingIndentation(t *testing.T) {
|
|
oldIndent := strings.Repeat(" ", 2)
|
|
newIndent := strings.Repeat(" ", 4)
|
|
tests := []struct {
|
|
src, want string
|
|
}{
|
|
{" foo\n bar\n baz", " foo\n bar\n baz"},
|
|
{" '`'\n '`'\n", " '`'\n '`'\n"},
|
|
{" '\\''\n '`'\n", " '\\''\n '`'\n"},
|
|
{" \"`\"\n \"`\"\n", " \"`\"\n \"`\"\n"},
|
|
{" `foo\n bar`", " `foo\n bar`"},
|
|
{" `foo\\`\n bar", " `foo\\`\n bar"},
|
|
{" '\\`'`foo\n bar", " '\\`'`foo\n bar"},
|
|
{
|
|
" if true {\n foo := `One\n \tTwo\nThree`\n }\n",
|
|
" if true {\n foo := `One\n \tTwo\n Three`\n }\n",
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
if got := replaceLeadingIndentation(tc.src, oldIndent, newIndent); got != tc.want {
|
|
t.Errorf("replaceLeadingIndentation:\n%v\n---\nhave:\n%v\n---\nwant:\n%v\n",
|
|
tc.src, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSrcBreadcrumbFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
path string
|
|
want string
|
|
}{
|
|
{"src/", `<span class="text-muted">src/</span>`},
|
|
{"src/fmt/", `<a href="/src">src</a>/<span class="text-muted">fmt/</span>`},
|
|
{"src/fmt/print.go", `<a href="/src">src</a>/<a href="/src/fmt">fmt</a>/<span class="text-muted">print.go</span>`},
|
|
} {
|
|
if got := srcBreadcrumbFunc(tc.path); got != tc.want {
|
|
t.Errorf("srcBreadcrumbFunc(%v) = %v; want %v", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSrcToPkgLinkFunc(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
path string
|
|
want string
|
|
}{
|
|
{"src/", `<a href="/pkg">Index</a>`},
|
|
{"src/fmt/", `<a href="/pkg/fmt">fmt</a>`},
|
|
{"pkg/", `<a href="/pkg">Index</a>`},
|
|
{"pkg/LICENSE", `<a href="/pkg">Index</a>`},
|
|
} {
|
|
if got := srcToPkgLinkFunc(tc.path); got != tc.want {
|
|
t.Errorf("srcToPkgLinkFunc(%v) = %v; want %v", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFilterOutBuildAnnotations(t *testing.T) {
|
|
src := []byte(`
|
|
// +build !foo
|
|
// +build !anothertag
|
|
|
|
// non-tag comment
|
|
|
|
package foo
|
|
|
|
func bar() int {
|
|
return 42
|
|
}`)
|
|
|
|
fset := token.NewFileSet()
|
|
af, err := parser.ParseFile(fset, "foo.go", src, parser.ParseComments)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var found bool
|
|
for _, cg := range af.Comments {
|
|
if strings.HasPrefix(cg.Text(), "+build ") {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("TestFilterOutBuildAnnotations is broken: missing build tag in test input")
|
|
}
|
|
|
|
found = false
|
|
for _, cg := range filterOutBuildAnnotations(af.Comments) {
|
|
if strings.HasPrefix(cg.Text(), "+build ") {
|
|
t.Errorf("filterOutBuildAnnotations failed to filter build tag")
|
|
}
|
|
|
|
if strings.Contains(cg.Text(), "non-tag comment") {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("filterOutBuildAnnotations should not remove non-build tag comment")
|
|
}
|
|
}
|