Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(gnovm): improve gnovm/pkg/gnolang test coverage #2143

Merged
merged 5 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions gnovm/pkg/gnolang/debugger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,65 @@ type writeNopCloser struct{ io.Writer }

func (writeNopCloser) Close() error { return nil }

func eval(debugAddr, in, file string) (string, string, error) {
out := bytes.NewBufferString("")
err := bytes.NewBufferString("")
// TODO (Marc): move evalTest to gnovm/tests package and remove code duplicates
mvertes marked this conversation as resolved.
Show resolved Hide resolved
func evalTest(debugAddr, in, file string) (out, err string) {
bout := bytes.NewBufferString("")
berr := bytes.NewBufferString("")
stdin := bytes.NewBufferString(in)
stdout := writeNopCloser{out}
stderr := writeNopCloser{err}
stdout := writeNopCloser{bout}
stderr := writeNopCloser{berr}
debug := in != "" || debugAddr != ""
mode := tests.ImportModeNativePreferred
if strings.HasSuffix(file, "_stdlibs.gno") {
mode = tests.ImportModeStdlibsPreferred
}

defer func() {
if r := recover(); r != nil {
err = fmt.Sprintf("%v", r)
}
out = strings.TrimSpace(out)
err = strings.TrimSpace(strings.ReplaceAll(err, "../../tests/files/", "files/"))
}()

testStore := tests.TestStore(gnoenv.RootDir(), "", stdin, stdout, stderr, tests.ImportModeStdlibsPreferred)
testStore := tests.TestStore(gnoenv.RootDir(), "../../tests/files", stdin, stdout, stderr, mode)

f := gnolang.MustReadFile(file)

m := gnolang.NewMachineWithOptions(gnolang.MachineOptions{
PkgPath: string(f.PkgName),
Input: stdin,
Output: stdout,
Store: testStore,
Debug: true,
DebugAddr: debugAddr,
PkgPath: string(f.PkgName),
Input: stdin,
Output: stdout,
Store: testStore,
Context: tests.TestContext(string(f.PkgName), nil),
Debug: debug,
})

defer m.Release()

if debugAddr != "" {
if err := m.Debugger.Serve(debugAddr); err != nil {
return "", "", err
if e := m.Debugger.Serve(debugAddr); e != nil {
err = e.Error()
return
}
}

m.RunFiles(f)
ex, _ := gnolang.ParseExpr("main()")
m.Eval(ex)
return out.String(), err.String(), nil
out, err = bout.String(), berr.String()
return
}

func runDebugTest(t *testing.T, targetPath string, tests []dtest) {
t.Helper()

for _, test := range tests {
t.Run("", func(t *testing.T) {
out, err, _ := eval("", test.in, targetPath)
out, err := evalTest("", test.in, targetPath)
t.Log("in:", test.in, "out:", out, "err:", err)
if !strings.Contains(out, test.out) {
t.Errorf("result does not contain \"%s\", got \"%s\"", test.out, out)
t.Errorf("unexpected output\nwant\"%s\"\n got \"%s\"", test.out, out)
}
})
}
Expand All @@ -77,7 +93,7 @@ func TestDebug(t *testing.T) {
cont2 := "break 21\ncontinue\n"

runDebugTest(t, debugTarget, []dtest{
{in: "", out: "Welcome to the Gnovm debugger. Type 'help' for list of commands."},
{in: "\n", out: "Welcome to the Gnovm debugger. Type 'help' for list of commands."},
{in: "help\n", out: "The following commands are available"},
{in: "h\n", out: "The following commands are available"},
{in: "help b\n", out: "Set a breakpoint."},
Expand Down Expand Up @@ -154,7 +170,7 @@ func TestRemoteDebug(t *testing.T) {
retry int
)

go eval(debugAddress, "", debugTarget)
go evalTest(debugAddress, "", debugTarget)

for retry = 100; retry > 0; retry-- {
conn, err = net.Dial("tcp", debugAddress)
Expand All @@ -177,8 +193,9 @@ func TestRemoteDebug(t *testing.T) {
}

func TestRemoteError(t *testing.T) {
_, _, err := eval(":xxx", "", debugTarget)
if !strings.Contains(err.Error(), "tcp/xxx: unknown port") {
_, err := evalTest(":xxx", "", debugTarget)
t.Log("err:", err)
if !strings.Contains(err, "tcp/xxx: unknown port") {
t.Error(err)
}
}
62 changes: 62 additions & 0 deletions gnovm/pkg/gnolang/eval_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package gnolang_test

import (
"os"
"path"
"strings"
"testing"
)

func TestEvalFiles(t *testing.T) {
dir := "../../tests/files"
files, err := os.ReadDir(dir)
if err != nil {
t.Fatal(err)
}
for _, f := range files {
wantOut, wantErr, ok := testData(dir, f)
if !ok {
continue
}
t.Run(f.Name(), func(t *testing.T) {
out, err := evalTest("", "", path.Join(dir, f.Name()))

if wantErr != "" && !strings.Contains(err, wantErr) ||
wantErr == "" && err != "" {
t.Fatalf("unexpected error\nWant: %s\n Got: %s", wantErr, err)
}
if wantOut != "" && out != wantOut {
t.Fatalf("unexpected output\nWant: %s\n Got: %s", wantOut, out)
}
})
}
}

// testData returns the expected output and error string, and true if entry is valid.
func testData(dir string, f os.DirEntry) (testOut, testErr string, ok bool) {
if f.IsDir() {
return "", "", false
}
name := path.Join(dir, f.Name())
if !strings.HasSuffix(name, ".gno") || strings.HasSuffix(name, "_long.gno") {
return "", "", false
}
buf, err := os.ReadFile(name)
if err != nil {
return "", "", false
}
str := string(buf)
if strings.Contains(str, "// PKGPATH:") {
return "", "", false
}
return commentFrom(str, "\n// Output:"), commentFrom(str, "\n// Error:"), true
}

// commentFrom returns the content from a trailing comment block in s starting with delim.
func commentFrom(s, delim string) string {
index := strings.Index(s, delim)
if index < 0 {
return ""
}
return strings.TrimSpace(strings.ReplaceAll(s[index+len(delim):], "\n// ", "\n"))
}
1 change: 0 additions & 1 deletion gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ type MachineOptions struct {
CheckTypes bool // not yet used
ReadOnly bool
Debug bool
DebugAddr string // debugger io stream address (stdin/stdout if empty)
Input io.Reader // used for default debugger input only
Output io.Writer // default os.Stdout
Store Store // default NewStore(Alloc, nil, nil)
Expand Down
5 changes: 3 additions & 2 deletions gnovm/tests/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestMachine(store gno.Store, stdout io.Writer, pkgPath string) *gno.Machine
}

func testMachineCustom(store gno.Store, pkgPath string, stdout io.Writer, maxAlloc int64, send std.Coins) *gno.Machine {
ctx := testContext(pkgPath, send)
ctx := TestContext(pkgPath, send)
m := gno.NewMachineWithOptions(gno.MachineOptions{
PkgPath: "", // set later.
Output: stdout,
Expand All @@ -47,7 +47,8 @@ func testMachineCustom(store gno.Store, pkgPath string, stdout io.Writer, maxAll
return m
}

func testContext(pkgPath string, send std.Coins) *teststd.TestExecContext {
// TestContext returns a TestExecContext. Usable for test purpose only.
func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext {
// FIXME: create a better package to manage this, with custom constructors
pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called.
caller := gno.DerivePkgAddr("user1.gno")
Expand Down
2 changes: 1 addition & 1 deletion gnovm/tests/files/convert4.gno
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ func main() {
println(int(nil))
}

// error: cannot convert (undefined) to int
// Error: cannot convert (undefined) to int
2 changes: 1 addition & 1 deletion gnovm/tests/files/convert5.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ func main() {
println(ints)
}

// error: cannot convert (undefined) to int
// Error: cannot convert (undefined) to int
6 changes: 3 additions & 3 deletions gnovm/tests/files/float5_stdlibs.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ func main() {
println(math.MaxFloat64, math.Float64bits(math.MaxFloat64))
}

// NOTE: 0x7f7fffff is 2139095039
// NOTE: 0x7fefffffffffffff is 9218868437227405311

// Output:
// 3.4028234663852886e+38 2139095039
// 1.7976931348623157e+308 9218868437227405311

// NOTE: 0x7f7fffff is 2139095039
// NOTE: 0x7fefffffffffffff is 9218868437227405311
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch8.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ func main() {
}

// Error:
// 5:2: fallthrough statement out of place
// fallthrough statement out of place
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch8b.gno
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ func main() {
}

// Error:
// 10:3: cannot fallthrough final case in switch
// cannot fallthrough final case in switch
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch8c.gno
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ func main() {
}

// Error:
// 7:3: fallthrough statement out of place
// fallthrough statement out of place
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch9.gno
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ func main() {
}

// Error:
// 9:3: cannot fallthrough in type switch
// cannot fallthrough in type switch
4 changes: 2 additions & 2 deletions gnovm/tests/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri
baseDir := filepath.Join(filesPath, "extern", pkgPath[len(testPath):])
memPkg := gno.ReadMemPackage(baseDir, pkgPath)
send := std.Coins{}
ctx := testContext(pkgPath, send)
ctx := TestContext(pkgPath, send)
m2 := gno.NewMachineWithOptions(gno.MachineOptions{
PkgPath: "test",
Output: stdout,
Expand Down Expand Up @@ -390,7 +390,7 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri
}

send := std.Coins{}
ctx := testContext(pkgPath, send)
ctx := TestContext(pkgPath, send)
m2 := gno.NewMachineWithOptions(gno.MachineOptions{
PkgPath: "test",
Output: stdout,
Expand Down
Loading