2012-03-21 12:14:44 -06:00
|
|
|
// skip
|
2012-02-20 20:28:49 -07:00
|
|
|
|
2016-04-10 15:32:26 -06:00
|
|
|
// Copyright 2012 The Go Authors. All rights reserved.
|
2012-02-20 20:28:49 -07:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Run runs tests in the test directory.
|
2012-12-22 11:16:31 -07:00
|
|
|
//
|
2012-02-20 20:28:49 -07:00
|
|
|
// TODO(bradfitz): docs of some sort, once we figure out how we're changing
|
|
|
|
// headers of files
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
2015-06-04 00:21:30 -06:00
|
|
|
"hash/fnv"
|
|
|
|
"io"
|
2012-02-20 20:28:49 -07:00
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2012-09-23 11:16:14 -06:00
|
|
|
"path"
|
2012-02-20 20:28:49 -07:00
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"runtime"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
2013-12-10 12:02:42 -07:00
|
|
|
"time"
|
2013-08-13 10:25:41 -06:00
|
|
|
"unicode"
|
2012-02-20 20:28:49 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2013-01-11 23:52:52 -07:00
|
|
|
verbose = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
|
2016-03-10 22:10:52 -07:00
|
|
|
keep = flag.Bool("k", false, "keep. keep temporary directory.")
|
2013-01-11 23:52:52 -07:00
|
|
|
numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
|
|
|
|
summary = flag.Bool("summary", false, "show summary of results")
|
|
|
|
showSkips = flag.Bool("show_skips", false, "show skipped tests")
|
2015-10-26 15:34:06 -06:00
|
|
|
runSkips = flag.Bool("run_skips", false, "run skipped tests (ignore skip and build tags)")
|
2015-10-26 19:54:19 -06:00
|
|
|
linkshared = flag.Bool("linkshared", false, "")
|
2015-02-19 12:00:11 -07:00
|
|
|
updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
|
2013-01-11 23:52:52 -07:00
|
|
|
runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
|
2015-06-04 00:21:30 -06:00
|
|
|
|
|
|
|
shard = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
|
|
|
|
shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
|
2012-02-20 20:28:49 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
goos, goarch string
|
2012-02-20 20:28:49 -07:00
|
|
|
|
|
|
|
// dirs are the directories to look for *.go files in.
|
|
|
|
// TODO(bradfitz): just use all directories?
|
2016-10-24 16:56:48 -06:00
|
|
|
dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs"}
|
2012-02-20 20:28:49 -07:00
|
|
|
|
|
|
|
// ratec controls the max number of tests running at a time.
|
|
|
|
ratec chan bool
|
|
|
|
|
|
|
|
// toRun is the channel of tests to run.
|
|
|
|
// It is nil until the first test is started.
|
|
|
|
toRun chan *test
|
2013-01-11 23:52:52 -07:00
|
|
|
|
|
|
|
// rungatec controls the max number of runoutput tests
|
|
|
|
// executed in parallel as they can each consume a lot of memory.
|
|
|
|
rungatec chan bool
|
2012-02-20 20:28:49 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// maxTests is an upper bound on the total number of tests.
|
|
|
|
// It is used as a channel buffer size to make sure sends don't block.
|
|
|
|
const maxTests = 5000
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
2012-03-06 21:43:25 -07:00
|
|
|
|
2014-07-24 15:18:54 -06:00
|
|
|
goos = getenv("GOOS", runtime.GOOS)
|
|
|
|
goarch = getenv("GOARCH", runtime.GOARCH)
|
|
|
|
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
findExecCmd()
|
|
|
|
|
2014-05-27 23:01:08 -06:00
|
|
|
// Disable parallelism if printing or if using a simulator.
|
|
|
|
if *verbose || len(findExecCmd()) > 0 {
|
|
|
|
*numParallel = 1
|
|
|
|
}
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
ratec = make(chan bool, *numParallel)
|
2013-01-11 23:52:52 -07:00
|
|
|
rungatec = make(chan bool, *runoutputLimit)
|
2012-02-20 20:28:49 -07:00
|
|
|
|
|
|
|
var tests []*test
|
|
|
|
if flag.NArg() > 0 {
|
|
|
|
for _, arg := range flag.Args() {
|
|
|
|
if arg == "-" || arg == "--" {
|
2012-08-06 19:38:35 -06:00
|
|
|
// Permit running:
|
2012-02-20 20:28:49 -07:00
|
|
|
// $ go run run.go - env.go
|
|
|
|
// $ go run run.go -- env.go
|
2012-08-06 19:38:35 -06:00
|
|
|
// $ go run run.go - ./fixedbugs
|
|
|
|
// $ go run run.go -- ./fixedbugs
|
2012-02-20 20:28:49 -07:00
|
|
|
continue
|
|
|
|
}
|
2012-08-06 19:38:35 -06:00
|
|
|
if fi, err := os.Stat(arg); err == nil && fi.IsDir() {
|
|
|
|
for _, baseGoFile := range goFiles(arg) {
|
|
|
|
tests = append(tests, startTest(arg, baseGoFile))
|
|
|
|
}
|
|
|
|
} else if strings.HasSuffix(arg, ".go") {
|
|
|
|
dir, file := filepath.Split(arg)
|
|
|
|
tests = append(tests, startTest(dir, file))
|
|
|
|
} else {
|
|
|
|
log.Fatalf("can't yet deal with non-directory and non-go file %q", arg)
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for _, dir := range dirs {
|
|
|
|
for _, baseGoFile := range goFiles(dir) {
|
|
|
|
tests = append(tests, startTest(dir, baseGoFile))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
failed := false
|
|
|
|
resCount := map[string]int{}
|
|
|
|
for _, test := range tests {
|
2014-08-01 14:34:36 -06:00
|
|
|
<-test.donec
|
2013-12-10 12:02:42 -07:00
|
|
|
status := "ok "
|
|
|
|
errStr := ""
|
2016-03-31 11:57:48 -06:00
|
|
|
if e, isSkip := test.err.(skipError); isSkip {
|
2013-12-10 12:02:42 -07:00
|
|
|
test.err = nil
|
2016-03-31 11:57:48 -06:00
|
|
|
errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + string(e)
|
2014-12-18 11:34:12 -07:00
|
|
|
status = "FAIL"
|
2013-12-10 12:02:42 -07:00
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
if test.err != nil {
|
2013-12-10 12:02:42 -07:00
|
|
|
status = "FAIL"
|
2012-02-20 20:28:49 -07:00
|
|
|
errStr = test.err.Error()
|
|
|
|
}
|
2013-12-10 12:02:42 -07:00
|
|
|
if status == "FAIL" {
|
2012-09-23 11:16:14 -06:00
|
|
|
failed = true
|
|
|
|
}
|
2013-12-10 12:02:42 -07:00
|
|
|
resCount[status]++
|
|
|
|
dt := fmt.Sprintf("%.3fs", test.dt.Seconds())
|
|
|
|
if status == "FAIL" {
|
|
|
|
fmt.Printf("# go run run.go -- %s\n%s\nFAIL\t%s\t%s\n",
|
|
|
|
path.Join(test.dir, test.gofile),
|
|
|
|
errStr, test.goFileName(), dt)
|
2012-02-20 20:28:49 -07:00
|
|
|
continue
|
2012-02-23 18:52:15 -07:00
|
|
|
}
|
2013-12-10 12:02:42 -07:00
|
|
|
if !*verbose {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fmt.Printf("%s\t%s\t%s\n", status, test.goFileName(), dt)
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if *summary {
|
|
|
|
for k, v := range resCount {
|
|
|
|
fmt.Printf("%5d %s\n", v, k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if failed {
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func toolPath(name string) string {
|
|
|
|
p := filepath.Join(os.Getenv("GOROOT"), "bin", "tool", name)
|
|
|
|
if _, err := os.Stat(p); err != nil {
|
|
|
|
log.Fatalf("didn't find binary at %s", p)
|
|
|
|
}
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2015-06-04 00:21:30 -06:00
|
|
|
func shardMatch(name string) bool {
|
|
|
|
if *shards == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
h := fnv.New32()
|
|
|
|
io.WriteString(h, name)
|
|
|
|
return int(h.Sum32()%uint32(*shards)) == *shard
|
|
|
|
}
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
func goFiles(dir string) []string {
|
|
|
|
f, err := os.Open(dir)
|
|
|
|
check(err)
|
|
|
|
dirnames, err := f.Readdirnames(-1)
|
|
|
|
check(err)
|
|
|
|
names := []string{}
|
|
|
|
for _, name := range dirnames {
|
2015-06-04 00:21:30 -06:00
|
|
|
if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && shardMatch(name) {
|
2012-02-20 20:28:49 -07:00
|
|
|
names = append(names, name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Strings(names)
|
|
|
|
return names
|
|
|
|
}
|
|
|
|
|
2012-10-06 01:23:31 -06:00
|
|
|
type runCmd func(...string) ([]byte, error)
|
|
|
|
|
2017-04-28 08:28:49 -06:00
|
|
|
func compileFile(runcmd runCmd, longname string, flags []string) (out []byte, err error) {
|
2015-10-26 19:54:19 -06:00
|
|
|
cmd := []string{"go", "tool", "compile", "-e"}
|
2017-04-28 08:28:49 -06:00
|
|
|
cmd = append(cmd, flags...)
|
2015-10-26 19:54:19 -06:00
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
|
|
|
|
}
|
|
|
|
cmd = append(cmd, longname)
|
|
|
|
return runcmd(cmd...)
|
2012-10-06 01:23:31 -06:00
|
|
|
}
|
|
|
|
|
2016-03-10 22:10:52 -07:00
|
|
|
func compileInDir(runcmd runCmd, dir string, flags []string, names ...string) (out []byte, err error) {
|
2015-05-21 11:28:13 -06:00
|
|
|
cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", "."}
|
2016-03-10 22:10:52 -07:00
|
|
|
cmd = append(cmd, flags...)
|
2015-10-26 19:54:19 -06:00
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
|
|
|
|
}
|
2013-01-02 13:31:49 -07:00
|
|
|
for _, name := range names {
|
|
|
|
cmd = append(cmd, filepath.Join(dir, name))
|
|
|
|
}
|
|
|
|
return runcmd(cmd...)
|
2012-10-06 01:23:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func linkFile(runcmd runCmd, goname string) (err error) {
|
2015-05-21 11:28:17 -06:00
|
|
|
pfile := strings.Replace(goname, ".go", ".o", -1)
|
2015-10-26 19:54:19 -06:00
|
|
|
cmd := []string{"go", "tool", "link", "-w", "-o", "a.exe", "-L", "."}
|
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-linkshared", "-installsuffix=dynlink")
|
|
|
|
}
|
|
|
|
cmd = append(cmd, pfile)
|
|
|
|
_, err = runcmd(cmd...)
|
2012-10-06 01:23:31 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
// skipError describes why a test was skipped.
|
|
|
|
type skipError string
|
|
|
|
|
|
|
|
func (s skipError) Error() string { return string(s) }
|
|
|
|
|
|
|
|
func check(err error) {
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// test holds the state of a test.
|
|
|
|
type test struct {
|
|
|
|
dir, gofile string
|
|
|
|
donec chan bool // closed when done
|
2014-08-01 14:34:36 -06:00
|
|
|
dt time.Duration
|
|
|
|
|
2016-09-22 11:50:16 -06:00
|
|
|
src string
|
2012-02-20 20:28:49 -07:00
|
|
|
|
|
|
|
tempDir string
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
2012-12-22 11:16:31 -07:00
|
|
|
// startTest
|
2012-02-20 20:28:49 -07:00
|
|
|
func startTest(dir, gofile string) *test {
|
|
|
|
t := &test{
|
|
|
|
dir: dir,
|
|
|
|
gofile: gofile,
|
|
|
|
donec: make(chan bool, 1),
|
|
|
|
}
|
|
|
|
if toRun == nil {
|
|
|
|
toRun = make(chan *test, maxTests)
|
|
|
|
go runTests()
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case toRun <- t:
|
|
|
|
default:
|
|
|
|
panic("toRun buffer size (maxTests) is too small")
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
// runTests runs tests in parallel, but respecting the order they
|
|
|
|
// were enqueued on the toRun channel.
|
|
|
|
func runTests() {
|
|
|
|
for {
|
|
|
|
ratec <- true
|
|
|
|
t := <-toRun
|
|
|
|
go func() {
|
|
|
|
t.run()
|
|
|
|
<-ratec
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
var cwd, _ = os.Getwd()
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
func (t *test) goFileName() string {
|
|
|
|
return filepath.Join(t.dir, t.gofile)
|
|
|
|
}
|
|
|
|
|
2012-07-30 13:12:05 -06:00
|
|
|
func (t *test) goDirName() string {
|
|
|
|
return filepath.Join(t.dir, strings.Replace(t.gofile, ".go", ".dir", -1))
|
|
|
|
}
|
|
|
|
|
2012-10-06 01:23:31 -06:00
|
|
|
func goDirFiles(longdir string) (filter []os.FileInfo, err error) {
|
|
|
|
files, dirErr := ioutil.ReadDir(longdir)
|
|
|
|
if dirErr != nil {
|
|
|
|
return nil, dirErr
|
|
|
|
}
|
|
|
|
for _, gofile := range files {
|
|
|
|
if filepath.Ext(gofile.Name()) == ".go" {
|
|
|
|
filter = append(filter, gofile)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-01-02 13:31:49 -07:00
|
|
|
var packageRE = regexp.MustCompile(`(?m)^package (\w+)`)
|
|
|
|
|
2016-06-21 16:33:04 -06:00
|
|
|
// If singlefilepkgs is set, each file is considered a separate package
|
|
|
|
// even if the package names are the same.
|
|
|
|
func goDirPackages(longdir string, singlefilepkgs bool) ([][]string, error) {
|
2013-01-02 13:31:49 -07:00
|
|
|
files, err := goDirFiles(longdir)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var pkgs [][]string
|
|
|
|
m := make(map[string]int)
|
|
|
|
for _, file := range files {
|
|
|
|
name := file.Name()
|
|
|
|
data, err := ioutil.ReadFile(filepath.Join(longdir, name))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
pkgname := packageRE.FindStringSubmatch(string(data))
|
|
|
|
if pkgname == nil {
|
|
|
|
return nil, fmt.Errorf("cannot find package name in %s", name)
|
|
|
|
}
|
|
|
|
i, ok := m[pkgname[1]]
|
2016-06-21 16:33:04 -06:00
|
|
|
if singlefilepkgs || !ok {
|
2013-01-02 13:31:49 -07:00
|
|
|
i = len(pkgs)
|
|
|
|
pkgs = append(pkgs, nil)
|
|
|
|
m[pkgname[1]] = i
|
|
|
|
}
|
|
|
|
pkgs[i] = append(pkgs[i], name)
|
|
|
|
}
|
|
|
|
return pkgs, nil
|
|
|
|
}
|
2013-01-11 14:00:48 -07:00
|
|
|
|
2013-08-13 10:25:41 -06:00
|
|
|
type context struct {
|
|
|
|
GOOS string
|
|
|
|
GOARCH string
|
|
|
|
}
|
|
|
|
|
2013-01-28 13:29:45 -07:00
|
|
|
// shouldTest looks for build tags in a source file and returns
|
|
|
|
// whether the file should be used according to the tags.
|
|
|
|
func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
|
2015-10-26 15:34:06 -06:00
|
|
|
if *runSkips {
|
|
|
|
return true, ""
|
|
|
|
}
|
2013-01-28 13:29:45 -07:00
|
|
|
for _, line := range strings.Split(src, "\n") {
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
if strings.HasPrefix(line, "//") {
|
|
|
|
line = line[2:]
|
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
if len(line) == 0 || line[0] != '+' {
|
|
|
|
continue
|
|
|
|
}
|
2013-08-13 10:25:41 -06:00
|
|
|
ctxt := &context{
|
|
|
|
GOOS: goos,
|
|
|
|
GOARCH: goarch,
|
|
|
|
}
|
2013-01-28 13:29:45 -07:00
|
|
|
words := strings.Fields(line)
|
|
|
|
if words[0] == "+build" {
|
2013-08-13 10:25:41 -06:00
|
|
|
ok := false
|
|
|
|
for _, word := range words[1:] {
|
|
|
|
if ctxt.match(word) {
|
|
|
|
ok = true
|
|
|
|
break
|
2013-01-28 13:29:45 -07:00
|
|
|
}
|
|
|
|
}
|
2013-08-13 10:25:41 -06:00
|
|
|
if !ok {
|
|
|
|
// no matching tag found.
|
|
|
|
return false, line
|
|
|
|
}
|
2013-01-28 13:29:45 -07:00
|
|
|
}
|
|
|
|
}
|
2013-08-13 10:25:41 -06:00
|
|
|
// no build tags
|
2013-01-28 13:29:45 -07:00
|
|
|
return true, ""
|
|
|
|
}
|
|
|
|
|
2013-08-13 10:25:41 -06:00
|
|
|
func (ctxt *context) match(name string) bool {
|
|
|
|
if name == "" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if i := strings.Index(name, ","); i >= 0 {
|
|
|
|
// comma-separated list
|
|
|
|
return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(name, "!!") { // bad syntax, reject always
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(name, "!") { // negation
|
|
|
|
return len(name) > 1 && !ctxt.match(name[1:])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tags must be letters, digits, underscores or dots.
|
|
|
|
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
|
|
|
for _, c := range name {
|
|
|
|
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if name == ctxt.GOOS || name == ctxt.GOARCH {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2015-12-04 20:51:03 -07:00
|
|
|
if name == "test_run" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2013-08-13 10:25:41 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2013-01-28 13:29:45 -07:00
|
|
|
func init() { checkShouldTest() }
|
|
|
|
|
2017-10-30 13:28:11 -06:00
|
|
|
// goGcflags returns the -gcflags argument to use with go build / go run.
|
|
|
|
// This must match the flags used for building the standard libary,
|
|
|
|
// or else the commands will rebuild any needed packages (like runtime)
|
|
|
|
// over and over.
|
|
|
|
func goGcflags() string {
|
|
|
|
return "-gcflags=" + os.Getenv("GO_GCFLAGS")
|
|
|
|
}
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
// run runs a test.
|
|
|
|
func (t *test) run() {
|
2013-12-10 12:02:42 -07:00
|
|
|
start := time.Now()
|
|
|
|
defer func() {
|
|
|
|
t.dt = time.Since(start)
|
|
|
|
close(t.donec)
|
|
|
|
}()
|
2012-02-20 20:28:49 -07:00
|
|
|
|
|
|
|
srcBytes, err := ioutil.ReadFile(t.goFileName())
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
t.src = string(srcBytes)
|
|
|
|
if t.src[0] == '\n' {
|
|
|
|
t.err = skipError("starts with newline")
|
|
|
|
return
|
|
|
|
}
|
2015-07-10 10:32:03 -06:00
|
|
|
|
|
|
|
// Execution recipe stops at first blank line.
|
2012-02-20 20:28:49 -07:00
|
|
|
pos := strings.Index(t.src, "\n\n")
|
|
|
|
if pos == -1 {
|
|
|
|
t.err = errors.New("double newline not found")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
action := t.src[:pos]
|
2013-01-28 13:29:45 -07:00
|
|
|
if nl := strings.Index(action, "\n"); nl >= 0 && strings.Contains(action[:nl], "+build") {
|
|
|
|
// skip first line
|
|
|
|
action = action[nl+1:]
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
if strings.HasPrefix(action, "//") {
|
|
|
|
action = action[2:]
|
|
|
|
}
|
2012-03-08 12:03:40 -07:00
|
|
|
|
2015-07-10 10:32:03 -06:00
|
|
|
// Check for build constraints only up to the actual code.
|
|
|
|
pkgPos := strings.Index(t.src, "\npackage")
|
|
|
|
if pkgPos == -1 {
|
|
|
|
pkgPos = pos // some files are intentionally malformed
|
|
|
|
}
|
|
|
|
if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
|
|
|
|
if *showSkips {
|
2016-09-22 11:50:16 -06:00
|
|
|
fmt.Printf("%-20s %-20s: %s\n", "skip", t.goFileName(), why)
|
2015-07-10 10:32:03 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2012-09-23 11:16:14 -06:00
|
|
|
var args, flags []string
|
2016-11-10 14:03:47 -07:00
|
|
|
var tim int
|
2012-09-23 11:16:14 -06:00
|
|
|
wantError := false
|
2016-09-22 11:50:16 -06:00
|
|
|
wantAuto := false
|
2016-06-21 16:33:04 -06:00
|
|
|
singlefilepkgs := false
|
2012-03-06 23:54:39 -07:00
|
|
|
f := strings.Fields(action)
|
|
|
|
if len(f) > 0 {
|
|
|
|
action = f[0]
|
|
|
|
args = f[1:]
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
|
2016-06-21 16:33:04 -06:00
|
|
|
// TODO: Clean up/simplify this switch statement.
|
2012-02-20 20:28:49 -07:00
|
|
|
switch action {
|
2012-10-06 01:23:31 -06:00
|
|
|
case "rundircmpout":
|
|
|
|
action = "rundir"
|
2012-02-23 19:17:26 -07:00
|
|
|
case "cmpout":
|
|
|
|
action = "run" // the run case already looks for <dir>/<test>.out files
|
2018-02-26 17:59:58 -07:00
|
|
|
case "compile", "compiledir", "build", "builddir", "run", "buildrun", "runoutput", "rundir", "asmcheck":
|
2016-09-22 11:50:16 -06:00
|
|
|
// nothing to do
|
2016-03-10 22:10:52 -07:00
|
|
|
case "errorcheckandrundir":
|
|
|
|
wantError = false // should be no error if also will run
|
2016-09-22 11:50:16 -06:00
|
|
|
case "errorcheckwithauto":
|
|
|
|
action = "errorcheck"
|
|
|
|
wantAuto = true
|
|
|
|
wantError = true
|
2012-11-07 13:33:54 -07:00
|
|
|
case "errorcheck", "errorcheckdir", "errorcheckoutput":
|
2012-09-23 11:16:14 -06:00
|
|
|
wantError = true
|
2012-03-21 12:14:44 -06:00
|
|
|
case "skip":
|
2015-10-26 15:34:06 -06:00
|
|
|
if *runSkips {
|
|
|
|
break
|
|
|
|
}
|
2012-03-21 12:14:44 -06:00
|
|
|
return
|
2012-02-20 20:28:49 -07:00
|
|
|
default:
|
|
|
|
t.err = skipError("skipped; unknown pattern: " + action)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-06-21 16:33:04 -06:00
|
|
|
// collect flags
|
|
|
|
for len(args) > 0 && strings.HasPrefix(args[0], "-") {
|
|
|
|
switch args[0] {
|
|
|
|
case "-0":
|
|
|
|
wantError = false
|
|
|
|
case "-s":
|
|
|
|
singlefilepkgs = true
|
2016-11-10 14:03:47 -07:00
|
|
|
case "-t": // timeout in seconds
|
|
|
|
args = args[1:]
|
|
|
|
var err error
|
|
|
|
tim, err = strconv.Atoi(args[0])
|
|
|
|
if err != nil {
|
|
|
|
t.err = fmt.Errorf("need number of seconds for -t timeout, got %s instead", args[0])
|
|
|
|
}
|
|
|
|
|
2016-06-21 16:33:04 -06:00
|
|
|
default:
|
|
|
|
flags = append(flags, args[0])
|
|
|
|
}
|
|
|
|
args = args[1:]
|
|
|
|
}
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
t.makeTempDir()
|
2016-03-10 22:10:52 -07:00
|
|
|
if !*keep {
|
|
|
|
defer os.RemoveAll(t.tempDir)
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
|
|
|
|
err = ioutil.WriteFile(filepath.Join(t.tempDir, t.gofile), srcBytes, 0644)
|
|
|
|
check(err)
|
2012-03-08 12:03:40 -07:00
|
|
|
|
2012-03-07 00:22:08 -07:00
|
|
|
// A few tests (of things like the environment) require these to be set.
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
if os.Getenv("GOOS") == "" {
|
|
|
|
os.Setenv("GOOS", runtime.GOOS)
|
|
|
|
}
|
|
|
|
if os.Getenv("GOARCH") == "" {
|
|
|
|
os.Setenv("GOARCH", runtime.GOARCH)
|
|
|
|
}
|
2012-03-07 00:22:08 -07:00
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
useTmp := true
|
|
|
|
runcmd := func(args ...string) ([]byte, error) {
|
|
|
|
cmd := exec.Command(args[0], args[1:]...)
|
|
|
|
var buf bytes.Buffer
|
|
|
|
cmd.Stdout = &buf
|
|
|
|
cmd.Stderr = &buf
|
|
|
|
if useTmp {
|
|
|
|
cmd.Dir = t.tempDir
|
2013-02-14 12:21:26 -07:00
|
|
|
cmd.Env = envForDir(cmd.Dir)
|
2015-09-06 20:39:07 -06:00
|
|
|
} else {
|
|
|
|
cmd.Env = os.Environ()
|
|
|
|
}
|
2016-11-10 14:03:47 -07:00
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
if tim != 0 {
|
|
|
|
err = cmd.Start()
|
|
|
|
// This command-timeout code adapted from cmd/go/test.go
|
|
|
|
if err == nil {
|
|
|
|
tick := time.NewTimer(time.Duration(tim) * time.Second)
|
|
|
|
done := make(chan error)
|
|
|
|
go func() {
|
|
|
|
done <- cmd.Wait()
|
|
|
|
}()
|
|
|
|
select {
|
|
|
|
case err = <-done:
|
|
|
|
// ok
|
|
|
|
case <-tick.C:
|
|
|
|
cmd.Process.Kill()
|
|
|
|
err = <-done
|
|
|
|
// err = errors.New("Test timeout")
|
|
|
|
}
|
|
|
|
tick.Stop()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = cmd.Run()
|
|
|
|
}
|
2012-10-06 01:23:31 -06:00
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("%s\n%s", err, buf.Bytes())
|
|
|
|
}
|
2012-03-06 23:54:39 -07:00
|
|
|
return buf.Bytes(), err
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
long := filepath.Join(cwd, t.goFileName())
|
2012-03-08 12:03:40 -07:00
|
|
|
switch action {
|
2012-03-06 23:54:39 -07:00
|
|
|
default:
|
|
|
|
t.err = fmt.Errorf("unimplemented action %q", action)
|
2012-02-20 20:28:49 -07:00
|
|
|
|
2018-02-26 17:59:58 -07:00
|
|
|
case "asmcheck":
|
|
|
|
ops, archs := t.wantedAsmOpcodes(long)
|
|
|
|
for _, arch := range archs {
|
|
|
|
os.Setenv("GOOS", "linux")
|
|
|
|
os.Setenv("GOARCH", arch)
|
|
|
|
|
|
|
|
cmdline := []string{"go", "build", "-gcflags", "-S"}
|
|
|
|
cmdline = append(cmdline, flags...)
|
|
|
|
cmdline = append(cmdline, long)
|
|
|
|
out, err := runcmd(cmdline...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
t.err = t.asmCheck(string(out), long, arch, ops[arch])
|
|
|
|
if t.err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
case "errorcheck":
|
2017-03-08 15:26:23 -07:00
|
|
|
// TODO(gri) remove need for -C (disable printing of columns in error messages)
|
|
|
|
cmdline := []string{"go", "tool", "compile", "-C", "-e", "-o", "a.o"}
|
2015-10-26 19:54:19 -06:00
|
|
|
// No need to add -dynlink even if linkshared if we're just checking for errors...
|
2012-09-23 11:16:14 -06:00
|
|
|
cmdline = append(cmdline, flags...)
|
|
|
|
cmdline = append(cmdline, long)
|
|
|
|
out, err := runcmd(cmdline...)
|
|
|
|
if wantError {
|
|
|
|
if err == nil {
|
|
|
|
t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err != nil {
|
2012-10-06 01:23:31 -06:00
|
|
|
t.err = err
|
2012-09-23 11:16:14 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2015-02-19 12:00:11 -07:00
|
|
|
if *updateErrors {
|
|
|
|
t.updateErrors(string(out), long)
|
|
|
|
}
|
2016-09-22 11:50:16 -06:00
|
|
|
t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
|
2012-02-20 20:28:49 -07:00
|
|
|
return
|
2012-03-08 12:03:40 -07:00
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
case "compile":
|
2017-04-28 08:28:49 -06:00
|
|
|
_, t.err = compileFile(runcmd, long, flags)
|
2012-03-08 12:03:40 -07:00
|
|
|
|
2012-07-30 13:12:05 -06:00
|
|
|
case "compiledir":
|
|
|
|
// Compile all files in the directory in lexicographic order.
|
|
|
|
longdir := filepath.Join(cwd, t.goDirName())
|
2016-06-21 16:33:04 -06:00
|
|
|
pkgs, err := goDirPackages(longdir, singlefilepkgs)
|
2012-10-06 01:23:31 -06:00
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
2012-07-30 13:12:05 -06:00
|
|
|
return
|
|
|
|
}
|
2013-01-02 13:31:49 -07:00
|
|
|
for _, gofiles := range pkgs {
|
2016-03-10 22:10:52 -07:00
|
|
|
_, t.err = compileInDir(runcmd, longdir, flags, gofiles...)
|
2012-10-06 01:23:31 -06:00
|
|
|
if t.err != nil {
|
|
|
|
return
|
2012-08-05 22:56:39 -06:00
|
|
|
}
|
2012-10-06 01:23:31 -06:00
|
|
|
}
|
|
|
|
|
2016-03-10 22:10:52 -07:00
|
|
|
case "errorcheckdir", "errorcheckandrundir":
|
2012-10-06 01:23:31 -06:00
|
|
|
// errorcheck all files in lexicographic order
|
|
|
|
// useful for finding importing errors
|
|
|
|
longdir := filepath.Join(cwd, t.goDirName())
|
2016-06-21 16:33:04 -06:00
|
|
|
pkgs, err := goDirPackages(longdir, singlefilepkgs)
|
2012-10-06 01:23:31 -06:00
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
2013-01-02 13:31:49 -07:00
|
|
|
for i, gofiles := range pkgs {
|
2016-03-10 22:10:52 -07:00
|
|
|
out, err := compileInDir(runcmd, longdir, flags, gofiles...)
|
2013-01-02 13:31:49 -07:00
|
|
|
if i == len(pkgs)-1 {
|
2012-10-06 01:23:31 -06:00
|
|
|
if wantError && err == nil {
|
|
|
|
t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
|
|
|
|
return
|
|
|
|
} else if !wantError && err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
2013-01-02 13:31:49 -07:00
|
|
|
var fullshort []string
|
|
|
|
for _, name := range gofiles {
|
|
|
|
fullshort = append(fullshort, filepath.Join(longdir, name), name)
|
|
|
|
}
|
2016-09-22 11:50:16 -06:00
|
|
|
t.err = t.errorCheck(string(out), wantAuto, fullshort...)
|
2012-10-06 01:23:31 -06:00
|
|
|
if t.err != nil {
|
2012-07-30 13:12:05 -06:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2016-03-10 22:10:52 -07:00
|
|
|
if action == "errorcheckdir" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fallthrough
|
2012-07-30 13:12:05 -06:00
|
|
|
|
2012-10-06 01:23:31 -06:00
|
|
|
case "rundir":
|
|
|
|
// Compile all files in the directory in lexicographic order.
|
|
|
|
// then link as if the last file is the main package and run it
|
|
|
|
longdir := filepath.Join(cwd, t.goDirName())
|
2016-06-21 16:33:04 -06:00
|
|
|
pkgs, err := goDirPackages(longdir, singlefilepkgs)
|
2012-10-06 01:23:31 -06:00
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
2013-01-11 14:00:48 -07:00
|
|
|
for i, gofiles := range pkgs {
|
2016-03-10 22:10:52 -07:00
|
|
|
_, err := compileInDir(runcmd, longdir, flags, gofiles...)
|
2012-10-06 01:23:31 -06:00
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
2013-01-11 14:00:48 -07:00
|
|
|
if i == len(pkgs)-1 {
|
|
|
|
err = linkFile(runcmd, gofiles[0])
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
var cmd []string
|
|
|
|
cmd = append(cmd, findExecCmd()...)
|
|
|
|
cmd = append(cmd, filepath.Join(t.tempDir, "a.exe"))
|
|
|
|
cmd = append(cmd, args...)
|
|
|
|
out, err := runcmd(cmd...)
|
2013-01-11 14:00:48 -07:00
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
|
|
|
|
t.err = fmt.Errorf("incorrect output\n%s", out)
|
|
|
|
}
|
|
|
|
}
|
2012-10-06 01:23:31 -06:00
|
|
|
}
|
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
case "build":
|
2017-10-30 13:28:11 -06:00
|
|
|
_, err := runcmd("go", "build", goGcflags(), "-o", "a.exe", long)
|
2012-03-06 23:54:39 -07:00
|
|
|
if err != nil {
|
2012-10-06 01:23:31 -06:00
|
|
|
t.err = err
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
2012-03-08 12:03:40 -07:00
|
|
|
|
2017-06-14 12:36:36 -06:00
|
|
|
case "builddir":
|
|
|
|
// Build an executable from all the .go and .s files in a subdirectory.
|
|
|
|
useTmp = true
|
|
|
|
longdir := filepath.Join(cwd, t.goDirName())
|
|
|
|
files, dirErr := ioutil.ReadDir(longdir)
|
|
|
|
if dirErr != nil {
|
|
|
|
t.err = dirErr
|
|
|
|
break
|
|
|
|
}
|
|
|
|
var gos []os.FileInfo
|
|
|
|
var asms []os.FileInfo
|
|
|
|
for _, file := range files {
|
|
|
|
switch filepath.Ext(file.Name()) {
|
|
|
|
case ".go":
|
|
|
|
gos = append(gos, file)
|
|
|
|
case ".s":
|
|
|
|
asms = append(asms, file)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
var objs []string
|
|
|
|
cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", ".", "-o", "go.o"}
|
2017-11-29 12:58:03 -07:00
|
|
|
if len(asms) > 0 {
|
|
|
|
cmd = append(cmd, "-asmhdr", "go_asm.h")
|
|
|
|
}
|
2017-06-14 12:36:36 -06:00
|
|
|
for _, file := range gos {
|
|
|
|
cmd = append(cmd, filepath.Join(longdir, file.Name()))
|
|
|
|
}
|
|
|
|
_, err := runcmd(cmd...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
break
|
|
|
|
}
|
|
|
|
objs = append(objs, "go.o")
|
|
|
|
if len(asms) > 0 {
|
|
|
|
cmd = []string{"go", "tool", "asm", "-e", "-I", ".", "-o", "asm.o"}
|
|
|
|
for _, file := range asms {
|
|
|
|
cmd = append(cmd, filepath.Join(longdir, file.Name()))
|
|
|
|
}
|
|
|
|
_, err = runcmd(cmd...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
break
|
|
|
|
}
|
|
|
|
objs = append(objs, "asm.o")
|
|
|
|
}
|
|
|
|
cmd = []string{"go", "tool", "pack", "c", "all.a"}
|
|
|
|
cmd = append(cmd, objs...)
|
|
|
|
_, err = runcmd(cmd...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
break
|
|
|
|
}
|
|
|
|
cmd = []string{"go", "tool", "link", "all.a"}
|
|
|
|
_, err = runcmd(cmd...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2016-11-10 14:03:47 -07:00
|
|
|
case "buildrun": // build binary, then run binary, instead of go run. Useful for timeout tests where failure mode is infinite loop.
|
|
|
|
// TODO: not supported on NaCl
|
|
|
|
useTmp = true
|
2017-10-30 13:28:11 -06:00
|
|
|
cmd := []string{"go", "build", goGcflags(), "-o", "a.exe"}
|
2016-11-10 14:03:47 -07:00
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-linkshared")
|
|
|
|
}
|
|
|
|
longdirgofile := filepath.Join(filepath.Join(cwd, t.dir), t.gofile)
|
|
|
|
cmd = append(cmd, flags...)
|
|
|
|
cmd = append(cmd, longdirgofile)
|
|
|
|
out, err := runcmd(cmd...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cmd = []string{"./a.exe"}
|
|
|
|
out, err = runcmd(append(cmd, args...)...)
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
|
|
|
|
t.err = fmt.Errorf("incorrect output\n%s", out)
|
|
|
|
}
|
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
case "run":
|
2015-09-09 18:39:31 -06:00
|
|
|
useTmp = false
|
2017-10-27 12:11:21 -06:00
|
|
|
var out []byte
|
|
|
|
var err error
|
|
|
|
if len(flags)+len(args) == 0 && goGcflags() == "" && !*linkshared {
|
|
|
|
// If we're not using special go command flags,
|
|
|
|
// skip all the go command machinery.
|
|
|
|
// This avoids any time the go command would
|
|
|
|
// spend checking whether, for example, the installed
|
|
|
|
// package runtime is up to date.
|
|
|
|
// Because we run lots of trivial test programs,
|
|
|
|
// the time adds up.
|
|
|
|
pkg := filepath.Join(t.tempDir, "pkg.a")
|
|
|
|
if _, err := runcmd("go", "tool", "compile", "-o", pkg, t.goFileName()); err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
exe := filepath.Join(t.tempDir, "test.exe")
|
|
|
|
cmd := []string{"go", "tool", "link", "-s", "-w"}
|
|
|
|
cmd = append(cmd, "-o", exe, pkg)
|
|
|
|
if _, err := runcmd(cmd...); err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
out, err = runcmd(append([]string{exe}, args...)...)
|
|
|
|
} else {
|
|
|
|
cmd := []string{"go", "run", goGcflags()}
|
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-linkshared")
|
|
|
|
}
|
|
|
|
cmd = append(cmd, flags...)
|
|
|
|
cmd = append(cmd, t.goFileName())
|
|
|
|
out, err = runcmd(append(cmd, args...)...)
|
2015-10-26 19:54:19 -06:00
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
if err != nil {
|
2012-10-06 01:23:31 -06:00
|
|
|
t.err = err
|
2014-09-11 13:47:17 -06:00
|
|
|
return
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
2012-09-19 10:27:23 -06:00
|
|
|
if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
|
2012-03-06 23:54:39 -07:00
|
|
|
t.err = fmt.Errorf("incorrect output\n%s", out)
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
2012-04-20 09:45:43 -06:00
|
|
|
|
|
|
|
case "runoutput":
|
2013-01-11 23:52:52 -07:00
|
|
|
rungatec <- true
|
|
|
|
defer func() {
|
|
|
|
<-rungatec
|
|
|
|
}()
|
2012-04-20 09:45:43 -06:00
|
|
|
useTmp = false
|
2017-10-30 13:28:11 -06:00
|
|
|
cmd := []string{"go", "run", goGcflags()}
|
2015-10-26 19:54:19 -06:00
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-linkshared")
|
|
|
|
}
|
|
|
|
cmd = append(cmd, t.goFileName())
|
|
|
|
out, err := runcmd(append(cmd, args...)...)
|
2012-04-20 09:45:43 -06:00
|
|
|
if err != nil {
|
2012-10-06 01:23:31 -06:00
|
|
|
t.err = err
|
2014-09-11 13:47:17 -06:00
|
|
|
return
|
2012-04-20 09:45:43 -06:00
|
|
|
}
|
|
|
|
tfile := filepath.Join(t.tempDir, "tmp__.go")
|
2013-01-11 23:52:52 -07:00
|
|
|
if err := ioutil.WriteFile(tfile, out, 0666); err != nil {
|
2012-04-20 09:45:43 -06:00
|
|
|
t.err = fmt.Errorf("write tempfile:%s", err)
|
|
|
|
return
|
|
|
|
}
|
2017-10-30 13:28:11 -06:00
|
|
|
cmd = []string{"go", "run", goGcflags()}
|
2015-10-26 19:54:19 -06:00
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-linkshared")
|
|
|
|
}
|
|
|
|
cmd = append(cmd, tfile)
|
|
|
|
out, err = runcmd(cmd...)
|
2012-04-20 09:45:43 -06:00
|
|
|
if err != nil {
|
2012-10-06 01:23:31 -06:00
|
|
|
t.err = err
|
2014-09-11 13:47:17 -06:00
|
|
|
return
|
2012-04-20 09:45:43 -06:00
|
|
|
}
|
|
|
|
if string(out) != t.expectedOutput() {
|
|
|
|
t.err = fmt.Errorf("incorrect output\n%s", out)
|
|
|
|
}
|
2012-11-07 13:33:54 -07:00
|
|
|
|
|
|
|
case "errorcheckoutput":
|
|
|
|
useTmp = false
|
2017-10-30 13:28:11 -06:00
|
|
|
cmd := []string{"go", "run", goGcflags()}
|
2015-10-26 19:54:19 -06:00
|
|
|
if *linkshared {
|
|
|
|
cmd = append(cmd, "-linkshared")
|
|
|
|
}
|
|
|
|
cmd = append(cmd, t.goFileName())
|
|
|
|
out, err := runcmd(append(cmd, args...)...)
|
2012-11-07 13:33:54 -07:00
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
2014-09-11 13:47:17 -06:00
|
|
|
return
|
2012-11-07 13:33:54 -07:00
|
|
|
}
|
|
|
|
tfile := filepath.Join(t.tempDir, "tmp__.go")
|
|
|
|
err = ioutil.WriteFile(tfile, out, 0666)
|
|
|
|
if err != nil {
|
|
|
|
t.err = fmt.Errorf("write tempfile:%s", err)
|
|
|
|
return
|
|
|
|
}
|
2015-05-21 11:28:17 -06:00
|
|
|
cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
|
2012-11-07 13:33:54 -07:00
|
|
|
cmdline = append(cmdline, flags...)
|
|
|
|
cmdline = append(cmdline, tfile)
|
|
|
|
out, err = runcmd(cmdline...)
|
|
|
|
if wantError {
|
|
|
|
if err == nil {
|
|
|
|
t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err != nil {
|
|
|
|
t.err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2016-09-22 11:50:16 -06:00
|
|
|
t.err = t.errorCheck(string(out), false, tfile, "tmp__.go")
|
2012-11-07 13:33:54 -07:00
|
|
|
return
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
var execCmd []string
|
|
|
|
|
|
|
|
func findExecCmd() []string {
|
|
|
|
if execCmd != nil {
|
|
|
|
return execCmd
|
|
|
|
}
|
|
|
|
execCmd = []string{} // avoid work the second time
|
|
|
|
if goos == runtime.GOOS && goarch == runtime.GOARCH {
|
|
|
|
return execCmd
|
|
|
|
}
|
|
|
|
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
|
|
|
|
if err == nil {
|
|
|
|
execCmd = []string{path}
|
|
|
|
}
|
|
|
|
return execCmd
|
2014-08-01 14:34:36 -06:00
|
|
|
}
|
all: merge NaCl branch (part 1)
See golang.org/s/go13nacl for design overview.
This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.
CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.
The exact change lists included are
15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047
2014-02-25 07:47:42 -07:00
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
func (t *test) String() string {
|
|
|
|
return filepath.Join(t.dir, t.gofile)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *test) makeTempDir() {
|
|
|
|
var err error
|
|
|
|
t.tempDir, err = ioutil.TempDir("", "")
|
|
|
|
check(err)
|
2016-03-10 22:10:52 -07:00
|
|
|
if *keep {
|
|
|
|
log.Printf("Temporary directory is %s", t.tempDir)
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *test) expectedOutput() string {
|
|
|
|
filename := filepath.Join(t.dir, t.gofile)
|
|
|
|
filename = filename[:len(filename)-len(".go")]
|
|
|
|
filename += ".out"
|
|
|
|
b, _ := ioutil.ReadFile(filename)
|
|
|
|
return string(b)
|
|
|
|
}
|
|
|
|
|
2016-09-22 11:50:16 -06:00
|
|
|
func splitOutput(out string, wantAuto bool) []string {
|
2015-06-23 17:50:12 -06:00
|
|
|
// gc error messages continue onto additional lines with leading tabs.
|
2012-02-20 20:28:49 -07:00
|
|
|
// Split the output at the beginning of each line that doesn't begin with a tab.
|
2015-06-16 16:28:01 -06:00
|
|
|
// <autogenerated> lines are impossible to match so those are filtered out.
|
2015-02-19 12:00:11 -07:00
|
|
|
var res []string
|
|
|
|
for _, line := range strings.Split(out, "\n") {
|
2012-09-23 11:16:14 -06:00
|
|
|
if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
|
2012-08-16 00:46:59 -06:00
|
|
|
line = line[:len(line)-1]
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
if strings.HasPrefix(line, "\t") {
|
2015-02-19 12:00:11 -07:00
|
|
|
res[len(res)-1] += "\n" + line
|
2016-09-22 11:50:16 -06:00
|
|
|
} else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "#") || !wantAuto && strings.HasPrefix(line, "<autogenerated>") {
|
2012-10-08 08:36:45 -06:00
|
|
|
continue
|
|
|
|
} else if strings.TrimSpace(line) != "" {
|
2015-02-19 12:00:11 -07:00
|
|
|
res = append(res, line)
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
}
|
2015-02-19 12:00:11 -07:00
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2016-09-22 11:50:16 -06:00
|
|
|
func (t *test) errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
|
2015-02-19 12:00:11 -07:00
|
|
|
defer func() {
|
|
|
|
if *verbose && err != nil {
|
|
|
|
log.Printf("%s gc output:\n%s", t, outStr)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
var errs []error
|
2016-09-22 11:50:16 -06:00
|
|
|
out := splitOutput(outStr, wantAuto)
|
2012-02-20 20:28:49 -07:00
|
|
|
|
2012-03-06 23:54:39 -07:00
|
|
|
// Cut directory name.
|
|
|
|
for i := range out {
|
2013-01-02 13:31:49 -07:00
|
|
|
for j := 0; j < len(fullshort); j += 2 {
|
|
|
|
full, short := fullshort[j], fullshort[j+1]
|
|
|
|
out[i] = strings.Replace(out[i], full, short, -1)
|
|
|
|
}
|
|
|
|
}
|
2013-01-11 14:00:48 -07:00
|
|
|
|
2013-01-02 13:31:49 -07:00
|
|
|
var want []wantedError
|
|
|
|
for j := 0; j < len(fullshort); j += 2 {
|
|
|
|
full, short := fullshort[j], fullshort[j+1]
|
|
|
|
want = append(want, t.wantedErrors(full, short)...)
|
2012-03-06 23:54:39 -07:00
|
|
|
}
|
|
|
|
|
2013-01-02 13:31:49 -07:00
|
|
|
for _, we := range want {
|
2012-02-20 20:28:49 -07:00
|
|
|
var errmsgs []string
|
2016-09-22 11:50:16 -06:00
|
|
|
if we.auto {
|
|
|
|
errmsgs, out = partitionStrings("<autogenerated>", out)
|
|
|
|
} else {
|
|
|
|
errmsgs, out = partitionStrings(we.prefix, out)
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
if len(errmsgs) == 0 {
|
2012-03-06 23:54:39 -07:00
|
|
|
errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr))
|
2012-02-20 20:28:49 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
matched := false
|
2013-02-01 21:10:02 -07:00
|
|
|
n := len(out)
|
2012-02-20 20:28:49 -07:00
|
|
|
for _, errmsg := range errmsgs {
|
2016-10-17 22:34:57 -06:00
|
|
|
// Assume errmsg says "file:line: foo".
|
|
|
|
// Cut leading "file:line: " to avoid accidental matching of file name instead of message.
|
|
|
|
text := errmsg
|
|
|
|
if i := strings.Index(text, " "); i >= 0 {
|
|
|
|
text = text[i+1:]
|
|
|
|
}
|
|
|
|
if we.re.MatchString(text) {
|
2012-02-20 20:28:49 -07:00
|
|
|
matched = true
|
|
|
|
} else {
|
|
|
|
out = append(out, errmsg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !matched {
|
2013-02-01 21:10:02 -07:00
|
|
|
errs = append(errs, fmt.Errorf("%s:%d: no match for %#q in:\n\t%s", we.file, we.lineNum, we.reStr, strings.Join(out[n:], "\n\t")))
|
2012-02-20 20:28:49 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-08 08:36:45 -06:00
|
|
|
if len(out) > 0 {
|
|
|
|
errs = append(errs, fmt.Errorf("Unmatched Errors:"))
|
|
|
|
for _, errLine := range out {
|
|
|
|
errs = append(errs, fmt.Errorf("%s", errLine))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-20 20:28:49 -07:00
|
|
|
if len(errs) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(errs) == 1 {
|
|
|
|
return errs[0]
|
|
|
|
}
|
|
|
|
var buf bytes.Buffer
|
2012-03-06 23:54:39 -07:00
|
|
|
fmt.Fprintf(&buf, "\n")
|
2012-02-20 20:28:49 -07:00
|
|
|
for _, err := range errs {
|
|
|
|
fmt.Fprintf(&buf, "%s\n", err.Error())
|
|
|
|
}
|
|
|
|
return errors.New(buf.String())
|
2015-02-19 12:00:11 -07:00
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
|
2016-02-29 08:43:18 -07:00
|
|
|
func (t *test) updateErrors(out, file string) {
|
|
|
|
base := path.Base(file)
|
2015-02-19 12:00:11 -07:00
|
|
|
// Read in source file.
|
|
|
|
src, err := ioutil.ReadFile(file)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
lines := strings.Split(string(src), "\n")
|
|
|
|
// Remove old errors.
|
|
|
|
for i, ln := range lines {
|
|
|
|
pos := strings.Index(ln, " // ERROR ")
|
|
|
|
if pos >= 0 {
|
|
|
|
lines[i] = ln[:pos]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Parse new errors.
|
|
|
|
errors := make(map[int]map[string]bool)
|
|
|
|
tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
|
2016-09-22 11:50:16 -06:00
|
|
|
for _, errStr := range splitOutput(out, false) {
|
2015-02-19 12:00:11 -07:00
|
|
|
colon1 := strings.Index(errStr, ":")
|
2015-04-27 17:50:05 -06:00
|
|
|
if colon1 < 0 || errStr[:colon1] != file {
|
2015-02-19 12:00:11 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
colon2 := strings.Index(errStr[colon1+1:], ":")
|
|
|
|
if colon2 < 0 {
|
|
|
|
continue
|
|
|
|
}
|
2015-04-27 17:50:05 -06:00
|
|
|
colon2 += colon1 + 1
|
|
|
|
line, err := strconv.Atoi(errStr[colon1+1 : colon2])
|
2015-02-19 12:00:11 -07:00
|
|
|
line--
|
|
|
|
if err != nil || line < 0 || line >= len(lines) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
msg := errStr[colon2+2:]
|
2016-02-29 08:43:18 -07:00
|
|
|
msg = strings.Replace(msg, file, base, -1) // normalize file mentions in error itself
|
|
|
|
msg = strings.TrimLeft(msg, " \t")
|
2015-02-19 12:00:11 -07:00
|
|
|
for _, r := range []string{`\`, `*`, `+`, `[`, `]`, `(`, `)`} {
|
2015-04-27 17:50:05 -06:00
|
|
|
msg = strings.Replace(msg, r, `\`+r, -1)
|
2015-02-19 12:00:11 -07:00
|
|
|
}
|
|
|
|
msg = strings.Replace(msg, `"`, `.`, -1)
|
|
|
|
msg = tmpRe.ReplaceAllLiteralString(msg, `autotmp_[0-9]+`)
|
|
|
|
if errors[line] == nil {
|
|
|
|
errors[line] = make(map[string]bool)
|
|
|
|
}
|
|
|
|
errors[line][msg] = true
|
|
|
|
}
|
|
|
|
// Add new errors.
|
|
|
|
for line, errs := range errors {
|
|
|
|
var sorted []string
|
|
|
|
for e := range errs {
|
|
|
|
sorted = append(sorted, e)
|
|
|
|
}
|
|
|
|
sort.Strings(sorted)
|
|
|
|
lines[line] += " // ERROR"
|
|
|
|
for _, e := range sorted {
|
|
|
|
lines[line] += fmt.Sprintf(` "%s$"`, e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Write new file.
|
|
|
|
err = ioutil.WriteFile(file, []byte(strings.Join(lines, "\n")), 0640)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Polish.
|
|
|
|
exec.Command("go", "fmt", file).CombinedOutput()
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
|
2014-03-11 21:58:24 -06:00
|
|
|
// matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
|
|
|
|
// That is, it needs the file name prefix followed by a : or a [,
|
|
|
|
// and possibly preceded by a directory name.
|
|
|
|
func matchPrefix(s, prefix string) bool {
|
|
|
|
i := strings.Index(s, ":")
|
|
|
|
if i < 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
j := strings.LastIndex(s[:i], "/")
|
|
|
|
s = s[j+1:]
|
|
|
|
if len(s) <= len(prefix) || s[:len(prefix)] != prefix {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
switch s[len(prefix)] {
|
|
|
|
case '[', ':':
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func partitionStrings(prefix string, strs []string) (matched, unmatched []string) {
|
2012-02-20 20:28:49 -07:00
|
|
|
for _, s := range strs {
|
2014-03-11 21:58:24 -06:00
|
|
|
if matchPrefix(s, prefix) {
|
2012-02-20 20:28:49 -07:00
|
|
|
matched = append(matched, s)
|
|
|
|
} else {
|
|
|
|
unmatched = append(unmatched, s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
type wantedError struct {
|
2014-08-01 14:34:36 -06:00
|
|
|
reStr string
|
|
|
|
re *regexp.Regexp
|
|
|
|
lineNum int
|
2016-09-22 11:50:16 -06:00
|
|
|
auto bool // match <autogenerated> line
|
2014-08-01 14:34:36 -06:00
|
|
|
file string
|
|
|
|
prefix string
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`)
|
2016-09-22 11:50:16 -06:00
|
|
|
errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`)
|
2012-02-20 20:28:49 -07:00
|
|
|
errQuotesRx = regexp.MustCompile(`"([^"]*)"`)
|
|
|
|
lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`)
|
|
|
|
)
|
|
|
|
|
2012-10-06 01:23:31 -06:00
|
|
|
func (t *test) wantedErrors(file, short string) (errs []wantedError) {
|
2014-03-11 21:58:24 -06:00
|
|
|
cache := make(map[string]*regexp.Regexp)
|
|
|
|
|
2012-10-06 01:23:31 -06:00
|
|
|
src, _ := ioutil.ReadFile(file)
|
|
|
|
for i, line := range strings.Split(string(src), "\n") {
|
2012-02-20 20:28:49 -07:00
|
|
|
lineNum := i + 1
|
|
|
|
if strings.Contains(line, "////") {
|
|
|
|
// double comment disables ERROR
|
|
|
|
continue
|
|
|
|
}
|
2016-09-22 11:50:16 -06:00
|
|
|
var auto bool
|
|
|
|
m := errAutoRx.FindStringSubmatch(line)
|
|
|
|
if m != nil {
|
|
|
|
auto = true
|
|
|
|
} else {
|
|
|
|
m = errRx.FindStringSubmatch(line)
|
|
|
|
}
|
2012-02-20 20:28:49 -07:00
|
|
|
if m == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
all := m[1]
|
|
|
|
mm := errQuotesRx.FindAllStringSubmatch(all, -1)
|
|
|
|
if mm == nil {
|
2013-02-01 21:10:02 -07:00
|
|
|
log.Fatalf("%s:%d: invalid errchk line: %s", t.goFileName(), lineNum, line)
|
2012-02-20 20:28:49 -07:00
|
|
|
}
|
|
|
|
for _, m := range mm {
|
|
|
|
rx := lineRx.ReplaceAllStringFunc(m[1], func(m string) string {
|
|
|
|
n := lineNum
|
|
|
|
if strings.HasPrefix(m, "LINE+") {
|
|
|
|
delta, _ := strconv.Atoi(m[5:])
|
|
|
|
n += delta
|
|
|
|
} else if strings.HasPrefix(m, "LINE-") {
|
|
|
|
delta, _ := strconv.Atoi(m[5:])
|
|
|
|
n -= delta
|
|
|
|
}
|
2012-10-06 01:23:31 -06:00
|
|
|
return fmt.Sprintf("%s:%d", short, n)
|
2012-02-20 20:28:49 -07:00
|
|
|
})
|
2014-03-11 21:58:24 -06:00
|
|
|
re := cache[rx]
|
|
|
|
if re == nil {
|
|
|
|
var err error
|
|
|
|
re, err = regexp.Compile(rx)
|
|
|
|
if err != nil {
|
2015-02-19 12:00:11 -07:00
|
|
|
log.Fatalf("%s:%d: invalid regexp \"%s\" in ERROR line: %v", t.goFileName(), lineNum, rx, err)
|
2014-03-11 21:58:24 -06:00
|
|
|
}
|
|
|
|
cache[rx] = re
|
2013-02-01 21:10:02 -07:00
|
|
|
}
|
2014-03-11 21:58:24 -06:00
|
|
|
prefix := fmt.Sprintf("%s:%d", short, lineNum)
|
2012-02-20 20:28:49 -07:00
|
|
|
errs = append(errs, wantedError{
|
2014-08-01 14:34:36 -06:00
|
|
|
reStr: rx,
|
|
|
|
re: re,
|
|
|
|
prefix: prefix,
|
2016-09-22 11:50:16 -06:00
|
|
|
auto: auto,
|
2014-08-01 14:34:36 -06:00
|
|
|
lineNum: lineNum,
|
|
|
|
file: short,
|
2012-02-20 20:28:49 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2012-09-23 11:16:14 -06:00
|
|
|
|
2018-02-26 17:59:58 -07:00
|
|
|
var (
|
|
|
|
rxAsmCheck = regexp.MustCompile(`//(?:\s+(\w+):((?:"(?:.+?)")|(?:` + "`" + `(?:.+?)` + "`" + `)))+`)
|
|
|
|
)
|
|
|
|
|
|
|
|
type wantedAsmOpcode struct {
|
|
|
|
line int
|
|
|
|
opcode *regexp.Regexp
|
|
|
|
negative bool
|
|
|
|
found bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpcode, []string) {
|
|
|
|
ops := make(map[string]map[string][]wantedAsmOpcode)
|
|
|
|
archs := make(map[string]bool)
|
|
|
|
|
|
|
|
src, _ := ioutil.ReadFile(fn)
|
|
|
|
for i, line := range strings.Split(string(src), "\n") {
|
|
|
|
matches := rxAsmCheck.FindStringSubmatch(line)
|
|
|
|
if len(matches) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
lnum := fn + ":" + strconv.Itoa(i+1)
|
|
|
|
for j := 1; j < len(matches); j += 2 {
|
|
|
|
rxsrc, err := strconv.Unquote(matches[j+1])
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("%s:%d: error unquoting string: %v", t.goFileName(), i+1, err)
|
|
|
|
}
|
|
|
|
oprx, err := regexp.Compile(rxsrc)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("%s:%d: %v", t.goFileName(), i+1, err)
|
|
|
|
}
|
|
|
|
arch := matches[j]
|
|
|
|
if ops[arch] == nil {
|
|
|
|
ops[arch] = make(map[string][]wantedAsmOpcode)
|
|
|
|
}
|
|
|
|
archs[arch] = true
|
|
|
|
ops[arch][lnum] = append(ops[arch][lnum], wantedAsmOpcode{
|
|
|
|
line: i + 1,
|
|
|
|
opcode: oprx,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var sarchs []string
|
|
|
|
for a := range archs {
|
|
|
|
sarchs = append(sarchs, a)
|
|
|
|
}
|
|
|
|
sort.Strings(sarchs)
|
|
|
|
|
|
|
|
return ops, sarchs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[string][]wantedAsmOpcode) (err error) {
|
|
|
|
defer func() {
|
|
|
|
if *verbose && err != nil {
|
|
|
|
log.Printf("%s gc output:\n%s", t, outStr)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
rxLine := regexp.MustCompile(fmt.Sprintf(`\((%s:\d+)\)\s+(.*)`, regexp.QuoteMeta(fn)))
|
|
|
|
|
|
|
|
for _, line := range strings.Split(outStr, "\n") {
|
|
|
|
matches := rxLine.FindStringSubmatch(line)
|
|
|
|
if len(matches) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
ops := fullops[matches[1]]
|
|
|
|
asm := matches[2]
|
|
|
|
for i := range ops {
|
|
|
|
if !ops[i].found && ops[i].opcode.FindString(asm) != "" {
|
|
|
|
ops[i].found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var notfound []wantedAsmOpcode
|
|
|
|
for _, ops := range fullops {
|
|
|
|
for _, o := range ops {
|
|
|
|
if !o.found {
|
|
|
|
notfound = append(notfound, o)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(notfound) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// At least one asmcheck failed; report them
|
|
|
|
sort.Slice(notfound, func(i, j int) bool {
|
|
|
|
return notfound[i].line < notfound[j].line
|
|
|
|
})
|
|
|
|
|
|
|
|
var errbuf bytes.Buffer
|
|
|
|
fmt.Fprintln(&errbuf)
|
|
|
|
for _, o := range notfound {
|
|
|
|
fmt.Fprintf(&errbuf, "%s:%d: %s: no match for opcode: %q\n", t.goFileName(), o.line, arch, o.opcode.String())
|
|
|
|
}
|
|
|
|
err = errors.New(errbuf.String())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-01-11 23:52:52 -07:00
|
|
|
// defaultRunOutputLimit returns the number of runoutput tests that
|
|
|
|
// can be executed in parallel.
|
|
|
|
func defaultRunOutputLimit() int {
|
|
|
|
const maxArmCPU = 2
|
|
|
|
|
|
|
|
cpu := runtime.NumCPU()
|
|
|
|
if runtime.GOARCH == "arm" && cpu > maxArmCPU {
|
|
|
|
cpu = maxArmCPU
|
|
|
|
}
|
|
|
|
return cpu
|
|
|
|
}
|
2013-01-28 13:29:45 -07:00
|
|
|
|
2013-08-13 10:25:41 -06:00
|
|
|
// checkShouldTest runs sanity checks on the shouldTest function.
|
2013-01-28 13:29:45 -07:00
|
|
|
func checkShouldTest() {
|
|
|
|
assert := func(ok bool, _ string) {
|
|
|
|
if !ok {
|
|
|
|
panic("fail")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assertNot := func(ok bool, _ string) { assert(!ok, "") }
|
2013-08-13 10:25:41 -06:00
|
|
|
|
|
|
|
// Simple tests.
|
2013-01-28 13:29:45 -07:00
|
|
|
assert(shouldTest("// +build linux", "linux", "arm"))
|
|
|
|
assert(shouldTest("// +build !windows", "linux", "arm"))
|
|
|
|
assertNot(shouldTest("// +build !windows", "windows", "amd64"))
|
2013-08-13 10:25:41 -06:00
|
|
|
|
|
|
|
// A file with no build tags will always be tested.
|
2013-01-28 13:29:45 -07:00
|
|
|
assert(shouldTest("// This is a test.", "os", "arch"))
|
2013-08-13 10:25:41 -06:00
|
|
|
|
|
|
|
// Build tags separated by a space are OR-ed together.
|
|
|
|
assertNot(shouldTest("// +build arm 386", "linux", "amd64"))
|
|
|
|
|
2013-12-27 09:59:02 -07:00
|
|
|
// Build tags separated by a comma are AND-ed together.
|
2013-08-13 10:25:41 -06:00
|
|
|
assertNot(shouldTest("// +build !windows,!plan9", "windows", "amd64"))
|
|
|
|
assertNot(shouldTest("// +build !windows,!plan9", "plan9", "386"))
|
|
|
|
|
|
|
|
// Build tags on multiple lines are AND-ed together.
|
|
|
|
assert(shouldTest("// +build !windows\n// +build amd64", "linux", "amd64"))
|
|
|
|
assertNot(shouldTest("// +build !windows\n// +build amd64", "windows", "amd64"))
|
|
|
|
|
|
|
|
// Test that (!a OR !b) matches anything.
|
|
|
|
assert(shouldTest("// +build !windows !plan9", "windows", "amd64"))
|
2013-01-28 13:29:45 -07:00
|
|
|
}
|
2013-02-14 12:21:26 -07:00
|
|
|
|
|
|
|
// envForDir returns a copy of the environment
|
|
|
|
// suitable for running in the given directory.
|
|
|
|
// The environment is the current process's environment
|
|
|
|
// but with an updated $PWD, so that an os.Getwd in the
|
|
|
|
// child will be faster.
|
|
|
|
func envForDir(dir string) []string {
|
|
|
|
env := os.Environ()
|
|
|
|
for i, kv := range env {
|
|
|
|
if strings.HasPrefix(kv, "PWD=") {
|
|
|
|
env[i] = "PWD=" + dir
|
|
|
|
return env
|
|
|
|
}
|
|
|
|
}
|
|
|
|
env = append(env, "PWD="+dir)
|
|
|
|
return env
|
|
|
|
}
|
2014-07-24 15:18:54 -06:00
|
|
|
|
|
|
|
func getenv(key, def string) string {
|
|
|
|
value := os.Getenv(key)
|
|
|
|
if value != "" {
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
return def
|
|
|
|
}
|