зеркало из https://github.com/golang/tools.git
cmd/godoc: fix careless crash introduced by recent analysis CL
+ basic integration test LGTM=bgarcia R=bgarcia, bradfitz CC=golang-codereviews https://golang.org/cl/76410045
This commit is contained in:
Родитель
80c4f06c0f
Коммит
7877131709
|
@ -5,7 +5,11 @@
|
|||
package main_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -13,6 +17,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var godocTests = []struct {
|
||||
|
@ -57,15 +62,18 @@ var godocTests = []struct {
|
|||
},
|
||||
}
|
||||
|
||||
// Basic regression test for godoc command-line tool.
|
||||
func TestGodoc(t *testing.T) {
|
||||
// buildGodoc builds the godoc executable.
|
||||
// It returns its path, and a cleanup function.
|
||||
//
|
||||
// TODO(adonovan): opt: do this at most once, and do the cleanup
|
||||
// exactly once. How though? There's no atexit.
|
||||
func buildGodoc(t *testing.T) (bin string, cleanup func()) {
|
||||
tmp, err := ioutil.TempDir("", "godoc-regtest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
bin := filepath.Join(tmp, "godoc")
|
||||
bin = filepath.Join(tmp, "godoc")
|
||||
if runtime.GOOS == "windows" {
|
||||
bin += ".exe"
|
||||
}
|
||||
|
@ -74,6 +82,13 @@ func TestGodoc(t *testing.T) {
|
|||
t.Fatalf("Building godoc: %v", err)
|
||||
}
|
||||
|
||||
return bin, func() { os.RemoveAll(tmp) }
|
||||
}
|
||||
|
||||
// Basic regression test for godoc command-line tool.
|
||||
func TestCLI(t *testing.T) {
|
||||
bin, cleanup := buildGodoc(t)
|
||||
defer cleanup()
|
||||
for _, test := range godocTests {
|
||||
cmd := exec.Command(bin, test.args...)
|
||||
cmd.Args[0] = "godoc"
|
||||
|
@ -96,3 +111,68 @@ func TestGodoc(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func serverAddress(t *testing.T) string {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
ln, err = net.Listen("tcp6", "[::1]:0")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
return ln.Addr().String()
|
||||
}
|
||||
|
||||
func waitForServer(t *testing.T, address string) {
|
||||
// Poll every 50ms for a total of 5s.
|
||||
for i := 0; i < 100; i++ {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
conn, err := net.Dial("tcp", address)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
t.Fatalf("Server %q failed to respond in 5 seconds", address)
|
||||
}
|
||||
|
||||
// Basic integration test for godoc HTTP interface.
|
||||
func TestWeb(t *testing.T) {
|
||||
bin, cleanup := buildGodoc(t)
|
||||
defer cleanup()
|
||||
addr := serverAddress(t)
|
||||
cmd := exec.Command(bin, fmt.Sprintf("-http=%s", addr))
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Args[0] = "godoc"
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("failed to start godoc: %s", err)
|
||||
}
|
||||
defer cmd.Process.Kill()
|
||||
waitForServer(t, addr)
|
||||
tests := []struct{ path, substr string }{
|
||||
{"/", "Go is an open source programming language"},
|
||||
{"/pkg/fmt/", "Package fmt implements formatted I/O"},
|
||||
{"/src/pkg/fmt/", "scan_test.go"},
|
||||
{"/src/pkg/fmt/print.go", "// Println formats using"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
url := fmt.Sprintf("http://%s%s", addr, test.path)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
t.Errorf("GET %s failed: %s", url, err)
|
||||
continue
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Errorf("GET %s: failed to read body: %s (response: %v)", url, err, resp)
|
||||
}
|
||||
if bytes.Index(body, []byte(test.substr)) < 0 {
|
||||
t.Errorf("GET %s: want substring %q in body, got:\n%s",
|
||||
url, test.substr, string(body))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,6 +218,9 @@ func (res *Result) fileInfo(url string) *fileInfo {
|
|||
res.mu.Lock()
|
||||
fi, ok := res.fileInfos[url]
|
||||
if !ok {
|
||||
if res.fileInfos == nil {
|
||||
res.fileInfos = make(map[string]*fileInfo)
|
||||
}
|
||||
fi = new(fileInfo)
|
||||
res.fileInfos[url] = fi
|
||||
}
|
||||
|
@ -240,6 +243,9 @@ func (res *Result) pkgInfo(importPath string) *pkgInfo {
|
|||
res.mu.Lock()
|
||||
pi, ok := res.pkgInfos[importPath]
|
||||
if !ok {
|
||||
if res.pkgInfos == nil {
|
||||
res.pkgInfos = make(map[string]*pkgInfo)
|
||||
}
|
||||
pi = new(pkgInfo)
|
||||
res.pkgInfos[importPath] = pi
|
||||
}
|
||||
|
@ -297,9 +303,6 @@ func (a *analysis) posURL(pos token.Pos, len int) string {
|
|||
// enabled by the pta flag.
|
||||
//
|
||||
func Run(pta bool, result *Result) {
|
||||
result.fileInfos = make(map[string]*fileInfo)
|
||||
result.pkgInfos = make(map[string]*pkgInfo)
|
||||
|
||||
conf := loader.Config{
|
||||
SourceImports: true,
|
||||
AllowTypeErrors: true,
|
||||
|
|
Загрузка…
Ссылка в новой задаче