mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-23 03:38:35 +00:00
Merge pull request #2382 from nspcc-dev/compiler-optimize
compiler: optimize tests
This commit is contained in:
commit
96cd415384
9 changed files with 804 additions and 783 deletions
|
@ -1,16 +1,21 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var assignTestCases = []testCase{
|
var assignTestCases = []testCase{
|
||||||
{
|
{
|
||||||
"chain define",
|
"chain define",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
y := x
|
y := x
|
||||||
z := y
|
z := y
|
||||||
|
@ -23,9 +28,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple assign",
|
"simple assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
x = 8
|
x = 8
|
||||||
return x
|
return x
|
||||||
|
@ -35,9 +38,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"add assign",
|
"add assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
x += 8
|
x += 8
|
||||||
return x
|
return x
|
||||||
|
@ -47,9 +48,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sub assign",
|
"sub assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
x -= 2
|
x -= 2
|
||||||
return x
|
return x
|
||||||
|
@ -59,9 +58,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mul assign",
|
"mul assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
x *= 2
|
x *= 2
|
||||||
return x
|
return x
|
||||||
|
@ -71,9 +68,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"div assign",
|
"div assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
x /= 2
|
x /= 2
|
||||||
return x
|
return x
|
||||||
|
@ -83,9 +78,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"add assign binary expr",
|
"add assign binary expr",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
x += 6 + 2
|
x += 6 + 2
|
||||||
return x
|
return x
|
||||||
|
@ -95,9 +88,7 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"add assign binary expr ident",
|
"add assign binary expr ident",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
y := 5
|
y := 5
|
||||||
x += 6 + y
|
x += 6 + y
|
||||||
|
@ -108,19 +99,17 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"add assign for string",
|
"add assign for string",
|
||||||
`package foo
|
`func F%d() string {
|
||||||
func Main() string {
|
|
||||||
s := "Hello, "
|
s := "Hello, "
|
||||||
s += "world!"
|
s += "world!"
|
||||||
return s
|
return s
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte("Hello, world!"),
|
[]byte("Hello, world!"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"decl assign",
|
"decl assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
var x int = 4
|
var x int = 4
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
@ -129,32 +118,41 @@ var assignTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"multi assign",
|
"multi assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x, y := 1, 2
|
x, y := 1, 2
|
||||||
return x + y
|
return x + y
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(3),
|
big.NewInt(3),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"many assignments",
|
||||||
|
`func F%d() int {
|
||||||
|
a := 0
|
||||||
|
` + strings.Repeat("a += 1\n", 1024) + `
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(1024),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAssignments(t *testing.T) {
|
func TestAssignments(t *testing.T) {
|
||||||
runTestCases(t, assignTestCases)
|
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
|
||||||
}
|
for i, tc := range assignTestCases {
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tc.src, i))
|
||||||
func TestManyAssignments(t *testing.T) {
|
|
||||||
src1 := `package foo
|
|
||||||
func Main() int {
|
|
||||||
a := 0
|
|
||||||
`
|
|
||||||
src2 := `return a
|
|
||||||
}`
|
|
||||||
|
|
||||||
for i := 0; i < 1024; i++ {
|
|
||||||
src1 += "a += 1\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eval(t, src1+src2, big.NewInt(1024))
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range assignTestCases {
|
||||||
|
v := vm.New()
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
v.Istack().Clear()
|
||||||
|
v.Estack().Clear()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, tc.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,7 @@ import (
|
||||||
var binaryExprTestCases = []testCase{
|
var binaryExprTestCases = []testCase{
|
||||||
{
|
{
|
||||||
"simple add",
|
"simple add",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2 + 2
|
x := 2 + 2
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
@ -26,9 +24,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple sub",
|
"simple sub",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2 - 2
|
x := 2 - 2
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
@ -37,9 +33,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple div",
|
"simple div",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2 / 2
|
x := 2 / 2
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
@ -48,10 +42,8 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple mod",
|
"simple mod",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
x := 3 %% 2
|
||||||
func Main() int {
|
|
||||||
x := 3 % 2
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -59,9 +51,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple mul",
|
"simple mul",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 4 * 2
|
x := 4 * 2
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
@ -70,9 +60,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple binary expr in return",
|
"simple binary expr in return",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2
|
x := 2
|
||||||
return 2 + x
|
return 2 + x
|
||||||
}
|
}
|
||||||
|
@ -81,9 +69,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"complex binary expr",
|
"complex binary expr",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 4
|
x := 4
|
||||||
y := 8
|
y := 8
|
||||||
z := x + 2 + 2 - 8
|
z := x + 2 + 2 - 8
|
||||||
|
@ -94,9 +80,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal strings with eql",
|
"compare not equal strings with eql",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
str := "a string"
|
str := "a string"
|
||||||
if str == "another string" {
|
if str == "another string" {
|
||||||
return 1
|
return 1
|
||||||
|
@ -108,9 +92,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal strings with eql",
|
"compare equal strings with eql",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
str := "a string"
|
str := "a string"
|
||||||
if str == "a string" {
|
if str == "a string" {
|
||||||
return 1
|
return 1
|
||||||
|
@ -122,9 +104,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal strings with neq",
|
"compare not equal strings with neq",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
str := "a string"
|
str := "a string"
|
||||||
if str != "another string" {
|
if str != "another string" {
|
||||||
return 1
|
return 1
|
||||||
|
@ -136,9 +116,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal strings with neq",
|
"compare equal strings with neq",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
str := "a string"
|
str := "a string"
|
||||||
if str != "a string" {
|
if str != "a string" {
|
||||||
return 1
|
return 1
|
||||||
|
@ -150,9 +128,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal ints with eql",
|
"compare equal ints with eql",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 10
|
x := 10
|
||||||
if x == 10 {
|
if x == 10 {
|
||||||
return 1
|
return 1
|
||||||
|
@ -164,9 +140,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal ints with neq",
|
"compare equal ints with neq",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 10
|
x := 10
|
||||||
if x != 10 {
|
if x != 10 {
|
||||||
return 1
|
return 1
|
||||||
|
@ -178,9 +152,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal ints with eql",
|
"compare not equal ints with eql",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 11
|
x := 11
|
||||||
if x == 10 {
|
if x == 10 {
|
||||||
return 1
|
return 1
|
||||||
|
@ -192,9 +164,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal ints with neq",
|
"compare not equal ints with neq",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 11
|
x := 11
|
||||||
if x != 10 {
|
if x != 10 {
|
||||||
return 1
|
return 1
|
||||||
|
@ -206,9 +176,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple add and assign",
|
"simple add and assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2
|
x := 2
|
||||||
x += 1
|
x += 1
|
||||||
return x
|
return x
|
||||||
|
@ -218,9 +186,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple sub and assign",
|
"simple sub and assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2
|
x := 2
|
||||||
x -= 1
|
x -= 1
|
||||||
return x
|
return x
|
||||||
|
@ -230,9 +196,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple mul and assign",
|
"simple mul and assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2
|
x := 2
|
||||||
x *= 2
|
x *= 2
|
||||||
return x
|
return x
|
||||||
|
@ -242,9 +206,7 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple div and assign",
|
"simple div and assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 2
|
x := 2
|
||||||
x /= 2
|
x /= 2
|
||||||
return x
|
return x
|
||||||
|
@ -254,11 +216,9 @@ var binaryExprTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple mod and assign",
|
"simple mod and assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package testcase
|
|
||||||
func Main() int {
|
|
||||||
x := 5
|
x := 5
|
||||||
x %= 2
|
x %%= 2
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -267,7 +227,23 @@ var binaryExprTestCases = []testCase{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBinaryExprs(t *testing.T) {
|
func TestBinaryExprs(t *testing.T) {
|
||||||
runTestCases(t, binaryExprTestCases)
|
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
|
||||||
|
for i, tc := range binaryExprTestCases {
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tc.src, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range binaryExprTestCases {
|
||||||
|
v := vm.New()
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
v.Istack().Clear()
|
||||||
|
v.Estack().Clear()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, tc.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addBoolExprTestFunc(testCases []testCase, b *bytes.Buffer, val bool, cond string) []testCase {
|
func addBoolExprTestFunc(testCases []testCase, b *bytes.Buffer, val bool, cond string) []testCase {
|
||||||
|
@ -381,7 +357,7 @@ func TestBooleanExprs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("Triple", func(t *testing.T) {
|
t.Run("Triple", func(t *testing.T) {
|
||||||
const step = 256 // empirically found value to make script less than 65536 in size
|
const step = 350 // empirically found value to make script less than 65536 in size
|
||||||
for start := 0; start < len(triple); start += step {
|
for start := 0; start < len(triple); start += step {
|
||||||
testCases = testCases[:0]
|
testCases = testCases[:0]
|
||||||
srcBuilder.Reset()
|
srcBuilder.Reset()
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
type convertTestCase struct {
|
type convertTestCase struct {
|
||||||
|
@ -25,12 +31,11 @@ func getFunctionName(typ string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConvert(t *testing.T) {
|
func TestConvert(t *testing.T) {
|
||||||
srcTmpl := `package foo
|
srcTmpl := `func F%d() %s {
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/convert"
|
|
||||||
func Main() %s {
|
|
||||||
arg := %s
|
arg := %s
|
||||||
return convert.To%s(arg)
|
return convert.To%s(arg)
|
||||||
}`
|
}
|
||||||
|
`
|
||||||
|
|
||||||
convertTestCases := []convertTestCase{
|
convertTestCases := []convertTestCase{
|
||||||
{"bool", "true", true},
|
{"bool", "true", true},
|
||||||
|
@ -53,11 +58,24 @@ func TestConvert(t *testing.T) {
|
||||||
{"[]byte", "[]byte{0, 1, 0}", []byte{0, 1, 0}},
|
{"[]byte", "[]byte{0, 1, 0}", []byte{0, 1, 0}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range convertTestCases {
|
srcBuilder := bytes.NewBuffer([]byte(`package testcase
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/convert"
|
||||||
|
`))
|
||||||
|
for i, tc := range convertTestCases {
|
||||||
name := getFunctionName(tc.returnType)
|
name := getFunctionName(tc.returnType)
|
||||||
t.Run(tc.argValue+"->"+name, func(t *testing.T) {
|
srcBuilder.WriteString(fmt.Sprintf(srcTmpl, i, tc.returnType, tc.argValue, name))
|
||||||
src := fmt.Sprintf(srcTmpl, tc.returnType, tc.argValue, name)
|
}
|
||||||
eval(t, src, tc.result)
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range convertTestCases {
|
||||||
|
v := vm.New()
|
||||||
|
t.Run(tc.argValue+getFunctionName(tc.returnType), func(t *testing.T) {
|
||||||
|
v.Istack().Clear()
|
||||||
|
v.Estack().Clear()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, tc.result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEntryPointWithMethod(t *testing.T) {
|
func TestEntryPointWithMethod(t *testing.T) {
|
||||||
|
@ -370,405 +375,368 @@ func TestDec(t *testing.T) {
|
||||||
eval(t, src, big.NewInt(1))
|
eval(t, src, big.NewInt(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForLoopEmpty(t *testing.T) {
|
var forLoopTestCases = []testCase{
|
||||||
src := `
|
{
|
||||||
package foo
|
"empty for loop",
|
||||||
func Main() int {
|
`func F%d() int {
|
||||||
x := 0
|
x := 0
|
||||||
for {
|
for {
|
||||||
x++
|
x++
|
||||||
if x == 2 {
|
if x == 2 { break }
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
return x
|
||||||
}
|
}
|
||||||
return x
|
`,
|
||||||
}
|
big.NewInt(2),
|
||||||
`
|
}, {
|
||||||
eval(t, src, big.NewInt(2))
|
"big iteration count",
|
||||||
}
|
`func F%d() int {
|
||||||
|
|
||||||
func TestForLoopBigIter(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
x := 0
|
x := 0
|
||||||
for i := 0; i < 100000; i++ {
|
for i := 0; i < 100000; i++ {
|
||||||
x = i
|
x = i
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
eval(t, src, big.NewInt(99999))
|
big.NewInt(99999),
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func TestForLoopNoInit(t *testing.T) {
|
"no init",
|
||||||
src := `
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
i := 0
|
i := 0
|
||||||
for ; i < 10; i++ {
|
for ; i < 10; i++ {
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
eval(t, src, big.NewInt(10))
|
big.NewInt(10),
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func TestForLoopNoPost(t *testing.T) {
|
"no post",
|
||||||
src := `
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
i := 0
|
i := 0
|
||||||
for i < 10 {
|
for i < 10 {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
eval(t, src, big.NewInt(10))
|
big.NewInt(10),
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func TestForLoopRange(t *testing.T) {
|
"range",
|
||||||
src := `
|
`func F%d() int {
|
||||||
package foo
|
sum := 0
|
||||||
func Main() int {
|
arr := []int{1, 2, 3}
|
||||||
sum := 0
|
for i := range arr {
|
||||||
arr := []int{1, 2, 3}
|
sum += arr[i]
|
||||||
for i := range arr {
|
|
||||||
sum += arr[i]
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(6))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForLoopRangeGlobalIndex(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
sum := 0
|
|
||||||
i := 0
|
|
||||||
arr := []int{1, 2, 3}
|
|
||||||
for i = range arr {
|
|
||||||
sum += arr[i]
|
|
||||||
}
|
|
||||||
return sum + i
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(8))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForLoopRangeChangeVariable(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
sum := 0
|
|
||||||
arr := []int{1, 2, 3}
|
|
||||||
for i := range arr {
|
|
||||||
sum += arr[i]
|
|
||||||
i++
|
|
||||||
sum += i
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(12))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForLoopBreak(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
var i int
|
|
||||||
for i < 10 {
|
|
||||||
i++
|
|
||||||
if i == 5 {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
return sum
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(6),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(5))
|
{
|
||||||
}
|
"range, global index",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopBreakLabel(t *testing.T) {
|
sum := 0
|
||||||
src := `
|
i := 0
|
||||||
package foo
|
arr := []int{1, 2, 3}
|
||||||
func Main() int {
|
for i = range arr {
|
||||||
var i int
|
sum += arr[i]
|
||||||
loop:
|
|
||||||
for i < 10 {
|
|
||||||
i++
|
|
||||||
if i == 5 {
|
|
||||||
break loop
|
|
||||||
}
|
}
|
||||||
|
return sum + i
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(8),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(5))
|
{
|
||||||
}
|
"range, change variable",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopNestedBreak(t *testing.T) {
|
sum := 0
|
||||||
src := `
|
arr := []int{1, 2, 3}
|
||||||
package foo
|
for i := range arr {
|
||||||
func Main() int {
|
sum += arr[i]
|
||||||
var i int
|
i++
|
||||||
for i < 10 {
|
sum += i
|
||||||
i++
|
}
|
||||||
for j := 0; j < 2; j++ {
|
return sum
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(12),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"break",
|
||||||
|
`func F%d() int {
|
||||||
|
var i int
|
||||||
|
for i < 10 {
|
||||||
i++
|
i++
|
||||||
if i == 5 {
|
if i == 5 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(5),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(11))
|
{
|
||||||
}
|
"break label",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopNestedBreakLabel(t *testing.T) {
|
var i int
|
||||||
src := `
|
loop:
|
||||||
package foo
|
for i < 10 {
|
||||||
func Main() int {
|
i++
|
||||||
var i int
|
|
||||||
loop:
|
|
||||||
for i < 10 {
|
|
||||||
i++
|
|
||||||
for j := 0; j < 2; j++ {
|
|
||||||
if i == 5 {
|
if i == 5 {
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(5),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nested break",
|
||||||
|
`func F%d() int {
|
||||||
|
var i int
|
||||||
|
for i < 10 {
|
||||||
i++
|
i++
|
||||||
|
for j := 0; j < 2; j++ {
|
||||||
|
i++
|
||||||
|
if i == 5 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(11),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(5))
|
{
|
||||||
}
|
"nested break label",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopContinue(t *testing.T) {
|
var i int
|
||||||
src := `
|
loop:
|
||||||
package foo
|
for i < 10 {
|
||||||
func Main() int {
|
i++
|
||||||
var i, j int
|
for j := 0; j < 2; j++ {
|
||||||
for i < 10 {
|
if i == 5 {
|
||||||
i++
|
break loop
|
||||||
if i >= 5 {
|
}
|
||||||
continue
|
i++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
j++
|
return i
|
||||||
}
|
}
|
||||||
return j
|
`,
|
||||||
}`
|
big.NewInt(5),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(4))
|
{
|
||||||
}
|
"continue",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopContinueLabel(t *testing.T) {
|
var i, j int
|
||||||
src := `
|
for i < 10 {
|
||||||
package foo
|
i++
|
||||||
func Main() int {
|
if i >= 5 {
|
||||||
var i, j int
|
|
||||||
loop:
|
|
||||||
for i < 10 {
|
|
||||||
i++
|
|
||||||
if i >= 5 {
|
|
||||||
continue loop
|
|
||||||
}
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
return j
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(4))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForLoopNestedContinue(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
var i, k int
|
|
||||||
for i < 10 {
|
|
||||||
i++
|
|
||||||
for j := 0; j < 3; j++ {
|
|
||||||
if j >= 2 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
k++
|
j++
|
||||||
}
|
}
|
||||||
|
return j
|
||||||
}
|
}
|
||||||
return k
|
`,
|
||||||
}`
|
big.NewInt(4),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(20))
|
{
|
||||||
}
|
"continue label",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopNestedContinueLabel(t *testing.T) {
|
var i, j int
|
||||||
src := `
|
loop:
|
||||||
package foo
|
for i < 10 {
|
||||||
func Main() int {
|
i++
|
||||||
var i int
|
if i >= 5 {
|
||||||
loop:
|
|
||||||
for ; i < 10; i += 10 {
|
|
||||||
i++
|
|
||||||
for j := 0; j < 4; j++ {
|
|
||||||
if i == 5 {
|
|
||||||
continue loop
|
continue loop
|
||||||
}
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nested continue",
|
||||||
|
`func F%d() int {
|
||||||
|
var i, k int
|
||||||
|
for i < 10 {
|
||||||
|
i++
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
if j >= 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(20),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nested continue label",
|
||||||
|
`func F%d() int {
|
||||||
|
var i int
|
||||||
|
loop:
|
||||||
|
for ; i < 10; i += 10 {
|
||||||
|
i++
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
if i == 5 {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(15),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"range break",
|
||||||
|
`func F%d() int {
|
||||||
|
var i int
|
||||||
|
arr := []int{1, 2, 3}
|
||||||
|
for i = range arr {
|
||||||
|
if arr[i] == 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"range nested break",
|
||||||
|
`func F%d() int {
|
||||||
|
k := 5
|
||||||
|
arr := []int{1, 2, 3}
|
||||||
|
urr := []int{4, 5, 6, 7}
|
||||||
|
loop:
|
||||||
|
for range arr {
|
||||||
|
k++
|
||||||
|
for j := range urr {
|
||||||
|
k++
|
||||||
|
if j == 3 {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(10),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"range continue",
|
||||||
|
`func F%d() int {
|
||||||
|
i := 6
|
||||||
|
arr := []int{1, 2, 3}
|
||||||
|
for j := range arr {
|
||||||
|
if arr[j] < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(8),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(15))
|
{
|
||||||
}
|
"range, no variable",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopRangeBreak(t *testing.T) {
|
sum := 0
|
||||||
src := `
|
arr := []int{1, 2, 3}
|
||||||
package foo
|
for range arr {
|
||||||
func Main() int {
|
sum += 1
|
||||||
var i int
|
|
||||||
arr := []int{1, 2, 3}
|
|
||||||
for i = range arr {
|
|
||||||
if arr[i] == 2 {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
return sum
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(3),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(1))
|
{
|
||||||
}
|
"range value",
|
||||||
|
`func f(a int) int { return a }
|
||||||
func TestForLoopRangeNestedBreak(t *testing.T) {
|
func F%d() int {
|
||||||
src := `
|
var sum int
|
||||||
package foo
|
arr := []int{1, 9, 4}
|
||||||
func Main() int {
|
for _, v := range arr {
|
||||||
k := 5
|
sum += f(v)
|
||||||
arr := []int{1, 2, 3}
|
|
||||||
urr := []int{4, 5, 6, 7}
|
|
||||||
loop:
|
|
||||||
for range arr {
|
|
||||||
k++
|
|
||||||
for j := range urr {
|
|
||||||
k++
|
|
||||||
if j == 3 {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return sum
|
||||||
}
|
}
|
||||||
return k
|
`,
|
||||||
}`
|
big.NewInt(14),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(10))
|
{
|
||||||
}
|
"range, map",
|
||||||
|
`func F%d() int {
|
||||||
func TestForLoopRangeContinue(t *testing.T) {
|
m := map[int]int{
|
||||||
src := `
|
1: 13,
|
||||||
package foo
|
11: 17,
|
||||||
func Main() int {
|
|
||||||
i := 6
|
|
||||||
arr := []int{1, 2, 3}
|
|
||||||
for j := range arr {
|
|
||||||
if arr[j] < 2 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
i++
|
var sum int
|
||||||
|
for i, v := range m {
|
||||||
|
sum += i
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
return sum
|
||||||
}
|
}
|
||||||
return i
|
`,
|
||||||
}`
|
big.NewInt(42),
|
||||||
|
},
|
||||||
eval(t, src, big.NewInt(8))
|
{
|
||||||
|
"range, type conversion",
|
||||||
|
`type intArr []int
|
||||||
|
func F%d() int {
|
||||||
|
a := []int{1, 2, 3}
|
||||||
|
s := 0
|
||||||
|
for _, v := range intArr(a) {
|
||||||
|
s += v
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(6),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForLoopRangeNoVariable(t *testing.T) {
|
func TestForLoop(t *testing.T) {
|
||||||
src := `
|
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
|
||||||
package foo
|
for i, tc := range forLoopTestCases {
|
||||||
func Main() int {
|
srcBuilder.WriteString(fmt.Sprintf(tc.src, i))
|
||||||
sum := 0
|
}
|
||||||
arr := []int{1, 2, 3}
|
|
||||||
for range arr {
|
|
||||||
sum += 1
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(3))
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
}
|
require.NoError(t, err)
|
||||||
|
|
||||||
func TestForLoopRangeValue(t *testing.T) {
|
for i, tc := range forLoopTestCases {
|
||||||
src := `
|
v := vm.New()
|
||||||
package foo
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
func f(a int) int { return a }
|
v.Istack().Clear()
|
||||||
func Main() int {
|
v.Estack().Clear()
|
||||||
var sum int
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
arr := []int{1, 9, 4}
|
runAndCheck(t, v, tc.result)
|
||||||
for _, v := range arr {
|
})
|
||||||
sum += f(v)
|
}
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(14))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForLoopRangeMap(t *testing.T) {
|
|
||||||
src := `package foo
|
|
||||||
func Main() int {
|
|
||||||
m := map[int]int{
|
|
||||||
1: 13,
|
|
||||||
11: 17,
|
|
||||||
}
|
|
||||||
var sum int
|
|
||||||
for i, v := range m {
|
|
||||||
sum += i
|
|
||||||
sum += v
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}`
|
|
||||||
|
|
||||||
eval(t, src, big.NewInt(42))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForLoopRangeTypeConversion(t *testing.T) {
|
|
||||||
src := `package foo
|
|
||||||
type intArr []int
|
|
||||||
func Main() int {
|
|
||||||
a := []int{1, 2, 3}
|
|
||||||
s := 0
|
|
||||||
for _, v := range intArr(a) {
|
|
||||||
s += v
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}`
|
|
||||||
eval(t, src, big.NewInt(6))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForLoopComplexConditions(t *testing.T) {
|
func TestForLoopComplexConditions(t *testing.T) {
|
||||||
src := `
|
forCondTestCases := []struct {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
var ok bool
|
|
||||||
_ = ok
|
|
||||||
i := 0
|
|
||||||
j := 0
|
|
||||||
%s
|
|
||||||
for %s {
|
|
||||||
i++
|
|
||||||
j++
|
|
||||||
%s
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}`
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
Name string
|
Name string
|
||||||
Cond string
|
Cond string
|
||||||
Assign string
|
Assign string
|
||||||
|
@ -788,14 +756,39 @@ func TestForLoopComplexConditions(t *testing.T) {
|
||||||
{Cond: "ok", Assign: "ok = (i < 2 && j < 4) || (i < 4 && j < 2)", Result: 2},
|
{Cond: "ok", Assign: "ok = (i < 2 && j < 4) || (i < 4 && j < 2)", Result: 2},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
tmpl := `func F%d() int {
|
||||||
|
var ok bool
|
||||||
|
_ = ok
|
||||||
|
i := 0
|
||||||
|
j := 0
|
||||||
|
%s
|
||||||
|
for %s {
|
||||||
|
i++
|
||||||
|
j++
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
`
|
||||||
|
srcBuilder := bytes.NewBufferString("package foo\n")
|
||||||
|
for i, tc := range forCondTestCases {
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tmpl, i, tc.Assign, tc.Cond, tc.Assign))
|
||||||
|
}
|
||||||
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range forCondTestCases {
|
||||||
|
v := vm.New()
|
||||||
name := tc.Cond
|
name := tc.Cond
|
||||||
if tc.Assign != "" {
|
if tc.Assign != "" {
|
||||||
name = tc.Assign
|
name = tc.Assign
|
||||||
}
|
}
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
s := fmt.Sprintf(src, tc.Assign, tc.Cond, tc.Assign)
|
v.Istack().Clear()
|
||||||
eval(t, s, big.NewInt(tc.Result))
|
v.Estack().Clear()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, big.NewInt(tc.Result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -24,6 +26,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -198,11 +201,23 @@ func TestNativeHelpersCompile(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runNativeTestCases(t *testing.T, ctr interop.ContractMD, name string, testCases []nativeTestCase) {
|
func runNativeTestCases(t *testing.T, ctr interop.ContractMD, name string, nativeTestCases []nativeTestCase) {
|
||||||
|
srcBuilder := bytes.NewBuffer([]byte(`package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/native/` + name + `"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
var _ interop.Hash160
|
||||||
|
`))
|
||||||
|
for i, tc := range nativeTestCases {
|
||||||
|
addNativeTestCase(t, srcBuilder, ctr, i, name, tc.method, tc.params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run(ctr.Name, func(t *testing.T) {
|
t.Run(ctr.Name, func(t *testing.T) {
|
||||||
for _, tc := range testCases {
|
for i, tc := range nativeTestCases {
|
||||||
t.Run(tc.method, func(t *testing.T) {
|
t.Run(tc.method, func(t *testing.T) {
|
||||||
runNativeTestCase(t, ctr, name, tc.method, tc.params...)
|
runNativeTestCase(t, ne, di, ctr, i, tc.method, tc.params...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -233,30 +248,32 @@ func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []strin
|
||||||
return md
|
return md
|
||||||
}
|
}
|
||||||
|
|
||||||
func runNativeTestCase(t *testing.T, ctr interop.ContractMD, name, method string, params ...string) {
|
func addNativeTestCase(t *testing.T, srcBuilder *bytes.Buffer, ctr interop.ContractMD, i int, name, method string, params ...string) {
|
||||||
md := getMethod(t, ctr, method, params)
|
md := getMethod(t, ctr, method, params)
|
||||||
isVoid := md.MD.ReturnType == smartcontract.VoidType
|
isVoid := md.MD.ReturnType == smartcontract.VoidType
|
||||||
srcTmpl := `package foo
|
srcBuilder.WriteString("func F" + strconv.Itoa(i) + "() ")
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/native/%s"
|
if !isVoid {
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
srcBuilder.WriteString("interface{} { return ")
|
||||||
var _ interop.Hash160
|
|
||||||
`
|
|
||||||
if isVoid {
|
|
||||||
srcTmpl += `func Main() { %s.%s(%s) }`
|
|
||||||
} else {
|
} else {
|
||||||
srcTmpl += `func Main() interface{} { return %s.%s(%s) }`
|
srcBuilder.WriteString("{ ")
|
||||||
}
|
}
|
||||||
methodUpper := strings.ToUpper(method[:1]) + method[1:] // ASCII only
|
methodUpper := strings.ToUpper(method[:1]) + method[1:] // ASCII only
|
||||||
methodUpper = strings.ReplaceAll(methodUpper, "Gas", "GAS")
|
methodUpper = strings.ReplaceAll(methodUpper, "Gas", "GAS")
|
||||||
methodUpper = strings.ReplaceAll(methodUpper, "Json", "JSON")
|
methodUpper = strings.ReplaceAll(methodUpper, "Json", "JSON")
|
||||||
src := fmt.Sprintf(srcTmpl, name, name, methodUpper, strings.Join(params, ","))
|
srcBuilder.WriteString(name)
|
||||||
|
srcBuilder.WriteRune('.')
|
||||||
|
srcBuilder.WriteString(methodUpper)
|
||||||
|
srcBuilder.WriteRune('(')
|
||||||
|
srcBuilder.WriteString(strings.Join(params, ", "))
|
||||||
|
srcBuilder.WriteString(") }\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runNativeTestCase(t *testing.T, b *nef.File, di *compiler.DebugInfo, ctr interop.ContractMD, i int, method string, params ...string) {
|
||||||
|
md := getMethod(t, ctr, method, params)
|
||||||
|
result := getTestStackItem(md.MD.ReturnType)
|
||||||
|
isVoid := md.MD.ReturnType == smartcontract.VoidType
|
||||||
|
|
||||||
v := vm.New()
|
v := vm.New()
|
||||||
v.GasLimit = -1
|
|
||||||
b, di, err := compiler.CompileWithOptions("foo.go", strings.NewReader(src), nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
result := getTestStackItem(md.MD.ReturnType)
|
|
||||||
v.LoadToken = func(id int32) error {
|
v.LoadToken = func(id int32) error {
|
||||||
t := b.Tokens[id]
|
t := b.Tokens[id]
|
||||||
if t.Hash != ctr.Hash {
|
if t.Hash != ctr.Hash {
|
||||||
|
@ -285,7 +302,7 @@ func runNativeTestCase(t *testing.T, ctr interop.ContractMD, name, method string
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
invokeMethod(t, testMainIdent, b.Script, v, di)
|
invokeMethod(t, fmt.Sprintf("F%d", i), b.Script, v, di)
|
||||||
require.NoError(t, v.Run())
|
require.NoError(t, v.Run())
|
||||||
if isVoid {
|
if isVoid {
|
||||||
require.Equal(t, 0, v.Estack().Len())
|
require.Equal(t, 0, v.Estack().Len())
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -13,9 +16,7 @@ import (
|
||||||
var sliceTestCases = []testCase{
|
var sliceTestCases = []testCase{
|
||||||
{
|
{
|
||||||
"constant index",
|
"constant index",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
a := []int{0,0}
|
a := []int{0,0}
|
||||||
a[1] = 42
|
a[1] = 42
|
||||||
return a[1]+0
|
return a[1]+0
|
||||||
|
@ -25,9 +26,7 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"variable index",
|
"variable index",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
a := []int{0,0}
|
a := []int{0,0}
|
||||||
i := 1
|
i := 1
|
||||||
a[i] = 42
|
a[i] = 42
|
||||||
|
@ -38,19 +37,17 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"increase slice element with +=",
|
"increase slice element with +=",
|
||||||
`package foo
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := []int{1, 2, 3}
|
a := []int{1, 2, 3}
|
||||||
a[1] += 40
|
a[1] += 40
|
||||||
return a[1]
|
return a[1]
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(42),
|
big.NewInt(42),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"complex test",
|
"complex test",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
a := []int{1,2,3}
|
a := []int{1,2,3}
|
||||||
x := a[0]
|
x := a[0]
|
||||||
a[x] = a[x] + 4
|
a[x] = a[x] + 4
|
||||||
|
@ -62,9 +59,7 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slice literals with variables",
|
"slice literals with variables",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
elem := 7
|
elem := 7
|
||||||
a := []int{6, elem, 8}
|
a := []int{6, elem, 8}
|
||||||
return a[1]
|
return a[1]
|
||||||
|
@ -74,9 +69,7 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slice literals with expressions",
|
"slice literals with expressions",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
elem := []int{3, 7}
|
elem := []int{3, 7}
|
||||||
a := []int{6, elem[1]*2+1, 24}
|
a := []int{6, elem[1]*2+1, 24}
|
||||||
return a[1]
|
return a[1]
|
||||||
|
@ -86,93 +79,88 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sub-slice with literal bounds",
|
"sub-slice with literal bounds",
|
||||||
`
|
`func F%d() []byte {
|
||||||
package foo
|
|
||||||
func Main() []byte {
|
|
||||||
a := []byte{0, 1, 2, 3}
|
a := []byte{0, 1, 2, 3}
|
||||||
b := a[1:3]
|
b := a[1:3]
|
||||||
return b
|
return b
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{1, 2},
|
[]byte{1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sub-slice with constant bounds",
|
"sub-slice with constant bounds",
|
||||||
`
|
`const x = 1
|
||||||
package foo
|
|
||||||
const x = 1
|
|
||||||
const y = 3
|
const y = 3
|
||||||
func Main() []byte {
|
func F%d() []byte {
|
||||||
a := []byte{0, 1, 2, 3}
|
a := []byte{0, 1, 2, 3}
|
||||||
b := a[x:y]
|
b := a[x:y]
|
||||||
return b
|
return b
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{1, 2},
|
[]byte{1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sub-slice with variable bounds",
|
"sub-slice with variable bounds",
|
||||||
`
|
`func F%d() []byte {
|
||||||
package foo
|
|
||||||
func Main() []byte {
|
|
||||||
a := []byte{0, 1, 2, 3}
|
a := []byte{0, 1, 2, 3}
|
||||||
x := 1
|
x := 1
|
||||||
y := 3
|
y := 3
|
||||||
b := a[x:y]
|
b := a[x:y]
|
||||||
return b
|
return b
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{1, 2},
|
[]byte{1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sub-slice with no lower bound",
|
"sub-slice with no lower bound",
|
||||||
`
|
`func F%d() []byte {
|
||||||
package foo
|
|
||||||
func Main() []byte {
|
|
||||||
a := []byte{0, 1, 2, 3}
|
a := []byte{0, 1, 2, 3}
|
||||||
b := a[:3]
|
b := a[:3]
|
||||||
return b
|
return b
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{0, 1, 2},
|
[]byte{0, 1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sub-slice with no upper bound",
|
"sub-slice with no upper bound",
|
||||||
`
|
`func F%d() []byte {
|
||||||
package foo
|
|
||||||
func Main() []byte {
|
|
||||||
a := []byte{0, 1, 2, 3}
|
a := []byte{0, 1, 2, 3}
|
||||||
b := a[2:]
|
b := a[2:]
|
||||||
return b
|
return b
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{2, 3},
|
[]byte{2, 3},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"declare byte slice",
|
"declare byte slice",
|
||||||
`package foo
|
`func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
var a []byte
|
var a []byte
|
||||||
a = append(a, 1)
|
a = append(a, 1)
|
||||||
a = append(a, 2)
|
a = append(a, 2)
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{1, 2},
|
[]byte{1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"append multiple bytes to a slice",
|
"append multiple bytes to a slice",
|
||||||
`package foo
|
`func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
var a []byte
|
var a []byte
|
||||||
a = append(a, 1, 2)
|
a = append(a, 1, 2)
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{1, 2},
|
[]byte{1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"append multiple ints to a slice",
|
"append multiple ints to a slice",
|
||||||
`package foo
|
`func F%d() []int {
|
||||||
func Main() []int {
|
|
||||||
var a []int
|
var a []int
|
||||||
a = append(a, 1, 2, 3)
|
a = append(a, 1, 2, 3)
|
||||||
a = append(a, 4, 5)
|
a = append(a, 4, 5)
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]stackitem.Item{
|
[]stackitem.Item{
|
||||||
stackitem.NewBigInteger(big.NewInt(1)),
|
stackitem.NewBigInteger(big.NewInt(1)),
|
||||||
stackitem.NewBigInteger(big.NewInt(2)),
|
stackitem.NewBigInteger(big.NewInt(2)),
|
||||||
|
@ -183,15 +171,15 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"int slice, append slice",
|
"int slice, append slice",
|
||||||
`package foo
|
` func getByte() byte { return 0x80 }
|
||||||
func getByte() byte { return 0x80 }
|
func F%d() []int {
|
||||||
func Main() []int {
|
|
||||||
x := []int{1}
|
x := []int{1}
|
||||||
y := []int{2, 3}
|
y := []int{2, 3}
|
||||||
x = append(x, y...)
|
x = append(x, y...)
|
||||||
x = append(x, y...)
|
x = append(x, y...)
|
||||||
return x
|
return x
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]stackitem.Item{
|
[]stackitem.Item{
|
||||||
stackitem.Make(1),
|
stackitem.Make(1),
|
||||||
stackitem.Make(2), stackitem.Make(3),
|
stackitem.Make(2), stackitem.Make(3),
|
||||||
|
@ -200,13 +188,13 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"declare compound slice",
|
"declare compound slice",
|
||||||
`package foo
|
`func F%d() []string {
|
||||||
func Main() []string {
|
|
||||||
var a []string
|
var a []string
|
||||||
a = append(a, "a")
|
a = append(a, "a")
|
||||||
a = append(a, "b")
|
a = append(a, "b")
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]stackitem.Item{
|
[]stackitem.Item{
|
||||||
stackitem.NewByteArray([]byte("a")),
|
stackitem.NewByteArray([]byte("a")),
|
||||||
stackitem.NewByteArray([]byte("b")),
|
stackitem.NewByteArray([]byte("b")),
|
||||||
|
@ -214,14 +202,14 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"declare compound slice alias",
|
"declare compound slice alias",
|
||||||
`package foo
|
`type strs []string
|
||||||
type strs []string
|
func F%d() []string {
|
||||||
func Main() []string {
|
|
||||||
var a strs
|
var a strs
|
||||||
a = append(a, "a")
|
a = append(a, "a")
|
||||||
a = append(a, "b")
|
a = append(a, "b")
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]stackitem.Item{
|
[]stackitem.Item{
|
||||||
stackitem.NewByteArray([]byte("a")),
|
stackitem.NewByteArray([]byte("a")),
|
||||||
stackitem.NewByteArray([]byte("b")),
|
stackitem.NewByteArray([]byte("b")),
|
||||||
|
@ -229,72 +217,70 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"byte-slice assignment",
|
"byte-slice assignment",
|
||||||
`package foo
|
`func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
a := []byte{0, 1, 2}
|
a := []byte{0, 1, 2}
|
||||||
a[1] = 42
|
a[1] = 42
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{0, 42, 2},
|
[]byte{0, 42, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"byte-slice assignment after string conversion",
|
"byte-slice assignment after string conversion",
|
||||||
`package foo
|
`func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
a := "abc"
|
a := "abc"
|
||||||
b := []byte(a)
|
b := []byte(a)
|
||||||
b[1] = 42
|
b[1] = 42
|
||||||
return []byte(a)
|
return []byte(a)
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{0x61, 0x62, 0x63},
|
[]byte{0x61, 0x62, 0x63},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"declare and append byte-slice",
|
"declare and append byte-slice",
|
||||||
`package foo
|
`func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
var a []byte
|
var a []byte
|
||||||
a = append(a, 1)
|
a = append(a, 1)
|
||||||
a = append(a, 2)
|
a = append(a, 2)
|
||||||
return a
|
return a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte{1, 2},
|
[]byte{1, 2},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nested slice assignment",
|
"nested slice assignment",
|
||||||
`package foo
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := [][]int{[]int{1, 2}, []int{3, 4}}
|
a := [][]int{[]int{1, 2}, []int{3, 4}}
|
||||||
a[1][0] = 42
|
a[1][0] = 42
|
||||||
return a[1][0]
|
return a[1][0]
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(42),
|
big.NewInt(42),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nested slice omitted type (slice)",
|
"nested slice omitted type (slice)",
|
||||||
`package foo
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := [][]int{{1, 2}, {3, 4}}
|
a := [][]int{{1, 2}, {3, 4}}
|
||||||
a[1][0] = 42
|
a[1][0] = 42
|
||||||
return a[1][0]
|
return a[1][0]
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(42),
|
big.NewInt(42),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nested slice omitted type (struct)",
|
"nested slice omitted type (struct)",
|
||||||
`package foo
|
`type pairA struct { a, b int }
|
||||||
type pair struct { a, b int }
|
func F%d() int {
|
||||||
func Main() int {
|
a := []pairA{{a: 1, b: 2}, {a: 3, b: 4}}
|
||||||
a := []pair{{a: 1, b: 2}, {a: 3, b: 4}}
|
|
||||||
a[1].a = 42
|
a[1].a = 42
|
||||||
return a[1].a
|
return a[1].a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(42),
|
big.NewInt(42),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaults to nil for byte slice",
|
"defaults to nil for byte slice",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
var a []byte
|
var a []byte
|
||||||
if a != nil { return 1}
|
if a != nil { return 1}
|
||||||
return 2
|
return 2
|
||||||
|
@ -304,9 +290,7 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaults to nil for int slice",
|
"defaults to nil for int slice",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
|
||||||
func Main() int {
|
|
||||||
var a []int
|
var a []int
|
||||||
if a != nil { return 1}
|
if a != nil { return 1}
|
||||||
return 2
|
return 2
|
||||||
|
@ -316,11 +300,9 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaults to nil for struct slice",
|
"defaults to nil for struct slice",
|
||||||
`
|
`type pairB struct { a, b int }
|
||||||
package foo
|
func F%d() int {
|
||||||
type pair struct { a, b int }
|
var a []pairB
|
||||||
func Main() int {
|
|
||||||
var a []pair
|
|
||||||
if a != nil { return 1}
|
if a != nil { return 1}
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
@ -329,28 +311,42 @@ var sliceTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"literal byte-slice with variable values",
|
"literal byte-slice with variable values",
|
||||||
`package foo
|
`const sym1 = 's'
|
||||||
const sym1 = 's'
|
func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
sym2 := byte('t')
|
sym2 := byte('t')
|
||||||
sym4 := byte('i')
|
sym4 := byte('i')
|
||||||
return []byte{sym1, sym2, 'r', sym4, 'n', 'g'}
|
return []byte{sym1, sym2, 'r', sym4, 'n', 'g'}
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte("string"),
|
[]byte("string"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"literal slice with function call",
|
"literal slice with function call",
|
||||||
`package foo
|
`func fn() byte { return 't' }
|
||||||
func fn() byte { return 't' }
|
func F%d() []byte {
|
||||||
func Main() []byte {
|
|
||||||
return []byte{'s', fn(), 'r'}
|
return []byte{'s', fn(), 'r'}
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
[]byte("str"),
|
[]byte("str"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSliceOperations(t *testing.T) {
|
func TestSliceOperations(t *testing.T) {
|
||||||
runTestCases(t, sliceTestCases)
|
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
|
||||||
|
for i, tc := range sliceTestCases {
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tc.src, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range sliceTestCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
v := vm.New()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, tc.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestByteSlices(t *testing.T) {
|
func TestByteSlices(t *testing.T) {
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var structTestCases = []testCase{
|
var structTestCases = []testCase{
|
||||||
{
|
{
|
||||||
"struct field assign",
|
"struct field assign",
|
||||||
`
|
`func F%d() int {
|
||||||
package foo
|
t := token1 {
|
||||||
func Main() int {
|
|
||||||
t := token {
|
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
|
@ -22,7 +26,7 @@ var structTestCases = []testCase{
|
||||||
return age
|
return age
|
||||||
}
|
}
|
||||||
|
|
||||||
type token struct {
|
type token1 struct {
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
@ -31,11 +35,9 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"struct field from func result",
|
"struct field from func result",
|
||||||
`
|
`type S struct { x int }
|
||||||
package foo
|
|
||||||
type S struct { x int }
|
|
||||||
func fn() int { return 2 }
|
func fn() int { return 2 }
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t := S{x: fn()}
|
t := S{x: fn()}
|
||||||
return t.x
|
return t.x
|
||||||
}
|
}
|
||||||
|
@ -44,15 +46,13 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"struct field return",
|
"struct field return",
|
||||||
`
|
`type token2 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t := token {
|
t := token2 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
|
@ -64,15 +64,13 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"struct field assign",
|
"struct field assign",
|
||||||
`
|
`type token3 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t := token {
|
t := token3 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
|
@ -84,17 +82,15 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"complex struct",
|
"complex struct",
|
||||||
`
|
`type token4 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
x := 10
|
x := 10
|
||||||
|
|
||||||
t := token {
|
t := token4 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
|
@ -108,95 +104,90 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"initialize struct field from variable",
|
"initialize struct field from variable",
|
||||||
`
|
`type token5 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
x := 10
|
x := 10
|
||||||
t := token {
|
t := token5 {
|
||||||
x: x,
|
x: x,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
y := t.x + t.y
|
y := t.x + t.y
|
||||||
return y
|
return y
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(14),
|
big.NewInt(14),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"assign a variable to a struct field",
|
"assign a variable to a struct field",
|
||||||
`
|
`type token6 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
ten := 10
|
ten := 10
|
||||||
t := token {
|
t := token6 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
t.x = ten
|
t.x = ten
|
||||||
y := t.y + t.x
|
y := t.y + t.x
|
||||||
return y
|
return y
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(14),
|
big.NewInt(14),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"increase struct field with +=",
|
"increase struct field with +=",
|
||||||
`package foo
|
`type token7 struct { x int }
|
||||||
type token struct { x int }
|
func F%d() int {
|
||||||
func Main() int {
|
t := token7{x: 2}
|
||||||
t := token{x: 2}
|
|
||||||
t.x += 3
|
t.x += 3
|
||||||
return t.x
|
return t.x
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(5),
|
big.NewInt(5),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"assign a struct field to a struct field",
|
"assign a struct field to a struct field",
|
||||||
`
|
`type token8 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t1 := token {
|
t1 := token8 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
t2 := token {
|
t2 := token8 {
|
||||||
x: 3,
|
x: 3,
|
||||||
y: 5,
|
y: 5,
|
||||||
}
|
}
|
||||||
t1.x = t2.y
|
t1.x = t2.y
|
||||||
y := t1.x + t2.x
|
y := t1.x + t2.x
|
||||||
return y
|
return y
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(8),
|
big.NewInt(8),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"initialize same struct twice",
|
"initialize same struct twice",
|
||||||
`
|
`type token9 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t1 := token {
|
t1 := token9 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
t2 := token {
|
t2 := token9 {
|
||||||
x: 2,
|
x: 2,
|
||||||
y: 4,
|
y: 4,
|
||||||
}
|
}
|
||||||
|
@ -207,18 +198,16 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"struct methods",
|
"struct methods",
|
||||||
`
|
`type token10 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
}
|
}
|
||||||
|
|
||||||
func(t token) getInteger() int {
|
func(t token10) getInteger() int {
|
||||||
return t.x
|
return t.x
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t := token {
|
t := token10 {
|
||||||
x: 4,
|
x: 4,
|
||||||
}
|
}
|
||||||
someInt := t.getInteger()
|
someInt := t.getInteger()
|
||||||
|
@ -229,19 +218,17 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"struct methods with arguments",
|
"struct methods with arguments",
|
||||||
`
|
`type token11 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also tests if x conflicts with t.x
|
// Also tests if x conflicts with t.x
|
||||||
func(t token) addIntegers(x int, y int) int {
|
func(t token11) addIntegers(x int, y int) int {
|
||||||
return t.x + x + y
|
return t.x + x + y
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t := token {
|
t := token11 {
|
||||||
x: 4,
|
x: 4,
|
||||||
}
|
}
|
||||||
someInt := t.addIntegers(2, 4)
|
someInt := t.addIntegers(2, 4)
|
||||||
|
@ -252,17 +239,15 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"initialize struct partially",
|
"initialize struct partially",
|
||||||
`
|
`type token12 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
z string
|
z string
|
||||||
b bool
|
b bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
t := token {
|
t := token12 {
|
||||||
x: 4,
|
x: 4,
|
||||||
}
|
}
|
||||||
return t.y
|
return t.y
|
||||||
|
@ -272,17 +257,15 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"test return struct from func",
|
"test return struct from func",
|
||||||
`
|
`type token13 struct {
|
||||||
package foo
|
|
||||||
type token struct {
|
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
z string
|
z string
|
||||||
b bool
|
b bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newToken() token {
|
func newToken() token13 {
|
||||||
return token{
|
return token13{
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 2,
|
y: 2,
|
||||||
z: "hello",
|
z: "hello",
|
||||||
|
@ -290,7 +273,7 @@ var structTestCases = []testCase{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() token {
|
func F%d() token13 {
|
||||||
return newToken()
|
return newToken()
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -303,10 +286,7 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pass struct as argument",
|
"pass struct as argument",
|
||||||
`
|
`type Bar struct {
|
||||||
package foo
|
|
||||||
|
|
||||||
type Bar struct {
|
|
||||||
amount int
|
amount int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +295,7 @@ var structTestCases = []testCase{
|
||||||
return bar.amount
|
return bar.amount
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
b := Bar{
|
b := Bar{
|
||||||
amount: 10,
|
amount: 10,
|
||||||
}
|
}
|
||||||
|
@ -328,110 +308,109 @@ var structTestCases = []testCase{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"declare struct literal",
|
"declare struct literal",
|
||||||
`package foo
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
var x struct {
|
var x struct {
|
||||||
a int
|
a int
|
||||||
}
|
}
|
||||||
x.a = 2
|
x.a = 2
|
||||||
return x.a
|
return x.a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(2),
|
big.NewInt(2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"declare struct type",
|
"declare struct type",
|
||||||
`package foo
|
`type withA struct {
|
||||||
type withA struct {
|
|
||||||
a int
|
a int
|
||||||
}
|
}
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
var x withA
|
var x withA
|
||||||
x.a = 2
|
x.a = 2
|
||||||
return x.a
|
return x.a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(2),
|
big.NewInt(2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nested selectors (simple read)",
|
"nested selectors (simple read)",
|
||||||
`package foo
|
`type S1 struct { x, y S2 }
|
||||||
type S1 struct { x, y S2 }
|
|
||||||
type S2 struct { a, b int }
|
type S2 struct { a, b int }
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
var s1 S1
|
var s1 S1
|
||||||
var s2 S2
|
var s2 S2
|
||||||
s2.a = 3
|
s2.a = 3
|
||||||
s1.y = s2
|
s1.y = s2
|
||||||
return s1.y.a
|
return s1.y.a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(3),
|
big.NewInt(3),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nested selectors (simple write)",
|
"nested selectors (simple write)",
|
||||||
`package foo
|
`type S3 struct { x S4 }
|
||||||
type S1 struct { x S2 }
|
type S4 struct { a int }
|
||||||
type S2 struct { a int }
|
func F%d() int {
|
||||||
func Main() int {
|
s1 := S3{
|
||||||
s1 := S1{
|
x: S4 {
|
||||||
x: S2 {
|
|
||||||
a: 3,
|
a: 3,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s1.x.a = 11
|
s1.x.a = 11
|
||||||
return s1.x.a
|
return s1.x.a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(11),
|
big.NewInt(11),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"complex struct default value",
|
"complex struct default value",
|
||||||
`package foo
|
`type S5 struct { x S6 }
|
||||||
type S1 struct { x S2 }
|
type S6 struct { y S7 }
|
||||||
type S2 struct { y S3 }
|
type S7 struct { a int }
|
||||||
type S3 struct { a int }
|
func F%d() int {
|
||||||
func Main() int {
|
var s1 S5
|
||||||
var s1 S1
|
|
||||||
s1.x.y.a = 11
|
s1.x.y.a = 11
|
||||||
return s1.x.y.a
|
return s1.x.y.a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(11),
|
big.NewInt(11),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lengthy struct default value",
|
"lengthy struct default value",
|
||||||
`package foo
|
`type SS struct { x int; y []byte; z bool }
|
||||||
type S struct { x int; y []byte; z bool }
|
func F%d() int {
|
||||||
func Main() int {
|
var s SS
|
||||||
var s S
|
|
||||||
return s.x
|
return s.x
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(0),
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nested selectors (complex write)",
|
"nested selectors (complex write)",
|
||||||
`package foo
|
`type S8 struct { x S9 }
|
||||||
type S1 struct { x S2 }
|
type S9 struct { y, z S10 }
|
||||||
type S2 struct { y, z S3 }
|
type S10 struct { a int }
|
||||||
type S3 struct { a int }
|
func F%d() int {
|
||||||
func Main() int {
|
var s1 S8
|
||||||
var s1 S1
|
|
||||||
s1.x.y.a, s1.x.z.a = 11, 31
|
s1.x.y.a, s1.x.z.a = 11, 31
|
||||||
return s1.x.y.a + s1.x.z.a
|
return s1.x.y.a + s1.x.z.a
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(42),
|
big.NewInt(42),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"omit field names",
|
"omit field names",
|
||||||
`package foo
|
`type pair struct { a, b int }
|
||||||
type pair struct { a, b int }
|
func F%d() int {
|
||||||
func Main() int {
|
|
||||||
p := pair{1, 2}
|
p := pair{1, 2}
|
||||||
x := p.a * 10
|
x := p.a * 10
|
||||||
return x + p.b
|
return x + p.b
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(12),
|
big.NewInt(12),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uninitialized struct fields",
|
"uninitialized struct fields",
|
||||||
`package foo
|
`type Foo struct {
|
||||||
type Foo struct {
|
|
||||||
i int
|
i int
|
||||||
m map[string]int
|
m map[string]int
|
||||||
b []byte
|
b []byte
|
||||||
|
@ -439,7 +418,7 @@ var structTestCases = []testCase{
|
||||||
s struct { ii int }
|
s struct { ii int }
|
||||||
}
|
}
|
||||||
func NewFoo() Foo { return Foo{} }
|
func NewFoo() Foo { return Foo{} }
|
||||||
func Main() int {
|
func F%d() int {
|
||||||
foo := NewFoo()
|
foo := NewFoo()
|
||||||
if foo.i != 0 { return 1 }
|
if foo.i != 0 { return 1 }
|
||||||
if len(foo.m) != 0 { return 1 }
|
if len(foo.m) != 0 { return 1 }
|
||||||
|
@ -448,11 +427,26 @@ var structTestCases = []testCase{
|
||||||
s := foo.s
|
s := foo.s
|
||||||
if s.ii != 0 { return 1 }
|
if s.ii != 0 { return 1 }
|
||||||
return 2
|
return 2
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(2),
|
big.NewInt(2),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStructs(t *testing.T) {
|
func TestStructs(t *testing.T) {
|
||||||
runTestCases(t, structTestCases)
|
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
|
||||||
|
for i, tc := range structTestCases {
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tc.src, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range structTestCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
v := vm.New()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, tc.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,34 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var switchTestCases = []testCase{
|
var switchTestCases = []testCase{
|
||||||
{
|
{
|
||||||
"simple switch success",
|
"simple switch success",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 5
|
a := 5
|
||||||
switch a {
|
switch a {
|
||||||
case 5: return 2
|
case 5: return 2
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(2),
|
big.NewInt(2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"switch with no tag",
|
"switch with no tag",
|
||||||
`package main
|
`func f() bool { return false }
|
||||||
func f() bool { return false }
|
func F%d() int {
|
||||||
func Main() int {
|
|
||||||
switch {
|
switch {
|
||||||
case f():
|
case f():
|
||||||
return 1
|
return 1
|
||||||
|
@ -30,14 +36,14 @@ var switchTestCases = []testCase{
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
return 3
|
return 3
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(2),
|
big.NewInt(2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type conversion in tag",
|
"type conversion in tag",
|
||||||
`package main
|
`type state int
|
||||||
type state int
|
func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 1
|
a := 1
|
||||||
switch state(a) {
|
switch state(a) {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -45,52 +51,52 @@ var switchTestCases = []testCase{
|
||||||
default:
|
default:
|
||||||
return 11
|
return 11
|
||||||
}
|
}
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(42),
|
big.NewInt(42),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple switch fail",
|
"simple switch fail",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 6
|
a := 6
|
||||||
switch a {
|
switch a {
|
||||||
case 5:
|
case 5:
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(1),
|
big.NewInt(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"multiple cases success",
|
"multiple cases success",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 6
|
a := 6
|
||||||
switch a {
|
switch a {
|
||||||
case 5: return 2
|
case 5: return 2
|
||||||
case 6: return 3
|
case 6: return 3
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(3),
|
big.NewInt(3),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"multiple cases fail",
|
"multiple cases fail",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 7
|
a := 7
|
||||||
switch a {
|
switch a {
|
||||||
case 5: return 2
|
case 5: return 2
|
||||||
case 6: return 3
|
case 6: return 3
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(1),
|
big.NewInt(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default case",
|
"default case",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 7
|
a := 7
|
||||||
switch a {
|
switch a {
|
||||||
case 5: return 2
|
case 5: return 2
|
||||||
|
@ -98,13 +104,13 @@ var switchTestCases = []testCase{
|
||||||
default: return 4
|
default: return 4
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(4),
|
big.NewInt(4),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"empty case before default",
|
"empty case before default",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 6
|
a := 6
|
||||||
switch a {
|
switch a {
|
||||||
case 5: return 2
|
case 5: return 2
|
||||||
|
@ -112,13 +118,13 @@ var switchTestCases = []testCase{
|
||||||
default: return 4
|
default: return 4
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(1),
|
big.NewInt(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expression in case clause",
|
"expression in case clause",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 6
|
a := 6
|
||||||
b := 3
|
b := 3
|
||||||
switch a {
|
switch a {
|
||||||
|
@ -126,13 +132,13 @@ var switchTestCases = []testCase{
|
||||||
case b*3-3: return 3
|
case b*3-3: return 3
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(3),
|
big.NewInt(3),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"multiple expressions in case",
|
"multiple expressions in case",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
a := 8
|
a := 8
|
||||||
b := 3
|
b := 3
|
||||||
switch a {
|
switch a {
|
||||||
|
@ -140,13 +146,13 @@ var switchTestCases = []testCase{
|
||||||
case b*3-3, 7, 8: return 3
|
case b*3-3, 7, 8: return 3
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(3),
|
big.NewInt(3),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"string switch",
|
"string switch",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
name := "Valera"
|
name := "Valera"
|
||||||
switch name {
|
switch name {
|
||||||
case "Misha": return 2
|
case "Misha": return 2
|
||||||
|
@ -154,13 +160,13 @@ var switchTestCases = []testCase{
|
||||||
case "Lera", "Valer" + "a": return 4
|
case "Lera", "Valer" + "a": return 4
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(4),
|
big.NewInt(4),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"break from switch",
|
"break from switch",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
i := 3
|
i := 3
|
||||||
switch i {
|
switch i {
|
||||||
case 2: return 2
|
case 2: return 2
|
||||||
|
@ -171,13 +177,13 @@ var switchTestCases = []testCase{
|
||||||
case 4: return 4
|
case 4: return 4
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(1),
|
big.NewInt(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"break from outer for",
|
"break from outer for",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
i := 3
|
i := 3
|
||||||
loop:
|
loop:
|
||||||
for i < 10 {
|
for i < 10 {
|
||||||
|
@ -191,13 +197,13 @@ var switchTestCases = []testCase{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(7),
|
big.NewInt(7),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"continue outer for",
|
"continue outer for",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
i := 2
|
i := 2
|
||||||
for i < 10 {
|
for i < 10 {
|
||||||
i++
|
i++
|
||||||
|
@ -214,13 +220,13 @@ var switchTestCases = []testCase{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(2),
|
big.NewInt(2),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple fallthrough",
|
"simple fallthrough",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
n := 2
|
n := 2
|
||||||
switch n {
|
switch n {
|
||||||
case 1: return 5
|
case 1: return 5
|
||||||
|
@ -228,13 +234,13 @@ var switchTestCases = []testCase{
|
||||||
case 3: return 6
|
case 3: return 6
|
||||||
}
|
}
|
||||||
return 7
|
return 7
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(6),
|
big.NewInt(6),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"double fallthrough",
|
"double fallthrough",
|
||||||
`package main
|
`func F%d() int {
|
||||||
func Main() int {
|
|
||||||
n := 2
|
n := 2
|
||||||
k := 5
|
k := 5
|
||||||
switch n {
|
switch n {
|
||||||
|
@ -249,15 +255,26 @@ var switchTestCases = []testCase{
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
return k
|
return k
|
||||||
}`,
|
}
|
||||||
|
`,
|
||||||
big.NewInt(6),
|
big.NewInt(6),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSwitch(t *testing.T) {
|
func TestSwitch(t *testing.T) {
|
||||||
for _, tc := range switchTestCases {
|
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
|
||||||
|
for i, tc := range switchTestCases {
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tc.src, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for i, tc := range switchTestCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
eval(t, tc.src, tc.result)
|
v := vm.New()
|
||||||
|
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
|
||||||
|
runAndCheck(t, v, tc.result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package compiler_test
|
package compiler_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -99,14 +100,41 @@ func TestSyscallExecution(t *testing.T) {
|
||||||
// It will be set in test and we want to fail if calling invalid syscall.
|
// It will be set in test and we want to fail if calling invalid syscall.
|
||||||
fs.Func = nil
|
fs.Func = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srcBuilder := bytes.NewBuffer(nil)
|
||||||
|
srcBuilder.WriteString(`package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
func unused() { var _ interop.Hash160 }
|
||||||
|
`)
|
||||||
|
for goName, tc := range interops {
|
||||||
|
realName := strings.ToTitle(strings.Replace(goName, ".", "", 1))
|
||||||
|
var tmpl string
|
||||||
|
if tc.isVoid {
|
||||||
|
tmpl = "func %s() { %s(%s) }\n"
|
||||||
|
} else {
|
||||||
|
tmpl = "func %s() interface{} { return %s(%s) }\n"
|
||||||
|
}
|
||||||
|
srcBuilder.WriteString(fmt.Sprintf(tmpl, realName, goName, strings.Join(tc.params, ", ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
nf, di, err := compiler.CompileWithOptions("foo.go", srcBuilder, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
for goName, tc := range interops {
|
for goName, tc := range interops {
|
||||||
t.Run(goName, func(t *testing.T) {
|
t.Run(goName, func(t *testing.T) {
|
||||||
runSyscallTestCase(t, ic, goName, tc)
|
name := strings.ToTitle(strings.Replace(goName, ".", "", 1))
|
||||||
|
runSyscallTestCase(t, ic, name, nf.Script, di, tc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSyscallTestCase(t *testing.T, ic *interop.Context, goName string, tc syscallTestCase) {
|
func runSyscallTestCase(t *testing.T, ic *interop.Context, realName string,
|
||||||
|
script []byte, debugInfo *compiler.DebugInfo, tc syscallTestCase) {
|
||||||
syscallID := interopnames.ToID([]byte(tc.method))
|
syscallID := interopnames.ToID([]byte(tc.method))
|
||||||
f := ic.GetFunction(syscallID)
|
f := ic.GetFunction(syscallID)
|
||||||
require.NotNil(t, f)
|
require.NotNil(t, f)
|
||||||
|
@ -127,30 +155,14 @@ func runSyscallTestCase(t *testing.T, ic *interop.Context, goName string, tc sys
|
||||||
}
|
}
|
||||||
defer func() { f.Func = nil }()
|
defer func() { f.Func = nil }()
|
||||||
|
|
||||||
srcTmpl := `package foo
|
invokeMethod(t, realName, script, ic.VM, debugInfo)
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/%s"
|
require.NoError(t, ic.VM.Run())
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
|
||||||
func unused() { var _ interop.Hash160 }
|
|
||||||
`
|
|
||||||
if tc.isVoid {
|
|
||||||
srcTmpl += `func Main() { %s(%s) }`
|
|
||||||
} else {
|
|
||||||
srcTmpl += `func Main() interface{} { return %s(%s) }`
|
|
||||||
}
|
|
||||||
ss := strings.Split(goName, ".")
|
|
||||||
src := fmt.Sprintf(srcTmpl, ss[0], goName, strings.Join(tc.params, ", "))
|
|
||||||
b, _, err := compiler.CompileWithOptions("foo.go", strings.NewReader(src), nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
v := ic.SpawnVM()
|
|
||||||
v.LoadScriptWithFlags(b.Script, callflag.All)
|
|
||||||
require.NoError(t, v.Run())
|
|
||||||
require.True(t, called)
|
require.True(t, called)
|
||||||
if tc.isVoid {
|
if tc.isVoid {
|
||||||
require.Equal(t, 0, v.Estack().Len())
|
require.Equal(t, 0, ic.VM.Estack().Len())
|
||||||
} else {
|
} else {
|
||||||
require.Equal(t, 1, v.Estack().Len())
|
require.Equal(t, 1, ic.VM.Estack().Len())
|
||||||
require.Equal(t, big.NewInt(42), v.Estack().Pop().Value())
|
require.Equal(t, big.NewInt(42), ic.VM.Estack().Pop().Value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue