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> = "NoDoc" 176 177 <span class="comment">// Doc has a comment</span> 178 <span id="Doc">Doc</span> = "Doc" 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 }