neoneo-go/pkg/compiler/debug_test.go
Anna Shaleva b5494320f9 compiler, cli: support events from .yml config file
We currently can't process events in codegen, so we have to provide
them via .yml config file. Do not delete the rest of the code connected
with conversion of MethodDebugInfo.Event into manifest.Event as we have
issue #1038.
2020-08-11 13:42:06 +03:00

293 lines
6.9 KiB
Go

package compiler
import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCodeGen_DebugInfo(t *testing.T) {
src := `package foo
func Main(op string) bool {
var s string
_ = s
res := MethodInt(op)
_ = MethodString()
_ = MethodByteArray()
_ = MethodArray()
_ = MethodStruct()
_ = MethodConcat("a", "b", "c")
_ = unexportedMethod()
return res == 42
}
func MethodInt(a string) int {
if a == "get42" {
return 42
}
return 3
}
func MethodConcat(a, b string, c string) string{
return a + b + c
}
func MethodString() string { return "" }
func MethodByteArray() []byte { return nil }
func MethodArray() []bool { return nil }
func MethodStruct() struct{} { return struct{}{} }
func unexportedMethod() int { return 1 }
`
info, err := getBuildInfo(src)
require.NoError(t, err)
pkg := info.program.Package(info.initialPackage)
c := newCodegen(info, pkg)
require.NoError(t, c.compile(info, pkg))
buf := c.prog.Bytes()
d := c.emitDebugInfo(buf)
require.NotNil(t, d)
t.Run("hash", func(t *testing.T) {
require.True(t, hash.Hash160(buf).Equals(d.Hash))
})
t.Run("return types", func(t *testing.T) {
returnTypes := map[string]string{
"MethodInt": "Integer",
"MethodConcat": "String",
"MethodString": "String", "MethodByteArray": "ByteString",
"MethodArray": "Array", "MethodStruct": "Struct",
"Main": "Boolean",
"unexportedMethod": "Integer",
}
for i := range d.Methods {
name := d.Methods[i].Name.Name
assert.Equal(t, returnTypes[name], d.Methods[i].ReturnType)
}
})
t.Run("variables", func(t *testing.T) {
vars := map[string][]string{
"Main": {"s,String", "res,Integer"},
}
for i := range d.Methods {
v, ok := vars[d.Methods[i].Name.Name]
if ok {
require.Equal(t, v, d.Methods[i].Variables)
}
}
})
t.Run("param types", func(t *testing.T) {
paramTypes := map[string][]DebugParam{
"MethodInt": {{
Name: "a",
Type: "String",
}},
"MethodConcat": {
{
Name: "a",
Type: "String",
},
{
Name: "b",
Type: "String",
},
{
Name: "c",
Type: "String",
},
},
"Main": {{
Name: "op",
Type: "String",
}},
}
for i := range d.Methods {
v, ok := paramTypes[d.Methods[i].Name.Name]
if ok {
require.Equal(t, v, d.Methods[i].Parameters)
}
}
})
// basic check that last instruction of every method is indeed RET
for i := range d.Methods {
index := d.Methods[i].Range.End
require.True(t, int(index) < len(buf))
require.EqualValues(t, opcode.RET, buf[index])
}
t.Run("convert to Manifest", func(t *testing.T) {
actual, err := d.ConvertToManifest(smartcontract.HasStorage, nil)
require.NoError(t, err)
// note: offsets are hard to predict, so we just take them from the output
expected := &manifest.Manifest{
ABI: manifest.ABI{
Hash: hash.Hash160(buf),
Methods: []manifest.Method{
{
Name: "main",
Offset: 0,
Parameters: []manifest.Parameter{
manifest.NewParameter("op", smartcontract.StringType),
},
ReturnType: smartcontract.BoolType,
},
{
Name: "methodInt",
Offset: 66,
Parameters: []manifest.Parameter{
{
Name: "a",
Type: smartcontract.StringType,
},
},
ReturnType: smartcontract.IntegerType,
},
{
Name: "methodString",
Offset: 97,
Parameters: []manifest.Parameter{},
ReturnType: smartcontract.StringType,
},
{
Name: "methodByteArray",
Offset: 103,
Parameters: []manifest.Parameter{},
ReturnType: smartcontract.ByteArrayType,
},
{
Name: "methodArray",
Offset: 108,
Parameters: []manifest.Parameter{},
ReturnType: smartcontract.ArrayType,
},
{
Name: "methodStruct",
Offset: 113,
Parameters: []manifest.Parameter{},
ReturnType: smartcontract.ArrayType,
},
{
Name: "methodConcat",
Offset: 88,
Parameters: []manifest.Parameter{
{
Name: "a",
Type: smartcontract.StringType,
},
{
Name: "b",
Type: smartcontract.StringType,
},
{
Name: "c",
Type: smartcontract.StringType,
},
},
ReturnType: smartcontract.StringType,
},
},
Events: []manifest.Event{},
},
Groups: []manifest.Group{},
Features: smartcontract.HasStorage,
Permissions: []manifest.Permission{
{
Contract: manifest.PermissionDesc{
Type: manifest.PermissionWildcard,
},
Methods: manifest.WildStrings{},
},
},
Trusts: manifest.WildUint160s{
Value: []util.Uint160{},
},
SafeMethods: manifest.WildStrings{
Value: []string{},
},
Extra: nil,
}
require.True(t, expected.ABI.Hash.Equals(actual.ABI.Hash))
require.ElementsMatch(t, expected.ABI.Methods, actual.ABI.Methods)
require.Equal(t, expected.ABI.Events, actual.ABI.Events)
require.Equal(t, expected.Groups, actual.Groups)
require.Equal(t, expected.Features, actual.Features)
require.Equal(t, expected.Permissions, actual.Permissions)
require.Equal(t, expected.Trusts, actual.Trusts)
require.Equal(t, expected.SafeMethods, actual.SafeMethods)
require.Equal(t, expected.Extra, actual.Extra)
})
}
func TestSequencePoints(t *testing.T) {
src := `package foo
func Main(op string) bool {
if op == "123" {
return true
}
return false
}`
info, err := getBuildInfo(src)
require.NoError(t, err)
pkg := info.program.Package(info.initialPackage)
c := newCodegen(info, pkg)
require.NoError(t, c.compile(info, pkg))
buf := c.prog.Bytes()
d := c.emitDebugInfo(buf)
require.NotNil(t, d)
// Main func has 2 return on 4-th and 6-th lines.
ps := d.Methods[0].SeqPoints
require.Equal(t, 2, len(ps))
require.Equal(t, 4, ps[0].StartLine)
require.Equal(t, 6, ps[1].StartLine)
}
func TestDebugInfo_MarshalJSON(t *testing.T) {
d := &DebugInfo{
Hash: util.Uint160{10, 11, 12, 13},
Documents: []string{"/path/to/file"},
Methods: []MethodDebugInfo{
{
ID: "id1",
Name: DebugMethodName{
Namespace: "default",
Name: "method1",
},
Range: DebugRange{Start: 10, End: 20},
Parameters: []DebugParam{
{"param1", "Integer"},
{"ok", "Boolean"},
},
ReturnType: "ByteString",
Variables: []string{},
SeqPoints: []DebugSeqPoint{
{
Opcode: 123,
Document: 1,
StartLine: 2,
StartCol: 3,
EndLine: 4,
EndCol: 5,
},
},
},
},
Events: []EventDebugInfo{},
}
testserdes.MarshalUnmarshalJSON(t, d, new(DebugInfo))
}