diff --git a/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala b/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala index 1b317a2d10..f7fc2ba070 100644 --- a/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/stack/StackInterpreter.scala @@ -48,7 +48,6 @@ trait StackInterpreter { def opDepth(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_DEPTH, "Top of script stack must be OP_DEPTH") require(program.script.size >= 1, "OP_DEPTH requires at least two elements on the script stack") - val operation = program.script.head val stackSize = program.stack.size val numberToPush : ScriptNumber= if (stackSize == 0) OP_0 else ScriptNumberImpl(stackSize) @@ -98,11 +97,10 @@ trait StackInterpreter { */ def opNip(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_NIP, "Top of script stack must be OP_NIP") - require(program.stack.size > 1,"Stack must have at least two items on it for OP_NIP") program.stack match { case h :: _ :: t => ScriptProgramFactory.factory(program, h :: t, program.script.tail) - case h :: t => throw new RuntimeException("Stack must have at least two items on it for OP_NIP") - case Nil => throw new RuntimeException("Stack must have at least two items on it for OP_NIP") + case h :: t => throw new IllegalArgumentException("Stack must have at least two items on it for OP_NIP") + case Nil => throw new IllegalArgumentException("Stack must have at least two items on it for OP_NIP") } } @@ -114,11 +112,10 @@ trait StackInterpreter { */ def opOver(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_OVER, "Top of script stack must be OP_OVER") - require(program.stack.size > 1,"Stack must have at least two items on it for OP_OVER") program.stack match { case _ :: h1 :: _ => ScriptProgramFactory.factory(program, h1 :: program.stack, program.script.tail) - case h :: t => throw new RuntimeException("Stack must have at least two items on it for OP_OVER") - case Nil => throw new RuntimeException("Stack must have at least two items on it for OP_OVER") + case h :: t => throw new IllegalArgumentException("Stack must have at least two items on it for OP_OVER") + case Nil => throw new IllegalArgumentException("Stack must have at least two items on it for OP_OVER") } } @@ -159,11 +156,10 @@ trait StackInterpreter { */ def opRot(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_ROT, "Top of script stack must be OP_ROT") - require(program.stack.size > 2,"Stack must have at least 3 items on it for OP_ROT") val newStack = program.stack match { case h :: h1 :: h2 :: t => h2 :: h :: h1 :: t - case _ => throw new RuntimeException("Stack must have at least 3 items on it for OP_ROT") + case _ => throw new IllegalArgumentException("Stack must have at least 3 items on it for OP_ROT") } ScriptProgramFactory.factory(program, newStack,program.script.tail) } @@ -176,11 +172,9 @@ trait StackInterpreter { */ def op2Rot(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_2ROT, "Top of script stack must be OP_2ROT") - require(program.stack.size > 5,"Stack must have at least 5 items on it for OP_2ROT") - val newStack = program.stack match { case h :: h1 :: h2 :: h3 :: h4 :: h5 :: t => h4 :: h5 :: h :: h1 :: h2 :: h3 :: t - case _ => throw new RuntimeException("Stack must have at least 5 items on it for OP_2ROT") + case _ => throw new IllegalArgumentException("Stack must have at least 5 items on it for OP_2ROT") } ScriptProgramFactory.factory(program, newStack,program.script.tail) } @@ -218,11 +212,10 @@ trait StackInterpreter { */ def opTuck(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_TUCK, "Top of script stack must be OP_TUCK") - require(program.stack.size > 1,"Stack must have at least 2 items on it for OP_TUCK") val newStack = program.stack match { case h :: h1 :: t => h1 :: h :: h1 :: t - case _ => throw new RuntimeException("Stack must have at least 2 items on it for OP_TUCK") + case _ => throw new IllegalArgumentException("Stack must have at least 2 items on it for OP_TUCK") } ScriptProgramFactory.factory(program, newStack, program.script.tail) } @@ -235,11 +228,10 @@ trait StackInterpreter { */ def op2Dup(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_2DUP, "Top of script stack must be OP_2DUP") - require(program.stack.size > 1,"Stack must have at least 2 items on it for OP_2DUP") val newStack = program.stack match { case h :: h1 :: t => h :: h1 :: h :: h1 :: t - case _ => throw new RuntimeException("Stack must have at least 2 items on it for OP_2DUP") + case _ => throw new IllegalArgumentException("Stack must have at least 2 items on it for OP_2DUP") } ScriptProgramFactory.factory(program, newStack, program.script.tail) } @@ -251,10 +243,9 @@ trait StackInterpreter { */ def op3Dup(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_3DUP, "Top of script stack must be OP_3DUP") - require(program.stack.size > 2,"Stack must have at least 3 items on it for OP_3DUP") val newStack = program.stack match { case h :: h1 :: h2 :: t => h :: h1 :: h2 :: h :: h1 :: h2 :: t - case _ => throw new RuntimeException("Stack must have at least 3 items on it for OP_3DUP") + case _ => throw new IllegalArgumentException("Stack must have at least 3 items on it for OP_3DUP") } ScriptProgramFactory.factory(program,newStack,program.script.tail) } @@ -268,10 +259,10 @@ trait StackInterpreter { */ def op2Over(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_2OVER, "Top of script stack must be OP_2OVER") - require(program.stack.size > 3,"Stack must have at least 4 items on it for OP_2OVER") + val newStack = program.stack match { case h :: h1 :: h2 :: h3 :: t => h2 :: h3 :: h :: h1 :: h2 :: h3 :: t - case _ => throw new RuntimeException("Stack must have at least 4 items on it for OP_2OVER") + case _ => throw new IllegalArgumentException("Stack must have at least 4 items on it for OP_2OVER") } ScriptProgramFactory.factory(program, newStack,program.script.tail) } @@ -283,11 +274,10 @@ trait StackInterpreter { */ def op2Swap(program : ScriptProgram) : ScriptProgram = { require(program.script.headOption.isDefined && program.script.head == OP_2SWAP, "Top of script stack must be OP_2SWAP") - require(program.stack.size > 3,"Stack must have at least 4 items on it for OP_2SWAP") val newStack = program.stack match { case h :: h1 :: h2 :: h3 :: t => h2 :: h3 :: h :: h1 :: t - case _ => throw new RuntimeException("Stack must have at least 4 items on it for OP_2SWAP") + case _ => throw new IllegalArgumentException("Stack must have at least 4 items on it for OP_2SWAP") } ScriptProgramFactory.factory(program,newStack,program.script.tail) } diff --git a/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala b/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala index b098aae20f..004718dc88 100644 --- a/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala +++ b/src/test/scala/org/scalacoin/script/stack/StackInterpreterTest.scala @@ -109,6 +109,28 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 2 elements on the stack for OP_NIP" in { + val stack = List(OP_0) + val script = List(OP_NIP) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = opNip(program) + } + } + + it must "throw an exception if there is no elements on the stack for OP_NIP" in { + val stack = List() + val script = List(OP_NIP) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = opNip(program) + } + } + it must "evaluate an OP_OVER correctly" in { val stack = List(OP_0,OP_1) val script = List(OP_OVER) @@ -118,6 +140,28 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 2 elements on the stack for OP_OVER" in { + val stack = List(OP_0) + val script = List(OP_OVER) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = opOver(program) + } + } + + it must "throw an exception if there is no elements on the stack for OP_OVER" in { + val stack = List() + val script = List(OP_OVER) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = opOver(program) + } + } + it must "evaluate an OP_PICK correctly" in { val stack = List(OP_0, ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) val script = List(OP_PICK) @@ -151,6 +195,18 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 3 elements on the stack for OP_ROT" in { + val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15")) + val script = List(OP_ROT) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = opRot(program) + } + } + + it must "evaluate an OP_2ROT correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) @@ -163,6 +219,18 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 6 elements on the stack for OP_2ROT" in { + val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), + ScriptConstantImpl("17"), ScriptConstantImpl("18")) + val script = List(OP_2ROT) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = op2Rot(program) + } + } + it must "evalauate an OP_2DROP correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) @@ -197,6 +265,17 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 2 elements on the stack for OP_TUCK" in { + val stack = List(OP_0) + val script = List(OP_TUCK) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = opTuck(program) + } + } + it must "evaluate an OP_2DUP correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) @@ -209,6 +288,17 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 2 elements on the stack for OP_2DUP" in { + val stack = List(OP_0) + val script = List(OP_2DUP) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = op2Dup(program) + } + } + it must "evaluate an OP_3DUP correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), ScriptConstantImpl("17"), ScriptConstantImpl("18"), ScriptConstantImpl("19")) @@ -235,6 +325,17 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre newProgram.script.isEmpty must be (true) } + it must "throw an exception if there is less than 4 elements on the stack for OP_2OVER" in { + val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) + val script = List(OP_2OVER) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = op2Over(program) + } + } + it must "evaluate an OP_2SWAP correctly" in { val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16"), @@ -247,4 +348,15 @@ class StackInterpreterTest extends FlatSpec with MustMatchers with StackInterpre ScriptConstantImpl("15"), ScriptConstantImpl("18"), ScriptConstantImpl("19"))) newProgram.script.isEmpty must be (true) } + + it must "throw an exception if there is less than 4 elements on the stack for OP_2SWAP" in { + val stack = List(ScriptConstantImpl("14"), ScriptConstantImpl("15"), ScriptConstantImpl("16")) + val script = List(OP_2SWAP) + + val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack,script) + + intercept[IllegalArgumentException] { + val newProgram = op2Swap(program) + } + } } diff --git a/src/test/scala/org/scalacoin/util/BinaryTreeTest.scala b/src/test/scala/org/scalacoin/util/BinaryTreeTest.scala index aa3110dbc7..2fafdd34c1 100644 --- a/src/test/scala/org/scalacoin/util/BinaryTreeTest.scala +++ b/src/test/scala/org/scalacoin/util/BinaryTreeTest.scala @@ -110,4 +110,17 @@ class BinaryTreeTest extends FlatSpec with MustMatchers { val tree = Node[String]("Hello",Node("there",Leaf("1"),Leaf("2")),Node("3",Empty,Leaf("4"))) tree.replace(Node("thre",Leaf("1"),Leaf("2")),Empty)() must be (tree) } + + it must "insert an element into an empty binary tree" in { + Empty.insert(1) must be (Leaf(1)) + } + + it must "insert an element into a leaf binary tree" in { + Leaf(1).insert(2) must be (Node(1,Leaf(2),Empty)) + } + + it must "insert an element into a node binary tree" in { + Node(1,Empty,Empty).insert(2) must be (Node(1,Leaf(2),Empty)) + } + }