github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/signature-fuzzer/internal/fuzz-generator/gen_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package generator 6 7 import ( 8 "bytes" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "runtime" 13 "testing" 14 15 "golang.org/x/tools/internal/testenv" 16 ) 17 18 func mkGenState() *genstate { 19 20 return &genstate{ 21 GenConfig: GenConfig{ 22 Tag: "gen", 23 OutDir: "/tmp", 24 NumTestPackages: 1, 25 NumTestFunctions: 10, 26 }, 27 ipref: "foo/", 28 derefFuncs: make(map[string]string), 29 assignFuncs: make(map[string]string), 30 allocFuncs: make(map[string]string), 31 globVars: make(map[string]string), 32 } 33 } 34 35 func TestBasic(t *testing.T) { 36 checkTunables(tunables) 37 s := mkGenState() 38 for i := 0; i < 1000; i++ { 39 s.wr = NewWrapRand(int64(i), RandCtlChecks|RandCtlPanic) 40 fp := s.GenFunc(i, i) 41 var buf bytes.Buffer 42 var b *bytes.Buffer = &buf 43 wr := NewWrapRand(int64(i), RandCtlChecks|RandCtlPanic) 44 s.wr = wr 45 s.emitCaller(fp, b, i) 46 s.wr = NewWrapRand(int64(i), RandCtlChecks|RandCtlPanic) 47 s.emitChecker(fp, b, i, true) 48 wr.Check(s.wr) 49 } 50 if s.errs != 0 { 51 t.Errorf("%d errors during Generate", s.errs) 52 } 53 } 54 55 func TestMoreComplicated(t *testing.T) { 56 saveit := tunables 57 defer func() { tunables = saveit }() 58 59 checkTunables(tunables) 60 s := mkGenState() 61 for i := 0; i < 10000; i++ { 62 s.wr = NewWrapRand(int64(i), RandCtlChecks|RandCtlPanic) 63 fp := s.GenFunc(i, i) 64 var buf bytes.Buffer 65 var b *bytes.Buffer = &buf 66 wr := NewWrapRand(int64(i), RandCtlChecks|RandCtlPanic) 67 s.wr = wr 68 s.emitCaller(fp, b, i) 69 verb(1, "finished iter %d caller", i) 70 s.wr = NewWrapRand(int64(i), RandCtlChecks|RandCtlPanic) 71 s.emitChecker(fp, b, i, true) 72 verb(1, "finished iter %d checker", i) 73 wr.Check(s.wr) 74 if s.errs != 0 { 75 t.Errorf("%d errors during Generate iter %d", s.errs, i) 76 } 77 } 78 } 79 80 func TestIsBuildable(t *testing.T) { 81 testenv.NeedsTool(t, "go") 82 if runtime.GOOS == "android" { 83 t.Skipf("the dependencies are not available on android") 84 } 85 86 td := t.TempDir() 87 verb(1, "generating into temp dir %s", td) 88 checkTunables(tunables) 89 pack := filepath.Base(td) 90 s := GenConfig{ 91 Tag: "x", 92 OutDir: td, 93 PkgPath: pack, 94 NumTestFunctions: 10, 95 NumTestPackages: 10, 96 MaxFail: 10, 97 RandCtl: RandCtlChecks | RandCtlPanic, 98 } 99 errs := Generate(s) 100 if errs != 0 { 101 t.Errorf("%d errors during Generate", errs) 102 } 103 104 verb(1, "building %s\n", td) 105 106 cmd := exec.Command("go", "run", ".") 107 cmd.Dir = td 108 coutput, cerr := cmd.CombinedOutput() 109 if cerr != nil { 110 t.Errorf("go build command failed: %s\n", string(coutput)) 111 } 112 verb(1, "output is: %s\n", string(coutput)) 113 } 114 115 // TestExhaustive does a series of code genreation runs, starting with 116 // (relatively) simple code and then getting progressively more 117 // complex (more params, deeper structs, turning on additional 118 // features such as address-taken vars and reflect testing). The 119 // intent here is mainly to insure that the tester still works if you 120 // turn things on and off, e.g. that each feature is separately 121 // controllable and not linked to other things. 122 func TestExhaustive(t *testing.T) { 123 testenv.NeedsTool(t, "go") 124 if runtime.GOOS == "android" { 125 t.Skipf("the dependencies are not available on android") 126 } 127 128 if testing.Short() { 129 t.Skip("skipping test in short mode.") 130 } 131 132 td := t.TempDir() 133 verb(1, "generating into temp dir %s", td) 134 135 scenarios := []struct { 136 name string 137 adjuster func() 138 }{ 139 { 140 "minimal", 141 func() { 142 tunables.nParmRange = 3 143 tunables.nReturnRange = 3 144 tunables.structDepth = 1 145 tunables.recurPerc = 0 146 tunables.methodPerc = 0 147 tunables.doReflectCall = false 148 tunables.doDefer = false 149 tunables.takeAddress = false 150 tunables.doFuncCallValues = false 151 tunables.doSkipCompare = false 152 checkTunables(tunables) 153 }, 154 }, 155 { 156 "moreparms", 157 func() { 158 tunables.nParmRange = 15 159 tunables.nReturnRange = 7 160 tunables.structDepth = 3 161 checkTunables(tunables) 162 }, 163 }, 164 { 165 "addrecur", 166 func() { 167 tunables.recurPerc = 20 168 checkTunables(tunables) 169 }, 170 }, 171 { 172 "addmethod", 173 func() { 174 tunables.methodPerc = 25 175 tunables.pointerMethodCallPerc = 30 176 checkTunables(tunables) 177 }, 178 }, 179 { 180 "addtakeaddr", 181 func() { 182 tunables.takeAddress = true 183 tunables.takenFraction = 20 184 checkTunables(tunables) 185 }, 186 }, 187 { 188 "addreflect", 189 func() { 190 tunables.doReflectCall = true 191 checkTunables(tunables) 192 }, 193 }, 194 { 195 "adddefer", 196 func() { 197 tunables.doDefer = true 198 checkTunables(tunables) 199 }, 200 }, 201 { 202 "addfuncval", 203 func() { 204 tunables.doFuncCallValues = true 205 checkTunables(tunables) 206 }, 207 }, 208 { 209 "addfuncval", 210 func() { 211 tunables.doSkipCompare = true 212 checkTunables(tunables) 213 }, 214 }, 215 } 216 217 // Loop over scenarios and make sure each one works properly. 218 for i, s := range scenarios { 219 t.Logf("running %s\n", s.name) 220 s.adjuster() 221 os.RemoveAll(td) 222 pack := filepath.Base(td) 223 c := GenConfig{ 224 Tag: "x", 225 OutDir: td, 226 PkgPath: pack, 227 NumTestFunctions: 10, 228 NumTestPackages: 10, 229 Seed: int64(i + 9), 230 MaxFail: 10, 231 RandCtl: RandCtlChecks | RandCtlPanic, 232 } 233 errs := Generate(c) 234 if errs != 0 { 235 t.Errorf("%d errors during scenarios %q Generate", errs, s.name) 236 } 237 cmd := exec.Command("go", "run", ".") 238 cmd.Dir = td 239 coutput, cerr := cmd.CombinedOutput() 240 if cerr != nil { 241 t.Fatalf("run failed for scenario %q: %s\n", s.name, string(coutput)) 242 } 243 verb(1, "output is: %s\n", string(coutput)) 244 } 245 } 246 247 func TestEmitBadBuildFailure(t *testing.T) { 248 testenv.NeedsTool(t, "go") 249 if runtime.GOOS == "android" { 250 t.Skipf("the dependencies are not available on android") 251 } 252 253 td := t.TempDir() 254 verb(1, "generating into temp dir %s", td) 255 256 checkTunables(tunables) 257 pack := filepath.Base(td) 258 s := GenConfig{ 259 Tag: "x", 260 OutDir: td, 261 PkgPath: pack, 262 NumTestFunctions: 10, 263 NumTestPackages: 10, 264 MaxFail: 10, 265 RandCtl: RandCtlChecks | RandCtlPanic, 266 EmitBad: 1, 267 } 268 errs := Generate(s) 269 if errs != 0 { 270 t.Errorf("%d errors during Generate", errs) 271 } 272 273 cmd := exec.Command("go", "build", ".") 274 cmd.Dir = td 275 coutput, cerr := cmd.CombinedOutput() 276 if cerr == nil { 277 t.Errorf("go build command passed, expected failure. output: %s\n", string(coutput)) 278 } 279 } 280 281 func TestEmitBadRunFailure(t *testing.T) { 282 testenv.NeedsTool(t, "go") 283 if runtime.GOOS == "android" { 284 t.Skipf("the dependencies are not available on android") 285 } 286 287 td := t.TempDir() 288 verb(1, "generating into temp dir %s", td) 289 290 checkTunables(tunables) 291 pack := filepath.Base(td) 292 s := GenConfig{ 293 Tag: "x", 294 OutDir: td, 295 PkgPath: pack, 296 NumTestFunctions: 10, 297 NumTestPackages: 10, 298 MaxFail: 10, 299 RandCtl: RandCtlChecks | RandCtlPanic, 300 EmitBad: 2, 301 } 302 errs := Generate(s) 303 if errs != 0 { 304 t.Errorf("%d errors during Generate", errs) 305 } 306 307 // build 308 cmd := exec.Command("go", "build", ".") 309 cmd.Dir = td 310 coutput, cerr := cmd.CombinedOutput() 311 if cerr != nil { 312 t.Fatalf("build failed: %s\n", string(coutput)) 313 } 314 315 // run 316 cmd = exec.Command("./" + pack) 317 cmd.Dir = td 318 coutput, cerr = cmd.CombinedOutput() 319 if cerr == nil { 320 t.Fatalf("run passed, expected failure -- run output: %s", string(coutput)) 321 } 322 }