1// Copyright 2017 The Wuffs Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package main 16 17import ( 18 "flag" 19 "fmt" 20 "os" 21 "os/exec" 22 "path/filepath" 23 "strings" 24 25 cf "github.com/google/wuffs/cmd/commonflags" 26) 27 28func doBench(wuffsRoot string, args []string) error { return doBenchTest(wuffsRoot, args, true) } 29func doTest(wuffsRoot string, args []string) error { return doBenchTest(wuffsRoot, args, false) } 30 31func doBenchTest(wuffsRoot string, args []string, bench bool) error { 32 flags := flag.NewFlagSet("test", flag.ExitOnError) 33 ccompilersFlag := flags.String("ccompilers", cf.CcompilersDefault, cf.CcompilersUsage) 34 cformatterFlag := flags.String("cformatter", cf.CformatterDefault, cf.CformatterUsage) 35 focusFlag := flags.String("focus", cf.FocusDefault, cf.FocusUsage) 36 iterscaleFlag := flags.Int("iterscale", cf.IterscaleDefault, cf.IterscaleUsage) 37 langsFlag := flags.String("langs", langsDefault, langsUsage) 38 mimicFlag := flags.Bool("mimic", cf.MimicDefault, cf.MimicUsage) 39 repsFlag := flags.Int("reps", cf.RepsDefault, cf.RepsUsage) 40 skipgenFlag := flags.Bool("skipgen", skipgenDefault, skipgenUsage) 41 skipgendepsFlag := flags.Bool("skipgendeps", skipgendepsDefault, skipgendepsUsage) 42 43 if err := flags.Parse(args); err != nil { 44 return err 45 } 46 47 langs, err := parseLangs(*langsFlag) 48 if err != nil { 49 return err 50 } 51 if !cf.IsAlphaNumericIsh(*ccompilersFlag) { 52 return fmt.Errorf("bad -ccompilers flag value %q", *ccompilersFlag) 53 } 54 if !cf.IsAlphaNumericIsh(*cformatterFlag) { 55 return fmt.Errorf("bad -cformatter flag value %q", *cformatterFlag) 56 } 57 if !cf.IsAlphaNumericIsh(*focusFlag) { 58 return fmt.Errorf("bad -focus flag value %q", *focusFlag) 59 } 60 if *iterscaleFlag < cf.IterscaleMin || cf.IterscaleMax < *iterscaleFlag { 61 return fmt.Errorf("bad -iterscale flag value %d, outside the range [%d..%d]", 62 *iterscaleFlag, cf.IterscaleMin, cf.IterscaleMax) 63 } 64 if *repsFlag < cf.RepsMin || cf.RepsMax < *repsFlag { 65 return fmt.Errorf("bad -reps flag value %d, outside the range [%d..%d]", 66 *repsFlag, cf.RepsMin, cf.RepsMax) 67 } 68 69 args = flags.Args() 70 if len(args) == 0 { 71 args = []string{"base", "std/..."} 72 } 73 74 cmdArgs := []string(nil) 75 if bench { 76 cmdArgs = append(cmdArgs, "bench", 77 fmt.Sprintf("-iterscale=%d", *iterscaleFlag), 78 fmt.Sprintf("-reps=%d", *repsFlag), 79 ) 80 } else { 81 cmdArgs = append(cmdArgs, "test") 82 } 83 if *focusFlag != "" { 84 cmdArgs = append(cmdArgs, fmt.Sprintf("-focus=%s", *focusFlag)) 85 } 86 if *mimicFlag { 87 cmdArgs = append(cmdArgs, "-mimic") 88 } 89 90 h := testHelper{ 91 wuffsRoot: wuffsRoot, 92 langs: langs, 93 cmdArgs: cmdArgs, 94 ccompilers: *ccompilersFlag, 95 } 96 97 // Ensure that we are testing the latest version of the generated code. 98 if !*skipgenFlag { 99 gh := genHelper{ 100 wuffsRoot: wuffsRoot, 101 langs: langs, 102 cformatter: *cformatterFlag, 103 skipgen: *skipgenFlag, 104 skipgendeps: *skipgendepsFlag, 105 } 106 for _, arg := range args { 107 recursive := strings.HasSuffix(arg, "/...") 108 if recursive { 109 arg = arg[:len(arg)-4] 110 } 111 if arg == "" { 112 continue 113 } 114 115 if err := gh.gen(arg, recursive); err != nil { 116 return err 117 } 118 } 119 if err := genrelease(wuffsRoot, langs, cf.Version{}); err != nil { 120 return err 121 } 122 } 123 124 failed := false 125 for _, arg := range args { 126 recursive := strings.HasSuffix(arg, "/...") 127 if recursive { 128 arg = arg[:len(arg)-4] 129 } 130 if arg == "" { 131 continue 132 } 133 134 // Proceed with benching / testing the generated code. 135 f, err := h.benchTest(arg, recursive) 136 if err != nil { 137 return err 138 } 139 failed = failed || f 140 } 141 if failed { 142 s0, s1 := "test", "tests" 143 if bench { 144 s0, s1 = "bench", "benchmarks" 145 } 146 return fmt.Errorf("wuffs %s: some %s failed", s0, s1) 147 } 148 return nil 149} 150 151type testHelper struct { 152 wuffsRoot string 153 langs []string 154 cmdArgs []string 155 ccompilers string 156} 157 158func (h *testHelper) benchTest(dirname string, recursive bool) (failed bool, err error) { 159 if dirname == "base" { 160 return false, nil 161 } 162 qualFilenames, dirnames, err := listDir( 163 filepath.Join(h.wuffsRoot, filepath.FromSlash(dirname)), ".wuffs", recursive) 164 if err != nil { 165 return false, err 166 } 167 if len(qualFilenames) > 0 { 168 f, err := h.benchTestDir(dirname) 169 if err != nil { 170 return false, err 171 } 172 failed = failed || f 173 } 174 if len(dirnames) > 0 { 175 for _, d := range dirnames { 176 f, err := h.benchTest(filepath.Join(dirname, d), recursive) 177 if err != nil { 178 return false, err 179 } 180 failed = failed || f 181 } 182 } 183 return failed, nil 184} 185 186func (h *testHelper) benchTestDir(dirname string) (failed bool, err error) { 187 if packageName := filepath.Base(dirname); !validName(packageName) { 188 return false, fmt.Errorf(`invalid package %q, not in [a-z0-9]+`, packageName) 189 } 190 191 for _, lang := range h.langs { 192 command := "wuffs-" + lang 193 args := []string(nil) 194 args = append(args, h.cmdArgs...) 195 if lang == "c" { 196 args = append(args, fmt.Sprintf("-ccompilers=%s", h.ccompilers)) 197 } 198 args = append(args, filepath.Join(h.wuffsRoot, "test", lang, filepath.FromSlash(dirname))) 199 cmd := exec.Command(command, args...) 200 cmd.Stdout = os.Stdout 201 cmd.Stderr = os.Stderr 202 if err := cmd.Run(); err == nil { 203 // No-op. 204 } else if _, ok := err.(*exec.ExitError); ok { 205 failed = true 206 } else { 207 return false, err 208 } 209 } 210 return failed, nil 211} 212