forked from TrueCloudLab/neoneo-go
Merge pull request #412 from nspcc-dev/feature/map
VM: implement maps, closes #359.
This commit is contained in:
commit
ab8d9c59d6
3 changed files with 452 additions and 24 deletions
|
@ -19,10 +19,18 @@ func makeStackItem(v interface{}) StackItem {
|
||||||
return &BigIntegerItem{
|
return &BigIntegerItem{
|
||||||
value: big.NewInt(int64(val)),
|
value: big.NewInt(int64(val)),
|
||||||
}
|
}
|
||||||
|
case int64:
|
||||||
|
return &BigIntegerItem{
|
||||||
|
value: big.NewInt(val),
|
||||||
|
}
|
||||||
case []byte:
|
case []byte:
|
||||||
return &ByteArrayItem{
|
return &ByteArrayItem{
|
||||||
value: val,
|
value: val,
|
||||||
}
|
}
|
||||||
|
case string:
|
||||||
|
return &ByteArrayItem{
|
||||||
|
value: []byte(val),
|
||||||
|
}
|
||||||
case bool:
|
case bool:
|
||||||
return &BoolItem{
|
return &BoolItem{
|
||||||
value: val,
|
value: val,
|
||||||
|
@ -193,3 +201,50 @@ func (i *ArrayItem) MarshalJSON() ([]byte, error) {
|
||||||
func (i *ArrayItem) String() string {
|
func (i *ArrayItem) String() string {
|
||||||
return "Array"
|
return "Array"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MapItem represents Map object.
|
||||||
|
type MapItem struct {
|
||||||
|
value map[interface{}]StackItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMapItem returns new MapItem object.
|
||||||
|
func NewMapItem() *MapItem {
|
||||||
|
return &MapItem{
|
||||||
|
value: make(map[interface{}]StackItem),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements StackItem interface.
|
||||||
|
func (i *MapItem) Value() interface{} {
|
||||||
|
return i.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
|
func (i *MapItem) String() string {
|
||||||
|
return "Map"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has checks if map has specified key.
|
||||||
|
func (i *MapItem) Has(key StackItem) (ok bool) {
|
||||||
|
_, ok = i.value[toMapKey(key)]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds key-value pair to the map.
|
||||||
|
func (i *MapItem) Add(key, value StackItem) {
|
||||||
|
i.value[toMapKey(key)] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// toMapKey converts StackItem so that it can be used as a map key.
|
||||||
|
func toMapKey(key StackItem) interface{} {
|
||||||
|
switch t := key.(type) {
|
||||||
|
case *BoolItem:
|
||||||
|
return t.value
|
||||||
|
case *BigIntegerItem:
|
||||||
|
return t.value.Int64()
|
||||||
|
case *ByteArrayItem:
|
||||||
|
return string(t.value)
|
||||||
|
default:
|
||||||
|
panic("wrong key type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
149
pkg/vm/vm.go
149
pkg/vm/vm.go
|
@ -478,6 +478,11 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
v.estack.PushVal(ta == tb)
|
v.estack.PushVal(ta == tb)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
} else if ma, ok := a.value.(*MapItem); ok {
|
||||||
|
if mb, ok := b.value.(*MapItem); ok {
|
||||||
|
v.estack.PushVal(ma == mb)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
v.estack.PushVal(reflect.DeepEqual(a, b))
|
v.estack.PushVal(reflect.DeepEqual(a, b))
|
||||||
|
|
||||||
|
@ -665,10 +670,7 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
itemElem := v.estack.Pop()
|
itemElem := v.estack.Pop()
|
||||||
arrElem := v.estack.Pop()
|
arrElem := v.estack.Pop()
|
||||||
|
|
||||||
val := itemElem.value
|
val := cloneIfStruct(itemElem.value)
|
||||||
if t, ok := itemElem.value.(*StructItem); ok {
|
|
||||||
val = t.Clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := arrElem.value.(type) {
|
switch t := arrElem.value.(type) {
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
|
@ -705,11 +707,11 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
v.estack.PushVal(l)
|
v.estack.PushVal(l)
|
||||||
|
|
||||||
case PICKITEM:
|
case PICKITEM:
|
||||||
var (
|
key := v.estack.Pop()
|
||||||
key = v.estack.Pop()
|
validateMapKey(key)
|
||||||
obj = v.estack.Pop()
|
|
||||||
index = int(key.BigInt().Int64())
|
obj := v.estack.Pop()
|
||||||
)
|
index := int(key.BigInt().Int64())
|
||||||
|
|
||||||
switch t := obj.value.(type) {
|
switch t := obj.value.(type) {
|
||||||
// Struct and Array items have their underlying value as []StackItem.
|
// Struct and Array items have their underlying value as []StackItem.
|
||||||
|
@ -720,6 +722,12 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
item := arr[index]
|
item := arr[index]
|
||||||
v.estack.PushVal(item)
|
v.estack.PushVal(item)
|
||||||
|
case *MapItem:
|
||||||
|
if !t.Has(key.value) {
|
||||||
|
panic("invalid key")
|
||||||
|
}
|
||||||
|
k := toMapKey(key.value)
|
||||||
|
v.estack.Push(&Element{value: t.value[k]})
|
||||||
default:
|
default:
|
||||||
arr := obj.Bytes()
|
arr := obj.Bytes()
|
||||||
if index < 0 || index >= len(arr) {
|
if index < 0 || index >= len(arr) {
|
||||||
|
@ -730,21 +738,24 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case SETITEM:
|
case SETITEM:
|
||||||
var (
|
item := v.estack.Pop().value
|
||||||
item = v.estack.Pop().value
|
key := v.estack.Pop()
|
||||||
key = v.estack.Pop()
|
validateMapKey(key)
|
||||||
obj = v.estack.Pop()
|
|
||||||
index = int(key.BigInt().Int64())
|
obj := v.estack.Pop()
|
||||||
)
|
|
||||||
|
|
||||||
switch t := obj.value.(type) {
|
switch t := obj.value.(type) {
|
||||||
// Struct and Array items have their underlying value as []StackItem.
|
// Struct and Array items have their underlying value as []StackItem.
|
||||||
case *ArrayItem, *StructItem:
|
case *ArrayItem, *StructItem:
|
||||||
arr := t.Value().([]StackItem)
|
arr := t.Value().([]StackItem)
|
||||||
|
index := int(key.BigInt().Int64())
|
||||||
if index < 0 || index >= len(arr) {
|
if index < 0 || index >= len(arr) {
|
||||||
panic("SETITEM: invalid index")
|
panic("SETITEM: invalid index")
|
||||||
}
|
}
|
||||||
arr[index] = item
|
arr[index] = item
|
||||||
|
case *MapItem:
|
||||||
|
t.Add(key.value, item)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("SETITEM: invalid item type %s", t))
|
panic(fmt.Sprintf("SETITEM: invalid item type %s", t))
|
||||||
}
|
}
|
||||||
|
@ -757,23 +768,31 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
key := int(v.estack.Pop().BigInt().Int64())
|
key := v.estack.Pop()
|
||||||
|
validateMapKey(key)
|
||||||
|
|
||||||
elem := v.estack.Pop()
|
elem := v.estack.Pop()
|
||||||
switch t := elem.value.(type) {
|
switch t := elem.value.(type) {
|
||||||
case *ArrayItem:
|
case *ArrayItem:
|
||||||
a := t.value
|
a := t.value
|
||||||
if key < 0 || key >= len(a) {
|
k := int(key.BigInt().Int64())
|
||||||
|
if k < 0 || k >= len(a) {
|
||||||
panic("REMOVE: invalid index")
|
panic("REMOVE: invalid index")
|
||||||
}
|
}
|
||||||
a = append(a[:key], a[key+1:]...)
|
a = append(a[:k], a[k+1:]...)
|
||||||
t.value = a
|
t.value = a
|
||||||
case *StructItem:
|
case *StructItem:
|
||||||
a := t.value
|
a := t.value
|
||||||
if key < 0 || key >= len(a) {
|
k := int(key.BigInt().Int64())
|
||||||
|
if k < 0 || k >= len(a) {
|
||||||
panic("REMOVE: invalid index")
|
panic("REMOVE: invalid index")
|
||||||
}
|
}
|
||||||
a = append(a[:key], a[key+1:]...)
|
a = append(a[:k], a[k+1:]...)
|
||||||
t.value = a
|
t.value = a
|
||||||
|
case *MapItem:
|
||||||
|
m := t.value
|
||||||
|
k := toMapKey(key.value)
|
||||||
|
delete(m, k)
|
||||||
default:
|
default:
|
||||||
panic("REMOVE: invalid type")
|
panic("REMOVE: invalid type")
|
||||||
}
|
}
|
||||||
|
@ -785,10 +804,10 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
switch t := elem.value.Value().(type) {
|
switch t := elem.value.Value().(type) {
|
||||||
case []StackItem:
|
case []StackItem:
|
||||||
v.estack.PushVal(len(t))
|
v.estack.PushVal(len(t))
|
||||||
case []uint8:
|
case map[interface{}]StackItem:
|
||||||
v.estack.PushVal(len(t))
|
v.estack.PushVal(len(t))
|
||||||
default:
|
default:
|
||||||
panic("ARRAYSIZE: item not of type []StackItem")
|
v.estack.PushVal(len(elem.Bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
case SIZE:
|
case SIZE:
|
||||||
|
@ -912,8 +931,71 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
v.estack.PushVal(sigok)
|
v.estack.PushVal(sigok)
|
||||||
|
|
||||||
case NEWMAP, HASKEY, KEYS, VALUES:
|
case NEWMAP:
|
||||||
panic("unimplemented")
|
v.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
|
||||||
|
case KEYS:
|
||||||
|
item := v.estack.Pop()
|
||||||
|
if item == nil {
|
||||||
|
panic("no argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
m, ok := item.value.(*MapItem)
|
||||||
|
if !ok {
|
||||||
|
panic("not a Map")
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := make([]StackItem, 0, len(m.value))
|
||||||
|
for k := range m.value {
|
||||||
|
arr = append(arr, makeStackItem(k))
|
||||||
|
}
|
||||||
|
v.estack.PushVal(arr)
|
||||||
|
|
||||||
|
case VALUES:
|
||||||
|
item := v.estack.Pop()
|
||||||
|
if item == nil {
|
||||||
|
panic("no argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
var arr []StackItem
|
||||||
|
switch t := item.value.(type) {
|
||||||
|
case *ArrayItem, *StructItem:
|
||||||
|
src := t.Value().([]StackItem)
|
||||||
|
arr = make([]StackItem, len(src))
|
||||||
|
for i := range src {
|
||||||
|
arr[i] = cloneIfStruct(src[i])
|
||||||
|
}
|
||||||
|
case *MapItem:
|
||||||
|
arr = make([]StackItem, 0, len(t.value))
|
||||||
|
for k := range t.value {
|
||||||
|
arr = append(arr, cloneIfStruct(t.value[k]))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("not a Map, Array or Struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
v.estack.PushVal(arr)
|
||||||
|
|
||||||
|
case HASKEY:
|
||||||
|
key := v.estack.Pop()
|
||||||
|
validateMapKey(key)
|
||||||
|
|
||||||
|
c := v.estack.Pop()
|
||||||
|
if c == nil {
|
||||||
|
panic("no value found")
|
||||||
|
}
|
||||||
|
switch t := c.value.(type) {
|
||||||
|
case *ArrayItem, *StructItem:
|
||||||
|
index := key.BigInt().Int64()
|
||||||
|
if index < 0 {
|
||||||
|
panic("negative index")
|
||||||
|
}
|
||||||
|
v.estack.PushVal(index < int64(len(c.Array())))
|
||||||
|
case *MapItem:
|
||||||
|
v.estack.PushVal(t.Has(key.value))
|
||||||
|
default:
|
||||||
|
panic("wrong collection type")
|
||||||
|
}
|
||||||
|
|
||||||
// Cryptographic operations.
|
// Cryptographic operations.
|
||||||
case SHA1:
|
case SHA1:
|
||||||
|
@ -950,6 +1032,15 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cloneIfStruct(item StackItem) StackItem {
|
||||||
|
switch it := item.(type) {
|
||||||
|
case *StructItem:
|
||||||
|
return it.Clone()
|
||||||
|
default:
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func makeArrayOfFalses(n int) []StackItem {
|
func makeArrayOfFalses(n int) []StackItem {
|
||||||
items := make([]StackItem, n)
|
items := make([]StackItem, n)
|
||||||
for i := range items {
|
for i := range items {
|
||||||
|
@ -958,6 +1049,16 @@ func makeArrayOfFalses(n int) []StackItem {
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateMapKey(key *Element) {
|
||||||
|
if key == nil {
|
||||||
|
panic("no key found")
|
||||||
|
}
|
||||||
|
switch key.value.(type) {
|
||||||
|
case *ArrayItem, *StructItem, *MapItem:
|
||||||
|
panic("key can't be a collection")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetPrefix("NEO-GO-VM > ")
|
log.SetPrefix("NEO-GO-VM > ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
|
|
|
@ -446,6 +446,27 @@ func TestEQUALArrayFalse(t *testing.T) {
|
||||||
assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value)
|
assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEQUALMapTrue(t *testing.T) {
|
||||||
|
prog := makeProgram(DUP, EQUAL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BoolItem{true}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEQUALMapFalse(t *testing.T) {
|
||||||
|
prog := makeProgram(EQUAL)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
vm.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &BoolItem{false}, 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)
|
||||||
|
@ -646,6 +667,39 @@ func TestPICKITEMByteArray(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPICKITEMMap(t *testing.T) {
|
||||||
|
prog := makeProgram(PICKITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(3))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(makeStackItem(5))
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(3), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSETITEMMap(t *testing.T) {
|
||||||
|
prog := makeProgram(SETITEM, PICKITEM)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(3))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(5)
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(5)
|
||||||
|
vm.estack.PushVal([]byte{0, 1})
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem([]byte{0, 1}), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSIZENoArgument(t *testing.T) {
|
func TestSIZENoArgument(t *testing.T) {
|
||||||
prog := makeProgram(SIZE)
|
prog := makeProgram(SIZE)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -673,6 +727,207 @@ func TestSIZEBool(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestARRAYSIZEArray(t *testing.T) {
|
||||||
|
prog := makeProgram(ARRAYSIZE)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{
|
||||||
|
makeStackItem(1),
|
||||||
|
makeStackItem([]byte{}),
|
||||||
|
})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestARRAYSIZEMap(t *testing.T) {
|
||||||
|
prog := makeProgram(ARRAYSIZE)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(6))
|
||||||
|
m.Add(makeStackItem([]byte{0, 1}), makeStackItem(6))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(2), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKEYSMap(t *testing.T) {
|
||||||
|
prog := makeProgram(KEYS)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(6))
|
||||||
|
m.Add(makeStackItem([]byte{0, 1}), makeStackItem(6))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
|
||||||
|
top := vm.estack.Pop().value.(*ArrayItem)
|
||||||
|
assert.Equal(t, 2, len(top.value))
|
||||||
|
assert.Contains(t, top.value, makeStackItem(5))
|
||||||
|
assert.Contains(t, top.value, makeStackItem([]byte{0, 1}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKEYSNoArgument(t *testing.T) {
|
||||||
|
prog := makeProgram(KEYS)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKEYSWrongType(t *testing.T) {
|
||||||
|
prog := makeProgram(KEYS)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVALUESMap(t *testing.T) {
|
||||||
|
prog := makeProgram(VALUES)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem([]byte{2, 3}))
|
||||||
|
m.Add(makeStackItem([]byte{0, 1}), makeStackItem([]StackItem{}))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
|
||||||
|
top := vm.estack.Pop().value.(*ArrayItem)
|
||||||
|
assert.Equal(t, 2, len(top.value))
|
||||||
|
assert.Contains(t, top.value, makeStackItem([]byte{2, 3}))
|
||||||
|
assert.Contains(t, top.value, makeStackItem([]StackItem{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVALUESArray(t *testing.T) {
|
||||||
|
prog := makeProgram(VALUES)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{makeStackItem(4)})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, &ArrayItem{[]StackItem{makeStackItem(4)}}, vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVALUESNoArgument(t *testing.T) {
|
||||||
|
prog := makeProgram(VALUES)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVALUESWrongType(t *testing.T) {
|
||||||
|
prog := makeProgram(VALUES)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(5)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYArrayTrue(t *testing.T) {
|
||||||
|
prog := makeProgram(PUSH5, NEWARRAY, PUSH4, HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(true), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYArrayFalse(t *testing.T) {
|
||||||
|
prog := makeProgram(PUSH5, NEWARRAY, PUSH5, HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYStructTrue(t *testing.T) {
|
||||||
|
prog := makeProgram(PUSH5, NEWSTRUCT, PUSH4, HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(true), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYStructFalse(t *testing.T) {
|
||||||
|
prog := makeProgram(PUSH5, NEWSTRUCT, PUSH5, HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYMapTrue(t *testing.T) {
|
||||||
|
prog := makeProgram(HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(6))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(5)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(true), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYMapFalse(t *testing.T) {
|
||||||
|
prog := makeProgram(HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(6))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(6)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYNoArguments(t *testing.T) {
|
||||||
|
prog := makeProgram(HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEY1Argument(t *testing.T) {
|
||||||
|
prog := makeProgram(HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYWrongKeyType(t *testing.T) {
|
||||||
|
prog := makeProgram(HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
vm.estack.PushVal([]StackItem{})
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHASKEYWrongCollectionType(t *testing.T) {
|
||||||
|
prog := makeProgram(HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
vm.estack.PushVal(1)
|
||||||
|
vm.estack.PushVal(2)
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, true, vm.HasFailed())
|
||||||
|
}
|
||||||
|
|
||||||
func TestSIGNNoArgument(t *testing.T) {
|
func TestSIGNNoArgument(t *testing.T) {
|
||||||
prog := makeProgram(SIGN)
|
prog := makeProgram(SIGN)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -1490,6 +1745,23 @@ func TestREMOVEGood(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestREMOVEMap(t *testing.T) {
|
||||||
|
prog := makeProgram(REMOVE, PUSH5, HASKEY)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
m := NewMapItem()
|
||||||
|
m.Add(makeStackItem(5), makeStackItem(3))
|
||||||
|
m.Add(makeStackItem([]byte{0, 1}), makeStackItem([]byte{2, 3}))
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.Push(&Element{value: m})
|
||||||
|
vm.estack.PushVal(makeStackItem(5))
|
||||||
|
|
||||||
|
vm.Run()
|
||||||
|
assert.Equal(t, false, vm.HasFailed())
|
||||||
|
assert.Equal(t, 1, vm.estack.Len())
|
||||||
|
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCHECKSIGNoArgs(t *testing.T) {
|
func TestCHECKSIGNoArgs(t *testing.T) {
|
||||||
prog := makeProgram(CHECKSIG)
|
prog := makeProgram(CHECKSIG)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
Loading…
Reference in a new issue