Merge pull request #963 from nspcc-dev/fix/tests

vm: restore JSON tests for NEO3
This commit is contained in:
Roman Khimov 2020-05-22 14:34:08 +03:00 committed by GitHub
commit 5ea51312e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 436 additions and 335 deletions

View file

@ -26,7 +26,7 @@ var binaryExprTestCases = []testCase{
return x
}
`,
[]byte{},
big.NewInt(0),
},
{
"simple div",
@ -97,7 +97,7 @@ var binaryExprTestCases = []testCase{
return 0
}
`,
[]byte{},
big.NewInt(0),
},
{
"compare equal strings with eql",
@ -139,7 +139,7 @@ var binaryExprTestCases = []testCase{
return 0
}
`,
[]byte{},
big.NewInt(0),
},
{
"compare equal ints with eql",
@ -167,7 +167,7 @@ var binaryExprTestCases = []testCase{
return 0
}
`,
[]byte{},
big.NewInt(0),
},
{
"compare not equal ints with eql",
@ -181,7 +181,7 @@ var binaryExprTestCases = []testCase{
return 0
}
`,
[]byte{},
big.NewInt(0),
},
{
"compare not equal ints with neq",

View file

@ -276,7 +276,7 @@ func TestIfUnaryInvert(t *testing.T) {
return 0
}
`
eval(t, src, []byte{})
eval(t, src, big.NewInt(0))
}
func TestAppendByte(t *testing.T) {

View file

@ -39,7 +39,7 @@ func TestNotAssignedFunctionCall(t *testing.T) {
// disable stack checks because it is hard right now
// to distinguish between simple function call traversal
// and the same traversal inside an assignment.
evalWithoutStackChecks(t, src, []byte{})
evalWithoutStackChecks(t, src, big.NewInt(0))
}
func TestMultipleFunctionCalls(t *testing.T) {

View file

@ -30,7 +30,7 @@ func TestGT(t *testing.T) {
return 0
}
`
eval(t, src, []byte{})
eval(t, src, big.NewInt(0))
}
func TestGTE(t *testing.T) {
@ -44,7 +44,7 @@ func TestGTE(t *testing.T) {
return 0
}
`
eval(t, src, []byte{})
eval(t, src, big.NewInt(0))
}
func TestLAND(t *testing.T) {
@ -89,5 +89,5 @@ func TestNestedIF(t *testing.T) {
return 0
}
`
eval(t, src, []byte{})
eval(t, src, big.NewInt(0))
}

View file

@ -32,7 +32,7 @@ func TestImportStruct(t *testing.T) {
return b.Y
}
`
eval(t, src, []byte{})
eval(t, src, big.NewInt(0))
}
func TestMultipleDirFileImport(t *testing.T) {

View file

@ -255,7 +255,7 @@ var structTestCases = []testCase{
return t.y
}
`,
[]byte{},
big.NewInt(0),
},
{
"test return struct from func",

View file

@ -11,6 +11,8 @@ import (
"math/big"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
@ -37,12 +39,12 @@ type (
vmUTExecutionContextState struct {
Instruction string `json:"nextInstruction"`
InstructionPointer int `json:"instructionPointer"`
AStack []vmUTStackItem `json:"altStack"`
EStack []vmUTStackItem `json:"evaluationStack"`
StaticFields []vmUTStackItem `json:"staticFields"`
}
vmUTExecutionEngineState struct {
State vmUTState `json:"state"`
State State `json:"state"`
ResultStack []vmUTStackItem `json:"resultStack"`
InvocationStack []vmUTExecutionContextState `json:"invocationStack"`
}
@ -59,8 +61,6 @@ type (
Result vmUTExecutionEngineState `json:"result"`
}
vmUTState State
vmUTStackItemType string
)
@ -73,25 +73,27 @@ type stackItemAUX struct {
}
const (
vmExecute vmUTActionType = "Execute"
vmStepInto vmUTActionType = "StepInto"
vmStepOut vmUTActionType = "StepOut"
vmStepOver vmUTActionType = "StepOver"
vmExecute vmUTActionType = "execute"
vmStepInto vmUTActionType = "stepinto"
vmStepOut vmUTActionType = "stepout"
vmStepOver vmUTActionType = "stepover"
typeArray vmUTStackItemType = "Array"
typeBoolean vmUTStackItemType = "Boolean"
typeByteArray vmUTStackItemType = "ByteArray"
typeInteger vmUTStackItemType = "Integer"
typeInterop vmUTStackItemType = "Interop"
typeMap vmUTStackItemType = "Map"
typeString vmUTStackItemType = "String"
typeStruct vmUTStackItemType = "Struct"
typeArray vmUTStackItemType = "array"
typeBoolean vmUTStackItemType = "boolean"
typeBuffer vmUTStackItemType = "buffer"
typeByteString vmUTStackItemType = "bytestring"
typeInteger vmUTStackItemType = "integer"
typeInterop vmUTStackItemType = "interop"
typeMap vmUTStackItemType = "map"
typeNull vmUTStackItemType = "null"
typePointer vmUTStackItemType = "pointer"
typeString vmUTStackItemType = "string"
typeStruct vmUTStackItemType = "struct"
testsDir = "testdata/neo-vm/tests/neo-vm.Tests/Tests/"
)
func TestUT(t *testing.T) {
t.Skip()
testsRan := false
err := filepath.Walk(testsDir, func(path string, info os.FileInfo, err error) error {
if !strings.HasSuffix(path, ".json") {
@ -110,7 +112,7 @@ func TestUT(t *testing.T) {
func getTestingInterop(id uint32) *InteropFuncPrice {
if id == binary.LittleEndian.Uint32([]byte{0x77, 0x77, 0x77, 0x77}) {
return &InteropFuncPrice{InteropFunc(func(v *VM) error {
v.estack.Push(&Element{value: (*InteropItem)(nil)})
v.estack.PushVal(&InteropItem{new(int)})
return nil
}), 0}
}
@ -121,12 +123,24 @@ func testFile(t *testing.T, filename string) {
data, err := ioutil.ReadFile(filename)
require.NoError(t, err)
// get rid of possible BOM
if len(data) > 2 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf {
data = data[3:]
}
if strings.HasSuffix(filename, "MEMCPY.json") {
return // FIXME not a valid JSON https://github.com/neo-project/neo-vm/issues/322
}
ut := new(vmUT)
require.NoError(t, json.Unmarshal(data, ut))
require.NoErrorf(t, json.Unmarshal(data, ut), "file: %s", filename)
t.Run(ut.Category+":"+ut.Name, func(t *testing.T) {
isRot := strings.HasSuffix(filename, "ROT.json")
for i := range ut.Tests {
test := ut.Tests[i]
if isRot && test.Name == "Without push" {
return // FIXME #927 single ROT is interpreted as PUSH1
}
t.Run(ut.Tests[i].Name, func(t *testing.T) {
prog := []byte(test.Script)
vm := load(prog)
@ -136,8 +150,8 @@ func testFile(t *testing.T, filename string) {
for i := range test.Steps {
execStep(t, vm, test.Steps[i])
result := test.Steps[i].Result
require.Equal(t, State(result.State), vm.state)
if result.State == vmUTState(faultState) { // do not compare stacks on fault
require.Equal(t, result.State, vm.state)
if result.State == faultState { // do not compare stacks on fault
continue
}
@ -146,10 +160,12 @@ func testFile(t *testing.T, filename string) {
ctx := vm.istack.Peek(i).Value().(*Context)
if ctx.nextip < len(ctx.prog) {
require.Equal(t, s.InstructionPointer, ctx.nextip)
require.Equal(t, s.Instruction, opcode.Opcode(ctx.prog[ctx.nextip]).String())
op, err := opcode.FromString(s.Instruction)
require.NoError(t, err)
require.Equal(t, op, opcode.Opcode(ctx.prog[ctx.nextip]))
}
compareStacks(t, s.EStack, vm.estack)
compareStacks(t, s.AStack, vm.astack)
compareSlots(t, s.StaticFields, vm.static)
}
}
@ -180,31 +196,47 @@ func compareItems(t *testing.T, a, b StackItem) {
default:
require.Fail(t, "wrong type")
}
case *PointerItem:
p, ok := b.(*PointerItem)
require.True(t, ok)
require.Equal(t, si.pos, p.pos) // there no script in test files
default:
require.Equal(t, a, b)
}
}
func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
compareItemArrays(t, expected, actual.Len(), func(i int) StackItem { return actual.Peek(i).Item() })
}
func compareSlots(t *testing.T, expected []vmUTStackItem, actual *Slot) {
if actual == nil && len(expected) == 0 {
return
}
require.NotNil(t, actual)
compareItemArrays(t, expected, actual.Size(), actual.Get)
}
func compareItemArrays(t *testing.T, expected []vmUTStackItem, n int, getItem func(i int) StackItem) {
if expected == nil {
return
}
require.Equal(t, len(expected), actual.Len())
require.Equal(t, len(expected), n)
for i, item := range expected {
e := actual.Peek(i)
require.NotNil(t, e)
it := getItem(i)
require.NotNil(t, it)
if item.Type == typeInterop {
require.IsType(t, (*InteropItem)(nil), e.value)
require.IsType(t, (*InteropItem)(nil), it)
continue
}
compareItems(t, item.toStackItem(), e.value)
compareItems(t, item.toStackItem(), it)
}
}
func (v *vmUTStackItem) toStackItem() StackItem {
switch v.Type {
switch v.Type.toLower() {
case typeArray:
items := v.Value.([]vmUTStackItem)
result := make([]StackItem, len(items))
@ -217,20 +249,19 @@ func (v *vmUTStackItem) toStackItem() StackItem {
case typeString:
panic("not implemented")
case typeMap:
items := v.Value.(map[string]vmUTStackItem)
result := NewMapItem()
for k, v := range items {
var item vmUTStackItem
_ = json.Unmarshal([]byte(`"`+k+`"`), &item)
result.Add(item.toStackItem(), v.toStackItem())
}
return result
return v.Value.(*MapItem)
case typeInterop:
panic("not implemented")
case typeByteArray:
case typeByteString:
return &ByteArrayItem{
v.Value.([]byte),
}
case typeBuffer:
return &BufferItem{v.Value.([]byte)}
case typePointer:
return NewPointerItem(v.Value.(int), nil)
case typeNull:
return NullItem{}
case typeBoolean:
return &BoolItem{
v.Value.(bool),
@ -249,14 +280,14 @@ func (v *vmUTStackItem) toStackItem() StackItem {
value: result,
}
default:
panic("invalid type")
panic(fmt.Sprintf("invalid type: %s", v.Type))
}
}
func execStep(t *testing.T, v *VM, step vmUTStep) {
for i, a := range step.Actions {
var err error
switch a {
switch a.toLower() {
case vmExecute:
err = v.Run()
case vmStepInto:
@ -276,30 +307,65 @@ func execStep(t *testing.T, v *VM, step vmUTStep) {
}
}
func (v *vmUTState) UnmarshalJSON(data []byte) error {
switch s := string(data); s {
case `"Break"`:
*v = vmUTState(breakState)
case `"Fault"`:
*v = vmUTState(faultState)
case `"Halt"`:
*v = vmUTState(haltState)
default:
panic(fmt.Sprintf("invalid state: %s", s))
func jsonStringToInteger(s string) StackItem {
b, err := decodeHex(s)
if err == nil {
return NewBigIntegerItem(new(big.Int).SetBytes(b))
}
return nil
}
func (v vmUTStackItemType) toLower() vmUTStackItemType {
return vmUTStackItemType(strings.ToLower(string(v)))
}
func (v *vmUTScript) UnmarshalJSON(data []byte) error {
b, err := decodeBytes(data)
if err != nil {
var ops []string
if err := json.Unmarshal(data, &ops); err != nil {
return err
}
*v = vmUTScript(b)
var script []byte
for i := range ops {
if b, ok := decodeSingle(ops[i]); ok {
script = append(script, b...)
} else {
const regex = `(?P<hex>(?:0x)?[0-9a-zA-Z]+)\*(?P<num>[0-9]+)`
re := regexp.MustCompile(regex)
ss := re.FindStringSubmatch(ops[i])
if len(ss) != 3 {
return fmt.Errorf("invalid script part: %s", ops[i])
}
b, ok := decodeSingle(ss[1])
if !ok {
return fmt.Errorf("invalid script part: %s", ops[i])
}
num, err := strconv.Atoi(ss[2])
if err != nil {
return fmt.Errorf("invalid script part: %s", ops[i])
}
for i := 0; i < num; i++ {
script = append(script, b...)
}
}
}
*v = script
return nil
}
func decodeSingle(s string) ([]byte, bool) {
if op, err := opcode.FromString(s); err == nil {
return []byte{byte(op)}, true
}
b, err := decodeHex(s)
return b, err == nil
}
func (v vmUTActionType) toLower() vmUTActionType {
return vmUTActionType(strings.ToLower(string(v)))
}
func (v *vmUTActionType) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, (*string)(v))
}
@ -312,14 +378,14 @@ func (v *vmUTStackItem) UnmarshalJSON(data []byte) error {
v.Type = si.Type
switch si.Type {
switch typ := si.Type.toLower(); typ {
case typeArray, typeStruct:
var a []vmUTStackItem
if err := json.Unmarshal(si.Value, &a); err != nil {
return err
}
v.Value = a
case typeInteger:
case typeInteger, typePointer:
num := new(big.Int)
var a int64
var s string
@ -330,27 +396,57 @@ func (v *vmUTStackItem) UnmarshalJSON(data []byte) error {
} else {
panic(fmt.Sprintf("invalid integer: %v", si.Value))
}
v.Value = num
if typ == typePointer {
v.Value = int(num.Int64())
} else {
v.Value = num
}
case typeBoolean:
var b bool
if err := json.Unmarshal(si.Value, &b); err != nil {
return err
}
v.Value = b
case typeByteArray:
case typeByteString, typeBuffer:
b, err := decodeBytes(si.Value)
if err != nil {
return err
}
v.Value = b
case typeInterop:
case typeInterop, typeNull:
v.Value = nil
case typeMap:
var m map[string]vmUTStackItem
if err := json.Unmarshal(si.Value, &m); err != nil {
return err
// we want to have the same order as in test file, so a custom decoder is used
d := json.NewDecoder(bytes.NewReader(si.Value))
if tok, err := d.Token(); err != nil || tok != json.Delim('{') {
return fmt.Errorf("invalid map start")
}
v.Value = m
result := NewMapItem()
for {
tok, err := d.Token()
if err != nil {
return err
} else if tok == json.Delim('}') {
break
}
key, ok := tok.(string)
if !ok {
return fmt.Errorf("string expected in map key")
}
var it vmUTStackItem
if err := d.Decode(&it); err != nil {
return fmt.Errorf("can't decode map value: %v", err)
}
item := jsonStringToInteger(key)
if item == nil {
return fmt.Errorf("can't unmarshal StackItem %s", key)
}
result.Add(item, it.toStackItem())
}
v.Value = result
case typeString:
panic("not implemented")
default:
@ -366,12 +462,18 @@ func decodeBytes(data []byte) ([]byte, error) {
return []byte{}, nil
}
hdata := data[3 : len(data)-1]
if b, err := hex.DecodeString(string(hdata)); err == nil {
data = data[1 : len(data)-1] // strip quotes
if b, err := decodeHex(string(data)); err == nil {
return b, nil
}
data = data[1 : len(data)-1]
r := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(data))
return ioutil.ReadAll(r)
}
func decodeHex(s string) ([]byte, error) {
if strings.HasPrefix(s, "0x") {
s = s[2:]
}
return hex.DecodeString(s)
}

View file

@ -0,0 +1,20 @@
package opcode
import "errors"
var stringToOpcode = make(map[string]Opcode)
func init() {
for i := 0; i < 255; i++ {
op := Opcode(i)
stringToOpcode[op.String()] = op
}
}
// FromString converts string representation to and opcode itself.
func FromString(s string) (Opcode, error) {
if op, ok := stringToOpcode[s]; ok {
return op, nil
}
return 0, errors.New("invalid opcode")
}

View file

@ -46,25 +46,25 @@ const (
// Flow control
NOP Opcode = 0x21
JMP Opcode = 0x22
JMPL Opcode = 0x23
JMPL Opcode = 0x23 // JMP_L
JMPIF Opcode = 0x24
JMPIFL Opcode = 0x25
JMPIFL Opcode = 0x25 // JMPIF_L
JMPIFNOT Opcode = 0x26
JMPIFNOTL Opcode = 0x27
JMPIFNOTL Opcode = 0x27 // JMPIFNOT_L
JMPEQ Opcode = 0x28
JMPEQL Opcode = 0x29
JMPEQL Opcode = 0x29 // JMPEQ_L
JMPNE Opcode = 0x2A
JMPNEL Opcode = 0x2B
JMPNEL Opcode = 0x2B // JMPNE_L
JMPGT Opcode = 0x2C
JMPGTL Opcode = 0x2D
JMPGTL Opcode = 0x2D // JMPGT_L
JMPGE Opcode = 0x2E
JMPGEL Opcode = 0x2F
JMPGEL Opcode = 0x2F // JMPGE_L
JMPLT Opcode = 0x30
JMPLTL Opcode = 0x31
JMPLTL Opcode = 0x31 // JMPLT_L
JMPLE Opcode = 0x32
JMPLEL Opcode = 0x33
JMPLEL Opcode = 0x33 // JMPLE_L
CALL Opcode = 0x34
CALLL Opcode = 0x35
CALLL Opcode = 0x35 // CALL_L
CALLA Opcode = 0x36
// Exceptions
@ -86,8 +86,8 @@ const (
PICK Opcode = 0x4D
TUCK Opcode = 0x4E
SWAP Opcode = 0x50
OLDPUSH1 Opcode = 0x51 // FIXME remove #927
ROT Opcode = 0x51
OLDPUSH1 Opcode = 0x51 // FIXME remove #927
ROLL Opcode = 0x52
REVERSE3 Opcode = 0x53
REVERSE4 Opcode = 0x54
@ -193,7 +193,7 @@ const (
UNPACK Opcode = 0xC1
NEWARRAY0 Opcode = 0xC2
NEWARRAY Opcode = 0xC3
NEWARRAYT Opcode = 0xC4
NEWARRAYT Opcode = 0xC4 // NEWARRAY_T
NEWSTRUCT0 Opcode = 0xC5
NEWSTRUCT Opcode = 0xC6
NEWMAP Opcode = 0xC8

View file

@ -1,4 +1,4 @@
// Code generated by "stringer -type Opcode"; DO NOT EDIT.
// Code generated by "stringer -type Opcode -linecomment"; DO NOT EDIT.
package opcode
@ -76,8 +76,8 @@ func _() {
_ = x[PICK-77]
_ = x[TUCK-78]
_ = x[SWAP-80]
_ = x[OLDPUSH1-81]
_ = x[ROT-81]
_ = x[OLDPUSH1-81]
_ = x[ROLL-82]
_ = x[REVERSE3-83]
_ = x[REVERSE4-84]
@ -192,7 +192,7 @@ func _() {
_ = x[CONVERT-219]
}
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPROTROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAY_TNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
var _Opcode_map = map[Opcode]string{
0: _Opcode_name[0:8],
@ -226,154 +226,154 @@ var _Opcode_map = map[Opcode]string{
32: _Opcode_name[187:193],
33: _Opcode_name[193:196],
34: _Opcode_name[196:199],
35: _Opcode_name[199:203],
36: _Opcode_name[203:208],
37: _Opcode_name[208:214],
38: _Opcode_name[214:222],
39: _Opcode_name[222:231],
40: _Opcode_name[231:236],
41: _Opcode_name[236:242],
42: _Opcode_name[242:247],
43: _Opcode_name[247:253],
44: _Opcode_name[253:258],
45: _Opcode_name[258:264],
46: _Opcode_name[264:269],
47: _Opcode_name[269:275],
48: _Opcode_name[275:280],
49: _Opcode_name[280:286],
50: _Opcode_name[286:291],
51: _Opcode_name[291:297],
52: _Opcode_name[297:301],
53: _Opcode_name[301:306],
54: _Opcode_name[306:311],
55: _Opcode_name[311:316],
56: _Opcode_name[316:322],
58: _Opcode_name[322:327],
64: _Opcode_name[327:330],
65: _Opcode_name[330:337],
67: _Opcode_name[337:342],
69: _Opcode_name[342:346],
70: _Opcode_name[346:349],
72: _Opcode_name[349:354],
73: _Opcode_name[354:359],
74: _Opcode_name[359:362],
75: _Opcode_name[362:366],
77: _Opcode_name[366:370],
78: _Opcode_name[370:374],
80: _Opcode_name[374:378],
81: _Opcode_name[378:386],
82: _Opcode_name[386:390],
83: _Opcode_name[390:398],
84: _Opcode_name[398:406],
85: _Opcode_name[406:414],
86: _Opcode_name[414:423],
87: _Opcode_name[423:431],
88: _Opcode_name[431:438],
89: _Opcode_name[438:445],
90: _Opcode_name[445:452],
91: _Opcode_name[452:459],
92: _Opcode_name[459:466],
93: _Opcode_name[466:473],
94: _Opcode_name[473:480],
95: _Opcode_name[480:486],
96: _Opcode_name[486:493],
97: _Opcode_name[493:500],
98: _Opcode_name[500:507],
99: _Opcode_name[507:514],
100: _Opcode_name[514:521],
101: _Opcode_name[521:528],
102: _Opcode_name[528:535],
103: _Opcode_name[535:541],
104: _Opcode_name[541:547],
105: _Opcode_name[547:553],
106: _Opcode_name[553:559],
107: _Opcode_name[559:565],
108: _Opcode_name[565:571],
109: _Opcode_name[571:577],
110: _Opcode_name[577:583],
111: _Opcode_name[583:588],
112: _Opcode_name[588:594],
113: _Opcode_name[594:600],
114: _Opcode_name[600:606],
115: _Opcode_name[606:612],
116: _Opcode_name[612:618],
117: _Opcode_name[618:624],
118: _Opcode_name[624:630],
119: _Opcode_name[630:635],
120: _Opcode_name[635:641],
121: _Opcode_name[641:647],
122: _Opcode_name[647:653],
123: _Opcode_name[653:659],
124: _Opcode_name[659:665],
125: _Opcode_name[665:671],
126: _Opcode_name[671:677],
127: _Opcode_name[677:682],
128: _Opcode_name[682:688],
129: _Opcode_name[688:694],
130: _Opcode_name[694:700],
131: _Opcode_name[700:706],
132: _Opcode_name[706:712],
133: _Opcode_name[712:718],
134: _Opcode_name[718:724],
135: _Opcode_name[724:729],
136: _Opcode_name[729:738],
137: _Opcode_name[738:744],
139: _Opcode_name[744:747],
140: _Opcode_name[747:753],
141: _Opcode_name[753:757],
142: _Opcode_name[757:762],
144: _Opcode_name[762:768],
145: _Opcode_name[768:771],
146: _Opcode_name[771:773],
147: _Opcode_name[773:776],
151: _Opcode_name[776:781],
152: _Opcode_name[781:789],
153: _Opcode_name[789:793],
154: _Opcode_name[793:796],
155: _Opcode_name[796:802],
156: _Opcode_name[802:805],
157: _Opcode_name[805:808],
158: _Opcode_name[808:811],
159: _Opcode_name[811:814],
160: _Opcode_name[814:817],
161: _Opcode_name[817:820],
162: _Opcode_name[820:823],
168: _Opcode_name[823:826],
169: _Opcode_name[826:829],
170: _Opcode_name[829:832],
171: _Opcode_name[832:839],
172: _Opcode_name[839:845],
177: _Opcode_name[845:847],
179: _Opcode_name[847:855],
180: _Opcode_name[855:866],
181: _Opcode_name[866:868],
182: _Opcode_name[868:871],
183: _Opcode_name[871:873],
184: _Opcode_name[873:876],
185: _Opcode_name[876:879],
186: _Opcode_name[879:882],
187: _Opcode_name[882:888],
192: _Opcode_name[888:892],
193: _Opcode_name[892:898],
194: _Opcode_name[898:907],
195: _Opcode_name[907:915],
196: _Opcode_name[915:924],
197: _Opcode_name[924:934],
198: _Opcode_name[934:943],
200: _Opcode_name[943:949],
202: _Opcode_name[949:953],
203: _Opcode_name[953:959],
204: _Opcode_name[959:963],
205: _Opcode_name[963:969],
206: _Opcode_name[969:977],
207: _Opcode_name[977:983],
208: _Opcode_name[983:990],
209: _Opcode_name[990:1002],
210: _Opcode_name[1002:1008],
211: _Opcode_name[1008:1018],
216: _Opcode_name[1018:1024],
217: _Opcode_name[1024:1030],
219: _Opcode_name[1030:1037],
35: _Opcode_name[199:204],
36: _Opcode_name[204:209],
37: _Opcode_name[209:216],
38: _Opcode_name[216:224],
39: _Opcode_name[224:234],
40: _Opcode_name[234:239],
41: _Opcode_name[239:246],
42: _Opcode_name[246:251],
43: _Opcode_name[251:258],
44: _Opcode_name[258:263],
45: _Opcode_name[263:270],
46: _Opcode_name[270:275],
47: _Opcode_name[275:282],
48: _Opcode_name[282:287],
49: _Opcode_name[287:294],
50: _Opcode_name[294:299],
51: _Opcode_name[299:306],
52: _Opcode_name[306:310],
53: _Opcode_name[310:316],
54: _Opcode_name[316:321],
55: _Opcode_name[321:326],
56: _Opcode_name[326:332],
58: _Opcode_name[332:337],
64: _Opcode_name[337:340],
65: _Opcode_name[340:347],
67: _Opcode_name[347:352],
69: _Opcode_name[352:356],
70: _Opcode_name[356:359],
72: _Opcode_name[359:364],
73: _Opcode_name[364:369],
74: _Opcode_name[369:372],
75: _Opcode_name[372:376],
77: _Opcode_name[376:380],
78: _Opcode_name[380:384],
80: _Opcode_name[384:388],
81: _Opcode_name[388:391],
82: _Opcode_name[391:395],
83: _Opcode_name[395:403],
84: _Opcode_name[403:411],
85: _Opcode_name[411:419],
86: _Opcode_name[419:428],
87: _Opcode_name[428:436],
88: _Opcode_name[436:443],
89: _Opcode_name[443:450],
90: _Opcode_name[450:457],
91: _Opcode_name[457:464],
92: _Opcode_name[464:471],
93: _Opcode_name[471:478],
94: _Opcode_name[478:485],
95: _Opcode_name[485:491],
96: _Opcode_name[491:498],
97: _Opcode_name[498:505],
98: _Opcode_name[505:512],
99: _Opcode_name[512:519],
100: _Opcode_name[519:526],
101: _Opcode_name[526:533],
102: _Opcode_name[533:540],
103: _Opcode_name[540:546],
104: _Opcode_name[546:552],
105: _Opcode_name[552:558],
106: _Opcode_name[558:564],
107: _Opcode_name[564:570],
108: _Opcode_name[570:576],
109: _Opcode_name[576:582],
110: _Opcode_name[582:588],
111: _Opcode_name[588:593],
112: _Opcode_name[593:599],
113: _Opcode_name[599:605],
114: _Opcode_name[605:611],
115: _Opcode_name[611:617],
116: _Opcode_name[617:623],
117: _Opcode_name[623:629],
118: _Opcode_name[629:635],
119: _Opcode_name[635:640],
120: _Opcode_name[640:646],
121: _Opcode_name[646:652],
122: _Opcode_name[652:658],
123: _Opcode_name[658:664],
124: _Opcode_name[664:670],
125: _Opcode_name[670:676],
126: _Opcode_name[676:682],
127: _Opcode_name[682:687],
128: _Opcode_name[687:693],
129: _Opcode_name[693:699],
130: _Opcode_name[699:705],
131: _Opcode_name[705:711],
132: _Opcode_name[711:717],
133: _Opcode_name[717:723],
134: _Opcode_name[723:729],
135: _Opcode_name[729:734],
136: _Opcode_name[734:743],
137: _Opcode_name[743:749],
139: _Opcode_name[749:752],
140: _Opcode_name[752:758],
141: _Opcode_name[758:762],
142: _Opcode_name[762:767],
144: _Opcode_name[767:773],
145: _Opcode_name[773:776],
146: _Opcode_name[776:778],
147: _Opcode_name[778:781],
151: _Opcode_name[781:786],
152: _Opcode_name[786:794],
153: _Opcode_name[794:798],
154: _Opcode_name[798:801],
155: _Opcode_name[801:807],
156: _Opcode_name[807:810],
157: _Opcode_name[810:813],
158: _Opcode_name[813:816],
159: _Opcode_name[816:819],
160: _Opcode_name[819:822],
161: _Opcode_name[822:825],
162: _Opcode_name[825:828],
168: _Opcode_name[828:831],
169: _Opcode_name[831:834],
170: _Opcode_name[834:837],
171: _Opcode_name[837:844],
172: _Opcode_name[844:850],
177: _Opcode_name[850:852],
179: _Opcode_name[852:860],
180: _Opcode_name[860:871],
181: _Opcode_name[871:873],
182: _Opcode_name[873:876],
183: _Opcode_name[876:878],
184: _Opcode_name[878:881],
185: _Opcode_name[881:884],
186: _Opcode_name[884:887],
187: _Opcode_name[887:893],
192: _Opcode_name[893:897],
193: _Opcode_name[897:903],
194: _Opcode_name[903:912],
195: _Opcode_name[912:920],
196: _Opcode_name[920:930],
197: _Opcode_name[930:940],
198: _Opcode_name[940:949],
200: _Opcode_name[949:955],
202: _Opcode_name[955:959],
203: _Opcode_name[959:965],
204: _Opcode_name[965:969],
205: _Opcode_name[969:975],
206: _Opcode_name[975:983],
207: _Opcode_name[983:989],
208: _Opcode_name[989:996],
209: _Opcode_name[996:1008],
210: _Opcode_name[1008:1014],
211: _Opcode_name[1014:1024],
216: _Opcode_name[1024:1030],
217: _Opcode_name[1030:1036],
219: _Opcode_name[1036:1043],
}
func (i Opcode) String() string {

View file

@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Nothing more to test here, really.
@ -18,3 +19,12 @@ func TestStringer(t *testing.T) {
assert.Equal(t, s, o.String())
}
}
func TestFromString(t *testing.T) {
_, err := FromString("abcdef")
require.Error(t, err)
op, err := FromString(MUL.String())
require.NoError(t, err)
require.Equal(t, MUL, op)
}

View file

@ -225,7 +225,9 @@ func (i *StructItem) Convert(typ StackItemType) (StackItem, error) {
case StructT:
return i, nil
case ArrayT:
return NewArrayItem(i.value), nil
arr := make([]StackItem, len(i.value))
copy(arr, i.value)
return NewArrayItem(arr), nil
case BooleanT:
return NewBoolItem(i.Bool()), nil
default:
@ -641,7 +643,9 @@ func (i *ArrayItem) Convert(typ StackItemType) (StackItem, error) {
case ArrayT:
return i, nil
case StructT:
return NewStructItem(i.value), nil
arr := make([]StackItem, len(i.value))
copy(arr, i.value)
return NewStructItem(arr), nil
case BooleanT:
return NewBoolItem(i.Bool()), nil
default:

View file

@ -338,7 +338,7 @@ func (v *VM) Run() error {
// check for breakpoint before executing the next instruction
ctx := v.Context()
if ctx != nil && ctx.atBreakPoint() {
v.state |= breakState
v.state = breakState
}
switch {
case v.state.HasFlag(faultState):
@ -376,7 +376,7 @@ func (v *VM) StepInto() error {
ctx := v.Context()
if ctx == nil {
v.state |= haltState
v.state = haltState
}
if v.HasStopped() {
@ -518,17 +518,14 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
}
switch op {
case opcode.PUSHM1, opcode.PUSH1, opcode.PUSH2, opcode.PUSH3,
case opcode.PUSHM1, opcode.PUSH0, opcode.PUSH1, opcode.PUSH2, opcode.PUSH3,
opcode.PUSH4, opcode.PUSH5, opcode.PUSH6, opcode.PUSH7,
opcode.PUSH8, opcode.PUSH9, opcode.PUSH10, opcode.PUSH11,
opcode.PUSH12, opcode.PUSH13, opcode.PUSH14, opcode.PUSH15,
opcode.PUSH16:
val := int(op) - int(opcode.PUSH1) + 1
val := int(op) - int(opcode.PUSH0)
v.estack.PushVal(val)
case opcode.PUSH0:
v.estack.PushVal([]byte{})
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
v.estack.PushVal(parameter)
@ -697,7 +694,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
}
s := v.estack.Pop().Bytes()
if t := len(s); l > t {
l = t
panic("size is too big")
}
v.estack.PushVal(NewBufferItem(s[:l]))
@ -984,46 +981,28 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
case opcode.NEWARRAY, opcode.NEWARRAYT:
item := v.estack.Pop()
switch t := item.value.(type) {
case *StructItem:
arr := make([]StackItem, len(t.value))
copy(arr, t.value)
v.estack.PushVal(&ArrayItem{arr})
case *ArrayItem:
v.estack.PushVal(t)
default:
n := item.BigInt().Int64()
if n > MaxArraySize {
panic("too long array")
}
typ := BooleanT
if op == opcode.NEWARRAYT {
typ = StackItemType(parameter[0])
}
items := makeArrayOfType(int(n), typ)
v.estack.PushVal(&ArrayItem{items})
n := item.BigInt().Int64()
if n > MaxArraySize {
panic("too long array")
}
typ := AnyT
if op == opcode.NEWARRAYT {
typ = StackItemType(parameter[0])
}
items := makeArrayOfType(int(n), typ)
v.estack.PushVal(&ArrayItem{items})
case opcode.NEWSTRUCT0:
v.estack.PushVal(&StructItem{[]StackItem{}})
case opcode.NEWSTRUCT:
item := v.estack.Pop()
switch t := item.value.(type) {
case *ArrayItem:
arr := make([]StackItem, len(t.value))
copy(arr, t.value)
v.estack.PushVal(&StructItem{arr})
case *StructItem:
v.estack.PushVal(t)
default:
n := item.BigInt().Int64()
if n > MaxArraySize {
panic("too long struct")
}
items := makeArrayOfType(int(n), BooleanT)
v.estack.PushVal(&StructItem{items})
n := item.BigInt().Int64()
if n > MaxArraySize {
panic("too long struct")
}
items := makeArrayOfType(int(n), AnyT)
v.estack.PushVal(&StructItem{items})
case opcode.APPEND:
itemElem := v.estack.Pop()

View file

@ -372,7 +372,7 @@ func appendBigStruct(size uint16) []opcode.Opcode {
return append(prog,
opcode.INITSSLOT, 1,
opcode.PUSHINT16, opcode.Opcode(size), opcode.Opcode(size>>8), // LE
opcode.PACK, opcode.NEWSTRUCT,
opcode.PACK, opcode.CONVERT, opcode.Opcode(StructT),
opcode.STSFLD0, opcode.LDSFLD0,
opcode.DUP,
opcode.PUSH0, opcode.NEWARRAY,
@ -401,20 +401,19 @@ func TestStackLimit(t *testing.T) {
{opcode.NEWARRAY, 3}, // array + 2 items
{opcode.STSFLD0, 3},
{opcode.LDSFLD0, 4},
{opcode.NEWSTRUCT, 6}, // all items are copied
{opcode.NEWMAP, 7},
{opcode.DUP, 8},
{opcode.PUSH2, 9},
{opcode.LDSFLD0, 10},
{opcode.SETITEM, 8}, // -3 items and 1 new element in map
{opcode.DUP, 9},
{opcode.PUSH2, 10},
{opcode.LDSFLD0, 11},
{opcode.SETITEM, 8}, // -3 items and no new elements in map
{opcode.DUP, 9},
{opcode.PUSH2, 10},
{opcode.REMOVE, 7}, // as we have right after NEWMAP
{opcode.DROP, 6}, // DROP map with no elements
{opcode.NEWMAP, 5},
{opcode.DUP, 6},
{opcode.PUSH2, 7},
{opcode.LDSFLD0, 8},
{opcode.SETITEM, 6}, // -3 items and 1 new element in map
{opcode.DUP, 7},
{opcode.PUSH2, 8},
{opcode.LDSFLD0, 9},
{opcode.SETITEM, 6}, // -3 items and no new elements in map
{opcode.DUP, 7},
{opcode.PUSH2, 8},
{opcode.REMOVE, 5}, // as we have right after NEWMAP
{opcode.DROP, 4}, // DROP map with no elements
}
prog := make([]opcode.Opcode, len(expected)+2)
@ -1188,45 +1187,37 @@ func TestNEWARRAYArray(t *testing.T) {
prog := makeProgram(opcode.NEWARRAY)
t.Run("ByteArray", getTestFuncForVM(prog, NewArrayItem([]StackItem{}), []byte{}))
t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1))
t.Run("Integer", getTestFuncForVM(prog, []StackItem{NewBoolItem(false)}, 1))
arr := []StackItem{makeStackItem(42)}
t.Run("Array", getTestFuncForVM(prog, arr, arr))
t.Run("Struct", getTestFuncForVM(prog, arr, NewStructItem(arr)))
t.Run("Integer", getTestFuncForVM(prog, []StackItem{NullItem{}}, 1))
}
func testNEWARRAYIssue437(t *testing.T, i1, i2 opcode.Opcode, appended bool) {
func testNEWARRAYIssue437(t *testing.T, i1 opcode.Opcode, t2 StackItemType, appended bool) {
prog := makeProgram(
opcode.PUSH2, i1,
opcode.DUP, opcode.PUSH3, opcode.APPEND,
opcode.INITSSLOT, 1,
opcode.STSFLD0, opcode.LDSFLD0, i2,
opcode.STSFLD0, opcode.LDSFLD0, opcode.CONVERT, opcode.Opcode(t2),
opcode.DUP, opcode.PUSH4, opcode.APPEND,
opcode.LDSFLD0, opcode.PUSH5, opcode.APPEND)
vm := load(prog)
vm.Run()
arr := makeArrayOfType(4, BooleanT)
arr := makeArrayOfType(4, AnyT)
arr[2] = makeStackItem(3)
arr[3] = makeStackItem(4)
if appended {
arr = append(arr, makeStackItem(5))
}
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
if i2 == opcode.NEWARRAY {
assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value)
if t2 == ArrayT {
runWithArgs(t, prog, &ArrayItem{arr})
} else {
assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value)
runWithArgs(t, prog, &StructItem{arr})
}
}
func TestNEWARRAYIssue437(t *testing.T) {
t.Run("Array+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, opcode.NEWARRAY, true) })
t.Run("Struct+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, opcode.NEWSTRUCT, true) })
t.Run("Array+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, opcode.NEWSTRUCT, false) })
t.Run("Struct+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) })
t.Run("Array+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, ArrayT, true) })
t.Run("Struct+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, StructT, true) })
t.Run("Array+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, StructT, false) })
t.Run("Struct+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, ArrayT, false) })
}
func TestNEWARRAYT(t *testing.T) {
@ -1247,11 +1238,7 @@ func TestNEWSTRUCT(t *testing.T) {
prog := makeProgram(opcode.NEWSTRUCT)
t.Run("ByteArray", getTestFuncForVM(prog, NewStructItem([]StackItem{}), []byte{}))
t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1))
t.Run("Integer", getTestFuncForVM(prog, NewStructItem([]StackItem{NewBoolItem(false)}), 1))
arr := []StackItem{makeStackItem(42)}
t.Run("Array", getTestFuncForVM(prog, NewStructItem(arr), NewArrayItem(arr)))
t.Run("Struct", getTestFuncForVM(prog, NewStructItem(arr), NewStructItem(arr)))
t.Run("Integer", getTestFuncForVM(prog, NewStructItem([]StackItem{NullItem{}}), 1))
}
func TestAPPEND(t *testing.T) {
@ -1827,7 +1814,7 @@ func TestLEFT(t *testing.T) {
t.Run("NoString", getTestFuncForVM(prog, nil, 2))
t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1))
t.Run("Good", getTestFuncForVM(prog, NewBufferItem([]byte("ab")), "abcdef", 2))
t.Run("GoodBigLen", getTestFuncForVM(prog, NewBufferItem([]byte("abcdef")), "abcdef", 8))
t.Run("BadBigLen", getTestFuncForVM(prog, nil, "abcdef", 8))
}
func TestRIGHT(t *testing.T) {
@ -1903,14 +1890,12 @@ func TestREVERSEITEMS(t *testing.T) {
t.Run("Buffer", getTestFuncForVM(prog, NewBufferItem([]byte{3, 2, 1}), NewBufferItem([]byte{1, 2, 3})))
}
func testREVERSEITEMSIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool) {
func testREVERSEITEMSIssue437(t *testing.T, i1 opcode.Opcode, t2 StackItemType, reversed bool) {
prog := makeProgram(
opcode.PUSH0, i1,
opcode.DUP, opcode.PUSH1, opcode.APPEND,
opcode.DUP, opcode.PUSH2, opcode.APPEND,
opcode.DUP, i2, opcode.REVERSEITEMS)
vm := load(prog)
vm.Run()
opcode.DUP, opcode.CONVERT, opcode.Opcode(t2), opcode.REVERSEITEMS)
arr := make([]StackItem, 2)
if reversed {
@ -1920,20 +1905,19 @@ func testREVERSEITEMSIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool)
arr[0] = makeStackItem(1)
arr[1] = makeStackItem(2)
}
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
if i1 == opcode.NEWARRAY {
assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value)
runWithArgs(t, prog, &ArrayItem{arr})
} else {
assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value)
runWithArgs(t, prog, &StructItem{arr})
}
}
func TestREVERSEITEMSIssue437(t *testing.T) {
t.Run("Array+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, opcode.NEWARRAY, true) })
t.Run("Struct+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, opcode.NEWSTRUCT, true) })
t.Run("Array+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, opcode.NEWSTRUCT, false) })
t.Run("Struct+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) })
t.Run("Array+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, ArrayT, true) })
t.Run("Struct+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, StructT, true) })
t.Run("Array+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, StructT, false) })
t.Run("Struct+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, ArrayT, false) })
}
func TestREVERSEITEMSGoodOneElem(t *testing.T) {
@ -2471,7 +2455,9 @@ func makeProgram(opcodes ...opcode.Opcode) []byte {
func load(prog []byte) *VM {
vm := New()
vm.LoadScript(prog)
if len(prog) != 0 {
vm.LoadScript(prog)
}
return vm
}