From a4ef027134980a3eaa6808aa4c0e3882e6fa29f2 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 10 Feb 2025 14:13:13 +0000 Subject: [PATCH 1/3] Add tests of transaction functions Cargo mutants found mutants in Transaction. Add a test to kill them. --- primitives/src/transaction.rs | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index e91540e55..9744a5ee0 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -598,3 +598,49 @@ impl<'a> Arbitrary<'a> for Txid { Ok(Txid(t)) } } + +#[cfg(feature = "alloc")] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn transaction_functions() { + let txin = TxIn { + previous_output: OutPoint { + txid: Txid::from_byte_array([0xAA; 32]), // Arbitrary invalid dummy value. + vout: 0, + }, + script_sig: ScriptBuf::new(), + sequence: Sequence::MAX, + witness: Witness::new(), + }; + + let txout = TxOut { + value: Amount::from_sat(123456789), + script_pubkey: ScriptBuf::new(), + }; + + let tx_orig = Transaction { + version: Version::ONE, + lock_time: absolute::LockTime::from_consensus(1738968231), // The time this was written + input: vec![txin.clone()], + output: vec![txout.clone()], + }; + + // Test changing the transaction + let mut tx = tx_orig.clone(); + tx.inputs_mut()[0].previous_output.txid = Txid::from_byte_array([0xFF; 32]); + tx.outputs_mut()[0].value = Amount::from_sat(987654321); + assert_eq!(tx.inputs()[0].previous_output.txid.to_byte_array(), [0xFF; 32]); + assert_eq!(tx.outputs()[0].value.to_sat(), 987654321); + + // Test uses_segwit_serialization + assert!(!tx.uses_segwit_serialization()); + tx.input[0].witness.push(vec![0xAB, 0xCD, 0xEF]); + assert!(tx.uses_segwit_serialization()); + + // Test partial ord + assert!(tx > tx_orig); + } +} From 957be3c978368218508f424e21c5fa2c0714d7e1 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 10 Feb 2025 14:16:44 +0000 Subject: [PATCH 2/3] Add OutPoint test Cargo mutant found mutants in OutPoint. Add a test to kill them. --- primitives/src/transaction.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 9744a5ee0..b8d4bbcb6 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -643,4 +643,30 @@ mod tests { // Test partial ord assert!(tx > tx_orig); } + + #[test] + fn outpoint_from_str() { + // Check format errors + let mut outpoint_str = "0".repeat(64); // No ":" + let outpoint: Result = outpoint_str.parse(); + assert_eq!(outpoint, Err(ParseOutPointError::Format)); + + outpoint_str.push(':'); // Empty vout + let outpoint: Result = outpoint_str.parse(); + assert_eq!(outpoint, Err(ParseOutPointError::Format)); + + outpoint_str.push('0'); // Correct format + let outpoint: OutPoint = outpoint_str.parse().unwrap(); + assert_eq!(outpoint.txid, Txid::from_byte_array([0; 32])); + assert_eq!(outpoint.vout, 0); + + // 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"); + let outpoint: Result = outpoint_str.parse(); + assert_eq!(outpoint, Err(ParseOutPointError::TooLong)); + } } From 435750f2922abc3093dc4386cd75f852dfb7190d Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 10 Feb 2025 14:17:51 +0000 Subject: [PATCH 3/3] Add a parse_vout test Add a test to kill the mutants in parse_vout(). --- primitives/src/transaction.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index b8d4bbcb6..3a3682f6a 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -669,4 +669,12 @@ mod tests { let outpoint: Result = outpoint_str.parse(); assert_eq!(outpoint, Err(ParseOutPointError::TooLong)); } + + #[test] + fn canonical_vout() { + assert_eq!(parse_vout("0").unwrap(), 0); + assert_eq!(parse_vout("1").unwrap(), 1); + assert!(parse_vout("01").is_err()); // Leading zero not allowed + assert!(parse_vout("+1").is_err()); // Non digits not allowed + } }