mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/doc: don't stop after first package if the symbol is not found
The test case is go doc rand.Float64 The first package it finds is crypto/rand, which does not have a Float64. Before this change, cmd/doc would stop there even though math/rand has the symbol. After this change, we get: % go doc rand.Float64 package rand // import "math/rand" func Float64() float64 Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) from the default Source. % Another nice consequence is that if a symbol is not found, we might get a longer list of packages that were examined: % go doc rand.Int64 doc: no symbol Int64 in packages crypto/rand, math/rand exit status 1 % This change introduces a coroutine to scan the file system so that if the symbol is not found, the coroutine can deliver another path to try. (This is darned close to the original motivation for coroutines.) Paths are delivered on an unbuffered channel so the scanner does not proceed until candidate paths are needed. The scanner is attached to a new type, called Dirs, that caches the results so if we need to scan a second time, we don't walk the file system again. This is significantly more efficient than the existing code, which could scan the tree multiple times looking for a package with the symbol. Change-Id: I2789505b9992cf04c19376c51ae09af3bc305f7f Reviewed-on: https://go-review.googlesource.com/14921 Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
parent
3f7c3e01db
commit
007fa019a3
4 changed files with 310 additions and 141 deletions
|
|
@ -7,13 +7,21 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func maybeSkip(t *testing.T) {
|
||||
if strings.HasPrefix(runtime.GOOS, "nacl") {
|
||||
t.Skip("nacl does not have a full file tree")
|
||||
}
|
||||
if runtime.GOOS == "darwin" && strings.HasPrefix(runtime.GOARCH, "arm") {
|
||||
t.Skip("darwin/arm does not have a full file tree")
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
dataDir = "testdata"
|
||||
binary = "testdoc"
|
||||
|
|
@ -301,9 +309,7 @@ var tests = []test{
|
|||
}
|
||||
|
||||
func TestDoc(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
|
||||
t.Skip("TODO: on darwin/arm, test fails: no such package cmd/doc/testdata")
|
||||
}
|
||||
maybeSkip(t)
|
||||
for _, test := range tests {
|
||||
var b bytes.Buffer
|
||||
var flagSet flag.FlagSet
|
||||
|
|
@ -339,12 +345,59 @@ func TestDoc(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// run runs the command, but calls t.Fatal if there is an error.
|
||||
func run(c *exec.Cmd, t *testing.T) []byte {
|
||||
output, err := c.CombinedOutput()
|
||||
if err != nil {
|
||||
os.Stdout.Write(output)
|
||||
t.Fatal(err)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue