Adding properties for bitwise operations in UInt8,UInt32

This commit is contained in:
Chris Stewart 2017-10-30 10:20:18 -05:00
parent 94c42d814f
commit 2255115a3b
3 changed files with 38 additions and 16 deletions

View file

@ -90,22 +90,14 @@ sealed abstract class UInt8 extends UnsignedNumber with NumberOperations[UInt8]
def <<(u: UInt8): UInt8 = this.<<(u.underlying) def <<(u: UInt8): UInt8 = this.<<(u.underlying)
def << (i: Int): UInt8 = { def << (i: Int): UInt8 = {
val r = underlying << i val r = (underlying << i) & 0xffL
checkResult(r) checkResult(r)
} }
override def hex = BitcoinSUtil.encodeHex(underlying).slice(2,4) override def hex = BitcoinSUtil.encodeHex(underlying).slice(2,4)
override def toInt: Int = { override def toInt: Int = toLong.toInt
require(underlying <= Int.MaxValue, "Overflow error when casting " + this + " to an integer.")
require(underlying >= 0, "Unsigned integer should not be cast to a number less than 0" + this)
underlying.toInt
}
def toLong: Long = { def toLong: Long = underlying
require(underlying <= Long.MaxValue, "Overflow error when casting " + this + " to an integer.")
require(underlying >= 0, "Unsigned integer should not be cast to a number less than 0" + this)
underlying.toLong
}
/** /**
* Checks the result of the arithmetic operation to see if an error occurred * Checks the result of the arithmetic operation to see if an error occurred
@ -113,8 +105,8 @@ sealed abstract class UInt8 extends UnsignedNumber with NumberOperations[UInt8]
* @param result the try type wrapping the result of the arithmetic operation * @param result the try type wrapping the result of the arithmetic operation
* @return the result of the unsigned number operation * @return the result of the unsigned number operation
*/ */
private def checkResult(result : Int): UInt8 = { private def checkResult(result : Long): UInt8 = {
if (result > Short.MaxValue || result < 0) throw new IllegalArgumentException("Result of operation was out of bounds for a UInt8: " + result) if (result > UInt8.max.underlying || result < UInt8.min.underlying) throw new IllegalArgumentException("Result of operation was out of bounds for a UInt8: " + result)
else UInt8(result.toShort) else UInt8(result.toShort)
} }
} }
@ -166,7 +158,6 @@ sealed trait UInt32 extends UnsignedNumber with NumberOperations[UInt32] {
if (l == 0) this if (l == 0) this
else { else {
//since we are going to shift left we can lose precision by converting .toInt //since we are going to shift left we can lose precision by converting .toInt
//TODO: There is a bug here wrt comparing shiftNoSignBit & (1 << 31) will always evaluate to false
val int = underlying.toInt val int = underlying.toInt
val shiftNoSignBit = (int << l) & 0xffffffffL val shiftNoSignBit = (int << l) & 0xffffffffL
val shift = if (((shiftNoSignBit & (1 << 31)) == (1 << 31))) { val shift = if (((shiftNoSignBit & (1 << 31)) == (1 << 31))) {

View file

@ -107,4 +107,11 @@ class UInt32Spec extends Properties("UInt32") {
r.isFailure r.isFailure
} }
} }
property(">>") =
Prop.forAll(NumberGenerator.uInt32s, Gen.choose(0,100)) { case (u32,shift) =>
val r = u32 >> shift
val expected = u32.underlying >> shift
r == UInt32(expected)
}
} }

View file

@ -1,10 +1,13 @@
package org.bitcoins.core.number package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator import org.bitcoins.core.gen.NumberGenerator
import org.scalacheck.{Prop, Properties} import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{Gen, Prop, Properties}
import scala.util.Try
class UInt8Spec extends Properties("UInt8Spec") { class UInt8Spec extends Properties("UInt8Spec") {
private val logger = BitcoinSLogger.logger
property("convert uint8 -> byte -> uint8") = { property("convert uint8 -> byte -> uint8") = {
Prop.forAll(NumberGenerator.uInt8) { case u8: UInt8 => Prop.forAll(NumberGenerator.uInt8) { case u8: UInt8 =>
UInt8(UInt8.toByte(u8)) == u8 UInt8(UInt8.toByte(u8)) == u8
@ -16,4 +19,25 @@ class UInt8Spec extends Properties("UInt8Spec") {
UInt8(u8.hex) == u8 UInt8(u8.hex) == u8
} }
} }
property("<<") = {
Prop.forAllNoShrink(NumberGenerator.uInt8, Gen.choose(0,8)) { case (u8: UInt8, shift: Int) =>
val r = Try(u8 << shift)
val expected = (u8.underlying << shift) & 0xffL
if (expected <= UInt8.max.underlying) {
r.get == UInt8(expected.toShort)
} else {
r.isFailure
}
}
}
property(">>") = {
Prop.forAllNoShrink(NumberGenerator.uInt8,Gen.choose(0,100)) { case (u8: UInt8, shift: Int) =>
val r = (u8 >> shift)
val expected = u8.underlying >> shift
r == UInt8(expected.toShort)
}
}
} }