mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[This CL is part of a sequence implementing the proposal #51082. The design doc is at https://go.dev/s/godocfmt-design.] Run the updated gofmt, which reformats doc comments, on the main repository. Vendored files are excluded. For #51082. Change-Id: I7332f099b60f716295fb34719c98c04eb1a85407 Reviewed-on: https://go-review.googlesource.com/c/go/+/384268 Reviewed-by: Jonathan Amsterdam <jba@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
1076 lines
30 KiB
Go
1076 lines
30 KiB
Go
// Copyright 2015 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 main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"go/build"
|
|
"internal/testenv"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
// Clear GOPATH so we don't access the user's own packages in the test.
|
|
buildCtx.GOPATH = ""
|
|
testGOPATH = true // force GOPATH mode; module test is in cmd/go/testdata/script/mod_doc.txt
|
|
|
|
// Set GOROOT in case runtime.GOROOT is wrong (for example, if the test was
|
|
// built with -trimpath). dirsInit would identify it using 'go env GOROOT',
|
|
// but we can't be sure that the 'go' in $PATH is the right one either.
|
|
buildCtx.GOROOT = testenv.GOROOT(nil)
|
|
build.Default.GOROOT = testenv.GOROOT(nil)
|
|
|
|
// Add $GOROOT/src/cmd/doc/testdata explicitly so we can access its contents in the test.
|
|
// Normally testdata directories are ignored, but sending it to dirs.scan directly is
|
|
// a hack that works around the check.
|
|
testdataDir, err := filepath.Abs("testdata")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
dirsInit(
|
|
Dir{importPath: "testdata", dir: testdataDir},
|
|
Dir{importPath: "testdata/nested", dir: filepath.Join(testdataDir, "nested")},
|
|
Dir{importPath: "testdata/nested/nested", dir: filepath.Join(testdataDir, "nested", "nested")})
|
|
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func maybeSkip(t *testing.T) {
|
|
if runtime.GOOS == "ios" {
|
|
t.Skip("iOS does not have a full file tree")
|
|
}
|
|
}
|
|
|
|
type isDotSlashTest struct {
|
|
str string
|
|
result bool
|
|
}
|
|
|
|
var isDotSlashTests = []isDotSlashTest{
|
|
{``, false},
|
|
{`x`, false},
|
|
{`...`, false},
|
|
{`.../`, false},
|
|
{`...\`, false},
|
|
|
|
{`.`, true},
|
|
{`./`, true},
|
|
{`.\`, true},
|
|
{`./x`, true},
|
|
{`.\x`, true},
|
|
|
|
{`..`, true},
|
|
{`../`, true},
|
|
{`..\`, true},
|
|
{`../x`, true},
|
|
{`..\x`, true},
|
|
}
|
|
|
|
func TestIsDotSlashPath(t *testing.T) {
|
|
for _, test := range isDotSlashTests {
|
|
if result := isDotSlash(test.str); result != test.result {
|
|
t.Errorf("isDotSlash(%q) = %t; expected %t", test.str, result, test.result)
|
|
}
|
|
}
|
|
}
|
|
|
|
type test struct {
|
|
name string
|
|
args []string // Arguments to "[go] doc".
|
|
yes []string // Regular expressions that should match.
|
|
no []string // Regular expressions that should not match.
|
|
}
|
|
|
|
const p = "cmd/doc/testdata"
|
|
|
|
var tests = []test{
|
|
// Sanity check.
|
|
{
|
|
"sanity check",
|
|
[]string{p},
|
|
[]string{`type ExportedType struct`},
|
|
nil,
|
|
},
|
|
|
|
// Package dump includes import, package statement.
|
|
{
|
|
"package clause",
|
|
[]string{p},
|
|
[]string{`package pkg.*cmd/doc/testdata`},
|
|
nil,
|
|
},
|
|
|
|
// Constants.
|
|
// Package dump
|
|
{
|
|
"full package",
|
|
[]string{p},
|
|
[]string{
|
|
`Package comment`,
|
|
`const ExportedConstant = 1`, // Simple constant.
|
|
`const ConstOne = 1`, // First entry in constant block.
|
|
`const ConstFive ...`, // From block starting with unexported constant.
|
|
`var ExportedVariable = 1`, // Simple variable.
|
|
`var VarOne = 1`, // First entry in variable block.
|
|
`func ExportedFunc\(a int\) bool`, // Function.
|
|
`func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
|
|
`type ExportedType struct{ ... }`, // Exported type.
|
|
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
|
|
`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
|
|
`const ConstLeft2 uint64 ...`, // Typed constant using unexported iota.
|
|
`const ConstGroup1 unexportedType = iota ...`, // Typed constant using unexported type.
|
|
`const ConstGroup4 ExportedType = ExportedType{}`, // Typed constant using exported type.
|
|
`const MultiLineConst = ...`, // Multi line constant.
|
|
`var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`, // Multi line variable.
|
|
`func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
|
|
`var LongLine = newLongLine\(("someArgument[1-4]", ){4}...\)`, // Long list of arguments.
|
|
`type T1 = T2`, // Type alias
|
|
`type SimpleConstraint interface{ ... }`,
|
|
`type TildeConstraint interface{ ... }`,
|
|
`type StructConstraint interface{ ... }`,
|
|
},
|
|
[]string{
|
|
`const internalConstant = 2`, // No internal constants.
|
|
`var internalVariable = 2`, // No internal variables.
|
|
`func internalFunc(a int) bool`, // No internal functions.
|
|
`Comment about exported constant`, // No comment for single constant.
|
|
`Comment about exported variable`, // No comment for single variable.
|
|
`Comment about block of constants`, // No comment for constant block.
|
|
`Comment about block of variables`, // No comment for variable block.
|
|
`Comment before ConstOne`, // No comment for first entry in constant block.
|
|
`Comment before VarOne`, // No comment for first entry in variable block.
|
|
`ConstTwo = 2`, // No second entry in constant block.
|
|
`VarTwo = 2`, // No second entry in variable block.
|
|
`VarFive = 5`, // From block starting with unexported variable.
|
|
`type unexportedType`, // No unexported type.
|
|
`unexportedTypedConstant`, // No unexported typed constant.
|
|
`\bField`, // No fields.
|
|
`Method`, // No methods.
|
|
`someArgument[5-8]`, // No truncated arguments.
|
|
`type T1 T2`, // Type alias does not display as type declaration.
|
|
},
|
|
},
|
|
// Package dump -all
|
|
{
|
|
"full package",
|
|
[]string{"-all", p},
|
|
[]string{
|
|
`package pkg .*import`,
|
|
`Package comment`,
|
|
`CONSTANTS`,
|
|
`Comment before ConstOne`,
|
|
`ConstOne = 1`,
|
|
`ConstTwo = 2 // Comment on line with ConstTwo`,
|
|
`ConstFive`,
|
|
`ConstSix`,
|
|
`Const block where first entry is unexported`,
|
|
`ConstLeft2, constRight2 uint64`,
|
|
`constLeft3, ConstRight3`,
|
|
`ConstLeft4, ConstRight4`,
|
|
`Duplicate = iota`,
|
|
`const CaseMatch = 1`,
|
|
`const Casematch = 2`,
|
|
`const ExportedConstant = 1`,
|
|
`const MultiLineConst = `,
|
|
`MultiLineString1`,
|
|
`VARIABLES`,
|
|
`Comment before VarOne`,
|
|
`VarOne = 1`,
|
|
`Comment about block of variables`,
|
|
`VarFive = 5`,
|
|
`var ExportedVariable = 1`,
|
|
`var ExportedVarOfUnExported unexportedType`,
|
|
`var LongLine = newLongLine\(`,
|
|
`var MultiLineVar = map\[struct {`,
|
|
`FUNCTIONS`,
|
|
`func ExportedFunc\(a int\) bool`,
|
|
`Comment about exported function`,
|
|
`func MultiLineFunc\(x interface`,
|
|
`func ReturnUnexported\(\) unexportedType`,
|
|
`TYPES`,
|
|
`type ExportedInterface interface`,
|
|
`type ExportedStructOneField struct`,
|
|
`type ExportedType struct`,
|
|
`Comment about exported type`,
|
|
`const ConstGroup4 ExportedType = ExportedType`,
|
|
`ExportedTypedConstant ExportedType = iota`,
|
|
`Constants tied to ExportedType`,
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`,
|
|
`Comment about constructor for exported type`,
|
|
`func ReturnExported\(\) ExportedType`,
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`Comment about exported method`,
|
|
`type T1 = T2`,
|
|
`type T2 int`,
|
|
`type SimpleConstraint interface {`,
|
|
`type TildeConstraint interface {`,
|
|
`type StructConstraint interface {`,
|
|
},
|
|
[]string{
|
|
`constThree`,
|
|
`_, _ uint64 = 2 \* iota, 1 << iota`,
|
|
`constLeft1, constRight1`,
|
|
`duplicate`,
|
|
`varFour`,
|
|
`func internalFunc`,
|
|
`unexportedField`,
|
|
`func \(unexportedType\)`,
|
|
},
|
|
},
|
|
// Package with just the package declaration. Issue 31457.
|
|
{
|
|
"only package declaration",
|
|
[]string{"-all", p + "/nested/empty"},
|
|
[]string{`package empty .*import`},
|
|
nil,
|
|
},
|
|
// Package dump -short
|
|
{
|
|
"full package with -short",
|
|
[]string{`-short`, p},
|
|
[]string{
|
|
`const ExportedConstant = 1`, // Simple constant.
|
|
`func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
|
|
},
|
|
[]string{
|
|
`MultiLine(String|Method|Field)`, // No data from multi line portions.
|
|
},
|
|
},
|
|
// Package dump -u
|
|
{
|
|
"full package with u",
|
|
[]string{`-u`, p},
|
|
[]string{
|
|
`const ExportedConstant = 1`, // Simple constant.
|
|
`const internalConstant = 2`, // Internal constants.
|
|
`func internalFunc\(a int\) bool`, // Internal functions.
|
|
`func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
|
|
},
|
|
[]string{
|
|
`Comment about exported constant`, // No comment for simple constant.
|
|
`Comment about block of constants`, // No comment for constant block.
|
|
`Comment about internal function`, // No comment for internal function.
|
|
`MultiLine(String|Method|Field)`, // No data from multi line portions.
|
|
},
|
|
},
|
|
// Package dump -u -all
|
|
{
|
|
"full package",
|
|
[]string{"-u", "-all", p},
|
|
[]string{
|
|
`package pkg .*import`,
|
|
`Package comment`,
|
|
`CONSTANTS`,
|
|
`Comment before ConstOne`,
|
|
`ConstOne += 1`,
|
|
`ConstTwo += 2 // Comment on line with ConstTwo`,
|
|
`constThree = 3 // Comment on line with constThree`,
|
|
`ConstFive`,
|
|
`const internalConstant += 2`,
|
|
`Comment about internal constant`,
|
|
`VARIABLES`,
|
|
`Comment before VarOne`,
|
|
`VarOne += 1`,
|
|
`Comment about block of variables`,
|
|
`varFour += 4`,
|
|
`VarFive += 5`,
|
|
`varSix += 6`,
|
|
`var ExportedVariable = 1`,
|
|
`var LongLine = newLongLine\(`,
|
|
`var MultiLineVar = map\[struct {`,
|
|
`var internalVariable = 2`,
|
|
`Comment about internal variable`,
|
|
`FUNCTIONS`,
|
|
`func ExportedFunc\(a int\) bool`,
|
|
`Comment about exported function`,
|
|
`func MultiLineFunc\(x interface`,
|
|
`func internalFunc\(a int\) bool`,
|
|
`Comment about internal function`,
|
|
`func newLongLine\(ss .*string\)`,
|
|
`TYPES`,
|
|
`type ExportedType struct`,
|
|
`type T1 = T2`,
|
|
`type T2 int`,
|
|
`type unexportedType int`,
|
|
`Comment about unexported type`,
|
|
`ConstGroup1 unexportedType = iota`,
|
|
`ConstGroup2`,
|
|
`ConstGroup3`,
|
|
`ExportedTypedConstant_unexported unexportedType = iota`,
|
|
`Constants tied to unexportedType`,
|
|
`const unexportedTypedConstant unexportedType = 1`,
|
|
`func ReturnUnexported\(\) unexportedType`,
|
|
`func \(unexportedType\) ExportedMethod\(\) bool`,
|
|
`func \(unexportedType\) unexportedMethod\(\) bool`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Single constant.
|
|
{
|
|
"single constant",
|
|
[]string{p, `ExportedConstant`},
|
|
[]string{
|
|
`Comment about exported constant`, // Include comment.
|
|
`const ExportedConstant = 1`,
|
|
},
|
|
nil,
|
|
},
|
|
// Single constant -u.
|
|
{
|
|
"single constant with -u",
|
|
[]string{`-u`, p, `internalConstant`},
|
|
[]string{
|
|
`Comment about internal constant`, // Include comment.
|
|
`const internalConstant = 2`,
|
|
},
|
|
nil,
|
|
},
|
|
// Block of constants.
|
|
{
|
|
"block of constants",
|
|
[]string{p, `ConstTwo`},
|
|
[]string{
|
|
`Comment before ConstOne.\n.*ConstOne = 1`, // First...
|
|
`ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up.
|
|
`Comment about block of constants`, // Comment does too.
|
|
},
|
|
[]string{
|
|
`constThree`, // No unexported constant.
|
|
},
|
|
},
|
|
// Block of constants -u.
|
|
{
|
|
"block of constants with -u",
|
|
[]string{"-u", p, `constThree`},
|
|
[]string{
|
|
`constThree = 3.*Comment on line with constThree`,
|
|
},
|
|
nil,
|
|
},
|
|
// Block of constants -src.
|
|
{
|
|
"block of constants with -src",
|
|
[]string{"-src", p, `ConstTwo`},
|
|
[]string{
|
|
`Comment about block of constants`, // Top comment.
|
|
`ConstOne.*=.*1`, // Each constant seen.
|
|
`ConstTwo.*=.*2.*Comment on line with ConstTwo`,
|
|
`constThree`, // Even unexported constants.
|
|
},
|
|
nil,
|
|
},
|
|
// Block of constants with carryover type from unexported field.
|
|
{
|
|
"block of constants with carryover type",
|
|
[]string{p, `ConstLeft2`},
|
|
[]string{
|
|
`ConstLeft2, constRight2 uint64`,
|
|
`constLeft3, ConstRight3`,
|
|
`ConstLeft4, ConstRight4`,
|
|
},
|
|
nil,
|
|
},
|
|
// Block of constants -u with carryover type from unexported field.
|
|
{
|
|
"block of constants with carryover type",
|
|
[]string{"-u", p, `ConstLeft2`},
|
|
[]string{
|
|
`_, _ uint64 = 2 \* iota, 1 << iota`,
|
|
`constLeft1, constRight1`,
|
|
`ConstLeft2, constRight2`,
|
|
`constLeft3, ConstRight3`,
|
|
`ConstLeft4, ConstRight4`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Single variable.
|
|
{
|
|
"single variable",
|
|
[]string{p, `ExportedVariable`},
|
|
[]string{
|
|
`ExportedVariable`, // Include comment.
|
|
`var ExportedVariable = 1`,
|
|
},
|
|
nil,
|
|
},
|
|
// Single variable -u.
|
|
{
|
|
"single variable with -u",
|
|
[]string{`-u`, p, `internalVariable`},
|
|
[]string{
|
|
`Comment about internal variable`, // Include comment.
|
|
`var internalVariable = 2`,
|
|
},
|
|
nil,
|
|
},
|
|
// Block of variables.
|
|
{
|
|
"block of variables",
|
|
[]string{p, `VarTwo`},
|
|
[]string{
|
|
`Comment before VarOne.\n.*VarOne = 1`, // First...
|
|
`VarTwo = 2.*Comment on line with VarTwo`, // And second show up.
|
|
`Comment about block of variables`, // Comment does too.
|
|
},
|
|
[]string{
|
|
`varThree= 3`, // No unexported variable.
|
|
},
|
|
},
|
|
// Block of variables -u.
|
|
{
|
|
"block of variables with -u",
|
|
[]string{"-u", p, `varThree`},
|
|
[]string{
|
|
`varThree = 3.*Comment on line with varThree`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Function.
|
|
{
|
|
"function",
|
|
[]string{p, `ExportedFunc`},
|
|
[]string{
|
|
`Comment about exported function`, // Include comment.
|
|
`func ExportedFunc\(a int\) bool`,
|
|
},
|
|
nil,
|
|
},
|
|
// Function -u.
|
|
{
|
|
"function with -u",
|
|
[]string{"-u", p, `internalFunc`},
|
|
[]string{
|
|
`Comment about internal function`, // Include comment.
|
|
`func internalFunc\(a int\) bool`,
|
|
},
|
|
nil,
|
|
},
|
|
// Function with -src.
|
|
{
|
|
"function with -src",
|
|
[]string{"-src", p, `ExportedFunc`},
|
|
[]string{
|
|
`Comment about exported function`, // Include comment.
|
|
`func ExportedFunc\(a int\) bool`,
|
|
`return true != false`, // Include body.
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Type.
|
|
{
|
|
"type",
|
|
[]string{p, `ExportedType`},
|
|
[]string{
|
|
`Comment about exported type`, // Include comment.
|
|
`type ExportedType struct`, // Type definition.
|
|
`Comment before exported field.*\n.*ExportedField +int` +
|
|
`.*Comment on line with exported field`,
|
|
`ExportedEmbeddedType.*Comment on line with exported embedded field`,
|
|
`Has unexported fields`,
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
},
|
|
[]string{
|
|
`unexportedField`, // No unexported field.
|
|
`int.*embedded`, // No unexported embedded field.
|
|
`Comment about exported method`, // No comment about exported method.
|
|
`unexportedMethod`, // No unexported method.
|
|
`unexportedTypedConstant`, // No unexported constant.
|
|
`error`, // No embedded error.
|
|
},
|
|
},
|
|
// Type with -src. Will see unexported fields.
|
|
{
|
|
"type",
|
|
[]string{"-src", p, `ExportedType`},
|
|
[]string{
|
|
`Comment about exported type`, // Include comment.
|
|
`type ExportedType struct`, // Type definition.
|
|
`Comment before exported field`,
|
|
`ExportedField.*Comment on line with exported field`,
|
|
`ExportedEmbeddedType.*Comment on line with exported embedded field`,
|
|
`unexportedType.*Comment on line with unexported embedded field`,
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
},
|
|
[]string{
|
|
`Comment about exported method`, // No comment about exported method.
|
|
`unexportedMethod`, // No unexported method.
|
|
`unexportedTypedConstant`, // No unexported constant.
|
|
},
|
|
},
|
|
// Type -all.
|
|
{
|
|
"type",
|
|
[]string{"-all", p, `ExportedType`},
|
|
[]string{
|
|
`type ExportedType struct {`, // Type definition as source.
|
|
`Comment about exported type`, // Include comment afterwards.
|
|
`const ConstGroup4 ExportedType = ExportedType\{\}`, // Related constants.
|
|
`ExportedTypedConstant ExportedType = iota`,
|
|
`Constants tied to ExportedType`,
|
|
`func ExportedTypeConstructor\(\) \*ExportedType`,
|
|
`Comment about constructor for exported type.`,
|
|
`func ReturnExported\(\) ExportedType`,
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`Comment about exported method.`,
|
|
`func \(ExportedType\) Uncommented\(a int\) bool\n\n`, // Ensure line gap after method with no comment
|
|
},
|
|
[]string{
|
|
`unexportedType`,
|
|
},
|
|
},
|
|
// Type T1 dump (alias).
|
|
{
|
|
"type T1",
|
|
[]string{p + ".T1"},
|
|
[]string{
|
|
`type T1 = T2`,
|
|
},
|
|
[]string{
|
|
`type T1 T2`,
|
|
`type ExportedType`,
|
|
},
|
|
},
|
|
// Type -u with unexported fields.
|
|
{
|
|
"type with unexported fields and -u",
|
|
[]string{"-u", p, `ExportedType`},
|
|
[]string{
|
|
`Comment about exported type`, // Include comment.
|
|
`type ExportedType struct`, // Type definition.
|
|
`Comment before exported field.*\n.*ExportedField +int`,
|
|
`unexportedField.*int.*Comment on line with unexported field`,
|
|
`ExportedEmbeddedType.*Comment on line with exported embedded field`,
|
|
`\*ExportedEmbeddedType.*Comment on line with exported embedded \*field`,
|
|
`\*qualified.ExportedEmbeddedType.*Comment on line with exported embedded \*selector.field`,
|
|
`unexportedType.*Comment on line with unexported embedded field`,
|
|
`\*unexportedType.*Comment on line with unexported embedded \*field`,
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
`error.*Comment on line with embedded error`,
|
|
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
|
|
`unexportedTypedConstant`,
|
|
},
|
|
[]string{
|
|
`Has unexported fields`,
|
|
},
|
|
},
|
|
// Unexported type with -u.
|
|
{
|
|
"unexported type with -u",
|
|
[]string{"-u", p, `unexportedType`},
|
|
[]string{
|
|
`Comment about unexported type`, // Include comment.
|
|
`type unexportedType int`, // Type definition.
|
|
`func \(unexportedType\) ExportedMethod\(\) bool`,
|
|
`func \(unexportedType\) unexportedMethod\(\) bool`,
|
|
`ExportedTypedConstant_unexported unexportedType = iota`,
|
|
`const unexportedTypedConstant unexportedType = 1`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Interface.
|
|
{
|
|
"interface type",
|
|
[]string{p, `ExportedInterface`},
|
|
[]string{
|
|
`Comment about exported interface`, // Include comment.
|
|
`type ExportedInterface interface`, // Interface definition.
|
|
`Comment before exported method.\n.*//\n.*// // Code block showing how to use ExportedMethod\n.*// func DoSomething\(\) error {\n.*// ExportedMethod\(\)\n.*// return nil\n.*// }\n.*//.*\n.*ExportedMethod\(\)` +
|
|
`.*Comment on line with exported method`,
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
`error.*Comment on line with embedded error`,
|
|
`Has unexported methods`,
|
|
},
|
|
[]string{
|
|
`unexportedField`, // No unexported field.
|
|
`Comment about exported method`, // No comment about exported method.
|
|
`unexportedMethod`, // No unexported method.
|
|
`unexportedTypedConstant`, // No unexported constant.
|
|
},
|
|
},
|
|
// Interface -u with unexported methods.
|
|
{
|
|
"interface type with unexported methods and -u",
|
|
[]string{"-u", p, `ExportedInterface`},
|
|
[]string{
|
|
`Comment about exported interface`, // Include comment.
|
|
`type ExportedInterface interface`, // Interface definition.
|
|
`Comment before exported method.\n.*//\n.*// // Code block showing how to use ExportedMethod\n.*// func DoSomething\(\) error {\n.*// ExportedMethod\(\)\n.*// return nil\n.*// }\n.*//.*\n.*ExportedMethod\(\)` + `.*Comment on line with exported method`,
|
|
`unexportedMethod\(\).*Comment on line with unexported method`,
|
|
`io.Reader.*Comment on line with embedded Reader`,
|
|
`error.*Comment on line with embedded error`,
|
|
},
|
|
[]string{
|
|
`Has unexported methods`,
|
|
},
|
|
},
|
|
|
|
// Interface method.
|
|
{
|
|
"interface method",
|
|
[]string{p, `ExportedInterface.ExportedMethod`},
|
|
[]string{
|
|
`Comment before exported method.\n.*//\n.*// // Code block showing how to use ExportedMethod\n.*// func DoSomething\(\) error {\n.*// ExportedMethod\(\)\n.*// return nil\n.*// }\n.*//.*\n.*ExportedMethod\(\)` +
|
|
`.*Comment on line with exported method`,
|
|
},
|
|
[]string{
|
|
`Comment about exported interface`,
|
|
},
|
|
},
|
|
// Interface method at package level.
|
|
{
|
|
"interface method at package level",
|
|
[]string{p, `ExportedMethod`},
|
|
[]string{
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`Comment about exported method`,
|
|
},
|
|
[]string{
|
|
`Comment before exported method.*\n.*ExportedMethod\(\)` +
|
|
`.*Comment on line with exported method`,
|
|
},
|
|
},
|
|
|
|
// Method.
|
|
{
|
|
"method",
|
|
[]string{p, `ExportedType.ExportedMethod`},
|
|
[]string{
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`Comment about exported method`,
|
|
},
|
|
nil,
|
|
},
|
|
// Method with -u.
|
|
{
|
|
"method with -u",
|
|
[]string{"-u", p, `ExportedType.unexportedMethod`},
|
|
[]string{
|
|
`func \(ExportedType\) unexportedMethod\(a int\) bool`,
|
|
`Comment about unexported method`,
|
|
},
|
|
nil,
|
|
},
|
|
// Method with -src.
|
|
{
|
|
"method with -src",
|
|
[]string{"-src", p, `ExportedType.ExportedMethod`},
|
|
[]string{
|
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
|
`Comment about exported method`,
|
|
`return true != true`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Field.
|
|
{
|
|
"field",
|
|
[]string{p, `ExportedType.ExportedField`},
|
|
[]string{
|
|
`type ExportedType struct`,
|
|
`ExportedField int`,
|
|
`Comment before exported field`,
|
|
`Comment on line with exported field`,
|
|
`other fields elided`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Field with -u.
|
|
{
|
|
"method with -u",
|
|
[]string{"-u", p, `ExportedType.unexportedField`},
|
|
[]string{
|
|
`unexportedField int`,
|
|
`Comment on line with unexported field`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Field of struct with only one field.
|
|
{
|
|
"single-field struct",
|
|
[]string{p, `ExportedStructOneField.OnlyField`},
|
|
[]string{`the only field`},
|
|
[]string{`other fields elided`},
|
|
},
|
|
|
|
// Case matching off.
|
|
{
|
|
"case matching off",
|
|
[]string{p, `casematch`},
|
|
[]string{
|
|
`CaseMatch`,
|
|
`Casematch`,
|
|
},
|
|
nil,
|
|
},
|
|
|
|
// Case matching on.
|
|
{
|
|
"case matching on",
|
|
[]string{"-c", p, `Casematch`},
|
|
[]string{
|
|
`Casematch`,
|
|
},
|
|
[]string{
|
|
`CaseMatch`,
|
|
},
|
|
},
|
|
|
|
// Merging comments with -src.
|
|
{
|
|
"merge comments with -src A",
|
|
[]string{"-src", p + "/merge", `A`},
|
|
[]string{
|
|
`A doc`,
|
|
`func A`,
|
|
`A comment`,
|
|
},
|
|
[]string{
|
|
`Package A doc`,
|
|
`Package B doc`,
|
|
`B doc`,
|
|
`B comment`,
|
|
`B doc`,
|
|
},
|
|
},
|
|
{
|
|
"merge comments with -src B",
|
|
[]string{"-src", p + "/merge", `B`},
|
|
[]string{
|
|
`B doc`,
|
|
`func B`,
|
|
`B comment`,
|
|
},
|
|
[]string{
|
|
`Package A doc`,
|
|
`Package B doc`,
|
|
`A doc`,
|
|
`A comment`,
|
|
`A doc`,
|
|
},
|
|
},
|
|
|
|
// No dups with -u. Issue 21797.
|
|
{
|
|
"case matching on, no dups",
|
|
[]string{"-u", p, `duplicate`},
|
|
[]string{
|
|
`Duplicate`,
|
|
`duplicate`,
|
|
},
|
|
[]string{
|
|
"\\)\n+const", // This will appear if the const decl appears twice.
|
|
},
|
|
},
|
|
{
|
|
"non-imported: pkg.sym",
|
|
[]string{"nested.Foo"},
|
|
[]string{"Foo struct"},
|
|
nil,
|
|
},
|
|
{
|
|
"non-imported: pkg only",
|
|
[]string{"nested"},
|
|
[]string{"Foo struct"},
|
|
nil,
|
|
},
|
|
{
|
|
"non-imported: pkg sym",
|
|
[]string{"nested", "Foo"},
|
|
[]string{"Foo struct"},
|
|
nil,
|
|
},
|
|
{
|
|
"formatted doc on function",
|
|
[]string{p, "ExportedFormattedDoc"},
|
|
[]string{
|
|
`func ExportedFormattedDoc\(a int\) bool`,
|
|
` Comment about exported function with formatting\.
|
|
|
|
Example
|
|
|
|
fmt\.Println\(FormattedDoc\(\)\)
|
|
|
|
Text after pre-formatted block\.`,
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"formatted doc on type field",
|
|
[]string{p, "ExportedFormattedType.ExportedField"},
|
|
[]string{
|
|
`type ExportedFormattedType struct`,
|
|
` // Comment before exported field with formatting\.
|
|
//[ ]
|
|
// Example
|
|
//[ ]
|
|
// a\.ExportedField = 123
|
|
//[ ]
|
|
// Text after pre-formatted block\.`,
|
|
`ExportedField int`,
|
|
},
|
|
nil,
|
|
},
|
|
}
|
|
|
|
func TestDoc(t *testing.T) {
|
|
maybeSkip(t)
|
|
defer log.SetOutput(log.Writer())
|
|
for _, test := range tests {
|
|
var b bytes.Buffer
|
|
var flagSet flag.FlagSet
|
|
var logbuf bytes.Buffer
|
|
log.SetOutput(&logbuf)
|
|
err := do(&b, &flagSet, test.args)
|
|
if err != nil {
|
|
t.Fatalf("%s %v: %s\n", test.name, test.args, err)
|
|
}
|
|
if logbuf.Len() > 0 {
|
|
t.Errorf("%s %v: unexpected log messages:\n%s", test.name, test.args, logbuf.Bytes())
|
|
}
|
|
output := b.Bytes()
|
|
failed := false
|
|
for j, yes := range test.yes {
|
|
re, err := regexp.Compile(yes)
|
|
if err != nil {
|
|
t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
|
|
}
|
|
if !re.Match(output) {
|
|
t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
|
|
failed = true
|
|
}
|
|
}
|
|
for j, no := range test.no {
|
|
re, err := regexp.Compile(no)
|
|
if err != nil {
|
|
t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
|
|
}
|
|
if re.Match(output) {
|
|
t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
|
|
failed = true
|
|
}
|
|
}
|
|
if bytes.Count(output, []byte("TYPES\n")) > 1 {
|
|
t.Fatalf("%s: repeating headers", test.name)
|
|
}
|
|
if failed {
|
|
t.Logf("\n%s", output)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test the code to try multiple packages. Our test case is
|
|
//
|
|
// go doc rand.Float64
|
|
//
|
|
// This needs to find math/rand.Float64; however crypto/rand, which doesn't
|
|
// have the symbol, usually appears first in the directory listing.
|
|
func TestMultiplePackages(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("scanning file system takes too long")
|
|
}
|
|
maybeSkip(t)
|
|
var b bytes.Buffer // We don't care about the output.
|
|
// Make sure crypto/rand does not have the symbol.
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"crypto/rand.float64"})
|
|
if err == nil {
|
|
t.Errorf("expected error from crypto/rand.float64")
|
|
} else if !strings.Contains(err.Error(), "no symbol float64") {
|
|
t.Errorf("unexpected error %q from crypto/rand.float64", err)
|
|
}
|
|
}
|
|
// Make sure math/rand does have the symbol.
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"math/rand.float64"})
|
|
if err != nil {
|
|
t.Errorf("unexpected error %q from math/rand.float64", err)
|
|
}
|
|
}
|
|
// Try the shorthand.
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"rand.float64"})
|
|
if err != nil {
|
|
t.Errorf("unexpected error %q from rand.float64", err)
|
|
}
|
|
}
|
|
// Now try a missing symbol. We should see both packages in the error.
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"rand.doesnotexit"})
|
|
if err == nil {
|
|
t.Errorf("expected error from rand.doesnotexit")
|
|
} else {
|
|
errStr := err.Error()
|
|
if !strings.Contains(errStr, "no symbol") {
|
|
t.Errorf("error %q should contain 'no symbol", errStr)
|
|
}
|
|
if !strings.Contains(errStr, "crypto/rand") {
|
|
t.Errorf("error %q should contain crypto/rand", errStr)
|
|
}
|
|
if !strings.Contains(errStr, "math/rand") {
|
|
t.Errorf("error %q should contain math/rand", errStr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test the code to look up packages when given two args. First test case is
|
|
//
|
|
// go doc binary BigEndian
|
|
//
|
|
// This needs to find encoding/binary.BigEndian, which means
|
|
// finding the package encoding/binary given only "binary".
|
|
// Second case is
|
|
//
|
|
// go doc rand Float64
|
|
//
|
|
// which again needs to find math/rand and not give up after crypto/rand,
|
|
// which has no such function.
|
|
func TestTwoArgLookup(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("scanning file system takes too long")
|
|
}
|
|
maybeSkip(t)
|
|
var b bytes.Buffer // We don't care about the output.
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"binary", "BigEndian"})
|
|
if err != nil {
|
|
t.Errorf("unexpected error %q from binary BigEndian", err)
|
|
}
|
|
}
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"rand", "Float64"})
|
|
if err != nil {
|
|
t.Errorf("unexpected error %q from rand Float64", err)
|
|
}
|
|
}
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"bytes", "Foo"})
|
|
if err == nil {
|
|
t.Errorf("expected error from bytes Foo")
|
|
} else if !strings.Contains(err.Error(), "no symbol Foo") {
|
|
t.Errorf("unexpected error %q from bytes Foo", err)
|
|
}
|
|
}
|
|
{
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"nosuchpackage", "Foo"})
|
|
if err == nil {
|
|
// actually present in the user's filesystem
|
|
} else if !strings.Contains(err.Error(), "no such package") {
|
|
t.Errorf("unexpected error %q from nosuchpackage Foo", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test the code to look up packages when the first argument starts with "./".
|
|
// Our test case is in effect "cd src/text; doc ./template". This should get
|
|
// text/template but before Issue 23383 was fixed would give html/template.
|
|
func TestDotSlashLookup(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("scanning file system takes too long")
|
|
}
|
|
maybeSkip(t)
|
|
where, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
if err := os.Chdir(where); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
if err := os.Chdir(filepath.Join(buildCtx.GOROOT, "src", "text")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var b bytes.Buffer
|
|
var flagSet flag.FlagSet
|
|
err = do(&b, &flagSet, []string{"./template"})
|
|
if err != nil {
|
|
t.Errorf("unexpected error %q from ./template", err)
|
|
}
|
|
// The output should contain information about the text/template package.
|
|
const want = `package template // import "text/template"`
|
|
output := b.String()
|
|
if !strings.HasPrefix(output, want) {
|
|
t.Fatalf("wrong package: %.*q...", len(want), output)
|
|
}
|
|
}
|
|
|
|
// Test that we don't print spurious package clauses
|
|
// when there should be no output at all. Issue 37969.
|
|
func TestNoPackageClauseWhenNoMatch(t *testing.T) {
|
|
maybeSkip(t)
|
|
var b bytes.Buffer
|
|
var flagSet flag.FlagSet
|
|
err := do(&b, &flagSet, []string{"template.ZZZ"})
|
|
// Expect an error.
|
|
if err == nil {
|
|
t.Error("expect an error for template.zzz")
|
|
}
|
|
// And the output should not contain any package clauses.
|
|
const dontWant = `package template // import `
|
|
output := b.String()
|
|
if strings.Contains(output, dontWant) {
|
|
t.Fatalf("improper package clause printed:\n%s", output)
|
|
}
|
|
}
|
|
|
|
type trimTest struct {
|
|
path string
|
|
prefix string
|
|
result string
|
|
ok bool
|
|
}
|
|
|
|
var trimTests = []trimTest{
|
|
{"", "", "", true},
|
|
{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
|
|
{"/usr/gopher/bar", "/usr/gopher", "bar", true},
|
|
{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
|
|
{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
|
|
}
|
|
|
|
func TestTrim(t *testing.T) {
|
|
for _, test := range trimTests {
|
|
result, ok := trim(test.path, test.prefix)
|
|
if ok != test.ok {
|
|
t.Errorf("%s %s expected %t got %t", test.path, test.prefix, test.ok, ok)
|
|
continue
|
|
}
|
|
if result != test.result {
|
|
t.Errorf("%s %s expected %q got %q", test.path, test.prefix, test.result, result)
|
|
continue
|
|
}
|
|
}
|
|
}
|