github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/pkg/integration/gno.go (about) 1 package integration 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "testing" 10 11 "github.com/gnolang/gno/gnovm/pkg/gnoenv" 12 osm "github.com/gnolang/gno/tm2/pkg/os" 13 "github.com/rogpeppe/go-internal/testscript" 14 ) 15 16 // SetupGno prepares the given testscript environment for tests that utilize the gno command. 17 // If the `gno` binary doesn't exist, it's built using the `go build` command into the specified buildDir. 18 // The function also include the `gno` command into `p.Cmds` to and wrap environment into p.Setup 19 // to correctly set up the environment variables needed for the `gno` command. 20 func SetupGno(p *testscript.Params, buildDir string) error { 21 // Try to fetch `GNOROOT` from the environment variables 22 gnoroot := gnoenv.RootDir() 23 24 if !osm.DirExists(buildDir) { 25 return fmt.Errorf("%q does not exist or is not a directory", buildDir) 26 } 27 28 // Determine the path to the gno binary within the build directory 29 gnoBin := filepath.Join(buildDir, "gno") 30 if _, err := os.Stat(gnoBin); err != nil { 31 if !errors.Is(err, os.ErrNotExist) { 32 // Handle other potential errors from os.Stat 33 return err 34 } 35 36 // Build a fresh gno binary in a temp directory 37 gnoArgsBuilder := []string{"build", "-o", gnoBin} 38 39 // Forward `-covermode` settings if set 40 if coverMode := testing.CoverMode(); coverMode != "" { 41 gnoArgsBuilder = append(gnoArgsBuilder, "-covermode", coverMode) 42 } 43 44 // Append the path to the gno command source 45 gnoArgsBuilder = append(gnoArgsBuilder, filepath.Join(gnoroot, "gnovm", "cmd", "gno")) 46 47 if err = exec.Command("go", gnoArgsBuilder...).Run(); err != nil { 48 return fmt.Errorf("unable to build gno binary: %w", err) 49 } 50 } 51 52 // Store the original setup scripts for potential wrapping 53 origSetup := p.Setup 54 p.Setup = func(env *testscript.Env) error { 55 // If there's an original setup, execute it 56 if origSetup != nil { 57 if err := origSetup(env); err != nil { 58 return err 59 } 60 } 61 62 // Set the GNOROOT environment variable 63 env.Setenv("GNOROOT", gnoroot) 64 65 // Create a temporary home directory because certain commands require access to $HOME/.cache/go-build 66 home, err := os.MkdirTemp("", "gno") 67 if err != nil { 68 return fmt.Errorf("unable to create temporary home directory: %w", err) 69 } 70 env.Setenv("HOME", home) 71 72 // Cleanup home folder 73 env.Defer(func() { os.RemoveAll(home) }) 74 75 return nil 76 } 77 78 // Initialize cmds map if needed 79 if p.Cmds == nil { 80 p.Cmds = make(map[string]func(ts *testscript.TestScript, neg bool, args []string)) 81 } 82 83 // Register the gno command for testscripts 84 p.Cmds["gno"] = func(ts *testscript.TestScript, neg bool, args []string) { 85 err := ts.Exec(gnoBin, args...) 86 if err != nil { 87 ts.Logf("gno command error: %+v", err) 88 } 89 90 commandSucceeded := (err == nil) 91 successExpected := !neg 92 93 // Compare the command's success status with the expected outcome. 94 if commandSucceeded != successExpected { 95 ts.Fatalf("unexpected gno command outcome (err=%t expected=%t)", commandSucceeded, successExpected) 96 } 97 } 98 99 return nil 100 }