github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/doc/doc_test.go (about) 1 // Copyright 2015 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 main 6 7 import ( 8 "bytes" 9 "flag" 10 "os" 11 "path/filepath" 12 "regexp" 13 "runtime" 14 "strings" 15 "testing" 16 ) 17 18 func TestMain(m *testing.M) { 19 // Clear GOPATH so we don't access the user's own packages in the test. 20 buildCtx.GOPATH = "" 21 testGOPATH = true // force GOPATH mode; module test is in cmd/go/testdata/script/mod_doc.txt 22 23 // Add $GOROOT/src/cmd/doc/testdata explicitly so we can access its contents in the test. 24 // Normally testdata directories are ignored, but sending it to dirs.scan directly is 25 // a hack that works around the check. 26 testdataDir, err := filepath.Abs("testdata") 27 if err != nil { 28 panic(err) 29 } 30 dirsInit(Dir{"testdata", testdataDir}, Dir{"testdata/nested", filepath.Join(testdataDir, "nested")}, Dir{"testdata/nested/nested", filepath.Join(testdataDir, "nested", "nested")}) 31 32 os.Exit(m.Run()) 33 } 34 35 func maybeSkip(t *testing.T) { 36 if strings.HasPrefix(runtime.GOOS, "nacl") { 37 t.Skip("nacl does not have a full file tree") 38 } 39 if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") { 40 t.Skip("darwin/arm does not have a full file tree") 41 } 42 } 43 44 type isDotSlashTest struct { 45 str string 46 result bool 47 } 48 49 var isDotSlashTests = []isDotSlashTest{ 50 {``, false}, 51 {`x`, false}, 52 {`...`, false}, 53 {`.../`, false}, 54 {`...\`, false}, 55 56 {`.`, true}, 57 {`./`, true}, 58 {`.\`, true}, 59 {`./x`, true}, 60 {`.\x`, true}, 61 62 {`..`, true}, 63 {`../`, true}, 64 {`..\`, true}, 65 {`../x`, true}, 66 {`..\x`, true}, 67 } 68 69 func TestIsDotSlashPath(t *testing.T) { 70 for _, test := range isDotSlashTests { 71 if result := isDotSlash(test.str); result != test.result { 72 t.Errorf("isDotSlash(%q) = %t; expected %t", test.str, result, test.result) 73 } 74 } 75 } 76 77 type test struct { 78 name string 79 args []string // Arguments to "[go] doc". 80 yes []string // Regular expressions that should match. 81 no []string // Regular expressions that should not match. 82 } 83 84 const p = "cmd/doc/testdata" 85 86 var tests = []test{ 87 // Sanity check. 88 { 89 "sanity check", 90 []string{p}, 91 []string{`type ExportedType struct`}, 92 nil, 93 }, 94 95 // Package dump includes import, package statement. 96 { 97 "package clause", 98 []string{p}, 99 []string{`package pkg.*cmd/doc/testdata`}, 100 nil, 101 }, 102 103 // Constants. 104 // Package dump 105 { 106 "full package", 107 []string{p}, 108 []string{ 109 `Package comment`, 110 `const ExportedConstant = 1`, // Simple constant. 111 `const ConstOne = 1`, // First entry in constant block. 112 `const ConstFive ...`, // From block starting with unexported constant. 113 `var ExportedVariable = 1`, // Simple variable. 114 `var VarOne = 1`, // First entry in variable block. 115 `func ExportedFunc\(a int\) bool`, // Function. 116 `func ReturnUnexported\(\) unexportedType`, // Function with unexported return type. 117 `type ExportedType struct{ ... }`, // Exported type. 118 `const ExportedTypedConstant ExportedType = iota`, // Typed constant. 119 `const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type. 120 `const ConstLeft2 uint64 ...`, // Typed constant using unexported iota. 121 `const ConstGroup1 unexportedType = iota ...`, // Typed constant using unexported type. 122 `const ConstGroup4 ExportedType = ExportedType{}`, // Typed constant using exported type. 123 `const MultiLineConst = ...`, // Multi line constant. 124 `var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`, // Multi line variable. 125 `func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function. 126 `var LongLine = newLongLine\(("someArgument[1-4]", ){4}...\)`, // Long list of arguments. 127 `type T1 = T2`, // Type alias 128 }, 129 []string{ 130 `const internalConstant = 2`, // No internal constants. 131 `var internalVariable = 2`, // No internal variables. 132 `func internalFunc(a int) bool`, // No internal functions. 133 `Comment about exported constant`, // No comment for single constant. 134 `Comment about exported variable`, // No comment for single variable. 135 `Comment about block of constants`, // No comment for constant block. 136 `Comment about block of variables`, // No comment for variable block. 137 `Comment before ConstOne`, // No comment for first entry in constant block. 138 `Comment before VarOne`, // No comment for first entry in variable block. 139 `ConstTwo = 2`, // No second entry in constant block. 140 `VarTwo = 2`, // No second entry in variable block. 141 `VarFive = 5`, // From block starting with unexported variable. 142 `type unexportedType`, // No unexported type. 143 `unexportedTypedConstant`, // No unexported typed constant. 144 `\bField`, // No fields. 145 `Method`, // No methods. 146 `someArgument[5-8]`, // No truncated arguments. 147 `type T1 T2`, // Type alias does not display as type declaration. 148 }, 149 }, 150 // Package dump -all 151 { 152 "full package", 153 []string{"-all", p}, 154 []string{ 155 `package pkg .*import`, 156 `Package comment`, 157 `CONSTANTS`, 158 `Comment before ConstOne`, 159 `ConstOne = 1`, 160 `ConstTwo = 2 // Comment on line with ConstTwo`, 161 `ConstFive`, 162 `ConstSix`, 163 `Const block where first entry is unexported`, 164 `ConstLeft2, constRight2 uint64`, 165 `constLeft3, ConstRight3`, 166 `ConstLeft4, ConstRight4`, 167 `Duplicate = iota`, 168 `const CaseMatch = 1`, 169 `const Casematch = 2`, 170 `const ExportedConstant = 1`, 171 `const MultiLineConst = `, 172 `MultiLineString1`, 173 `VARIABLES`, 174 `Comment before VarOne`, 175 `VarOne = 1`, 176 `Comment about block of variables`, 177 `VarFive = 5`, 178 `var ExportedVariable = 1`, 179 `var LongLine = newLongLine\(`, 180 `var MultiLineVar = map\[struct {`, 181 `FUNCTIONS`, 182 `func ExportedFunc\(a int\) bool`, 183 `Comment about exported function`, 184 `func MultiLineFunc\(x interface`, 185 `func ReturnUnexported\(\) unexportedType`, 186 `TYPES`, 187 `type ExportedInterface interface`, 188 `type ExportedStructOneField struct`, 189 `type ExportedType struct`, 190 `Comment about exported type`, 191 `const ConstGroup4 ExportedType = ExportedType`, 192 `ExportedTypedConstant ExportedType = iota`, 193 `Constants tied to ExportedType`, 194 `func ExportedTypeConstructor\(\) \*ExportedType`, 195 `Comment about constructor for exported type`, 196 `func ReturnExported\(\) ExportedType`, 197 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 198 `Comment about exported method`, 199 `type T1 = T2`, 200 `type T2 int`, 201 }, 202 []string{ 203 `constThree`, 204 `_, _ uint64 = 2 \* iota, 1 << iota`, 205 `constLeft1, constRight1`, 206 `duplicate`, 207 `varFour`, 208 `func internalFunc`, 209 `unexportedField`, 210 `func \(unexportedType\)`, 211 }, 212 }, 213 // Package dump -u 214 { 215 "full package with u", 216 []string{`-u`, p}, 217 []string{ 218 `const ExportedConstant = 1`, // Simple constant. 219 `const internalConstant = 2`, // Internal constants. 220 `func internalFunc\(a int\) bool`, // Internal functions. 221 `func ReturnUnexported\(\) unexportedType`, // Function with unexported return type. 222 }, 223 []string{ 224 `Comment about exported constant`, // No comment for simple constant. 225 `Comment about block of constants`, // No comment for constant block. 226 `Comment about internal function`, // No comment for internal function. 227 `MultiLine(String|Method|Field)`, // No data from multi line portions. 228 }, 229 }, 230 // Package dump -u -all 231 { 232 "full package", 233 []string{"-u", "-all", p}, 234 []string{ 235 `package pkg .*import`, 236 `Package comment`, 237 `CONSTANTS`, 238 `Comment before ConstOne`, 239 `ConstOne += 1`, 240 `ConstTwo += 2 // Comment on line with ConstTwo`, 241 `constThree = 3 // Comment on line with constThree`, 242 `ConstFive`, 243 `const internalConstant += 2`, 244 `Comment about internal constant`, 245 `VARIABLES`, 246 `Comment before VarOne`, 247 `VarOne += 1`, 248 `Comment about block of variables`, 249 `varFour += 4`, 250 `VarFive += 5`, 251 `varSix += 6`, 252 `var ExportedVariable = 1`, 253 `var LongLine = newLongLine\(`, 254 `var MultiLineVar = map\[struct {`, 255 `var internalVariable = 2`, 256 `Comment about internal variable`, 257 `FUNCTIONS`, 258 `func ExportedFunc\(a int\) bool`, 259 `Comment about exported function`, 260 `func MultiLineFunc\(x interface`, 261 `func internalFunc\(a int\) bool`, 262 `Comment about internal function`, 263 `func newLongLine\(ss .*string\)`, 264 `TYPES`, 265 `type ExportedType struct`, 266 `type T1 = T2`, 267 `type T2 int`, 268 `type unexportedType int`, 269 `Comment about unexported type`, 270 `ConstGroup1 unexportedType = iota`, 271 `ConstGroup2`, 272 `ConstGroup3`, 273 `ExportedTypedConstant_unexported unexportedType = iota`, 274 `Constants tied to unexportedType`, 275 `const unexportedTypedConstant unexportedType = 1`, 276 `func ReturnUnexported\(\) unexportedType`, 277 `func \(unexportedType\) ExportedMethod\(\) bool`, 278 `func \(unexportedType\) unexportedMethod\(\) bool`, 279 }, 280 nil, 281 }, 282 283 // Single constant. 284 { 285 "single constant", 286 []string{p, `ExportedConstant`}, 287 []string{ 288 `Comment about exported constant`, // Include comment. 289 `const ExportedConstant = 1`, 290 }, 291 nil, 292 }, 293 // Single constant -u. 294 { 295 "single constant with -u", 296 []string{`-u`, p, `internalConstant`}, 297 []string{ 298 `Comment about internal constant`, // Include comment. 299 `const internalConstant = 2`, 300 }, 301 nil, 302 }, 303 // Block of constants. 304 { 305 "block of constants", 306 []string{p, `ConstTwo`}, 307 []string{ 308 `Comment before ConstOne.\n.*ConstOne = 1`, // First... 309 `ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up. 310 `Comment about block of constants`, // Comment does too. 311 }, 312 []string{ 313 `constThree`, // No unexported constant. 314 }, 315 }, 316 // Block of constants -u. 317 { 318 "block of constants with -u", 319 []string{"-u", p, `constThree`}, 320 []string{ 321 `constThree = 3.*Comment on line with constThree`, 322 }, 323 nil, 324 }, 325 // Block of constants -src. 326 { 327 "block of constants with -src", 328 []string{"-src", p, `ConstTwo`}, 329 []string{ 330 `Comment about block of constants`, // Top comment. 331 `ConstOne.*=.*1`, // Each constant seen. 332 `ConstTwo.*=.*2.*Comment on line with ConstTwo`, 333 `constThree`, // Even unexported constants. 334 }, 335 nil, 336 }, 337 // Block of constants with carryover type from unexported field. 338 { 339 "block of constants with carryover type", 340 []string{p, `ConstLeft2`}, 341 []string{ 342 `ConstLeft2, constRight2 uint64`, 343 `constLeft3, ConstRight3`, 344 `ConstLeft4, ConstRight4`, 345 }, 346 nil, 347 }, 348 // Block of constants -u with carryover type from unexported field. 349 { 350 "block of constants with carryover type", 351 []string{"-u", p, `ConstLeft2`}, 352 []string{ 353 `_, _ uint64 = 2 \* iota, 1 << iota`, 354 `constLeft1, constRight1`, 355 `ConstLeft2, constRight2`, 356 `constLeft3, ConstRight3`, 357 `ConstLeft4, ConstRight4`, 358 }, 359 nil, 360 }, 361 362 // Single variable. 363 { 364 "single variable", 365 []string{p, `ExportedVariable`}, 366 []string{ 367 `ExportedVariable`, // Include comment. 368 `var ExportedVariable = 1`, 369 }, 370 nil, 371 }, 372 // Single variable -u. 373 { 374 "single variable with -u", 375 []string{`-u`, p, `internalVariable`}, 376 []string{ 377 `Comment about internal variable`, // Include comment. 378 `var internalVariable = 2`, 379 }, 380 nil, 381 }, 382 // Block of variables. 383 { 384 "block of variables", 385 []string{p, `VarTwo`}, 386 []string{ 387 `Comment before VarOne.\n.*VarOne = 1`, // First... 388 `VarTwo = 2.*Comment on line with VarTwo`, // And second show up. 389 `Comment about block of variables`, // Comment does too. 390 }, 391 []string{ 392 `varThree= 3`, // No unexported variable. 393 }, 394 }, 395 // Block of variables -u. 396 { 397 "block of variables with -u", 398 []string{"-u", p, `varThree`}, 399 []string{ 400 `varThree = 3.*Comment on line with varThree`, 401 }, 402 nil, 403 }, 404 405 // Function. 406 { 407 "function", 408 []string{p, `ExportedFunc`}, 409 []string{ 410 `Comment about exported function`, // Include comment. 411 `func ExportedFunc\(a int\) bool`, 412 }, 413 nil, 414 }, 415 // Function -u. 416 { 417 "function with -u", 418 []string{"-u", p, `internalFunc`}, 419 []string{ 420 `Comment about internal function`, // Include comment. 421 `func internalFunc\(a int\) bool`, 422 }, 423 nil, 424 }, 425 // Function with -src. 426 { 427 "function with -src", 428 []string{"-src", p, `ExportedFunc`}, 429 []string{ 430 `Comment about exported function`, // Include comment. 431 `func ExportedFunc\(a int\) bool`, 432 `return true != false`, // Include body. 433 }, 434 nil, 435 }, 436 437 // Type. 438 { 439 "type", 440 []string{p, `ExportedType`}, 441 []string{ 442 `Comment about exported type`, // Include comment. 443 `type ExportedType struct`, // Type definition. 444 `Comment before exported field.*\n.*ExportedField +int` + 445 `.*Comment on line with exported field`, 446 `ExportedEmbeddedType.*Comment on line with exported embedded field`, 447 `Has unexported fields`, 448 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 449 `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant. 450 `func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor. 451 `io.Reader.*Comment on line with embedded Reader`, 452 }, 453 []string{ 454 `unexportedField`, // No unexported field. 455 `int.*embedded`, // No unexported embedded field. 456 `Comment about exported method`, // No comment about exported method. 457 `unexportedMethod`, // No unexported method. 458 `unexportedTypedConstant`, // No unexported constant. 459 `error`, // No embedded error. 460 }, 461 }, 462 // Type with -src. Will see unexported fields. 463 { 464 "type", 465 []string{"-src", p, `ExportedType`}, 466 []string{ 467 `Comment about exported type`, // Include comment. 468 `type ExportedType struct`, // Type definition. 469 `Comment before exported field`, 470 `ExportedField.*Comment on line with exported field`, 471 `ExportedEmbeddedType.*Comment on line with exported embedded field`, 472 `unexportedType.*Comment on line with unexported embedded field`, 473 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 474 `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant. 475 `func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor. 476 `io.Reader.*Comment on line with embedded Reader`, 477 }, 478 []string{ 479 `Comment about exported method`, // No comment about exported method. 480 `unexportedMethod`, // No unexported method. 481 `unexportedTypedConstant`, // No unexported constant. 482 }, 483 }, 484 // Type -all. 485 { 486 "type", 487 []string{"-all", p, `ExportedType`}, 488 []string{ 489 `type ExportedType struct {`, // Type definition as source. 490 `Comment about exported type`, // Include comment afterwards. 491 `const ConstGroup4 ExportedType = ExportedType\{\}`, // Related constants. 492 `ExportedTypedConstant ExportedType = iota`, 493 `Constants tied to ExportedType`, 494 `func ExportedTypeConstructor\(\) \*ExportedType`, 495 `Comment about constructor for exported type.`, 496 `func ReturnExported\(\) ExportedType`, 497 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 498 `Comment about exported method.`, 499 }, 500 []string{ 501 `unexportedType`, 502 }, 503 }, 504 // Type T1 dump (alias). 505 { 506 "type T1", 507 []string{p + ".T1"}, 508 []string{ 509 `type T1 = T2`, 510 }, 511 []string{ 512 `type T1 T2`, 513 `type ExportedType`, 514 }, 515 }, 516 // Type -u with unexported fields. 517 { 518 "type with unexported fields and -u", 519 []string{"-u", p, `ExportedType`}, 520 []string{ 521 `Comment about exported type`, // Include comment. 522 `type ExportedType struct`, // Type definition. 523 `Comment before exported field.*\n.*ExportedField +int`, 524 `unexportedField.*int.*Comment on line with unexported field`, 525 `ExportedEmbeddedType.*Comment on line with exported embedded field`, 526 `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field`, 527 `\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field`, 528 `unexportedType.*Comment on line with unexported embedded field`, 529 `\*unexportedType.*Comment on line with unexported embedded \*field`, 530 `io.Reader.*Comment on line with embedded Reader`, 531 `error.*Comment on line with embedded error`, 532 `func \(ExportedType\) unexportedMethod\(a int\) bool`, 533 `unexportedTypedConstant`, 534 }, 535 []string{ 536 `Has unexported fields`, 537 }, 538 }, 539 // Unexported type with -u. 540 { 541 "unexported type with -u", 542 []string{"-u", p, `unexportedType`}, 543 []string{ 544 `Comment about unexported type`, // Include comment. 545 `type unexportedType int`, // Type definition. 546 `func \(unexportedType\) ExportedMethod\(\) bool`, 547 `func \(unexportedType\) unexportedMethod\(\) bool`, 548 `ExportedTypedConstant_unexported unexportedType = iota`, 549 `const unexportedTypedConstant unexportedType = 1`, 550 }, 551 nil, 552 }, 553 554 // Interface. 555 { 556 "interface type", 557 []string{p, `ExportedInterface`}, 558 []string{ 559 `Comment about exported interface`, // Include comment. 560 `type ExportedInterface interface`, // Interface definition. 561 `Comment before exported method.*\n.*ExportedMethod\(\)` + 562 `.*Comment on line with exported method`, 563 `io.Reader.*Comment on line with embedded Reader`, 564 `error.*Comment on line with embedded error`, 565 `Has unexported methods`, 566 }, 567 []string{ 568 `unexportedField`, // No unexported field. 569 `Comment about exported method`, // No comment about exported method. 570 `unexportedMethod`, // No unexported method. 571 `unexportedTypedConstant`, // No unexported constant. 572 }, 573 }, 574 // Interface -u with unexported methods. 575 { 576 "interface type with unexported methods and -u", 577 []string{"-u", p, `ExportedInterface`}, 578 []string{ 579 `Comment about exported interface`, // Include comment. 580 `type ExportedInterface interface`, // Interface definition. 581 `Comment before exported method.*\n.*ExportedMethod\(\)` + 582 `.*Comment on line with exported method`, 583 `unexportedMethod\(\).*Comment on line with unexported method`, 584 `io.Reader.*Comment on line with embedded Reader`, 585 `error.*Comment on line with embedded error`, 586 }, 587 []string{ 588 `Has unexported methods`, 589 }, 590 }, 591 592 // Interface method. 593 { 594 "interface method", 595 []string{p, `ExportedInterface.ExportedMethod`}, 596 []string{ 597 `Comment before exported method.*\n.*ExportedMethod\(\)` + 598 `.*Comment on line with exported method`, 599 }, 600 []string{ 601 `Comment about exported interface`, 602 }, 603 }, 604 605 // Method. 606 { 607 "method", 608 []string{p, `ExportedType.ExportedMethod`}, 609 []string{ 610 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 611 `Comment about exported method`, 612 }, 613 nil, 614 }, 615 // Method with -u. 616 { 617 "method with -u", 618 []string{"-u", p, `ExportedType.unexportedMethod`}, 619 []string{ 620 `func \(ExportedType\) unexportedMethod\(a int\) bool`, 621 `Comment about unexported method`, 622 }, 623 nil, 624 }, 625 // Method with -src. 626 { 627 "method with -src", 628 []string{"-src", p, `ExportedType.ExportedMethod`}, 629 []string{ 630 `func \(ExportedType\) ExportedMethod\(a int\) bool`, 631 `Comment about exported method`, 632 `return true != true`, 633 }, 634 nil, 635 }, 636 637 // Field. 638 { 639 "field", 640 []string{p, `ExportedType.ExportedField`}, 641 []string{ 642 `type ExportedType struct`, 643 `ExportedField int`, 644 `Comment before exported field`, 645 `Comment on line with exported field`, 646 `other fields elided`, 647 }, 648 nil, 649 }, 650 651 // Field with -u. 652 { 653 "method with -u", 654 []string{"-u", p, `ExportedType.unexportedField`}, 655 []string{ 656 `unexportedField int`, 657 `Comment on line with unexported field`, 658 }, 659 nil, 660 }, 661 662 // Field of struct with only one field. 663 { 664 "single-field struct", 665 []string{p, `ExportedStructOneField.OnlyField`}, 666 []string{`the only field`}, 667 []string{`other fields elided`}, 668 }, 669 670 // Case matching off. 671 { 672 "case matching off", 673 []string{p, `casematch`}, 674 []string{ 675 `CaseMatch`, 676 `Casematch`, 677 }, 678 nil, 679 }, 680 681 // Case matching on. 682 { 683 "case matching on", 684 []string{"-c", p, `Casematch`}, 685 []string{ 686 `Casematch`, 687 }, 688 []string{ 689 `CaseMatch`, 690 }, 691 }, 692 693 // No dups with -u. Issue 21797. 694 { 695 "case matching on, no dups", 696 []string{"-u", p, `duplicate`}, 697 []string{ 698 `Duplicate`, 699 `duplicate`, 700 }, 701 []string{ 702 "\\)\n+const", // This will appear if the const decl appears twice. 703 }, 704 }, 705 { 706 "non-imported: pkg.sym", 707 []string{"nested.Foo"}, 708 []string{"Foo struct"}, 709 nil, 710 }, 711 { 712 "non-imported: pkg only", 713 []string{"nested"}, 714 []string{"Foo struct"}, 715 nil, 716 }, 717 { 718 "non-imported: pkg sym", 719 []string{"nested", "Foo"}, 720 []string{"Foo struct"}, 721 nil, 722 }, 723 } 724 725 func TestDoc(t *testing.T) { 726 maybeSkip(t) 727 for _, test := range tests { 728 var b bytes.Buffer 729 var flagSet flag.FlagSet 730 err := do(&b, &flagSet, test.args) 731 if err != nil { 732 t.Fatalf("%s %v: %s\n", test.name, test.args, err) 733 } 734 output := b.Bytes() 735 failed := false 736 for j, yes := range test.yes { 737 re, err := regexp.Compile(yes) 738 if err != nil { 739 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err) 740 } 741 if !re.Match(output) { 742 t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes) 743 failed = true 744 } 745 } 746 for j, no := range test.no { 747 re, err := regexp.Compile(no) 748 if err != nil { 749 t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err) 750 } 751 if re.Match(output) { 752 t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no) 753 failed = true 754 } 755 } 756 if bytes.Count(output, []byte("TYPES\n")) > 1 { 757 t.Fatalf("%s: repeating headers", test.name) 758 } 759 if failed { 760 t.Logf("\n%s", output) 761 } 762 } 763 } 764 765 // Test the code to try multiple packages. Our test case is 766 // go doc rand.Float64 767 // This needs to find math/rand.Float64; however crypto/rand, which doesn't 768 // have the symbol, usually appears first in the directory listing. 769 func TestMultiplePackages(t *testing.T) { 770 if testing.Short() { 771 t.Skip("scanning file system takes too long") 772 } 773 maybeSkip(t) 774 var b bytes.Buffer // We don't care about the output. 775 // Make sure crypto/rand does not have the symbol. 776 { 777 var flagSet flag.FlagSet 778 err := do(&b, &flagSet, []string{"crypto/rand.float64"}) 779 if err == nil { 780 t.Errorf("expected error from crypto/rand.float64") 781 } else if !strings.Contains(err.Error(), "no symbol float64") { 782 t.Errorf("unexpected error %q from crypto/rand.float64", err) 783 } 784 } 785 // Make sure math/rand does have the symbol. 786 { 787 var flagSet flag.FlagSet 788 err := do(&b, &flagSet, []string{"math/rand.float64"}) 789 if err != nil { 790 t.Errorf("unexpected error %q from math/rand.float64", err) 791 } 792 } 793 // Try the shorthand. 794 { 795 var flagSet flag.FlagSet 796 err := do(&b, &flagSet, []string{"rand.float64"}) 797 if err != nil { 798 t.Errorf("unexpected error %q from rand.float64", err) 799 } 800 } 801 // Now try a missing symbol. We should see both packages in the error. 802 { 803 var flagSet flag.FlagSet 804 err := do(&b, &flagSet, []string{"rand.doesnotexit"}) 805 if err == nil { 806 t.Errorf("expected error from rand.doesnotexit") 807 } else { 808 errStr := err.Error() 809 if !strings.Contains(errStr, "no symbol") { 810 t.Errorf("error %q should contain 'no symbol", errStr) 811 } 812 if !strings.Contains(errStr, "crypto/rand") { 813 t.Errorf("error %q should contain crypto/rand", errStr) 814 } 815 if !strings.Contains(errStr, "math/rand") { 816 t.Errorf("error %q should contain math/rand", errStr) 817 } 818 } 819 } 820 } 821 822 // Test the code to look up packages when given two args. First test case is 823 // go doc binary BigEndian 824 // This needs to find encoding/binary.BigEndian, which means 825 // finding the package encoding/binary given only "binary". 826 // Second case is 827 // go doc rand Float64 828 // which again needs to find math/rand and not give up after crypto/rand, 829 // which has no such function. 830 func TestTwoArgLookup(t *testing.T) { 831 if testing.Short() { 832 t.Skip("scanning file system takes too long") 833 } 834 maybeSkip(t) 835 var b bytes.Buffer // We don't care about the output. 836 { 837 var flagSet flag.FlagSet 838 err := do(&b, &flagSet, []string{"binary", "BigEndian"}) 839 if err != nil { 840 t.Errorf("unexpected error %q from binary BigEndian", err) 841 } 842 } 843 { 844 var flagSet flag.FlagSet 845 err := do(&b, &flagSet, []string{"rand", "Float64"}) 846 if err != nil { 847 t.Errorf("unexpected error %q from rand Float64", err) 848 } 849 } 850 { 851 var flagSet flag.FlagSet 852 err := do(&b, &flagSet, []string{"bytes", "Foo"}) 853 if err == nil { 854 t.Errorf("expected error from bytes Foo") 855 } else if !strings.Contains(err.Error(), "no symbol Foo") { 856 t.Errorf("unexpected error %q from bytes Foo", err) 857 } 858 } 859 { 860 var flagSet flag.FlagSet 861 err := do(&b, &flagSet, []string{"nosuchpackage", "Foo"}) 862 if err == nil { 863 // actually present in the user's filesystem 864 } else if !strings.Contains(err.Error(), "no such package") { 865 t.Errorf("unexpected error %q from nosuchpackage Foo", err) 866 } 867 } 868 } 869 870 // Test the code to look up packages when the first argument starts with "./". 871 // Our test case is in effect "cd src/text; doc ./template". This should get 872 // text/template but before Issue 23383 was fixed would give html/template. 873 func TestDotSlashLookup(t *testing.T) { 874 if testing.Short() { 875 t.Skip("scanning file system takes too long") 876 } 877 maybeSkip(t) 878 where := pwd() 879 defer func() { 880 if err := os.Chdir(where); err != nil { 881 t.Fatal(err) 882 } 883 }() 884 if err := os.Chdir(filepath.Join(buildCtx.GOROOT, "src", "text")); err != nil { 885 t.Fatal(err) 886 } 887 var b bytes.Buffer 888 var flagSet flag.FlagSet 889 err := do(&b, &flagSet, []string{"./template"}) 890 if err != nil { 891 t.Errorf("unexpected error %q from ./template", err) 892 } 893 // The output should contain information about the text/template package. 894 const want = `package template // import "text/template"` 895 output := b.String() 896 if !strings.HasPrefix(output, want) { 897 t.Fatalf("wrong package: %.*q...", len(want), output) 898 } 899 } 900 901 type trimTest struct { 902 path string 903 prefix string 904 result string 905 ok bool 906 } 907 908 var trimTests = []trimTest{ 909 {"", "", "", true}, 910 {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, 911 {"/usr/gopher/bar", "/usr/gopher", "bar", true}, 912 {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false}, 913 {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false}, 914 } 915 916 func TestTrim(t *testing.T) { 917 for _, test := range trimTests { 918 result, ok := trim(test.path, test.prefix) 919 if ok != test.ok { 920 t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok) 921 continue 922 } 923 if result != test.result { 924 t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result) 925 continue 926 } 927 } 928 }