Skip to content

Commit

Permalink
fix execution errors
Browse files Browse the repository at this point in the history
  • Loading branch information
notJoon committed Oct 15, 2024
1 parent 1776969 commit 3142978
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 48 deletions.
104 changes: 64 additions & 40 deletions gnovm/pkg/doctest/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func ExecuteCodeBlock(c codeBlock, stdlibDir string) (string, error) {
}

// Extract the actual language from the lang field
lang := strings.Split(c.lang, ",")[0]
lang := extractLanguage(c.lang)

if lang != goLang && lang != gnoLang {
return fmt.Sprintf("SKIPPED (Unsupported language: %s)", lang), nil
Expand All @@ -76,39 +76,10 @@ func ExecuteCodeBlock(c codeBlock, stdlibDir string) (string, error) {

// get the result from the cache if it exists
if result, found := cache.get(hashKey); found {
res := strings.TrimSpace(result)

if c.expectedOutput == "" && c.expectedError == "" {
return fmt.Sprintf("%s (cached)", res), nil
}

res, err := compareResults(res, c.expectedOutput, c.expectedError)
if err != nil {
return "", err
}

return fmt.Sprintf("%s (cached)", res), nil
return handleCachedResult(result, c)
}

baseKey := store.NewStoreKey("baseKey")
iavlKey := store.NewStoreKey("iavlKey")

db := memdb.NewMemDB()

ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(baseKey, dbadapter.StoreConstructor, db)
ms.MountStoreWithDB(iavlKey, iavl.StoreConstructor, db)
ms.LoadLatestVersion()

ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger())
acck := authm.NewAccountKeeper(iavlKey, std.ProtoBaseAccount)
bank := bankm.NewBankKeeper(acck)
stdlibsDir := GetStdlibsDir()
vmk := vm.NewVMKeeper(baseKey, iavlKey, acck, bank, stdlibsDir, 100_000_000)

mcw := ms.MultiCacheWrap()
vmk.Initialize(log.NewNoopLogger(), mcw, true)
mcw.MultiWrite()
ctx, acck, _, vmk, stdlibCtx := setupEnvironment()

files := []*std.MemFile{
{Name: fmt.Sprintf("%d.%s", c.index, lang), Body: c.content},
Expand All @@ -120,15 +91,9 @@ func ExecuteCodeBlock(c codeBlock, stdlibDir string) (string, error) {

msg2 := vm.NewMsgRun(addr, std.Coins{}, files)

res, err := vmk.Run(ctx, msg2)
res, err := vmk.Run(stdlibCtx, msg2)
if c.options.PanicMessage != "" {
if err == nil {
return "", fmt.Errorf("expected panic with message: %s, but executed successfully", c.options.PanicMessage)
}
if !strings.Contains(err.Error(), c.options.PanicMessage) {
return "", fmt.Errorf("expected panic with message: %s, but got: %s", c.options.PanicMessage, err.Error())
}
return fmt.Sprintf("panicked as expected: %v", err), nil
return handlePanicMessage(err, c.options.PanicMessage)
}

if err != nil {
Expand All @@ -147,6 +112,65 @@ func ExecuteCodeBlock(c codeBlock, stdlibDir string) (string, error) {
return compareResults(res, c.expectedOutput, c.expectedError)
}

func extractLanguage(lang string) string {
return strings.Split(lang, ",")[0]
}

func handleCachedResult(result string, c codeBlock) (string, error) {
res := strings.TrimSpace(result)

if c.expectedOutput == "" && c.expectedError == "" {
return fmt.Sprintf("%s (cached)", res), nil
}

res, err := compareResults(res, c.expectedOutput, c.expectedError)
if err != nil {
return "", err
}

return fmt.Sprintf("%s (cached)", res), nil
}

func setupEnvironment() (sdk.Context, authm.AccountKeeper, bankm.BankKeeper, *vm.VMKeeper, sdk.Context) {
baseKey := store.NewStoreKey("baseKey")
iavlKey := store.NewStoreKey("iavlKey")

db := memdb.NewMemDB()

ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(baseKey, dbadapter.StoreConstructor, db)
ms.MountStoreWithDB(iavlKey, iavl.StoreConstructor, db)
ms.LoadLatestVersion()

ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger())
acck := authm.NewAccountKeeper(iavlKey, std.ProtoBaseAccount)
bank := bankm.NewBankKeeper(acck)
stdlibsDir := GetStdlibsDir()
vmk := vm.NewVMKeeper(baseKey, iavlKey, acck, bank, 100_000_000)

mcw := ms.MultiCacheWrap()

vmk.Initialize(log.NewNoopLogger(), mcw)

stdlibCtx := vmk.MakeGnoTransactionStore(ctx.WithMultiStore(mcw))
vmk.LoadStdlib(stdlibCtx, stdlibsDir)
vmk.CommitGnoTransactionStore(stdlibCtx)

mcw.MultiWrite()

return ctx, acck, bank, vmk, stdlibCtx
}

func handlePanicMessage(err error, panicMessage string) (string, error) {
if err == nil {
return "", fmt.Errorf("expected panic with message: %s, but executed successfully", panicMessage)
}
if !strings.Contains(err.Error(), panicMessage) {
return "", fmt.Errorf("expected panic with message: %s, but got: %s", panicMessage, err.Error())
}
return fmt.Sprintf("panicked as expected: %v", err), nil
}

// compareResults compares the actual output of code execution with the expected output or error.
func compareResults(actual, expectedOutput, expectedError string) (string, error) {
actual = strings.TrimSpace(actual)
Expand Down
22 changes: 14 additions & 8 deletions gnovm/pkg/doctest/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ import (
"github.com/yuin/goldmark/text"
)

var (
outputRegex = regexp.MustCompile(`(?m)^// Output:$([\s\S]*?)(?:^(?://\s*$|// Error:|$))`)
errorRegex = regexp.MustCompile(`(?m)^// Error:$([\s\S]*?)(?:^(?://\s*$|// Output:|$))`)
)

// codeBlock represents a block of code extracted from the input text.
type codeBlock struct {
content string // The content of the code block.
Expand All @@ -39,7 +44,10 @@ func GetCodeBlocks(body string) []codeBlock {
mast.Walk(doc, func(n mast.Node, entering bool) (mast.WalkStatus, error) {
if entering {
if cb, ok := n.(*mast.FencedCodeBlock); ok {
codeBlock := createCodeBlock(cb, body, len(codeBlocks))
codeBlock, err := createCodeBlock(cb, body, len(codeBlocks))
if err != nil {
return mast.WalkStop, err
}
codeBlock.name = generateCodeBlockName(codeBlock.content, codeBlock.expectedOutput)
codeBlocks = append(codeBlocks, codeBlock)
}
Expand All @@ -51,7 +59,7 @@ func GetCodeBlocks(body string) []codeBlock {
}

// createCodeBlock creates a CodeBlock from a code block node.
func createCodeBlock(node *mast.FencedCodeBlock, body string, index int) codeBlock {
func createCodeBlock(node *mast.FencedCodeBlock, body string, index int) (codeBlock, error) {
var buf bytes.Buffer
lines := node.Lines()
for i := 0; i < lines.Len(); i++ {
Expand All @@ -73,7 +81,7 @@ func createCodeBlock(node *mast.FencedCodeBlock, body string, index int) codeBlo

expectedOutput, expectedError, err := parseExpectedResults(content)
if err != nil {
panic(err)
return codeBlock{}, err
}

return codeBlock{
Expand All @@ -85,15 +93,12 @@ func createCodeBlock(node *mast.FencedCodeBlock, body string, index int) codeBlo
expectedOutput: expectedOutput,
expectedError: expectedError,
options: options,
}
}, nil
}

// parseExpectedResults scans the code block content for expecting outputs and errors,
// which are typically indicated by special comments in the code.
func parseExpectedResults(content string) (string, string, error) {
outputRegex := regexp.MustCompile(`(?m)^// Output:$([\s\S]*?)(?:^(?://\s*$|// Error:|$))`)
errorRegex := regexp.MustCompile(`(?m)^// Error:$([\s\S]*?)(?:^(?://\s*$|// Output:|$))`)

var outputs, errors []string

outputMatches := outputRegex.FindAllStringSubmatch(content, -1)
Expand Down Expand Up @@ -362,7 +367,8 @@ func parseExecutionOptions(language string, firstLine []byte) ExecutionOptions {
if match[2] != nil {
options.PanicMessage = string(match[2])
}
// TODO: add more options
case "ignore":
options.Ignore = true
}
}
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ require (
github.com/nxadm/tail v1.4.11 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/yuin/goldmark v1.7.6 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3142978

Please sign in to comment.