// SPDX-License-Identifier: CC0-1.0 //! Test the API surface of `primitives`. //! //! The point of these tests are to check the API surface as opposed to test the API functionality. //! //! ref: #![allow(dead_code)] #![allow(unused_imports)] // No benefit in running this test without features enabled. #![cfg(feature = "alloc")] #![cfg(feature = "hex")] #![cfg(feature = "arbitrary")] use arbitrary::Arbitrary; use bitcoin_primitives::block::{Checked, Unchecked}; use bitcoin_primitives::script::{self, ScriptHash, WScriptHash}; use bitcoin_primitives::{ absolute, block, merkle_tree, pow, relative, transaction, witness, OutPoint, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, Wtxid, }; use hashes::sha256t; /// A struct that includes all public non-error enums. #[derive(Debug)] // All public types implement Debug (C-DEBUG). struct Enums { a: block::Checked, // Empty enums are not constructable. b: block::Unchecked, c: absolute::LockTime, d: relative::LockTime, } /// A struct that includes all public non-error structs. #[derive(Debug)] // All public types implement Debug (C-DEBUG). struct Structs<'a> { a: block::Block, b: block::Block, c: block::Header, d: block::Version, e: block::BlockHash, f: block::WitnessCommitment, g: merkle_tree::TxMerkleNode, h: merkle_tree::WitnessMerkleNode, i: pow::CompactTarget, j: &'a Script, k: ScriptHash, l: WScriptHash, m: ScriptBuf, n: Sequence, o: Transaction, p: TxIn, q: TxOut, r: OutPoint, s: Txid, t: Wtxid, u: transaction::Version, v: Witness, // w: witness::Iter<'a>, } static SCRIPT: ScriptBuf = ScriptBuf::new(); static BYTES: [u8; 32] = [0x00; 32]; /// Public structs that derive common traits. // C-COMMON-TRAITS excluding `Debug`, `Default`, `Display`, `Ord`, `PartialOrd, `Hash`. #[derive(Clone, PartialEq, Eq)] struct CommonTraits { a: block::Block, b: block::Block, c: block::Header, d: block::Version, e: block::BlockHash, f: block::WitnessCommitment, g: merkle_tree::TxMerkleNode, h: merkle_tree::WitnessMerkleNode, i: pow::CompactTarget, // j: &'a Script, k: ScriptHash, l: WScriptHash, m: ScriptBuf, n: Sequence, o: Transaction, p: TxIn, q: TxOut, r: OutPoint, s: Txid, t: Wtxid, u: transaction::Version, v: Witness, // w: witness::Iter<'a>, } /// A struct that includes all types that implement `Clone`. #[derive(Clone)] // C-COMMON-TRAITS: `Clone` struct Clone<'a> { a: block::Block, b: block::Block, c: block::Header, d: block::Version, e: block::BlockHash, f: block::WitnessCommitment, g: merkle_tree::TxMerkleNode, h: merkle_tree::WitnessMerkleNode, i: pow::CompactTarget, // j: &'a Script, k: ScriptHash, l: WScriptHash, m: ScriptBuf, n: Sequence, o: Transaction, p: TxIn, q: TxOut, r: OutPoint, s: Txid, t: Wtxid, u: transaction::Version, v: Witness, w: witness::Iter<'a>, } /// Public structs that derive common traits. // C-COMMON-TRAITS excluding `Clone`, `Debug`, `Default`, and `Display` #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] struct Ord { // a: block::Block, // b: block::Block, c: block::Header, d: block::Version, e: block::BlockHash, f: block::WitnessCommitment, g: merkle_tree::TxMerkleNode, h: merkle_tree::WitnessMerkleNode, i: pow::CompactTarget, // j: &'a Script, // Doesn't implement `Clone`. k: ScriptHash, l: WScriptHash, m: ScriptBuf, n: Sequence, o: Transaction, p: TxIn, q: TxOut, r: OutPoint, s: Txid, t: Wtxid, u: transaction::Version, v: Witness, // w: witness::Iter<'a>, } /// A struct that includes all types that implement `Default`. #[derive(Default, Debug, PartialEq, Eq)] // C-COMMON-TRAITS: `Default` (others just so we can test). struct Default { a: block::Version, b: &'static Script, c: ScriptBuf, d: Sequence, e: Witness, } /// A struct that includes all public error types. // These derives are the policy of `rust-bitcoin` not Rust API guidelines. #[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG). struct Errors { a: transaction::ParseOutPointError, b: relative::DisabledLockTimeError, c: relative::IsSatisfiedByError, d: relative::IsSatisfiedByHeightError, e: relative::IsSatisfiedByTimeError, f: script::RedeemScriptSizeError, g: script::WitnessScriptSizeError, } #[test] fn api_can_use_units_modules_from_crate_root() { use bitcoin_primitives::{amount, block, fee_rate, locktime, weight}; } #[test] fn api_can_use_units_types_from_crate_root() { use bitcoin_primitives::{Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight}; } #[test] fn api_can_use_all_units_types_from_module_amount() { use bitcoin_primitives::amount::{ Amount, Denomination, Display, InputTooLargeError, InvalidCharacterError, MissingDenominationError, MissingDigitsError, OutOfRangeError, ParseAmountError, ParseDenominationError, ParseError, PossiblyConfusingDenominationError, SignedAmount, TooPreciseError, UnknownDenominationError, }; } #[test] fn api_can_use_modules_from_crate_root() { use bitcoin_primitives::{ block, locktime, merkle_tree, pow, script, sequence, transaction, witness, }; } #[test] fn api_can_use_types_from_crate_root() { use bitcoin_primitives::{ Block, BlockHash, BlockHeader, BlockVersion, CompactTarget, OutPoint, Script, ScriptBuf, Sequence, Transaction, TransactionVersion, TxIn, TxMerkleNode, TxOut, Txid, Witness, WitnessCommitment, WitnessMerkleNode, Wtxid, }; } #[test] fn api_can_use_all_types_from_module_locktime() { use bitcoin_primitives::locktime::relative::{ DisabledLockTimeError, InvalidHeightError, InvalidTimeError, LockTime, }; use bitcoin_primitives::locktime::{absolute, relative}; } #[test] fn api_can_use_all_types_from_module_script() { use bitcoin_primitives::script::{ RedeemScriptSizeError, Script, ScriptBuf, ScriptHash, WScriptHash, WitnessScriptSizeError, }; } // `Debug` representation is never empty (C-DEBUG-NONEMPTY). #[test] fn api_all_non_error_types_have_non_empty_debug() { macro_rules! check_debug { ($($t:expr);* $(;)?) => { $( let debug = format!("{:?}", $t); assert!(!debug.is_empty()); )* } } // All the enums. check_debug! { absolute::LockTime::ZERO; relative::LockTime::ZERO }; // We abuse `Arbitrary` here to get a quick and dirty instance. let ab: [u8; 32] = [0xab; 32]; let mut u = arbitrary::Unstructured::new(&ab); let transaction = Transaction::arbitrary(&mut u).unwrap(); // All the structs. check_debug! { block::Block::::arbitrary(&mut u).unwrap().assume_checked(None); block::Block::::arbitrary(&mut u).unwrap(); block::Header::arbitrary(&mut u).unwrap(); block::Version::arbitrary(&mut u).unwrap(); block::BlockHash::from_byte_array(BYTES); block::WitnessCommitment::from_byte_array(BYTES); merkle_tree::TxMerkleNode::from_byte_array(BYTES); merkle_tree::WitnessMerkleNode::from_byte_array(BYTES); pow::CompactTarget::from_consensus(0x1d00_ffff); SCRIPT.as_script(); ScriptHash::from_script(&SCRIPT).unwrap(); WScriptHash::from_script(&SCRIPT).unwrap(); SCRIPT.clone(); Sequence::arbitrary(&mut u).unwrap(); Transaction::arbitrary(&mut u).unwrap(); TxIn::arbitrary(&mut u).unwrap(); TxOut::arbitrary(&mut u).unwrap(); OutPoint::arbitrary(&mut u).unwrap(); transaction.compute_txid(); transaction.compute_wtxid(); transaction.version; Witness::arbitrary(&mut u).unwrap(); // ad: witness::Iter<'a>, }; } #[test] fn all_types_implement_send_sync() { fn assert_send() {} fn assert_sync() {} // Types are `Send` and `Sync` where possible (C-SEND-SYNC). assert_send::(); assert_sync::(); assert_send::(); assert_sync::(); // Error types should implement the Send and Sync traits (C-GOOD-ERR). assert_send::(); assert_sync::(); } #[test] fn regression_default() { let got: Default = Default::default(); let want = Default { a: block::Version::NO_SOFT_FORK_SIGNALLING, b: Script::from_bytes(&[]), c: ScriptBuf::from_bytes(Vec::new()), d: Sequence::MAX, e: Witness::new(), }; assert_eq!(got, want); } #[test] // The only trait in this crate is `block::Validation` and it is not dyn compatible. fn dyn_compatible() {}