Skip to content

Commit

Permalink
test/run: process build tags like go/build
Browse files Browse the repository at this point in the history
R=bradfitz, dave, rsc, r
CC=golang-dev
https://golang.org/cl/10001045
  • Loading branch information
ality authored and rsc committed Aug 13, 2013
1 parent 71c6da3 commit a538558
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 33 deletions.
87 changes: 69 additions & 18 deletions test/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"sort"
"strconv"
"strings"
"unicode"
)

var (
Expand Down Expand Up @@ -299,14 +300,17 @@ func goDirPackages(longdir string) ([][]string, error) {
return pkgs, nil
}

type context struct {
GOOS string
GOARCH string
}

// 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) {
if idx := strings.Index(src, "\npackage"); idx >= 0 {
src = src[:idx]
}
notgoos := "!" + goos
notgoarch := "!" + goarch
for _, line := range strings.Split(src, "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "//") {
Expand All @@ -318,29 +322,59 @@ func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
if len(line) == 0 || line[0] != '+' {
continue
}
ctxt := &context{
GOOS: goos,
GOARCH: goarch,
}
words := strings.Fields(line)
if words[0] == "+build" {
for _, word := range words {
switch word {
case goos, goarch:
return true, ""
case notgoos, notgoarch:
continue
default:
if word[0] == '!' {
// NOT something-else
return true, ""
}
ok := false
for _, word := range words[1:] {
if ctxt.match(word) {
ok = true
break
}
}
// no matching tag found.
return false, line
if !ok {
// no matching tag found.
return false, line
}
}
}
// no build tags.
// no build tags
return true, ""
}

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
}

return false
}

func init() { checkShouldTest() }

// run runs a test.
Expand Down Expand Up @@ -815,19 +849,36 @@ func defaultRunOutputLimit() int {
return cpu
}

// checkShouldTest runs canity checks on the shouldTest function.
// checkShouldTest runs sanity checks on the shouldTest function.
func checkShouldTest() {
assert := func(ok bool, _ string) {
if !ok {
panic("fail")
}
}
assertNot := func(ok bool, _ string) { assert(!ok, "") }

// Simple tests.
assert(shouldTest("// +build linux", "linux", "arm"))
assert(shouldTest("// +build !windows", "linux", "arm"))
assertNot(shouldTest("// +build !windows", "windows", "amd64"))
assertNot(shouldTest("// +build arm 386", "linux", "amd64"))

// A file with no build tags will always be tested.
assert(shouldTest("// This is a test.", "os", "arch"))

// Build tags separated by a space are OR-ed together.
assertNot(shouldTest("// +build arm 386", "linux", "amd64"))

// Build tags seperated by a comma are AND-ed together.
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"))
}

// envForDir returns a copy of the environment
Expand Down
51 changes: 36 additions & 15 deletions test/testlib
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,50 @@ pkgs() {
done | sort
}

_match() {
case $1 in
*,*)
#echo >&2 "match comma separated $1"
first=$(echo $1 | sed 's/,.*//')
rest=$(echo $1 | sed 's/[^,]*,//')
if _match $first && _match $rest; then
return 0
fi
return 1
;;
'!'*)
#echo >&2 "match negation $1"
neg=$(echo $1 | sed 's/^!//')
if _match $neg; then
return 1
fi
return 0
;;
$GOARCH|$GOOS)
#echo >&2 "match GOARCH or GOOS $1"
return 0
;;
esac
return 1
}

# +build aborts execution if the supplied tags don't match,
# i.e. none of the tags (x or !x) matches GOARCH or GOOS.
+build() {
if (( $# == 0 )); then
return
fi
m=0
for tag; do
case $tag in
$GOARCH|$GOOS)
#echo >&2 "match $tag in $1"
return # don't exclude.
;;
'!'$GOARCH|'!'$GOOS)
;;
'!'*)
# not x where x is neither GOOS nor GOARCH.
#echo >&2 "match $tag in $1"
return # don't exclude
;;
esac
if _match $tag; then
m=1
fi
done
# no match.
exit 0
if [ $m = 0 ]; then
#echo >&2 no match
exit 0
fi
unset m
}

compile() {
Expand Down

0 comments on commit a538558

Please sign in to comment.