cmd/doc: add test

Refactor main a bit to make it possible to run tests without an exec every time.
(Makes a huge difference in run time.)

Add a silver test. Not quite golden, since it looks for pieces rather than the
full output, and also includes tests for what should not appear.

Fixes #10920.

Change-Id: I6a4951cc14e61763379754a10b0cc3484d30c267
Reviewed-on: https://go-review.googlesource.com/11272
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Rob Pike <r@golang.org>
This commit is contained in:
Rob Pike 2015-06-19 12:39:02 +10:00
parent 5ac5a98562
commit d0652e7f82
5 changed files with 514 additions and 28 deletions

View file

@ -13,6 +13,7 @@ import (
"go/format"
"go/parser"
"go/token"
"io"
"log"
"os"
"unicode"
@ -20,19 +21,36 @@ import (
)
type Package struct {
name string // Package name, json for encoding/json.
userPath string // String the user used to find this package.
pkg *ast.Package // Parsed package.
file *ast.File // Merged from all files in the package
doc *doc.Package
build *build.Package
fs *token.FileSet // Needed for printing.
buf bytes.Buffer
writer io.Writer // Destination for output.
name string // Package name, json for encoding/json.
userPath string // String the user used to find this package.
unexported bool
matchCase bool
pkg *ast.Package // Parsed package.
file *ast.File // Merged from all files in the package
doc *doc.Package
build *build.Package
fs *token.FileSet // Needed for printing.
buf bytes.Buffer
}
type PackageError string // type returned by pkg.Fatalf.
func (p PackageError) Error() string {
return string(p)
}
// pkg.Fatalf is like log.Fatalf, but panics so it can be recovered in the
// main do function, so it doesn't cause an exit. Allows testing to work
// without running a subprocess. The log prefix will be added when
// logged in main; it is not added here.
func (pkg *Package) Fatalf(format string, args ...interface{}) {
panic(PackageError(fmt.Sprintf(format, args...)))
}
// parsePackage turns the build package we found into a parsed package
// we can then use to generate documentation.
func parsePackage(pkg *build.Package, userPath string) *Package {
func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package {
fs := token.NewFileSet()
// include tells parser.ParseDir which files to include.
// That means the file must be in the build package's GoFiles or CgoFiles
@ -56,7 +74,7 @@ func parsePackage(pkg *build.Package, userPath string) *Package {
}
// Make sure they are all in one package.
if len(pkgs) != 1 {
log.Fatalf("multiple packages directory %s", pkg.Dir)
log.Fatalf("multiple packages in directory %s", pkg.Dir)
}
astPkg := pkgs[pkg.Name]
@ -76,6 +94,7 @@ func parsePackage(pkg *build.Package, userPath string) *Package {
}
return &Package{
writer: writer,
name: pkg.Name,
userPath: userPath,
pkg: astPkg,
@ -91,7 +110,7 @@ func (pkg *Package) Printf(format string, args ...interface{}) {
}
func (pkg *Package) flush() {
_, err := os.Stdout.Write(pkg.buf.Bytes())
_, err := pkg.writer.Write(pkg.buf.Bytes())
if err != nil {
log.Fatal(err)
}
@ -391,7 +410,7 @@ func (pkg *Package) symbolDoc(symbol string) {
// trimUnexportedElems modifies spec in place to elide unexported fields from
// structs and methods from interfaces (unless the unexported flag is set).
func trimUnexportedElems(spec *ast.TypeSpec) {
if *unexported {
if unexported {
return
}
switch typ := spec.Type.(type) {
@ -450,7 +469,7 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
if symbol == "" {
return false
}
log.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
pkg.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
}
found := false
for _, typ := range types {
@ -470,7 +489,7 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
func (pkg *Package) methodDoc(symbol, method string) {
defer pkg.flush()
if !pkg.printMethodDoc(symbol, method) {
log.Fatalf("no method %s.%s in package %s installed in %q", symbol, method, pkg.name, pkg.build.ImportPath)
pkg.Fatalf("no method %s.%s in package %s installed in %q", symbol, method, pkg.name, pkg.build.ImportPath)
}
}
@ -481,7 +500,7 @@ func match(user, program string) bool {
if !isExported(program) {
return false
}
if *matchCase {
if matchCase {
return user == program
}
for _, u := range user {