tutus-chain/pkg/compiler/builtin_test.go

299 lines
5.7 KiB
Go
Executable File

package compiler_test
import (
"fmt"
"math/big"
"strings"
"testing"
"git.marketally.com/tutus-one/tutus-chain/pkg/compiler"
"git.marketally.com/tutus-one/tutus-chain/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
func TestMaxMin(t *testing.T) {
tests := []struct {
name string
args []stackitem.Item
expected map[string]*big.Int
expectedErr string
srcTemplate string
}{
{
name: "invalid type named",
expectedErr: "only integer types are supported by %s",
srcTemplate: `
package foo
type MyInt int
func Main() {
_ = %s(MyInt(1))
}
`,
},
{
name: "invalid type string",
expectedErr: "only integer types are supported by %s, got untyped string at 1",
srcTemplate: `
package foo
func Main() {
_ = %s("42")
}
`,
},
{
name: "single value as func call",
expected: map[string]*big.Int{
"max": big.NewInt(42),
"min": big.NewInt(42),
},
srcTemplate: `
package foo
func f() int {
return 42
}
func Main() int {
return %s(f())
}
`,
},
{
name: "two values",
args: []stackitem.Item{stackitem.Make(10), stackitem.Make(7)},
expected: map[string]*big.Int{
"max": big.NewInt(10),
"min": big.NewInt(7),
},
srcTemplate: `
package foo
func Main(args []any) int {
return %s(args[0].(int), args[1].(int))
}
`,
},
{
name: "three values",
args: []stackitem.Item{stackitem.Make(5), stackitem.Make(6), stackitem.Make(3)},
expected: map[string]*big.Int{
"max": big.NewInt(6),
"min": big.NewInt(3),
},
srcTemplate: `
package foo
func Main(args []any) int {
return %s(args[0].(int), args[1].(int), args[2].(int))
}
`,
},
}
for _, op := range []string{"max", "min"} {
for _, tc := range tests {
src := fmt.Sprintf(tc.srcTemplate, op)
if tc.expectedErr != "" {
_, _, err := compiler.CompileWithOptions("main.go", strings.NewReader(src), nil)
require.ErrorContains(t, err, fmt.Sprintf(tc.expectedErr, op))
} else {
evalWithArgs(t, src, nil, tc.args, tc.expected[op])
}
}
}
}
func TestClear(t *testing.T) {
tests := []struct {
name string
src string
expectedErr string
expected any
}{
{
name: "invalid type array",
src: `package foo
func Main() [42]int {
var m = [42]int{}
clear(m)
return m
}`,
expectedErr: "invalid argument: cannot clear m (variable of type [42]int): " +
"argument must be (or constrained by) map or slice",
},
{
name: "map",
src: `package foo
func Main() map[string]int {
var m = map[string]int{
"one": 1,
"two": 2,
}
clear(m)
return m
}`,
expected: []stackitem.MapElement{},
},
{
name: "slice of integers",
src: `package foo
func Main() []int {
var s = []int{1, 2, 3}
clear(s)
return s
}`,
expected: []stackitem.Item{stackitem.Make(0), stackitem.Make(0), stackitem.Make(0)},
},
{
name: "slice of strings",
src: `package foo
func Main() []string {
var s = []string{"one", "two", "three"}
clear(s)
return s
}`,
expected: []stackitem.Item{stackitem.Make(""), stackitem.Make(""), stackitem.Make("")},
},
{
name: "slice of structs",
src: `package foo
type S2 struct {
A int
B string
C bool
}
type S1 struct {
S S2
}
func Main() []S1 {
var s = []S1 {
{
S: S2 {
A: 42,
B: "first",
C: true,
},
},
{
S: S2 {
A: 24,
B: "second",
C: true,
},
},
}
clear(s)
return s
}`,
expected: []stackitem.Item{
stackitem.NewStruct([]stackitem.Item{
stackitem.NewStruct([]stackitem.Item{
stackitem.Make(0),
stackitem.Make(""),
stackitem.Make(false),
}),
}),
stackitem.NewStruct([]stackitem.Item{
stackitem.NewStruct([]stackitem.Item{
stackitem.Make(0),
stackitem.Make(""),
stackitem.Make(false),
}),
}),
},
},
{
name: "slice of slices",
src: `package foo
func Main() [][]int {
var s = [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8}}
clear(s)
return s
}`,
expected: []stackitem.Item{stackitem.Null{}, stackitem.Null{}, stackitem.Null{}},
},
{
name: "slice of maps",
src: `package foo
func Main() []map[string]string {
var s = []map[string]string{
{
"key": "val",
},
{
"key": "val",
},
}
clear(s)
return s
}`,
expected: []stackitem.Item{stackitem.Null{}, stackitem.Null{}},
},
{
name: "empty slice",
src: `package foo
func Main() []any {
var s = []any{}
clear(s)
return s
}`,
expected: []stackitem.Item{},
},
{
name: "empty map",
src: `package foo
func Main() map[any]any {
var m = map[any]any{}
clear(m)
return m
}`,
expected: []stackitem.MapElement{},
},
{
name: "slice of simple structs",
src: `package foo
type S struct {
A int
}
func Main() []S {
var s = []S {
{
A: 1,
},
{
A: 2,
},
}
clear(s)
s[0].A = 42
return s
}`,
expected: []stackitem.Item{
stackitem.NewStruct([]stackitem.Item{
stackitem.Make(42),
}),
stackitem.NewStruct([]stackitem.Item{
stackitem.Make(0),
}),
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if tc.expectedErr != "" {
_, _, err := compiler.CompileWithOptions("main.go", strings.NewReader(tc.src), nil)
require.ErrorContains(t, err, tc.expectedErr)
} else {
eval(t, tc.src, tc.expected)
}
})
}
}