From f3338655f153834395ff2486a8f965df4453ceeb Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 17:14:16 +0100 Subject: [PATCH 1/5] Test OutPoint edge case to kill mutant There is a mutant found in `FromStr for OutPoint`. Add a test to check an edge case to kill the mutant. --- primitives/src/transaction.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index ef322e62b..6dec85fa6 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -729,9 +729,20 @@ mod tests { // Check the number of bytes OutPoint contributes to the transaction is equal to SIZE let outpoint_size = outpoint.txid.as_byte_array().len() + outpoint.vout.to_le_bytes().len(); assert_eq!(outpoint_size, OutPoint::SIZE); + } - // Check TooLong error - outpoint_str.push_str("0000000000"); + #[test] + #[cfg(feature = "hex")] + fn outpoint_from_str_too_long() { + // Check edge case: length exactly 75 + let mut outpoint_str = "0".repeat(64); + outpoint_str.push_str(":1234567890"); + assert_eq!(outpoint_str.len(), 75); + assert!(outpoint_str.parse::().is_ok()); + + // Check TooLong error (length 76) + outpoint_str.push('0'); + assert_eq!(outpoint_str.len(), 76); let outpoint: Result = outpoint_str.parse(); assert_eq!(outpoint, Err(ParseOutPointError::TooLong)); } From 0b4b17307ded47467845ca19b08ee1b8a2d0df87 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 17:27:20 +0100 Subject: [PATCH 2/5] Test SignedAmount edge case to kill mutant There is a mutant found in `SignedAmount::positive_sub`. Add an edge case to the test to kill the mutant. --- units/src/amount/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 1eebfe6f4..47809e460 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -259,6 +259,7 @@ fn checked_arithmetic() { #[test] fn positive_sub() { assert_eq!(ssat(10).positive_sub(ssat(7)).unwrap(), ssat(3)); + assert_eq!(ssat(10).positive_sub(ssat(10)).unwrap(), ssat(0)); assert!(ssat(-10).positive_sub(ssat(7)).is_none()); assert!(ssat(10).positive_sub(ssat(-7)).is_none()); assert!(ssat(10).positive_sub(ssat(11)).is_none()); From bd50943234e74047b21c32ef3fdb96a313df5538 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 17:32:30 +0100 Subject: [PATCH 3/5] Add a roundtrip test to kill a mutant There is a mutant found in relative locktime `to_512_second_intervals`. Add a round trip test to kill the mutant. --- units/src/locktime/relative.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 5edafe01e..ca2fbe8af 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -307,6 +307,13 @@ mod tests { assert_eq!(NumberOf512Seconds::from_512_second_intervals(1).to_seconds(), 512); } + #[test] + fn from_512_second_intervals_roundtrip() { + let intervals = 100_u16; + let locktime = NumberOf512Seconds::from_512_second_intervals(intervals); + assert_eq!(locktime.to_512_second_intervals(), intervals); + } + #[test] fn from_seconds_ceil_success() { let actual = NumberOf512Seconds::from_seconds_ceil(100).unwrap(); From 5edcc5dad411cf5cc2d51fcb3c55395475c1abad Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 20:35:32 +0100 Subject: [PATCH 4/5] Remove repeated fee_rate test One of the tests is a copy of the test two above it with a similar name. Remove the copy of the test. --- units/src/fee_rate/mod.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 6c223f956..0a856b7f9 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -383,12 +383,6 @@ mod tests { assert_eq!(fee_rate, FeeRate::from_sat_per_mvb(11_000)); } - #[test] - fn from_sat_per_vb() { - let fee_rate = FeeRate::from_sat_per_vb(10); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); - } - #[test] fn raw_feerate() { let fee_rate = FeeRate::from_sat_per_kwu(749); From ef56baa69670f9c2e453cb981d6f3488247d000c Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 20:37:01 +0100 Subject: [PATCH 5/5] Improve fee_rate test to kill a mutant There is a mutant found in `FeeRate` `to_sat_per_kvb_floor` and `ceil`. Add to the existing test so that all 6 to_sat floor and ceil functions are tested. --- units/src/fee_rate/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 0a856b7f9..b61e24d39 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -384,11 +384,20 @@ mod tests { } #[test] - fn raw_feerate() { - let fee_rate = FeeRate::from_sat_per_kwu(749); - assert_eq!(fee_rate.to_sat_per_kwu_floor(), 749); + fn fee_rate_to_sat_per_x() { + let fee_rate = FeeRate::from_sat_per_mvb(2_000_400); + + // sat/kwu: 2_000_400 / 4_000 = 500.1 + assert_eq!(fee_rate.to_sat_per_kwu_floor(), 500); + assert_eq!(fee_rate.to_sat_per_kwu_ceil(), 501); + + // sat/vB: 2_000_400 / 1_000_000 = 2.0004 assert_eq!(fee_rate.to_sat_per_vb_floor(), 2); assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3); + + // sat/kvb: 2_000_400 / 1_000 = 2_000.4 + assert_eq!(fee_rate.to_sat_per_kvb_floor(), 2_000); + assert_eq!(fee_rate.to_sat_per_kvb_ceil(), 2_001); } #[test]