locktime: Add mutation testing

Add mutation testing to the `locktime` module and add unit tests to
cover all mutants and ensure they are killed.
This commit is contained in:
Tobin C. Harding 2022-12-30 11:13:42 +11:00
parent 26c0da41b4
commit ca471557a5
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 156 additions and 0 deletions

View File

@ -14,6 +14,9 @@ use core::str::FromStr;
use bitcoin_internals::write_err; use bitcoin_internals::write_err;
#[cfg(all(test, mutate))]
use mutagen::mutate;
use crate::consensus::encode::{self, Decodable, Encodable}; use crate::consensus::encode::{self, Decodable, Encodable};
use crate::error::ParseIntError; use crate::error::ParseIntError;
use crate::io::{self, Read, Write}; use crate::io::{self, Read, Write};
@ -198,6 +201,7 @@ impl LockTime {
/// } /// }
/// ```` /// ````
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_satisfied_by(&self, height: Height, time: Time) -> bool { pub fn is_satisfied_by(&self, height: Height, time: Time) -> bool {
use LockTime::*; use LockTime::*;
@ -227,6 +231,7 @@ impl LockTime {
/// assert!(lock_time.is_implied_by(check)); /// assert!(lock_time.is_implied_by(check));
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_implied_by(&self, other: LockTime) -> bool { pub fn is_implied_by(&self, other: LockTime) -> bool {
use LockTime::*; use LockTime::*;
@ -791,4 +796,90 @@ mod tests {
let result = Height::from_hex_str(hex); let result = Height::from_hex_str(hex);
assert!(result.is_err()); assert!(result.is_err());
} }
#[test]
fn parses_correctly_to_height_or_time() {
let lock = LockTime::from_consensus(750_000);
assert!(lock.is_block_height());
assert!(!lock.is_block_time());
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let lock = LockTime::from_consensus(t);
assert!(!lock.is_block_height());
assert!(lock.is_block_time());
}
#[test]
fn satisfied_by_height() {
let lock = LockTime::from_consensus(750_000);
let height = Height::from_consensus(800_000).expect("failed to parse height");
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let time = Time::from_consensus(t).expect("invalid time value");
assert!(lock.is_satisfied_by(height, time))
}
#[test]
fn satisfied_by_time() {
let lock = LockTime::from_consensus(1053195600);
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let time = Time::from_consensus(t).expect("invalid time value");
let height = Height::from_consensus(800_000).expect("failed to parse height");
assert!(lock.is_satisfied_by(height, time))
}
#[test]
fn satisfied_by_same_height() {
let h = 750_000;
let lock = LockTime::from_consensus(h);
let height = Height::from_consensus(h).expect("failed to parse height");
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let time = Time::from_consensus(t).expect("invalid time value");
assert!(lock.is_satisfied_by(height, time))
}
#[test]
fn satisfied_by_same_time() {
let t: u32 = 1653195600; // May 22nd, 5am UTC.
let lock = LockTime::from_consensus(t);
let time = Time::from_consensus(t).expect("invalid time value");
let height = Height::from_consensus(800_000).expect("failed to parse height");
assert!(lock.is_satisfied_by(height, time))
}
#[test]
fn height_correctly_implies() {
let lock = LockTime::from_consensus(750_005);
assert!(!lock.is_implied_by(LockTime::from_consensus(750_004)));
assert!(lock.is_implied_by(LockTime::from_consensus(750_005)));
assert!(lock.is_implied_by(LockTime::from_consensus(750_006)));
}
#[test]
fn time_correctly_implies() {
let t: u32 = 1700000005;
let lock = LockTime::from_consensus(t);
assert!(!lock.is_implied_by(LockTime::from_consensus(1700000004)));
assert!(lock.is_implied_by(LockTime::from_consensus(1700000005)));
assert!(lock.is_implied_by(LockTime::from_consensus(1700000006)));
}
#[test]
fn incorrect_units_do_not_imply() {
let lock = LockTime::from_consensus(750_005);
assert!(!lock.is_implied_by(LockTime::from_consensus(1700000004)));
}
} }

View File

@ -10,6 +10,9 @@
use core::fmt; use core::fmt;
use core::convert::TryFrom; use core::convert::TryFrom;
#[cfg(all(test, mutate))]
use mutagen::mutate;
#[cfg(docsrs)] #[cfg(docsrs)]
use crate::relative; use crate::relative;
@ -53,6 +56,7 @@ impl LockTime {
/// assert!(lock.is_satisfied_by(current_height(), current_time())); /// assert!(lock.is_satisfied_by(current_height(), current_time()));
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_satisfied_by(&self, h: Height, t: Time) -> bool { pub fn is_satisfied_by(&self, h: Height, t: Time) -> bool {
if let Ok(true) = self.is_satisfied_by_height(h) { if let Ok(true) = self.is_satisfied_by_height(h) {
true true
@ -94,6 +98,7 @@ impl LockTime {
/// assert!(satisfied); /// assert!(satisfied);
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_implied_by(&self, other: LockTime) -> bool { pub fn is_implied_by(&self, other: LockTime) -> bool {
use LockTime::*; use LockTime::*;
@ -121,6 +126,7 @@ impl LockTime {
/// assert!(lock.is_satisfied_by_height(Height::from(height+1)).expect("a height")); /// assert!(lock.is_satisfied_by_height(Height::from(height+1)).expect("a height"));
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_satisfied_by_height(&self, h: Height) -> Result<bool, Error> { pub fn is_satisfied_by_height(&self, h: Height) -> Result<bool, Error> {
use LockTime::*; use LockTime::*;
@ -147,6 +153,7 @@ impl LockTime {
/// assert!(lock.is_satisfied_by_time(Time::from_512_second_intervals(intervals + 10)).expect("a time")); /// assert!(lock.is_satisfied_by_time(Time::from_512_second_intervals(intervals + 10)).expect("a time"));
/// ``` /// ```
#[inline] #[inline]
#[cfg_attr(all(test, mutate), mutate)]
pub fn is_satisfied_by_time(&self, t: Time) -> Result<bool, Error> { pub fn is_satisfied_by_time(&self, t: Time) -> Result<bool, Error> {
use LockTime::*; use LockTime::*;
@ -294,3 +301,61 @@ impl std::error::Error for Error {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn satisfied_by_height() {
let height = Height::from(10);
let time = Time::from_512_second_intervals(70);
let lock = LockTime::from(height);
assert!(!lock.is_satisfied_by(Height::from(9), time));
assert!(lock.is_satisfied_by(Height::from(10), time));
assert!(lock.is_satisfied_by(Height::from(11), time));
}
#[test]
fn satisfied_by_time() {
let height = Height::from(10);
let time = Time::from_512_second_intervals(70);
let lock = LockTime::from(time);
assert!(!lock.is_satisfied_by(height, Time::from_512_second_intervals(69)));
assert!(lock.is_satisfied_by(height, Time::from_512_second_intervals(70)));
assert!(lock.is_satisfied_by(height, Time::from_512_second_intervals(71)));
}
#[test]
fn height_correctly_implies() {
let height = Height::from(10);
let lock = LockTime::from(height);
assert!(!lock.is_implied_by(LockTime::from(Height::from(9))));
assert!(lock.is_implied_by(LockTime::from(Height::from(10))));
assert!(lock.is_implied_by(LockTime::from(Height::from(11))));
}
#[test]
fn time_correctly_implies() {
let time = Time::from_512_second_intervals(70);
let lock = LockTime::from(time);
assert!(!lock.is_implied_by(LockTime::from(Time::from_512_second_intervals(69))));
assert!(lock.is_implied_by(LockTime::from(Time::from_512_second_intervals(70))));
assert!(lock.is_implied_by(LockTime::from(Time::from_512_second_intervals(71))));
}
#[test]
fn incorrect_units_do_not_imply() {
let time = Time::from_512_second_intervals(70);
let height = Height::from(10);
let lock = LockTime::from(time);
assert!(!lock.is_implied_by(LockTime::from(height)));
}
}