You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
4.7 KiB
230 lines
4.7 KiB
4 months ago
|
// 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.
|
||
|
|
||
|
// run runs the docs tests found in this directory.
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"flag"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"regexp"
|
||
|
"runtime"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
const usage = `go run run.go [tests]
|
||
|
|
||
|
run.go runs the docs tests in this directory.
|
||
|
If no tests are provided, it runs all tests.
|
||
|
Tests may be specified without their .go suffix.
|
||
|
`
|
||
|
|
||
|
func main() {
|
||
|
start := time.Now()
|
||
|
|
||
|
flag.Usage = func() {
|
||
|
fmt.Fprintf(os.Stderr, usage)
|
||
|
flag.PrintDefaults()
|
||
|
os.Exit(2)
|
||
|
}
|
||
|
|
||
|
flag.Parse()
|
||
|
if flag.NArg() == 0 {
|
||
|
// run all tests
|
||
|
fixcgo()
|
||
|
} else {
|
||
|
// run specified tests
|
||
|
onlyTest(flag.Args()...)
|
||
|
}
|
||
|
|
||
|
tmpdir, err := ioutil.TempDir("", "go-progs")
|
||
|
if err != nil {
|
||
|
fmt.Fprintln(os.Stderr, err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
// ratec limits the number of tests running concurrently.
|
||
|
// None of the tests are intensive, so don't bother
|
||
|
// trying to manually adjust for slow builders.
|
||
|
ratec := make(chan bool, runtime.NumCPU())
|
||
|
errc := make(chan error, len(tests))
|
||
|
|
||
|
for _, tt := range tests {
|
||
|
tt := tt
|
||
|
ratec <- true
|
||
|
go func() {
|
||
|
errc <- test(tmpdir, tt.file, tt.want)
|
||
|
<-ratec
|
||
|
}()
|
||
|
}
|
||
|
|
||
|
var rc int
|
||
|
for range tests {
|
||
|
if err := <-errc; err != nil {
|
||
|
fmt.Fprintln(os.Stderr, err)
|
||
|
rc = 1
|
||
|
}
|
||
|
}
|
||
|
os.Remove(tmpdir)
|
||
|
if rc == 0 {
|
||
|
fmt.Printf("ok\t%s\t%s\n", filepath.Base(os.Args[0]), time.Since(start).Round(time.Millisecond))
|
||
|
}
|
||
|
os.Exit(rc)
|
||
|
}
|
||
|
|
||
|
// test builds the test in the given file.
|
||
|
// If want is non-empty, test also runs the test
|
||
|
// and checks that the output matches the regexp want.
|
||
|
func test(tmpdir, file, want string) error {
|
||
|
// Build the program.
|
||
|
prog := filepath.Join(tmpdir, file+".exe")
|
||
|
cmd := exec.Command("go", "build", "-o", prog, file+".go")
|
||
|
out, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("go build %s.go failed: %v\nOutput:\n%s", file, err, out)
|
||
|
}
|
||
|
defer os.Remove(prog)
|
||
|
|
||
|
// Only run the test if we have output to check.
|
||
|
if want == "" {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
cmd = exec.Command(prog)
|
||
|
out, err = cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("%s failed: %v\nOutput:\n%s", file, err, out)
|
||
|
}
|
||
|
|
||
|
// Canonicalize output.
|
||
|
out = bytes.TrimRight(out, "\n")
|
||
|
out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
|
||
|
|
||
|
// Check the result.
|
||
|
match, err := regexp.Match(want, out)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to parse regexp %q: %v", want, err)
|
||
|
}
|
||
|
if !match {
|
||
|
return fmt.Errorf("%s.go:\n%q\ndoes not match %s", file, out, want)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type testcase struct {
|
||
|
file string
|
||
|
want string
|
||
|
}
|
||
|
|
||
|
var tests = []testcase{
|
||
|
// defer_panic_recover
|
||
|
{"defer", `^0 3210 2$`},
|
||
|
{"defer2", `^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$`},
|
||
|
|
||
|
// effective_go
|
||
|
{"eff_bytesize", `^1.00YB 9.09TB$`},
|
||
|
{"eff_qr", ""},
|
||
|
{"eff_sequence", `^\[-1 2 6 16 44\]$`},
|
||
|
{"eff_unused2", ""},
|
||
|
|
||
|
// error_handling
|
||
|
{"error", ""},
|
||
|
{"error2", ""},
|
||
|
{"error3", ""},
|
||
|
{"error4", ""},
|
||
|
|
||
|
// law_of_reflection
|
||
|
{"interface", ""},
|
||
|
{"interface2", `^type: float64$`},
|
||
|
|
||
|
// c_go_cgo
|
||
|
{"cgo1", ""},
|
||
|
{"cgo2", ""},
|
||
|
{"cgo3", ""},
|
||
|
{"cgo4", ""},
|
||
|
|
||
|
// timeout
|
||
|
{"timeout1", ""},
|
||
|
{"timeout2", ""},
|
||
|
|
||
|
// gobs
|
||
|
{"gobs1", ""},
|
||
|
{"gobs2", ""},
|
||
|
|
||
|
// json
|
||
|
{"json1", `^$`},
|
||
|
{"json2", `the reciprocal of i is`},
|
||
|
{"json3", `Age is int 6`},
|
||
|
{"json4", `^$`},
|
||
|
{"json5", ""},
|
||
|
|
||
|
// image_package
|
||
|
{"image_package1", `^X is 2 Y is 1$`},
|
||
|
{"image_package2", `^3 4 false$`},
|
||
|
{"image_package3", `^3 4 true$`},
|
||
|
{"image_package4", `^image.Point{X:2, Y:1}$`},
|
||
|
{"image_package5", `^{255 0 0 255}$`},
|
||
|
{"image_package6", `^8 4 true$`},
|
||
|
|
||
|
// other
|
||
|
{"go1", `^Christmas is a holiday: true .*go1.go already exists$`},
|
||
|
{"slices", ""},
|
||
|
}
|
||
|
|
||
|
func onlyTest(files ...string) {
|
||
|
var new []testcase
|
||
|
NextFile:
|
||
|
for _, file := range files {
|
||
|
file = strings.TrimSuffix(file, ".go")
|
||
|
for _, tt := range tests {
|
||
|
if tt.file == file {
|
||
|
new = append(new, tt)
|
||
|
continue NextFile
|
||
|
}
|
||
|
}
|
||
|
fmt.Fprintf(os.Stderr, "test %s.go not found\n", file)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
tests = new
|
||
|
}
|
||
|
|
||
|
func skipTest(file string) {
|
||
|
for i, tt := range tests {
|
||
|
if tt.file == file {
|
||
|
copy(tests[i:], tests[i+1:])
|
||
|
tests = tests[:len(tests)-1]
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
panic("delete(" + file + "): not found")
|
||
|
}
|
||
|
|
||
|
func fixcgo() {
|
||
|
if os.Getenv("CGO_ENABLED") != "1" {
|
||
|
skipTest("cgo1")
|
||
|
skipTest("cgo2")
|
||
|
skipTest("cgo3")
|
||
|
skipTest("cgo4")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
switch runtime.GOOS {
|
||
|
case "freebsd":
|
||
|
// cgo1 and cgo2 don't run on freebsd, srandom has a different signature
|
||
|
skipTest("cgo1")
|
||
|
skipTest("cgo2")
|
||
|
case "netbsd":
|
||
|
// cgo1 and cgo2 don't run on netbsd, srandom has a different signature
|
||
|
skipTest("cgo1")
|
||
|
skipTest("cgo2")
|
||
|
}
|
||
|
}
|