code-intelligence.com/cifuzz@v0.40.0/internal/testutil/testutil.go (about) 1 package testutil 2 3 import ( 4 "io" 5 "io/fs" 6 "log" 7 "os" 8 "path/filepath" 9 "runtime" 10 "sync" 11 "testing" 12 13 "github.com/stretchr/testify/require" 14 15 "code-intelligence.com/cifuzz/internal/installer" 16 "code-intelligence.com/cifuzz/util/envutil" 17 "code-intelligence.com/cifuzz/util/fileutil" 18 ) 19 20 var ChdirMutex sync.Mutex 21 22 // RegisterTestDeps ensures that the test calling this function is rerun (despite caching) if any of the files and 23 // directories (and their recursive contents) under the provided paths change. 24 func RegisterTestDeps(path ...string) { 25 // Workaround for https://github.com/golang/go/issues/53053 26 // Explicitly stat all data dirs and files so that the Go test runner picks up the data dependency and knows how to 27 // rerun the test if the data dir contents change. Without this explicit recursive walk, changes to files in 28 // subdirectories aren't picked up automatically. 29 for _, p := range path { 30 err := filepath.Walk(p, func(path string, info fs.FileInfo, err error) error { 31 if err != nil { 32 return err 33 } 34 _, err = os.Stat(path) 35 return err 36 }) 37 if err != nil { 38 panic(err) 39 } 40 } 41 } 42 43 // RegisterTestDepOnCIFuzz registers test dependencies on the cifuzz 44 // executable and all its dependencies. Go doesn't recognize those 45 // dependencies on its own in tests which build and execute cifuzz as an 46 // external command. 47 func RegisterTestDepOnCIFuzz() { 48 var deps []string 49 _, b, _, _ := runtime.Caller(0) 50 // Note: The number of levels we go up here has to be adjusted if 51 // this source file is moved. 52 basepath := filepath.Dir(filepath.Dir(filepath.Dir(b))) 53 for _, dep := range installer.Deps { 54 deps = append(deps, filepath.Join(basepath, dep)) 55 } 56 RegisterTestDeps(deps...) 57 } 58 59 // ChdirToTempDir creates and changes the working directory to new tmp dir 60 func ChdirToTempDir(prefix string) (tempDir string, cleanup func()) { //nolint:nonamedreturns 61 ChdirMutex.Lock() 62 oldWd, err := os.Getwd() 63 if err != nil { 64 log.Printf("Failed to get current working directory: %+v", err) 65 os.Exit(1) 66 } 67 68 testTempDir, err := os.MkdirTemp("", prefix) 69 if err != nil { 70 log.Printf("Failed to create temp dir for tests: %+v", err) 71 os.Exit(1) 72 } 73 74 err = os.Chdir(testTempDir) 75 if err != nil { 76 log.Printf("Failed to change working dir for tests: %+v", err) 77 fileutil.Cleanup(testTempDir) 78 os.Exit(1) 79 } 80 81 cleanup = func() { 82 err = os.Chdir(oldWd) 83 if err != nil { 84 log.Printf("Failed to change working directory back to %s: %+v", oldWd, err) 85 os.Exit(1) 86 } 87 ChdirMutex.Unlock() 88 fileutil.Cleanup(testTempDir) 89 } 90 91 return testTempDir, cleanup 92 } 93 94 // CheckOutput checks that the strings are contained in the reader output 95 func CheckOutput(t *testing.T, r io.Reader, s ...string) { 96 output, err := io.ReadAll(r) 97 require.NoError(t, err) 98 for _, str := range s { 99 require.Contains(t, string(output), str) 100 } 101 } 102 103 // MkdirTemp wraps os.MkdirTemp and makes sure that errors are checked and 104 // directories will be deleted 105 func MkdirTemp(t *testing.T, dir, pattern string) string { 106 tempDir, err := os.MkdirTemp(dir, pattern) 107 require.NoError(t, err) 108 t.Cleanup(func() { fileutil.Cleanup(tempDir) }) 109 return tempDir 110 } 111 112 // RepoRoot returns the path pointing to the root of the cifuzz project 113 func RepoRoot(t *testing.T) string { 114 _, b, _, _ := runtime.Caller(0) 115 // Note: The number of levels we go up here has to be adjusted if 116 // this source file is moved. 117 basepath := filepath.Dir(filepath.Dir(filepath.Dir(b))) 118 return basepath 119 } 120 121 // SetupCoverage creates a directory for coverage data and sets the 122 // needed environment variable 123 func SetupCoverage(t *testing.T, env []string, subdir string) []string { 124 t.Helper() 125 covDir := filepath.Join(RepoRoot(t), "coverage", subdir) 126 err := os.MkdirAll(covDir, 0755) 127 require.NoError(t, err) 128 env, err = envutil.Setenv(env, "GOCOVERDIR", covDir) 129 require.NoError(t, err) 130 return env 131 }