pow: Add more mutation testing
Recently we introduced some mutation testing to the `pow` module but testing is never done - add more `mutate` attributes and add unit tests to ensure all mutants are killed. Of note, the `from_compact` and `to_compact_lossy` functions are not done, doing so results in a bunch of surviving mutants.
This commit is contained in:
parent
948b04927d
commit
308c727c82
|
@ -224,6 +224,7 @@ impl Target {
|
||||||
///
|
///
|
||||||
/// Proof-of-work validity for a block requires the hash of the block to be less than or equal
|
/// Proof-of-work validity for a block requires the hash of the block to be less than or equal
|
||||||
/// to the target.
|
/// to the target.
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
pub fn is_met_by(&self, hash: BlockHash) -> bool {
|
pub fn is_met_by(&self, hash: BlockHash) -> bool {
|
||||||
use crate::hashes::Hash;
|
use crate::hashes::Hash;
|
||||||
let hash = U256::from_le_bytes(hash.into_inner());
|
let hash = U256::from_le_bytes(hash.into_inner());
|
||||||
|
@ -257,6 +258,7 @@ impl Target {
|
||||||
///
|
///
|
||||||
/// [max]: Target::max
|
/// [max]: Target::max
|
||||||
/// [target]: crate::blockdata::block::Header::target
|
/// [target]: crate::blockdata::block::Header::target
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
pub fn difficulty(&self) -> u128 {
|
pub fn difficulty(&self) -> u128 {
|
||||||
let d = Target::MAX.0 / self.0;
|
let d = Target::MAX.0 / self.0;
|
||||||
d.saturating_to_u128()
|
d.saturating_to_u128()
|
||||||
|
@ -390,6 +392,7 @@ impl U256 {
|
||||||
#[cfg_attr(all(test, mutate), mutate)]
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn is_one(&self) -> bool { self.0 == 0 && self.1 == 1 }
|
fn is_one(&self) -> bool { self.0 == 0 && self.1 == 1 }
|
||||||
|
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn is_max(&self) -> bool { self.0 == u128::max_value() && self.1 == u128::max_value() }
|
fn is_max(&self) -> bool { self.0 == u128::max_value() && self.1 == u128::max_value() }
|
||||||
|
|
||||||
/// Returns the low 32 bits.
|
/// Returns the low 32 bits.
|
||||||
|
@ -402,6 +405,7 @@ impl U256 {
|
||||||
fn low_u128(&self) -> u128 { self.1 }
|
fn low_u128(&self) -> u128 { self.1 }
|
||||||
|
|
||||||
/// Returns `self` as a `u128` saturating to `u128::MAX` if `self` is too big.
|
/// Returns `self` as a `u128` saturating to `u128::MAX` if `self` is too big.
|
||||||
|
// Matagen gives false positive because >= and > both return u128::MAX
|
||||||
fn saturating_to_u128(&self) -> u128 {
|
fn saturating_to_u128(&self) -> u128 {
|
||||||
if *self > U256::from(u128::max_value()) {
|
if *self > U256::from(u128::max_value()) {
|
||||||
u128::max_value()
|
u128::max_value()
|
||||||
|
@ -411,6 +415,7 @@ impl U256 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the least number of bits needed to represent the number.
|
/// Returns the least number of bits needed to represent the number.
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn bits(&self) -> u32 {
|
fn bits(&self) -> u32 {
|
||||||
if self.0 > 0 {
|
if self.0 > 0 {
|
||||||
256 - self.0.leading_zeros()
|
256 - self.0.leading_zeros()
|
||||||
|
@ -425,6 +430,7 @@ impl U256 {
|
||||||
///
|
///
|
||||||
/// The multiplication result along with a boolean indicating whether an arithmetic overflow
|
/// The multiplication result along with a boolean indicating whether an arithmetic overflow
|
||||||
/// occurred. If an overflow occurred then the wrapped value is returned.
|
/// occurred. If an overflow occurred then the wrapped value is returned.
|
||||||
|
// mutagen false positive: binop_bit, replace `|` with `^`
|
||||||
fn mul_u64(self, rhs: u64) -> (U256, bool) {
|
fn mul_u64(self, rhs: u64) -> (U256, bool) {
|
||||||
let mut carry: u128 = 0;
|
let mut carry: u128 = 0;
|
||||||
let mut split_le = [self.1 as u64, (self.1 >> 64) as u64, self.0 as u64, (self.0 >> 64) as u64];
|
let mut split_le = [self.1 as u64, (self.1 >> 64) as u64, self.0 as u64, (self.0 >> 64) as u64];
|
||||||
|
@ -452,6 +458,7 @@ impl U256 {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If `rhs` is zero.
|
/// If `rhs` is zero.
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn div_rem(self, rhs: Self) -> (Self, Self) {
|
fn div_rem(self, rhs: Self) -> (Self, Self) {
|
||||||
let mut sub_copy = self;
|
let mut sub_copy = self;
|
||||||
let mut shift_copy = rhs;
|
let mut shift_copy = rhs;
|
||||||
|
@ -491,6 +498,7 @@ impl U256 {
|
||||||
/// Returns a tuple of the addition along with a boolean indicating whether an arithmetic
|
/// Returns a tuple of the addition along with a boolean indicating whether an arithmetic
|
||||||
/// overflow would occur. If an overflow would have occurred then the wrapped value is returned.
|
/// overflow would occur. If an overflow would have occurred then the wrapped value is returned.
|
||||||
#[must_use = "this returns the result of the operation, without modifying the original"]
|
#[must_use = "this returns the result of the operation, without modifying the original"]
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
|
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
|
||||||
let mut ret = U256::ZERO;
|
let mut ret = U256::ZERO;
|
||||||
let mut ret_overflow = false;
|
let mut ret_overflow = false;
|
||||||
|
@ -515,6 +523,7 @@ impl U256 {
|
||||||
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic
|
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic
|
||||||
/// overflow would occur. If an overflow would have occurred then the wrapped value is returned.
|
/// overflow would occur. If an overflow would have occurred then the wrapped value is returned.
|
||||||
#[must_use = "this returns the result of the operation, without modifying the original"]
|
#[must_use = "this returns the result of the operation, without modifying the original"]
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
|
fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
|
||||||
let ret = self.wrapping_add(!rhs).wrapping_add(Self::ONE);
|
let ret = self.wrapping_add(!rhs).wrapping_add(Self::ONE);
|
||||||
let overflow = rhs > self;
|
let overflow = rhs > self;
|
||||||
|
@ -527,6 +536,7 @@ impl U256 {
|
||||||
/// indicating whether an arithmetic overflow would occur. If an
|
/// indicating whether an arithmetic overflow would occur. If an
|
||||||
/// overflow would have occurred then the wrapped value is returned.
|
/// overflow would have occurred then the wrapped value is returned.
|
||||||
#[must_use = "this returns the result of the operation, without modifying the original"]
|
#[must_use = "this returns the result of the operation, without modifying the original"]
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
|
fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
|
||||||
let mut ret = U256::ZERO;
|
let mut ret = U256::ZERO;
|
||||||
let mut ret_overflow = false;
|
let mut ret_overflow = false;
|
||||||
|
@ -594,6 +604,7 @@ impl U256 {
|
||||||
/// restricted to the range of the type, rather than the bits shifted out of the LHS being
|
/// restricted to the range of the type, rather than the bits shifted out of the LHS being
|
||||||
/// returned to the other end. We do not currently support `rotate_left`.
|
/// returned to the other end. We do not currently support `rotate_left`.
|
||||||
#[must_use = "this returns the result of the operation, without modifying the original"]
|
#[must_use = "this returns the result of the operation, without modifying the original"]
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn wrapping_shl(self, rhs: u32) -> Self {
|
fn wrapping_shl(self, rhs: u32) -> Self {
|
||||||
let shift = rhs & 0x000000ff;
|
let shift = rhs & 0x000000ff;
|
||||||
|
|
||||||
|
@ -620,6 +631,7 @@ impl U256 {
|
||||||
/// restricted to the range of the type, rather than the bits shifted out of the LHS being
|
/// restricted to the range of the type, rather than the bits shifted out of the LHS being
|
||||||
/// returned to the other end. We do not currently support `rotate_right`.
|
/// returned to the other end. We do not currently support `rotate_right`.
|
||||||
#[must_use = "this returns the result of the operation, without modifying the original"]
|
#[must_use = "this returns the result of the operation, without modifying the original"]
|
||||||
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
fn wrapping_shr(self, rhs: u32) -> Self {
|
fn wrapping_shr(self, rhs: u32) -> Self {
|
||||||
let shift = rhs & 0x000000ff;
|
let shift = rhs & 0x000000ff;
|
||||||
|
|
||||||
|
@ -942,6 +954,9 @@ mod tests {
|
||||||
assert_eq!(U256::from(60000_u64).bits(), 16);
|
assert_eq!(U256::from(60000_u64).bits(), 16);
|
||||||
assert_eq!(U256::from(70000_u64).bits(), 17);
|
assert_eq!(U256::from(70000_u64).bits(), 17);
|
||||||
|
|
||||||
|
let u = U256::from(u128::max_value()) << 1;
|
||||||
|
assert_eq!(u.bits(), 129);
|
||||||
|
|
||||||
// Try to read the following lines out loud quickly
|
// Try to read the following lines out loud quickly
|
||||||
let mut shl = U256::from(70000_u64);
|
let mut shl = U256::from(70000_u64);
|
||||||
shl = shl << 100;
|
shl = shl << 100;
|
||||||
|
@ -1199,7 +1214,11 @@ mod tests {
|
||||||
assert_eq!(u << 1, U256::from(2_u64));
|
assert_eq!(u << 1, U256::from(2_u64));
|
||||||
assert_eq!(u << 63, U256::from(0x8000_0000_0000_0000_u64));
|
assert_eq!(u << 63, U256::from(0x8000_0000_0000_0000_u64));
|
||||||
assert_eq!(u << 64, U256::from_array([0, 0, 0x0000_0000_0000_0001, 0]));
|
assert_eq!(u << 64, U256::from_array([0, 0, 0x0000_0000_0000_0001, 0]));
|
||||||
|
assert_eq!(u << 127, U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000));
|
||||||
assert_eq!(u << 128, U256(1, 0));
|
assert_eq!(u << 128, U256(1, 0));
|
||||||
|
|
||||||
|
let x = U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000);
|
||||||
|
assert_eq!(x << 1, U256(1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1207,6 +1226,7 @@ mod tests {
|
||||||
let u = U256(1, 0);
|
let u = U256(1, 0);
|
||||||
assert_eq!(u >> 0, u);
|
assert_eq!(u >> 0, u);
|
||||||
assert_eq!(u >> 1, U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000));
|
assert_eq!(u >> 1, U256(0, 0x8000_0000_0000_0000_0000_0000_0000_0000));
|
||||||
|
assert_eq!(u >> 127, U256(0, 2));
|
||||||
assert_eq!(u >> 128, U256(0, 1));
|
assert_eq!(u >> 128, U256(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1319,6 +1339,29 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u256_addition() {
|
||||||
|
let x = U256::from(u128::max_value());
|
||||||
|
let (add, overflow) = x.overflowing_add(U256::ONE);
|
||||||
|
assert!(!overflow);
|
||||||
|
assert_eq!(add, U256(1, 0));
|
||||||
|
|
||||||
|
let (add, _) = add.overflowing_add(U256::ONE);
|
||||||
|
assert_eq!(add, U256(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u256_subtraction() {
|
||||||
|
let (sub, overflow) = U256::ONE.overflowing_sub(U256::ONE);
|
||||||
|
assert!(!overflow);
|
||||||
|
assert_eq!(sub, U256::ZERO);
|
||||||
|
|
||||||
|
let x = U256(1, 0);
|
||||||
|
let (sub, overflow) = x.overflowing_sub(U256::ONE);
|
||||||
|
assert!(!overflow);
|
||||||
|
assert_eq!(sub, U256::from(u128::max_value()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn u256_multiplication() {
|
fn u256_multiplication() {
|
||||||
let u64_val = U256::from(0xDEAD_BEEF_DEAD_BEEF_u64);
|
let u64_val = U256::from(0xDEAD_BEEF_DEAD_BEEF_u64);
|
||||||
|
@ -1338,6 +1381,23 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u256_multiplication_bits_in_each_word() {
|
||||||
|
// Put a digit in the least significant bit of each 64 bit word.
|
||||||
|
let u = 1_u128 << 64 | 1_u128;
|
||||||
|
let x = U256(u, u);
|
||||||
|
|
||||||
|
// Put a digit in the second least significant bit of each 64 bit word.
|
||||||
|
let u = 2_u128 << 64 | 2_u128;
|
||||||
|
let y = U256(u, u);
|
||||||
|
|
||||||
|
let (got, overflow) = x.overflowing_mul(y);
|
||||||
|
|
||||||
|
let want = U256(0x0000_0000_0000_0008_0000_0000_0000_0008, 0x0000_0000_0000_0006_0000_0000_0000_0004);
|
||||||
|
assert!(!overflow);
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn u256_increment() {
|
fn u256_increment() {
|
||||||
let mut val = U256(
|
let mut val = U256(
|
||||||
|
@ -1427,6 +1487,22 @@ mod tests {
|
||||||
.is_err()); // invalid length
|
.is_err()); // invalid length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u256_is_max_correct_negative() {
|
||||||
|
let tc = vec![U256::ZERO, U256::ONE, U256::from(u128::max_value())];
|
||||||
|
for t in tc {
|
||||||
|
assert!(!t.is_max())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u256_is_max_correct_positive() {
|
||||||
|
assert!(U256::MAX.is_max());
|
||||||
|
|
||||||
|
let u = u128::max_value();
|
||||||
|
assert!(((U256::from(u) << 128) + U256::from(u)).is_max());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_target_from_hex_str_happy_path() {
|
fn compact_target_from_hex_str_happy_path() {
|
||||||
let actual = CompactTarget::from_hex_str("0x01003456").unwrap();
|
let actual = CompactTarget::from_hex_str("0x01003456").unwrap();
|
||||||
|
@ -1467,6 +1543,16 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn target_is_met_by_for_target_equals_hash() {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use crate::hashes::Hash;
|
||||||
|
|
||||||
|
let hash = BlockHash::from_str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c").expect("failed to parse block hash");
|
||||||
|
let target = Target(U256::from_le_bytes(hash.into_inner()));
|
||||||
|
assert!(target.is_met_by(hash));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max_target_from_compact() {
|
fn max_target_from_compact() {
|
||||||
// The highest possible target is defined as 0x1d00ffff
|
// The highest possible target is defined as 0x1d00ffff
|
||||||
|
|
Loading…
Reference in New Issue