diff --git a/pkg/vm/csharp-interop-test/push/pushbytes1.json b/pkg/vm/csharp-interop-test/push/pushbytes1.json new file mode 100644 index 000000000..474944423 --- /dev/null +++ b/pkg/vm/csharp-interop-test/push/pushbytes1.json @@ -0,0 +1,81 @@ +{ + "category": "Push", + "name": "PUSHBYTES1", + "tests": + [ + { + "name": "Good definition", + "script": "0x0100", + "steps": + [ + { + "actions": + [ + "StepInto" + ], + "result": + { + "state": "Break", + "invocationStack": + [ + { + "scriptHash": "0xFBC22D517F38E7612798ECE8E5957CF6C41D8CAF", + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": + [ + { + "type": "ByteArray", + "value": "0x00" + } + ] + } + ] + } + }, + { + "actions": + [ + "StepInto" + ], + "result": + { + "state": "Halt", + "resultStack": + [ + { + "type": "ByteArray", + "value": "0x00" + } + ] + } + } + ] + }, + { + "name": "Wrong definition (without enough length)", + "script": "0x01", + "steps": + [ + { + "actions": + [ + "StepInto" + ], + "result": + { + "state": "Fault", + "invocationStack": + [ + { + "scriptHash": "0xC51B66BCED5E4491001BD702669770DCCF440982", + "instructionPointer": 1, + "nextInstruction": "RET" + } + ] + } + } + ] + } + ] +} \ No newline at end of file diff --git a/pkg/vm/csharp-interop-test/readme.md b/pkg/vm/csharp-interop-test/readme.md new file mode 100644 index 000000000..0e457c7c0 --- /dev/null +++ b/pkg/vm/csharp-interop-test/readme.md @@ -0,0 +1,6 @@ +## Package VM Interop + + +This package will use the tests in the neo-vm repo to test interopabilty + + diff --git a/pkg/vm/csharp-interop-test/testStruct.go b/pkg/vm/csharp-interop-test/testStruct.go new file mode 100644 index 000000000..c0da0112b --- /dev/null +++ b/pkg/vm/csharp-interop-test/testStruct.go @@ -0,0 +1,26 @@ +package csharpinterop + +// VMUnitTest is a struct for capturing the fields in the json files +type VMUnitTest struct { + Category string `json:"category"` + Name string `json:"name"` + Tests []struct { + Name string `json:"name"` + Script string `json:"script"` + Steps []struct { + Actions []string `json:"actions"` + Result struct { + State string `json:"state"` + InvocationStack []struct { + ScriptHash string `json:"scriptHash"` + InstructionPointer int `json:"instructionPointer"` + NextInstruction string `json:"nextInstruction"` + EvaluationStack []struct { + Type string `json:"type"` + Value string `json:"value"` + } `json:"evaluationStack"` + } `json:"invocationStack"` + } `json:"result"` + } `json:"steps"` + } `json:"tests"` +} diff --git a/pkg/vm/stack/Int.go b/pkg/vm/stack/Int.go index 08e800e36..12b77aa53 100644 --- a/pkg/vm/stack/Int.go +++ b/pkg/vm/stack/Int.go @@ -115,6 +115,20 @@ func (i *Int) Abs() (*Int, error) { return b, nil } +// Lte returns a bool value from the comparison of two integers, a and b. +// value is true if a <= b. +// value is false if a > b. +func (i *Int) Lte(s *Int) bool { + return i.Value().Cmp(s.Value()) != 1 +} + +// Gte returns a bool value from the comparison of two integers, a and b. +// value is true if a >= b. +// value is false if a < b. +func (i *Int) Gte(s *Int) bool { + return i.Value().Cmp(s.Value()) != -1 +} + // Lt returns a bool value from the comparison of two integers, a and b. // value is true if a < b. // value is false if a >= b. @@ -133,4 +147,28 @@ func (i *Int) Gt(s *Int) bool { func (i *Int) Hash() (string, error) { data := fmt.Sprintf("%T %v", i, i.Value()) return KeyGenerator([]byte(data)) + + // Min returns the mininum between two integers. +func Min(a *Int, b *Int) *Int { + if a.Lte(b) { + return a + } + return b + +} + +// Max returns the maximun between two integers. +func Max(a *Int, b *Int) *Int { + if a.Gte(b) { + return a + } + return b +} + +// Within returns a bool whose value is true +// iff the value of the integer i is within the specified +// range [a,b) (left-inclusive). +func (i *Int) Within(a *Int, b *Int) bool { + // i >= a && i < b + return i.Gte(a) && i.Lt(b) } diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index d50609462..50868960a 100644 --- a/pkg/vm/vm_ops.go +++ b/pkg/vm/vm_ops.go @@ -5,12 +5,17 @@ import "github.com/CityOfZion/neo-go/pkg/vm/stack" type stackInfo func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) var opFunc = map[stack.Instruction]stackInfo{ + stack.MIN: Min, + stack.MAX: Max, + stack.WITHIN: Within, stack.NUMEQUAL: NumEqual, stack.NUMNOTEQUAL: NumNotEqual, stack.BOOLAND: BoolAnd, stack.BOOLOR: BoolOr, stack.LT: Lt, + stack.LTE: Lte, stack.GT: Gt, + stack.GTE: Gte, stack.SHR: Shr, stack.SHL: Shl, stack.INC: Inc, diff --git a/pkg/vm/vm_ops_maths.go b/pkg/vm/vm_ops_maths.go index e23a7a4a0..ab4b52f71 100644 --- a/pkg/vm/vm_ops_maths.go +++ b/pkg/vm/vm_ops_maths.go @@ -205,6 +205,54 @@ func NumNotEqual(op stack.Instruction, ctx *stack.Context, istack *stack.Invocat return NONE, nil } +// Min pops two integers, a and b, off of the stack and pushes an integer to the stack +// whose value is is the minum between a and b's value. +// Returns an error if either items cannot be casted to an integer +func Min(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + operandA, operandB, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res := stack.Min(operandA, operandB) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// Max pops two integers, a and b, off of the stack and pushes an integer to the stack +// whose value is is the maximum between a and b's value. +// Returns an error if either items cannot be casted to an integer +func Max(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + operandA, operandB, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res := stack.Max(operandA, operandB) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// Within pops three integers, a, b, and c off of the stack and pushes a boolean to the stack +// whose value is true iff c's value is within b's value (include) and a's value. +// Returns an error if at least one item cannot be casted to an boolean. +func Within(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + a, b, c, err := popThreeIntegers(ctx) + if err != nil { + return FAULT, err + } + res := stack.NewBoolean(c.Within(b, a)) + + ctx.Estack.Push(res) + + return NONE, nil +} + // Abs pops an integer off of the stack and pushes its absolute value onto the stack. // Returns an error if the popped value is not an integer or if the absolute value cannot be taken func Abs(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { @@ -317,17 +365,36 @@ func Negate(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, return NONE, nil } -func popTwoIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, error) { - operandA, err := ctx.Estack.PopInt() - if err != nil { - return nil, nil, err - } - operandB, err := ctx.Estack.PopInt() - if err != nil { - return nil, nil, err - } +// Lte pops two integers, a and b, off of the stack and pushes a boolean the stack +// whose value is true if a's value is less than or equal to b's value. +// Returns an error if either items cannot be casted to an integer +func Lte(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { - return operandA, operandB, nil + operandA, operandB, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res := operandB.Lte(operandA) + + ctx.Estack.Push(stack.NewBoolean(res)) + + return NONE, nil +} + +// Gte pops two integers, a and b, off of the stack and pushes a boolean the stack +// whose value is true if a's value is greated than or equal to b's value. +// Returns an error if either items cannot be casted to an integer +func Gte(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + operandA, operandB, err := popTwoIntegers(ctx) + if err != nil { + return FAULT, err + } + res := operandB.Gte(operandA) + + ctx.Estack.Push(stack.NewBoolean(res)) + + return NONE, nil } // Shl pops two integers, a and b, off of the stack and pushes an integer to the stack @@ -402,6 +469,36 @@ func Gt(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rsta return NONE, nil } +func popTwoIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, error) { + operandA, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, err + } + operandB, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, err + } + + return operandA, operandB, nil +} + +func popThreeIntegers(ctx *stack.Context) (*stack.Int, *stack.Int, *stack.Int, error) { + operandA, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, nil, err + } + operandB, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, nil, err + } + operandC, err := ctx.Estack.PopInt() + if err != nil { + return nil, nil, nil, err + } + + return operandA, operandB, operandC, nil +} + func popTwoByteArrays(ctx *stack.Context) (*stack.ByteArray, *stack.ByteArray, error) { // Pop first stack item and cast as byte array ba1, err := ctx.Estack.PopByteArray() diff --git a/pkg/vm/vm_ops_maths_test.go b/pkg/vm/vm_ops_maths_test.go index b8478f29b..14e8c88a3 100644 --- a/pkg/vm/vm_ops_maths_test.go +++ b/pkg/vm/vm_ops_maths_test.go @@ -13,9 +13,7 @@ func TestIncOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -26,9 +24,7 @@ func TestIncOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(21), item.Value().Int64()) } @@ -38,9 +34,7 @@ func TestDecOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -51,9 +45,7 @@ func TestDecOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(19), item.Value().Int64()) } @@ -63,13 +55,10 @@ func TestAddOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(23)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -80,9 +69,7 @@ func TestAddOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(43), item.Value().Int64()) @@ -93,13 +80,10 @@ func TestSubOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(30)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(40)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -110,9 +94,7 @@ func TestSubOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(-10), item.Value().Int64()) @@ -123,13 +105,10 @@ func TestDivOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(4)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -140,9 +119,7 @@ func TestDivOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(2), item.Value().Int64()) } @@ -152,13 +129,10 @@ func TestModOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(15)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(4)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -169,9 +143,7 @@ func TestModOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(3), item.Value().Int64()) } @@ -181,9 +153,7 @@ func TestNzOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -194,9 +164,7 @@ func TestNzOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -206,13 +174,10 @@ func TestMulOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -223,9 +188,7 @@ func TestMulOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(400), item.Value().Int64()) } @@ -235,9 +198,7 @@ func TestAbsOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(-20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -248,9 +209,7 @@ func TestAbsOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(20), item.Value().Int64()) } @@ -270,9 +229,7 @@ func TestNotOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -282,13 +239,10 @@ func TestNumEqual(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(6)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(6)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -299,9 +253,7 @@ func TestNumEqual(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -311,13 +263,10 @@ func TestNumNotEqual(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(5)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(6)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -328,9 +277,7 @@ func TestNumNotEqual(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } @@ -340,9 +287,7 @@ func TestSignOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(-20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -353,9 +298,7 @@ func TestSignOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(-1), item.Value().Int64()) } @@ -365,9 +308,7 @@ func TestNegateOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(-20)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a) @@ -378,25 +319,78 @@ func TestNegateOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(20), item.Value().Int64()) } +func TestLteOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + assert.Nil(t, err) + + b, err := stack.NewInt(big.NewInt(10)) + assert.Nil(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + // b is the first item pop. + // a is the second item pop. + // we perform a <= b and place + // the result on top of the evaluation + // stack + v.executeOp(stack.LTE, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopBoolean() + assert.Nil(t, err) + + assert.Equal(t, true, item.Value()) +} + +func TestGteOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + assert.Nil(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.Nil(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + // b is the first item pop. + // a is the second item pop. + // we perform a >= b and place + // the result on top of the evaluation + // stack + v.executeOp(stack.GTE, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopBoolean() + assert.Nil(t, err) + + assert.Equal(t, true, item.Value()) +} + func TestShlOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(2)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(3)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -412,9 +406,7 @@ func TestShlOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(16), item.Value().Int64()) } @@ -424,13 +416,10 @@ func TestShrOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) + b, err := stack.NewInt(big.NewInt(2)) - if err != nil { - t.Fail() - } + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -446,57 +435,51 @@ func TestShrOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopInt() - if err != nil { - t.Fail() - } + assert.Nil(t, err) assert.Equal(t, int64(2), item.Value().Int64()) } func TestBoolAndOp(t *testing.T) { - v := VM{} + v := VM{} - a := stack.NewBoolean(true) + a := stack.NewBoolean(true) b := stack.NewBoolean(true) - ctx := stack.NewContext([]byte{}) + ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) - v.executeOp(stack.BOOLAND, ctx) + v.executeOp(stack.BOOLAND, ctx) - // Stack should have one item + // Stack should have one item assert.Equal(t, 1, ctx.Estack.Len()) - item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + item, err := ctx.Estack.PopBoolean() + assert.Nil(t, err) - assert.Equal(t, true, item.Value()) + assert.Equal(t, true, item.Value()) } - func TestBoolOrOp(t *testing.T) { +func TestBoolOrOp(t *testing.T) { - v := VM{} + v := VM{} - a := stack.NewBoolean(false) + a := stack.NewBoolean(false) b := stack.NewBoolean(true) - ctx := stack.NewContext([]byte{}) + ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) - v.executeOp(stack.BOOLOR, ctx) + v.executeOp(stack.BOOLOR, ctx) - // Stack should have one item + // Stack should have one item assert.Equal(t, 1, ctx.Estack.Len()) - item, err := ctx.Estack.PopBoolean() - if err != nil { - t.Fail() - } + item, err := ctx.Estack.PopBoolean() + assert.Nil(t, err) - assert.Equal(t, true, item.Value()) + assert.Equal(t, true, item.Value()) } func TestLtOp(t *testing.T) { @@ -504,10 +487,10 @@ func TestLtOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -523,7 +506,7 @@ func TestLtOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, false, item.Value()) } @@ -533,10 +516,10 @@ func TestGtOp(t *testing.T) { v := VM{} a, err := stack.NewInt(big.NewInt(10)) - assert.NoError(t, err) + assert.Nil(t, err) b, err := stack.NewInt(big.NewInt(2)) - assert.NoError(t, err) + assert.Nil(t, err) ctx := stack.NewContext([]byte{}) ctx.Estack.Push(a).Push(b) @@ -552,8 +535,89 @@ func TestGtOp(t *testing.T) { assert.Equal(t, 1, ctx.Estack.Len()) item, err := ctx.Estack.PopBoolean() - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, true, item.Value()) } +func TestMinOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + assert.Nil(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.Nil(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.MIN, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopInt() + assert.Nil(t, err) + + assert.Equal(t, int64(2), item.Value().Int64()) +} + +func TestMaxOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(10)) + assert.Nil(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.Nil(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b) + + v.executeOp(stack.MAX, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopInt() + assert.Nil(t, err) + + assert.Equal(t, int64(10), item.Value().Int64()) +} + +func TestWithinOp(t *testing.T) { + + v := VM{} + + a, err := stack.NewInt(big.NewInt(5)) + assert.Nil(t, err) + + b, err := stack.NewInt(big.NewInt(2)) + assert.Nil(t, err) + + c, err := stack.NewInt(big.NewInt(10)) + assert.Nil(t, err) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(a).Push(b).Push(c) + + // c is the first item popped. + // b is the second item popped. + // a is the third item popped. + // if a is within [b, c) we place a boolean, + // whose value is true, on top of the evaluation + // stack. Otherwise we place a boolean with + // false value. + v.executeOp(stack.WITHIN, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.PopBoolean() + assert.Nil(t, err) + + assert.Equal(t, true, item.Value()) +}