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