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  }