Merge pull request #394 from nspcc-dev/fix/json-tests-bugs
VM: fix some bugs from neo-vm JSON tests
This commit is contained in:
commit
0838948540
9 changed files with 323 additions and 64 deletions
|
@ -121,6 +121,8 @@ func (e *Element) Array() []StackItem {
|
||||||
switch t := e.value.(type) {
|
switch t := e.value.(type) {
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
return t.value
|
return t.value
|
||||||
|
case *StructItem:
|
||||||
|
return t.value
|
||||||
default:
|
default:
|
||||||
panic("element is not an array")
|
panic("element is not an array")
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(0),
|
[]byte{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple div",
|
"simple div",
|
||||||
|
@ -86,7 +86,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(0),
|
[]byte{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal strings with eql",
|
"compare equal strings with eql",
|
||||||
|
@ -128,7 +128,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(0),
|
[]byte{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal ints with eql",
|
"compare equal ints with eql",
|
||||||
|
@ -156,7 +156,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(0),
|
[]byte{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal ints with eql",
|
"compare not equal ints with eql",
|
||||||
|
@ -170,7 +170,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(0),
|
[]byte{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal ints with neq",
|
"compare not equal ints with neq",
|
||||||
|
|
|
@ -275,7 +275,7 @@ func TestIfUnaryInvert(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, big.NewInt(0))
|
eval(t, src, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppendByte(t *testing.T) {
|
func TestAppendByte(t *testing.T) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ func TestNotAssignedFunctionCall(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, big.NewInt(0))
|
eval(t, src, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleFunctionCalls(t *testing.T) {
|
func TestMultipleFunctionCalls(t *testing.T) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestGT(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, big.NewInt(0))
|
eval(t, src, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGTE(t *testing.T) {
|
func TestGTE(t *testing.T) {
|
||||||
|
@ -44,7 +44,7 @@ func TestGTE(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, big.NewInt(0))
|
eval(t, src, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLAND(t *testing.T) {
|
func TestLAND(t *testing.T) {
|
||||||
|
@ -89,5 +89,5 @@ func TestNestedIF(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, big.NewInt(0))
|
eval(t, src, []byte{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func TestImportStruct(t *testing.T) {
|
||||||
return b.Y
|
return b.Y
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, big.NewInt(0))
|
eval(t, src, []byte{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleDirFileImport(t *testing.T) {
|
func TestMultipleDirFileImport(t *testing.T) {
|
||||||
|
|
|
@ -179,7 +179,7 @@ var structTestCases = []testCase{
|
||||||
return t.y
|
return t.y
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
big.NewInt(0),
|
[]byte{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"test return struct from func",
|
"test return struct from func",
|
||||||
|
@ -209,7 +209,7 @@ var structTestCases = []testCase{
|
||||||
vm.NewBigIntegerItem(1),
|
vm.NewBigIntegerItem(1),
|
||||||
vm.NewBigIntegerItem(2),
|
vm.NewBigIntegerItem(2),
|
||||||
vm.NewByteArrayItem([]byte("hello")),
|
vm.NewByteArrayItem([]byte("hello")),
|
||||||
vm.NewBigIntegerItem(0),
|
vm.NewByteArrayItem([]byte{}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
97
pkg/vm/vm.go
97
pkg/vm/vm.go
|
@ -257,7 +257,7 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
v.estack.PushVal(val)
|
v.estack.PushVal(val)
|
||||||
|
|
||||||
case PUSH0:
|
case PUSH0:
|
||||||
v.estack.PushVal(0)
|
v.estack.PushVal([]byte{})
|
||||||
|
|
||||||
case PUSHDATA1:
|
case PUSHDATA1:
|
||||||
n := ctx.readByte()
|
n := ctx.readByte()
|
||||||
|
@ -375,7 +375,7 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
|
|
||||||
case XTUCK:
|
case XTUCK:
|
||||||
n := int(v.estack.Pop().BigInt().Int64())
|
n := int(v.estack.Pop().BigInt().Int64())
|
||||||
if n < 0 {
|
if n <= 0 {
|
||||||
panic("XTUCK: invalid length")
|
panic("XTUCK: invalid length")
|
||||||
}
|
}
|
||||||
a := v.estack.Dup(0)
|
a := v.estack.Dup(0)
|
||||||
|
@ -388,21 +388,20 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
v.estack.InsertAt(a, n)
|
v.estack.InsertAt(a, n)
|
||||||
|
|
||||||
case ROT:
|
case ROT:
|
||||||
c := v.estack.Pop()
|
e := v.estack.RemoveAt(2)
|
||||||
b := v.estack.Pop()
|
if e == nil {
|
||||||
a := v.estack.Pop()
|
panic("no top-level element found")
|
||||||
|
}
|
||||||
v.estack.Push(b)
|
v.estack.Push(e)
|
||||||
v.estack.Push(c)
|
|
||||||
v.estack.Push(a)
|
|
||||||
|
|
||||||
case DEPTH:
|
case DEPTH:
|
||||||
v.estack.PushVal(v.estack.Len())
|
v.estack.PushVal(v.estack.Len())
|
||||||
|
|
||||||
case NIP:
|
case NIP:
|
||||||
elem := v.estack.Pop()
|
elem := v.estack.RemoveAt(1)
|
||||||
_ = v.estack.Pop()
|
if elem == nil {
|
||||||
v.estack.Push(elem)
|
panic("no second element found")
|
||||||
|
}
|
||||||
|
|
||||||
case OVER:
|
case OVER:
|
||||||
b := v.estack.Pop()
|
b := v.estack.Pop()
|
||||||
|
@ -441,11 +440,20 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case DROP:
|
case DROP:
|
||||||
|
if v.estack.Len() < 1 {
|
||||||
|
panic("stack is too small")
|
||||||
|
}
|
||||||
v.estack.Pop()
|
v.estack.Pop()
|
||||||
|
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
b := v.estack.Pop()
|
b := v.estack.Pop()
|
||||||
|
if b == nil {
|
||||||
|
panic("no top-level element found")
|
||||||
|
}
|
||||||
a := v.estack.Pop()
|
a := v.estack.Pop()
|
||||||
|
if a == nil {
|
||||||
|
panic("no second-to-the-top element found")
|
||||||
|
}
|
||||||
v.estack.PushVal(reflect.DeepEqual(a, b))
|
v.estack.PushVal(reflect.DeepEqual(a, b))
|
||||||
|
|
||||||
// Bit operations.
|
// Bit operations.
|
||||||
|
@ -497,11 +505,17 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
|
|
||||||
case SHL:
|
case SHL:
|
||||||
b := v.estack.Pop().BigInt()
|
b := v.estack.Pop().BigInt()
|
||||||
|
if b.Int64() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
a := v.estack.Pop().BigInt()
|
a := v.estack.Pop().BigInt()
|
||||||
v.estack.PushVal(new(big.Int).Lsh(a, uint(b.Int64())))
|
v.estack.PushVal(new(big.Int).Lsh(a, uint(b.Int64())))
|
||||||
|
|
||||||
case SHR:
|
case SHR:
|
||||||
b := v.estack.Pop().BigInt()
|
b := v.estack.Pop().BigInt()
|
||||||
|
if b.Int64() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
a := v.estack.Pop().BigInt()
|
a := v.estack.Pop().BigInt()
|
||||||
v.estack.PushVal(new(big.Int).Rsh(a, uint(b.Int64())))
|
v.estack.PushVal(new(big.Int).Rsh(a, uint(b.Int64())))
|
||||||
|
|
||||||
|
@ -601,31 +615,27 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
case NEWARRAY:
|
case NEWARRAY:
|
||||||
item := v.estack.Pop()
|
item := v.estack.Pop()
|
||||||
switch t := item.value.(type) {
|
switch t := item.value.(type) {
|
||||||
case *BigIntegerItem:
|
|
||||||
n := t.value.Int64()
|
|
||||||
items := make([]StackItem, n)
|
|
||||||
v.estack.PushVal(&ArrayItem{items})
|
|
||||||
case *StructItem:
|
case *StructItem:
|
||||||
v.estack.PushVal(&ArrayItem{t.value})
|
v.estack.PushVal(&ArrayItem{t.value})
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
v.estack.PushVal(t)
|
v.estack.PushVal(t)
|
||||||
default:
|
default:
|
||||||
panic("NEWARRAY: invalid operand")
|
n := item.BigInt()
|
||||||
|
items := makeArrayOfFalses(int(n.Int64()))
|
||||||
|
v.estack.PushVal(&ArrayItem{items})
|
||||||
}
|
}
|
||||||
|
|
||||||
case NEWSTRUCT:
|
case NEWSTRUCT:
|
||||||
item := v.estack.Pop()
|
item := v.estack.Pop()
|
||||||
switch t := item.value.(type) {
|
switch t := item.value.(type) {
|
||||||
case *BigIntegerItem:
|
|
||||||
n := t.value.Int64()
|
|
||||||
items := make([]StackItem, n)
|
|
||||||
v.estack.PushVal(&StructItem{items})
|
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
v.estack.PushVal(&StructItem{t.value})
|
v.estack.PushVal(&StructItem{t.value})
|
||||||
case *StructItem:
|
case *StructItem:
|
||||||
v.estack.PushVal(t)
|
v.estack.PushVal(t)
|
||||||
default:
|
default:
|
||||||
panic("NEWSTRUCT: invalid operand")
|
n := item.BigInt()
|
||||||
|
items := makeArrayOfFalses(int(n.Int64()))
|
||||||
|
v.estack.PushVal(&StructItem{items})
|
||||||
}
|
}
|
||||||
|
|
||||||
case APPEND:
|
case APPEND:
|
||||||
|
@ -683,7 +693,12 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
item := arr[index]
|
item := arr[index]
|
||||||
v.estack.PushVal(item)
|
v.estack.PushVal(item)
|
||||||
default:
|
default:
|
||||||
panic("PICKITEM: unknown type")
|
arr := obj.Bytes()
|
||||||
|
if index < 0 || index >= len(arr) {
|
||||||
|
panic("PICKITEM: invalid index")
|
||||||
|
}
|
||||||
|
item := arr[index]
|
||||||
|
v.estack.PushVal(int(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
case SETITEM:
|
case SETITEM:
|
||||||
|
@ -707,7 +722,7 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case REVERSE:
|
case REVERSE:
|
||||||
a := v.estack.Peek(0).Array()
|
a := v.estack.Pop().Array()
|
||||||
if len(a) > 1 {
|
if len(a) > 1 {
|
||||||
for i, j := 0, len(a)-1; i <= j; i, j = i+1, j-1 {
|
for i, j := 0, len(a)-1; i <= j; i, j = i+1, j-1 {
|
||||||
a[i], a[j] = a[j], a[i]
|
a[i], a[j] = a[j], a[i]
|
||||||
|
@ -715,10 +730,25 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
key := int(v.estack.Pop().BigInt().Int64())
|
key := int(v.estack.Pop().BigInt().Int64())
|
||||||
elem := v.estack.Peek(0)
|
elem := v.estack.Pop()
|
||||||
a := elem.Array()
|
switch t := elem.value.(type) {
|
||||||
|
case *ArrayItem:
|
||||||
|
a := t.value
|
||||||
|
if key < 0 || key >= len(a) {
|
||||||
|
panic("REMOVE: invalid index")
|
||||||
|
}
|
||||||
a = append(a[:key], a[key+1:]...)
|
a = append(a[:key], a[key+1:]...)
|
||||||
elem.value = makeStackItem(a)
|
t.value = a
|
||||||
|
case *StructItem:
|
||||||
|
a := t.value
|
||||||
|
if key < 0 || key >= len(a) {
|
||||||
|
panic("REMOVE: invalid index")
|
||||||
|
}
|
||||||
|
a = append(a[:key], a[key+1:]...)
|
||||||
|
t.value = a
|
||||||
|
default:
|
||||||
|
panic("REMOVE: invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
case ARRAYSIZE:
|
case ARRAYSIZE:
|
||||||
elem := v.estack.Pop()
|
elem := v.estack.Pop()
|
||||||
|
@ -735,10 +765,7 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
|
|
||||||
case SIZE:
|
case SIZE:
|
||||||
elem := v.estack.Pop()
|
elem := v.estack.Pop()
|
||||||
arr, ok := elem.value.Value().([]uint8)
|
arr := elem.Bytes()
|
||||||
if !ok {
|
|
||||||
panic("SIZE: item not of type []uint8")
|
|
||||||
}
|
|
||||||
v.estack.PushVal(len(arr))
|
v.estack.PushVal(len(arr))
|
||||||
|
|
||||||
case JMP, JMPIF, JMPIFNOT:
|
case JMP, JMPIF, JMPIFNOT:
|
||||||
|
@ -840,6 +867,14 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeArrayOfFalses(n int) []StackItem {
|
||||||
|
items := make([]StackItem, n)
|
||||||
|
for i := range items {
|
||||||
|
items[i] = &BoolItem{false}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetPrefix("NEO-GO-VM > ")
|
log.SetPrefix("NEO-GO-VM > ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
|
|
|
@ -283,6 +283,50 @@ func TestSub(t *testing.T) {
|
||||||
assert.Equal(t, int64(2), vm.estack.Pop().BigInt().Int64())
|
assert.Equal(t, int64(2), vm.estack.Pop().BigInt().Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSHRGood(t *testing.T) {
|
||||||
|
prog := makeProgram(SHR)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(4)
|
||||||
|
vm.estack.PushVal(2)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSHRZero(t *testing.T) {
|
||||||
|
prog := makeProgram(SHR)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{0, 1})
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSHLGood(t *testing.T) {
|
||||||
|
prog := makeProgram(SHL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(4)
|
||||||
|
vm.estack.PushVal(2)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(16), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSHLZero(t *testing.T) {
|
||||||
|
prog := makeProgram(SHL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{0, 1})
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestLT(t *testing.T) {
|
func TestLT(t *testing.T) {
|
||||||
prog := makeProgram(LT)
|
prog := makeProgram(LT)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -335,6 +379,32 @@ func TestDepth(t *testing.T) {
|
||||||
assert.Equal(t, int64(3), vm.estack.Pop().BigInt().Int64())
|
assert.Equal(t, int64(3), vm.estack.Pop().BigInt().Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEQUALNoArguments(t *testing.T) {
|
||||||
|
prog := makeProgram(EQUAL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEQUALBad1Argument(t *testing.T) {
|
||||||
|
prog := makeProgram(EQUAL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEQUALGoodInteger(t *testing.T) {
|
||||||
|
prog := makeProgram(EQUAL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(5)
|
||||||
|
vm.estack.PushVal(5)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNumEqual(t *testing.T) {
|
func TestNumEqual(t *testing.T) {
|
||||||
prog := makeProgram(NUMEQUAL)
|
prog := makeProgram(NUMEQUAL)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -371,7 +441,7 @@ func TestNEWARRAYInteger(t *testing.T) {
|
||||||
vm.Run()
|
vm.Run()
|
||||||
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
assert.Equal(t, &ArrayItem{make([]StackItem, 1)}, vm.estack.Pop().value)
|
assert.Equal(t, &ArrayItem{[]StackItem{makeStackItem(false)}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWARRAYStruct(t *testing.T) {
|
func TestNEWARRAYStruct(t *testing.T) {
|
||||||
|
@ -396,12 +466,14 @@ func TestNEWARRAYArray(t *testing.T) {
|
||||||
assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value)
|
assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWARRAYWrongType(t *testing.T) {
|
func TestNEWARRAYByteArray(t *testing.T) {
|
||||||
prog := makeProgram(NEWARRAY)
|
prog := makeProgram(NEWARRAY)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
vm.estack.Push(NewElement([]byte{}))
|
vm.estack.PushVal([]byte{})
|
||||||
vm.Run()
|
vm.Run()
|
||||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &ArrayItem{[]StackItem{}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWSTRUCTInteger(t *testing.T) {
|
func TestNEWSTRUCTInteger(t *testing.T) {
|
||||||
|
@ -411,7 +483,7 @@ func TestNEWSTRUCTInteger(t *testing.T) {
|
||||||
vm.Run()
|
vm.Run()
|
||||||
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
assert.Equal(t, &StructItem{make([]StackItem, 1)}, vm.estack.Pop().value)
|
assert.Equal(t, &StructItem{[]StackItem{makeStackItem(false)}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWSTRUCTArray(t *testing.T) {
|
func TestNEWSTRUCTArray(t *testing.T) {
|
||||||
|
@ -436,12 +508,14 @@ func TestNEWSTRUCTStruct(t *testing.T) {
|
||||||
assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value)
|
assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWSTRUCTWrongType(t *testing.T) {
|
func TestNEWSTRUCTByteArray(t *testing.T) {
|
||||||
prog := makeProgram(NEWSTRUCT)
|
prog := makeProgram(NEWSTRUCT)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
vm.estack.Push(NewElement([]byte{}))
|
vm.estack.PushVal([]byte{})
|
||||||
vm.Run()
|
vm.Run()
|
||||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &StructItem{[]StackItem{}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPPENDArray(t *testing.T) {
|
func TestAPPENDArray(t *testing.T) {
|
||||||
|
@ -488,6 +562,64 @@ func TestAPPENDWrongType(t *testing.T) {
|
||||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPICKITEMBadIndex(t *testing.T) {
|
||||||
|
prog := makeProgram(PICKITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPICKITEMArray(t *testing.T) {
|
||||||
|
prog := makeProgram(PICKITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{makeStackItem(1), makeStackItem(2)})
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPICKITEMByteArray(t *testing.T) {
|
||||||
|
prog := makeProgram(PICKITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{1, 2})
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIZENoArgument(t *testing.T) {
|
||||||
|
prog := makeProgram(SIZE)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIZEByteArray(t *testing.T) {
|
||||||
|
prog := makeProgram(SIZE)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]byte{0, 1})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSIZEBool(t *testing.T) {
|
||||||
|
prog := makeProgram(SIZE)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(false)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSIGNNoArgument(t *testing.T) {
|
func TestSIGNNoArgument(t *testing.T) {
|
||||||
prog := makeProgram(SIGN)
|
prog := makeProgram(SIGN)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -633,6 +765,29 @@ func TestPICKgood(t *testing.T) {
|
||||||
assert.Equal(t, int64(result), vm.estack.Pop().BigInt().Int64())
|
assert.Equal(t, int64(result), vm.estack.Pop().BigInt().Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestROTBad(t *testing.T) {
|
||||||
|
prog := makeProgram(ROT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.estack.PushVal(2)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestROTGood(t *testing.T) {
|
||||||
|
prog := makeProgram(ROT)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.estack.PushVal(2)
|
||||||
|
vm.estack.PushVal(3)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 3, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
|
assert.Equal(t, makeStackItem(3), vm.estack.Pop().value)
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestXTUCKbadNoitem(t *testing.T) {
|
func TestXTUCKbadNoitem(t *testing.T) {
|
||||||
prog := makeProgram(XTUCK)
|
prog := makeProgram(XTUCK)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -658,6 +813,15 @@ func TestXTUCKbadNegative(t *testing.T) {
|
||||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestXTUCKbadZero(t *testing.T) {
|
||||||
|
prog := makeProgram(XTUCK)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.estack.PushVal(0)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
func TestXTUCKgood(t *testing.T) {
|
func TestXTUCKgood(t *testing.T) {
|
||||||
prog := makeProgram(XTUCK)
|
prog := makeProgram(XTUCK)
|
||||||
topelement := 5
|
topelement := 5
|
||||||
|
@ -745,6 +909,41 @@ func TestOVERgood(t *testing.T) {
|
||||||
assert.Equal(t, 3, vm.estack.Len())
|
assert.Equal(t, 3, vm.estack.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNIPBadNoItem(t *testing.T) {
|
||||||
|
prog := makeProgram(NIP)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNIPGood(t *testing.T) {
|
||||||
|
prog := makeProgram(NIP)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.estack.PushVal(2)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDROPBadNoItem(t *testing.T) {
|
||||||
|
prog := makeProgram(DROP)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDROPGood(t *testing.T) {
|
||||||
|
prog := makeProgram(DROP)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 0, vm.estack.Len())
|
||||||
|
}
|
||||||
|
|
||||||
func TestXDROPbadNoitem(t *testing.T) {
|
func TestXDROPbadNoitem(t *testing.T) {
|
||||||
prog := makeProgram(XDROP)
|
prog := makeProgram(XDROP)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -1118,7 +1317,7 @@ func TestREVERSEBadNotArray(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestREVERSEGoodOneElem(t *testing.T) {
|
func TestREVERSEGoodOneElem(t *testing.T) {
|
||||||
prog := makeProgram(REVERSE)
|
prog := makeProgram(DUP, REVERSE)
|
||||||
elements := []int{22}
|
elements := []int{22}
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
vm.estack.PushVal(1)
|
vm.estack.PushVal(1)
|
||||||
|
@ -1132,13 +1331,42 @@ func TestREVERSEGoodOneElem(t *testing.T) {
|
||||||
assert.Equal(t, int64(elements[0]), e.Int64())
|
assert.Equal(t, int64(elements[0]), e.Int64())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestREVERSEGoodStruct(t *testing.T) {
|
||||||
|
eodd := []int{22, 34, 42, 55, 81}
|
||||||
|
even := []int{22, 34, 42, 55, 81, 99}
|
||||||
|
eall := [][]int{eodd, even}
|
||||||
|
|
||||||
|
for _, elements := range eall {
|
||||||
|
prog := makeProgram(DUP, REVERSE)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
|
||||||
|
arr := make([]StackItem, len(elements))
|
||||||
|
for i := range elements {
|
||||||
|
arr[i] = makeStackItem(elements[i])
|
||||||
|
}
|
||||||
|
vm.estack.Push(&Element{value: &StructItem{arr}})
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
|
assert.Equal(t, 2, vm.estack.Len())
|
||||||
|
a := vm.estack.Peek(0).Array()
|
||||||
|
assert.Equal(t, len(elements), len(a))
|
||||||
|
for k, v := range elements {
|
||||||
|
e := a[len(a)-1-k].Value().(*big.Int)
|
||||||
|
assert.Equal(t, int64(v), e.Int64())
|
||||||
|
}
|
||||||
|
assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestREVERSEGood(t *testing.T) {
|
func TestREVERSEGood(t *testing.T) {
|
||||||
eodd := []int{22, 34, 42, 55, 81}
|
eodd := []int{22, 34, 42, 55, 81}
|
||||||
even := []int{22, 34, 42, 55, 81, 99}
|
even := []int{22, 34, 42, 55, 81, 99}
|
||||||
eall := [][]int{eodd, even}
|
eall := [][]int{eodd, even}
|
||||||
|
|
||||||
for _, elements := range eall {
|
for _, elements := range eall {
|
||||||
prog := makeProgram(REVERSE)
|
prog := makeProgram(DUP, REVERSE)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
vm.estack.PushVal(1)
|
vm.estack.PushVal(1)
|
||||||
vm.estack.PushVal(elements)
|
vm.estack.PushVal(elements)
|
||||||
|
@ -1190,23 +1418,17 @@ func TestREMOVEBadIndex(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestREMOVEGood(t *testing.T) {
|
func TestREMOVEGood(t *testing.T) {
|
||||||
prog := makeProgram(REMOVE)
|
prog := makeProgram(DUP, PUSH2, REMOVE)
|
||||||
elements := []int{22, 34, 42, 55, 81}
|
elements := []int{22, 34, 42, 55, 81}
|
||||||
reselements := []int{22, 34, 55, 81}
|
reselements := []int{22, 34, 55, 81}
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
vm.estack.PushVal(1)
|
vm.estack.PushVal(1)
|
||||||
vm.estack.PushVal(elements)
|
vm.estack.PushVal(elements)
|
||||||
vm.estack.PushVal(2)
|
|
||||||
vm.Run()
|
vm.Run()
|
||||||
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||||
assert.Equal(t, 2, vm.estack.Len())
|
assert.Equal(t, 2, vm.estack.Len())
|
||||||
a := vm.estack.Peek(0).Array()
|
assert.Equal(t, makeStackItem(reselements), vm.estack.Pop().value)
|
||||||
assert.Equal(t, len(reselements), len(a))
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
for k, v := range reselements {
|
|
||||||
e := a[k].Value().(*big.Int)
|
|
||||||
assert.Equal(t, int64(v), e.Int64())
|
|
||||||
}
|
|
||||||
assert.Equal(t, int64(1), vm.estack.Peek(1).BigInt().Int64())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeProgram(opcodes ...Instruction) []byte {
|
func makeProgram(opcodes ...Instruction) []byte {
|
||||||
|
|
Loading…
Reference in a new issue