forked from gnolang/gno
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: setup testscripts coverage (gnolang#1249)
Co-authored-by: Manfred Touron <[email protected]>
- Loading branch information
Showing
7 changed files
with
255 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package integration | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/rogpeppe/go-internal/testscript" | ||
) | ||
|
||
var coverageEnv struct { | ||
coverdir string | ||
} | ||
|
||
func init() { | ||
flag.StringVar(&coverageEnv.coverdir, | ||
"txtarcoverdir", "", "write testscripts coverage intermediate files to this directory") | ||
} | ||
|
||
// ResolveCoverageDir attempts to resolve the coverage directory from the 'TXTARCOVERDIR' | ||
// environment variable first, and if not set, from the 'test.txtarcoverdir' flag. | ||
// It returns the resolved directory and a boolean indicating if the resolution was successful. | ||
func ResolveCoverageDir() (string, bool) { | ||
// Attempt to resolve the cover directory from the environment variable or flag | ||
coverdir := os.Getenv("TXTARCOVERDIR") | ||
if coverdir == "" { | ||
coverdir = coverageEnv.coverdir | ||
} | ||
|
||
return coverdir, coverdir != "" | ||
} | ||
|
||
// SetupTestscriptsCoverage sets up the given testscripts environment for coverage. | ||
// It will mostly override `GOCOVERDIR` with the target cover directory | ||
func SetupTestscriptsCoverage(p *testscript.Params, coverdir string) error { | ||
// Check if the given coverage directory exist | ||
info, err := os.Stat(coverdir) | ||
if err != nil { | ||
return fmt.Errorf("output directory %q inaccessible: %w", coverdir, err) | ||
} else if !info.IsDir() { | ||
return fmt.Errorf("output %q not a directory", coverdir) | ||
} | ||
|
||
// We need to have an absolute path here, because current directory | ||
// context will change while executing testscripts. | ||
if !filepath.IsAbs(coverdir) { | ||
var err error | ||
if coverdir, err = filepath.Abs(coverdir); err != nil { | ||
return fmt.Errorf("unable to determine absolute path of %q: %w", coverdir, err) | ||
} | ||
} | ||
|
||
// Backup the original setup function | ||
origSetup := p.Setup | ||
p.Setup = func(env *testscript.Env) error { | ||
if origSetup != nil { | ||
// Call previous setup first | ||
origSetup(env) | ||
} | ||
|
||
// Override `GOCOVEDIR` directory for sub-execution | ||
env.Setenv("GOCOVERDIR", coverdir) | ||
return nil | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package integration | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
|
||
osm "github.com/gnolang/gno/tm2/pkg/os" | ||
"github.com/rogpeppe/go-internal/testscript" | ||
) | ||
|
||
// SetupGno prepares the given testscript environment for tests that utilize the gno command. | ||
// If the `gno` binary doesn't exist, it's built using the `go build` command into the specified buildDir. | ||
// The function also include the `gno` command into `p.Cmds` to and wrap environment into p.Setup | ||
// to correctly set up the environment variables needed for the `gno` command. | ||
func SetupGno(p *testscript.Params, buildDir string) error { | ||
// Try to fetch `GNOROOT` from the environment variables | ||
gnoroot := os.Getenv("GNOROOT") | ||
if gnoroot == "" { | ||
// If `GNOROOT` isn't set, determine the root directory of github.com/gnolang/gno | ||
goModPath, err := exec.Command("go", "env", "GOMOD").CombinedOutput() | ||
if err != nil { | ||
return fmt.Errorf("unable to determine gno root directory") | ||
} | ||
|
||
gnoroot = filepath.Dir(string(goModPath)) | ||
} | ||
|
||
if !osm.DirExists(buildDir) { | ||
return fmt.Errorf("%q does not exist or is not a directory", buildDir) | ||
} | ||
|
||
// Determine the path to the gno binary within the build directory | ||
gnoBin := filepath.Join(buildDir, "gno") | ||
if _, err := os.Stat(gnoBin); err != nil { | ||
if !errors.Is(err, os.ErrNotExist) { | ||
// Handle other potential errors from os.Stat | ||
return err | ||
} | ||
|
||
// Build a fresh gno binary in a temp directory | ||
gnoArgsBuilder := []string{"build", "-o", gnoBin} | ||
|
||
// Forward `-covermode` settings if set | ||
if coverMode := testing.CoverMode(); coverMode != "" { | ||
gnoArgsBuilder = append(gnoArgsBuilder, "-covermode", coverMode) | ||
} | ||
|
||
// Append the path to the gno command source | ||
gnoArgsBuilder = append(gnoArgsBuilder, filepath.Join(gnoroot, "gnovm", "cmd", "gno")) | ||
|
||
if err = exec.Command("go", gnoArgsBuilder...).Run(); err != nil { | ||
return fmt.Errorf("unable to build gno binary: %w", err) | ||
} | ||
} | ||
|
||
// Store the original setup scripts for potential wrapping | ||
origSetup := p.Setup | ||
p.Setup = func(env *testscript.Env) error { | ||
// If there's an original setup, execute it | ||
if origSetup != nil { | ||
if err := origSetup(env); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Set the GNOROOT environment variable | ||
env.Setenv("GNOROOT", gnoroot) | ||
|
||
// Create a temporary home directory because certain commands require access to $HOME/.cache/go-build | ||
home, err := os.MkdirTemp("", "gno") | ||
if err != nil { | ||
return fmt.Errorf("unable to create temporary home directory: %w", err) | ||
} | ||
env.Setenv("HOME", home) | ||
|
||
// Cleanup home folder | ||
env.Defer(func() { os.RemoveAll(home) }) | ||
|
||
return nil | ||
} | ||
|
||
// Initialize cmds map if needed | ||
if p.Cmds == nil { | ||
p.Cmds = make(map[string]func(ts *testscript.TestScript, neg bool, args []string)) | ||
} | ||
|
||
// Register the gno command for testscripts | ||
p.Cmds["gno"] = func(ts *testscript.TestScript, neg bool, args []string) { | ||
err := ts.Exec(gnoBin, args...) | ||
if err != nil { | ||
ts.Logf("gno command error: %v", err) | ||
} | ||
|
||
commandSucceeded := (err == nil) | ||
successExpected := !neg | ||
|
||
// Compare the command's success status with the expected outcome. | ||
if commandSucceeded != successExpected { | ||
ts.Fatalf("unexpected gno command outcome (err=%t expected=%t)", commandSucceeded, successExpected) | ||
} | ||
} | ||
|
||
return nil | ||
} |