blob: 4316a658eb9933ccbce1f912fb60ffe819169b27 [file] [log] [blame]
// Copyright 2017 The Puffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
cf "github.com/google/puffs/cmd/commonflags"
)
func doBench(puffsRoot string, args []string) error { return doBenchTest(puffsRoot, args, true) }
func doTest(puffsRoot string, args []string) error { return doBenchTest(puffsRoot, args, false) }
func doBenchTest(puffsRoot string, args []string, bench bool) error {
flags := flag.NewFlagSet("test", flag.ExitOnError)
ccompilersFlag := flags.String("ccompilers", cf.CcompilersDefault, cf.CcompilersUsage)
focusFlag := flags.String("focus", cf.FocusDefault, cf.FocusUsage)
langsFlag := flags.String("langs", langsDefault, langsUsage)
mimicFlag := flags.Bool("mimic", cf.MimicDefault, cf.MimicUsage)
repsFlag := flags.Int("reps", cf.RepsDefault, cf.RepsUsage)
skipgenFlag := flags.Bool("skipgen", skipgenDefault, skipgenUsage)
if err := flags.Parse(args); err != nil {
return err
}
langs, err := parseLangs(*langsFlag)
if err != nil {
return err
}
if !cf.IsAlphaNumericIsh(*ccompilersFlag) {
return fmt.Errorf("bad -ccompilers flag value %q", *ccompilersFlag)
}
if !cf.IsAlphaNumericIsh(*focusFlag) {
return fmt.Errorf("bad -focus flag value %q", *focusFlag)
}
if *repsFlag < cf.RepsMin || cf.RepsMax < *repsFlag {
return fmt.Errorf("bad -reps flag value %d, outside the range [%d..%d]", *repsFlag, cf.RepsMin, cf.RepsMax)
}
args = flags.Args()
if len(args) == 0 {
args = []string{"std/..."}
}
cmdArgs := []string(nil)
if bench {
cmdArgs = append(cmdArgs, "bench", fmt.Sprintf("-reps=%d", *repsFlag))
} else {
cmdArgs = append(cmdArgs, "test")
}
if *focusFlag != "" {
cmdArgs = append(cmdArgs, fmt.Sprintf("-focus=%s", *focusFlag))
}
if *mimicFlag {
cmdArgs = append(cmdArgs, "-mimic")
}
b := btHelper{
puffsRoot: puffsRoot,
langs: langs,
cmdArgs: cmdArgs,
ccompilers: *ccompilersFlag,
}
failed := false
for _, arg := range args {
recursive := strings.HasSuffix(arg, "/...")
if recursive {
arg = arg[:len(arg)-4]
}
// Ensure that we are testing the latest version of the generated code.
if !*skipgenFlag {
if _, err := gen(nil, puffsRoot, arg, langs, recursive); err != nil {
return err
}
}
// Proceed with benching / testing the generated code.
f, err := b.benchTest(arg, recursive)
if err != nil {
return err
}
failed = failed || f
}
if failed {
s0, s1 := "test", "tests"
if bench {
s0, s1 = "bench", "benchmarks"
}
return fmt.Errorf("puffs %s: some %s failed", s0, s1)
}
return nil
}
type btHelper struct {
puffsRoot string
langs []string
cmdArgs []string
ccompilers string
}
func (b *btHelper) benchTest(dirname string, recursive bool) (failed bool, err error) {
filenames, dirnames, err := listDir(b.puffsRoot, dirname, recursive)
if err != nil {
return false, err
}
if len(filenames) > 0 {
f, err := b.benchTestDir(dirname)
if err != nil {
return false, err
}
failed = failed || f
}
if len(dirnames) > 0 {
for _, d := range dirnames {
f, err := b.benchTest(filepath.Join(dirname, d), recursive)
if err != nil {
return false, err
}
failed = failed || f
}
}
return failed, nil
}
func (b *btHelper) benchTestDir(dirname string) (failed bool, err error) {
if packageName := filepath.Base(dirname); !validName(packageName) {
return false, fmt.Errorf(`invalid package %q, not in [a-z0-9]+`, packageName)
}
for _, lang := range b.langs {
command := "puffs-" + lang
args := []string(nil)
args = append(args, b.cmdArgs...)
if lang == "c" {
args = append(args, fmt.Sprintf("-ccompilers=%s", b.ccompilers))
}
args = append(args, filepath.Join(b.puffsRoot, "test", lang, filepath.FromSlash(dirname)))
cmd := exec.Command(command, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err == nil {
// No-op.
} else if _, ok := err.(*exec.ExitError); ok {
failed = true
} else {
return false, err
}
}
return failed, nil
}