Skip to content

Commit

Permalink
feat(gnovm): add 'gno test -print-events' + cleanup machine between t…
Browse files Browse the repository at this point in the history
…ests

Signed-off-by: moul <[email protected]>
  • Loading branch information
moul committed Oct 17, 2024
1 parent 05cd4f5 commit 68ca01d
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 5 deletions.
29 changes: 27 additions & 2 deletions gnovm/cmd/gno/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/gnovm/pkg/gnomod"
"github.com/gnolang/gno/gnovm/tests"
teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/errors"
"github.com/gnolang/gno/tm2/pkg/random"
Expand All @@ -35,6 +36,7 @@ type testCfg struct {
timeout time.Duration
updateGoldenTests bool
printRuntimeMetrics bool
printEvents bool
withNativeFallback bool
}

Expand Down Expand Up @@ -149,6 +151,13 @@ func (c *testCfg) RegisterFlags(fs *flag.FlagSet) {
false,
"print runtime metrics (gas, memory, cpu cycles)",
)

fs.BoolVar(
&c.printEvents,
"print-events",
false,
"print emitted events",
)
}

func execTest(cfg *testCfg, args []string, io commands.IO) error {
Expand Down Expand Up @@ -228,6 +237,7 @@ func gnoTestPkg(
rootDir = cfg.rootDir
runFlag = cfg.run
printRuntimeMetrics = cfg.printRuntimeMetrics
printEvents = cfg.printEvents

stdin = io.In()
stdout = io.Out()
Expand Down Expand Up @@ -295,7 +305,7 @@ func gnoTestPkg(
m.Alloc = gno.NewAllocator(maxAllocTx)
}
m.RunMemPackage(memPkg, true)
err := runTestFiles(m, tfiles, memPkg.Name, verbose, printRuntimeMetrics, runFlag, io)
err := runTestFiles(m, tfiles, memPkg.Name, verbose, printRuntimeMetrics, printEvents, runFlag, io)
if err != nil {
errs = multierr.Append(errs, err)
}
Expand Down Expand Up @@ -329,7 +339,7 @@ func gnoTestPkg(
memPkg.Path = memPkg.Path + "_test"
m.RunMemPackage(memPkg, true)

err := runTestFiles(m, ifiles, testPkgName, verbose, printRuntimeMetrics, runFlag, io)
err := runTestFiles(m, ifiles, testPkgName, verbose, printRuntimeMetrics, printEvents, runFlag, io)
if err != nil {
errs = multierr.Append(errs, err)
}
Expand Down Expand Up @@ -419,6 +429,7 @@ func runTestFiles(
pkgName string,
verbose bool,
printRuntimeMetrics bool,
printEvents bool,
runFlag string,
io commands.IO,
) (errs error) {
Expand Down Expand Up @@ -448,10 +459,24 @@ func runTestFiles(
m.RunFiles(n)

for _, test := range testFuncs.Tests {
// cleanup machine between tests
tests.CleanupMachine(m)

testFuncStr := fmt.Sprintf("%q", test.Name)

eval := m.Eval(gno.Call("runtest", testFuncStr))

if printEvents {
events := m.Context.(*teststd.TestExecContext).EventLogger.Events()
if events != nil {
res, err := json.Marshal(events)
if err != nil {
panic(err)

Check warning on line 474 in gnovm/cmd/gno/test.go

View check run for this annotation

Codecov / codecov/patch

gnovm/cmd/gno/test.go#L474

Added line #L474 was not covered by tests
}
io.ErrPrintfln("EVENTS: %s", string(res))
}
}

ret := eval[0].GetString()
if ret == "" {
err := errors.New("failed to execute unit test: %q", test.Name)
Expand Down
33 changes: 33 additions & 0 deletions gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Test with a valid _filetest.gno file

gno test -print-events .

! stdout .+
stderr 'ok \. \d\.\d\ds'

gno test -print-events -v .

! stdout .+
stderr '=== RUN file/valid_filetest.gno'
stderr '--- PASS: file/valid_filetest.gno \(\d\.\d\ds\)'
stderr 'ok \. \d\.\d\ds'

-- valid.gno --
package valid

-- valid_filetest.gno --
package main

import "std"

func main() {
println("test")
std.Emit("EventA")
std.Emit("EventB", "keyA", "valA")
}

// Output:
// test

// Events:
// [{"type":"EventA","attrs":[],"pkg_path":"","func":"main"},{"type":"EventB","attrs":[{"key":"keyA","value":"valA"}],"pkg_path":"","func":"main"}]
26 changes: 26 additions & 0 deletions gnovm/cmd/gno/testdata/gno_test/multitest_events.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Test with a valid _test.gno file

gno test -print-events .

! stdout .+
stderr 'EVENTS: \[{\"type\":\"EventA\",\"attrs\":\[\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestA\"}\]'
stderr 'EVENTS: \[{\"type\":\"EventB\",\"attrs\":\[{\"key\":\"keyA\",\"value\":\"valA\"}\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestB\"},{\"type\":\"EventC\",\"attrs\":\[{\"key\":\"keyD\",\"value\":\"valD\"}\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestB\"}\]'
stderr 'ok \. \d\.\d\ds'

-- valid.gno --
package valid

-- valid_test.gno --
package valid

import "testing"
import "std"

func TestA(t *testing.T) {
std.Emit("EventA")
}

func TestB(t *testing.T) {
std.Emit("EventB", "keyA", "valA")
std.Emit("EventC", "keyD", "valD")
}
63 changes: 60 additions & 3 deletions gnovm/tests/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tests

import (
"bytes"
"encoding/json"
"fmt"
"go/ast"
"go/parser"
Expand Down Expand Up @@ -54,7 +55,7 @@ func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext {
pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called.
caller := gno.DerivePkgAddr("user1.gno")

pkgCoins := std.MustParseCoins(ugnot.ValueString(200000000)).Add(send) // >= send.
pkgCoins := std.MustParseCoins(ugnot.ValueString(200_000_000)).Add(send) // >= send.
banker := newTestBanker(pkgAddr.Bech32(), pkgCoins)
ctx := stdlibs.ExecContext{
ChainID: "dev",
Expand All @@ -74,6 +75,19 @@ func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext {
}
}

// CleanupMachine can be called during two tests while reusing the same Machine instance.
func CleanupMachine(m *gno.Machine) {
prevCtx := m.Context.(*teststd.TestExecContext)
prevSend := prevCtx.OrigSend

newCtx := TestContext("", prevCtx.OrigSend)
pkgCoins := std.MustParseCoins(ugnot.ValueString(200_000_000)).Add(prevSend) // >= send.
banker := newTestBanker(prevCtx.OrigPkgAddr, pkgCoins)
newCtx.OrigPkgAddr = prevCtx.OrigPkgAddr
newCtx.Banker = banker
m.Context = newCtx
}

type runFileTestOptions struct {
nativeLibs bool
logger loggerFunc
Expand Down Expand Up @@ -110,7 +124,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error {
opt(&f)
}

directives, pkgPath, resWanted, errWanted, rops, stacktraceWanted, maxAlloc, send := wantedFromComment(path)
directives, pkgPath, resWanted, errWanted, rops, eventsWanted, stacktraceWanted, maxAlloc, send := wantedFromComment(path)
if pkgPath == "" {
pkgPath = "main"
}
Expand Down Expand Up @@ -347,6 +361,45 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error {
}
}
}
case "Events":
// panic if got unexpected error

if pnc != nil {
if tv, ok := pnc.(*gno.TypedValue); ok {
panic(fmt.Sprintf("fail on %s: got unexpected error: %s", path, tv.Sprint(m)))
} else { // happens on 'unknown import path ...'
panic(fmt.Sprintf("fail on %s: got unexpected error: %v", path, pnc))

Check warning on line 371 in gnovm/tests/file.go

View check run for this annotation

Codecov / codecov/patch

gnovm/tests/file.go#L368-L371

Added lines #L368 - L371 were not covered by tests
}
}
// check result
events := m.Context.(*teststd.TestExecContext).EventLogger.Events()
evtjson, err := json.Marshal(events)
if err != nil {
panic(err)

Check warning on line 378 in gnovm/tests/file.go

View check run for this annotation

Codecov / codecov/patch

gnovm/tests/file.go#L378

Added line #L378 was not covered by tests
}
evtstr := trimTrailingSpaces(string(evtjson))
if evtstr != eventsWanted {
if f.syncWanted {
// write output to file.
replaceWantedInPlace(path, "Events", evtstr)
} else {
// panic so tests immediately fail (for now).
if eventsWanted == "" {
panic(fmt.Sprintf("fail on %s: got unexpected events: %s", path, evtstr))
} else {
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(eventsWanted),
B: difflib.SplitLines(evtstr),
FromFile: "Expected",
FromDate: "",
ToFile: "Actual",
ToDate: "",
Context: 1,
})
panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff))

Check warning on line 399 in gnovm/tests/file.go

View check run for this annotation

Codecov / codecov/patch

gnovm/tests/file.go#L382-L399

Added lines #L382 - L399 were not covered by tests
}
}
}
case "Realm":
// panic if got unexpected error
if pnc != nil {
Expand Down Expand Up @@ -421,7 +474,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error {
return nil
}

func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, stacktrace string, maxAlloc int64, send std.Coins) {
func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, events, stacktrace string, maxAlloc int64, send std.Coins) {
fset := token.NewFileSet()
f, err2 := parser.ParseFile(fset, p, nil, parser.ParseComments)
if err2 != nil {
Expand Down Expand Up @@ -463,6 +516,10 @@ func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops,
rops = strings.TrimPrefix(text, "Realm:\n")
rops = strings.TrimSpace(rops)
directives = append(directives, "Realm")
} else if strings.HasPrefix(text, "Events:\n") {
events = strings.TrimPrefix(text, "Events:\n")
events = strings.TrimSpace(events)
directives = append(directives, "Events")
} else if strings.HasPrefix(text, "Stacktrace:\n") {
stacktrace = strings.TrimPrefix(text, "Stacktrace:\n")
stacktrace = strings.TrimSpace(stacktrace)
Expand Down

0 comments on commit 68ca01d

Please sign in to comment.