|
| 1 | +// SPDX-License-Identifier: CC0-1.0 |
| 2 | + |
| 3 | +//! Test the API surface of `primitives`. |
| 4 | +//! |
| 5 | +//! The point of these tests are to check the API surface as opposed to test the API functionality. |
| 6 | +//! |
| 7 | +//! ref: <https://rust-lang.github.io/api-guidelines/about.html> |
| 8 | +
|
| 9 | +#![allow(dead_code)] |
| 10 | +#![allow(unused_imports)] |
| 11 | +// No benefit in running this test without features enabled. |
| 12 | +#![cfg(feature = "alloc")] |
| 13 | +#![cfg(feature = "hex")] |
| 14 | +#![cfg(feature = "arbitrary")] |
| 15 | + |
| 16 | +use arbitrary::Arbitrary; |
| 17 | +use bitcoin_primitives::block::{Checked, Unchecked}; |
| 18 | +use bitcoin_primitives::script::{self, ScriptHash, WScriptHash}; |
| 19 | +use bitcoin_primitives::{ |
| 20 | + absolute, block, merkle_tree, pow, relative, transaction, witness, OutPoint, Script, ScriptBuf, |
| 21 | + Sequence, Transaction, TxIn, TxOut, Txid, Witness, Wtxid, |
| 22 | +}; |
| 23 | +use hashes::sha256t; |
| 24 | + |
| 25 | +/// A struct that includes all public non-error enums. |
| 26 | +#[derive(Debug)] // All public types implement Debug (C-DEBUG). |
| 27 | +struct Enums { |
| 28 | + a: block::Checked, // Empty enums are not constructable. |
| 29 | + b: block::Unchecked, |
| 30 | + c: absolute::LockTime, |
| 31 | + d: relative::LockTime, |
| 32 | +} |
| 33 | + |
| 34 | +/// A struct that includes all public non-error structs. |
| 35 | +#[derive(Debug)] // All public types implement Debug (C-DEBUG). |
| 36 | +struct Structs<'a> { |
| 37 | + a: block::Block<Checked>, |
| 38 | + b: block::Block<Unchecked>, |
| 39 | + c: block::Header, |
| 40 | + d: block::Version, |
| 41 | + e: block::BlockHash, |
| 42 | + f: block::WitnessCommitment, |
| 43 | + g: merkle_tree::TxMerkleNode, |
| 44 | + h: merkle_tree::WitnessMerkleNode, |
| 45 | + i: pow::CompactTarget, |
| 46 | + j: &'a Script, |
| 47 | + k: ScriptHash, |
| 48 | + l: WScriptHash, |
| 49 | + m: ScriptBuf, |
| 50 | + n: Sequence, |
| 51 | + o: Transaction, |
| 52 | + p: TxIn, |
| 53 | + q: TxOut, |
| 54 | + r: OutPoint, |
| 55 | + s: Txid, |
| 56 | + t: Wtxid, |
| 57 | + u: transaction::Version, |
| 58 | + v: Witness, |
| 59 | + // w: witness::Iter<'a>, |
| 60 | +} |
| 61 | + |
| 62 | +static SCRIPT: ScriptBuf = ScriptBuf::new(); |
| 63 | +static BYTES: [u8; 32] = [0x00; 32]; |
| 64 | + |
| 65 | +/// Public structs that derive common traits. |
| 66 | +// C-COMMON-TRAITS excluding `Debug, Default, Display, Ord, PartialOrd, Hash`. |
| 67 | +#[derive(Clone, PartialEq, Eq)] |
| 68 | +struct CommonTraits { |
| 69 | + a: block::Block<Checked>, |
| 70 | + b: block::Block<Unchecked>, |
| 71 | + c: block::Header, |
| 72 | + d: block::Version, |
| 73 | + e: block::BlockHash, |
| 74 | + f: block::WitnessCommitment, |
| 75 | + g: merkle_tree::TxMerkleNode, |
| 76 | + h: merkle_tree::WitnessMerkleNode, |
| 77 | + i: pow::CompactTarget, |
| 78 | + // j: &'a Script, |
| 79 | + k: ScriptHash, |
| 80 | + l: WScriptHash, |
| 81 | + m: ScriptBuf, |
| 82 | + n: Sequence, |
| 83 | + o: Transaction, |
| 84 | + p: TxIn, |
| 85 | + q: TxOut, |
| 86 | + r: OutPoint, |
| 87 | + s: Txid, |
| 88 | + t: Wtxid, |
| 89 | + u: transaction::Version, |
| 90 | + v: Witness, |
| 91 | + // w: witness::Iter<'a>, |
| 92 | +} |
| 93 | + |
| 94 | +/// A struct that includes all types that implement `Clone`. |
| 95 | +#[derive(Clone)] // C-COMMON-TRAITS: `Clone` |
| 96 | +struct Clone<'a> { |
| 97 | + a: block::Block<Checked>, |
| 98 | + b: block::Block<Unchecked>, |
| 99 | + c: block::Header, |
| 100 | + d: block::Version, |
| 101 | + e: block::BlockHash, |
| 102 | + f: block::WitnessCommitment, |
| 103 | + g: merkle_tree::TxMerkleNode, |
| 104 | + h: merkle_tree::WitnessMerkleNode, |
| 105 | + i: pow::CompactTarget, |
| 106 | + // j: &'a Script, |
| 107 | + k: ScriptHash, |
| 108 | + l: WScriptHash, |
| 109 | + m: ScriptBuf, |
| 110 | + n: Sequence, |
| 111 | + o: Transaction, |
| 112 | + p: TxIn, |
| 113 | + q: TxOut, |
| 114 | + r: OutPoint, |
| 115 | + s: Txid, |
| 116 | + t: Wtxid, |
| 117 | + u: transaction::Version, |
| 118 | + v: Witness, |
| 119 | + w: witness::Iter<'a>, |
| 120 | +} |
| 121 | + |
| 122 | +/// Public structs that derive common traits. |
| 123 | +// C-COMMON-TRAITS excluding `Clone`, `Debug, `Default`, and `Display` |
| 124 | +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 125 | +struct Ord { |
| 126 | + // a: block::Block<Checked>, |
| 127 | + // b: block::Block<Unchecked>, |
| 128 | + c: block::Header, |
| 129 | + d: block::Version, |
| 130 | + e: block::BlockHash, |
| 131 | + f: block::WitnessCommitment, |
| 132 | + g: merkle_tree::TxMerkleNode, |
| 133 | + h: merkle_tree::WitnessMerkleNode, |
| 134 | + i: pow::CompactTarget, |
| 135 | + // j: &'a Script, // Doesn't implement `Clone`. |
| 136 | + k: ScriptHash, |
| 137 | + l: WScriptHash, |
| 138 | + m: ScriptBuf, |
| 139 | + n: Sequence, |
| 140 | + o: Transaction, |
| 141 | + p: TxIn, |
| 142 | + q: TxOut, |
| 143 | + r: OutPoint, |
| 144 | + s: Txid, |
| 145 | + t: Wtxid, |
| 146 | + u: transaction::Version, |
| 147 | + v: Witness, |
| 148 | + // w: witness::Iter<'a>, |
| 149 | +} |
| 150 | + |
| 151 | +/// A struct that includes all types that implement `Default`. |
| 152 | +#[derive(Default, Debug, PartialEq, Eq)] // C-COMMON-TRAITS: `Default` (others just so we can test). |
| 153 | +struct Default { |
| 154 | + a: block::Version, |
| 155 | + b: &'static Script, |
| 156 | + c: ScriptBuf, |
| 157 | + d: Sequence, |
| 158 | + e: Witness, |
| 159 | +} |
| 160 | + |
| 161 | +/// A struct that includes all public error types. |
| 162 | +// These derives are the policy of `rust-bitcoin` not Rust API guidelines. |
| 163 | +#[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG). |
| 164 | +struct Errors { |
| 165 | + a: transaction::ParseOutPointError, |
| 166 | + b: relative::IncompatibleHeightError, |
| 167 | + c: relative::IncompatibleTimeError, |
| 168 | + d: relative::IncompatibleHeightError, |
| 169 | + e: relative::IncompatibleTimeError, |
| 170 | + f: relative::DisabledLockTimeError, |
| 171 | + g: relative::DisabledLockTimeError, |
| 172 | + h: script::RedeemScriptSizeError, |
| 173 | + i: script::WitnessScriptSizeError, |
| 174 | +} |
| 175 | + |
| 176 | +#[test] |
| 177 | +fn api_can_use_units_modules_from_crate_root() { |
| 178 | + use bitcoin_primitives::{amount, block, fee_rate, locktime, weight}; |
| 179 | +} |
| 180 | + |
| 181 | +#[test] |
| 182 | +fn api_can_use_units_types_from_crate_root() { |
| 183 | + use bitcoin_primitives::{Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight}; |
| 184 | +} |
| 185 | + |
| 186 | +#[test] |
| 187 | +fn api_can_use_all_units_types_from_module_amount() { |
| 188 | + use bitcoin_primitives::amount::{ |
| 189 | + Amount, Denomination, Display, InputTooLargeError, InvalidCharacterError, |
| 190 | + MissingDenominationError, MissingDigitsError, OutOfRangeError, ParseAmountError, |
| 191 | + ParseDenominationError, ParseError, PossiblyConfusingDenominationError, SignedAmount, |
| 192 | + TooPreciseError, UnknownDenominationError, |
| 193 | + }; |
| 194 | +} |
| 195 | + |
| 196 | +#[test] |
| 197 | +fn api_can_use_modules_from_crate_root() { |
| 198 | + use bitcoin_primitives::{ |
| 199 | + block, locktime, merkle_tree, pow, script, sequence, transaction, witness, |
| 200 | + }; |
| 201 | +} |
| 202 | + |
| 203 | +#[test] |
| 204 | +fn api_can_use_types_from_crate_root() { |
| 205 | + use bitcoin_primitives::{ |
| 206 | + Block, BlockHash, BlockHeader, BlockVersion, CompactTarget, OutPoint, Script, ScriptBuf, |
| 207 | + Sequence, Transaction, TransactionVersion, TxIn, TxMerkleNode, TxOut, Txid, Witness, |
| 208 | + WitnessCommitment, WitnessMerkleNode, Wtxid, |
| 209 | + }; |
| 210 | +} |
| 211 | + |
| 212 | +#[test] |
| 213 | +fn api_can_use_all_types_from_module_locktime() { |
| 214 | + use bitcoin_primitives::locktime::relative::{ |
| 215 | + DisabledLockTimeError, IncompatibleHeightError, IncompatibleTimeError, LockTime, |
| 216 | + }; |
| 217 | + use bitcoin_primitives::locktime::{absolute, relative}; |
| 218 | +} |
| 219 | + |
| 220 | +#[test] |
| 221 | +fn api_can_use_all_types_from_module_script() { |
| 222 | + use bitcoin_primitives::script::{ |
| 223 | + RedeemScriptSizeError, Script, ScriptBuf, ScriptHash, WScriptHash, WitnessScriptSizeError, |
| 224 | + }; |
| 225 | +} |
| 226 | + |
| 227 | +// `Debug` representation is never empty (C-DEBUG-NONEMPTY). |
| 228 | +#[test] |
| 229 | +fn api_all_non_error_types_have_non_empty_debug() { |
| 230 | + macro_rules! check_debug { |
| 231 | + ($($t:expr);* $(;)?) => { |
| 232 | + $( |
| 233 | + let debug = format!("{:?}", $t); |
| 234 | + assert!(!debug.is_empty()); |
| 235 | + )* |
| 236 | + } |
| 237 | + } |
| 238 | + |
| 239 | + // All the enums. |
| 240 | + check_debug! { |
| 241 | + absolute::LockTime::ZERO; |
| 242 | + relative::LockTime::ZERO |
| 243 | + }; |
| 244 | + |
| 245 | + // We abuse `Arbitrary` here to get a quick and dirty instance. |
| 246 | + let ab: [u8; 32] = [0xab; 32]; |
| 247 | + let mut u = arbitrary::Unstructured::new(&ab); |
| 248 | + let transaction = Transaction::arbitrary(&mut u).unwrap(); |
| 249 | + |
| 250 | + // All the structs. |
| 251 | + check_debug! { |
| 252 | + block::Block::<Unchecked>::arbitrary(&mut u).unwrap().assume_checked(None); |
| 253 | + block::Block::<Unchecked>::arbitrary(&mut u).unwrap(); |
| 254 | + block::Header::arbitrary(&mut u).unwrap(); |
| 255 | + block::Version::arbitrary(&mut u).unwrap(); |
| 256 | + block::BlockHash::from_byte_array(BYTES); |
| 257 | + block::WitnessCommitment::from_byte_array(BYTES); |
| 258 | + merkle_tree::TxMerkleNode::from_byte_array(BYTES); |
| 259 | + merkle_tree::WitnessMerkleNode::from_byte_array(BYTES); |
| 260 | + pow::CompactTarget::from_consensus(0x1d00_ffff); |
| 261 | + SCRIPT.as_script(); |
| 262 | + ScriptHash::from_script(&SCRIPT).unwrap(); |
| 263 | + WScriptHash::from_script(&SCRIPT).unwrap(); |
| 264 | + SCRIPT.clone(); |
| 265 | + Sequence::arbitrary(&mut u).unwrap(); |
| 266 | + Transaction::arbitrary(&mut u).unwrap(); |
| 267 | + TxIn::arbitrary(&mut u).unwrap(); |
| 268 | + TxOut::arbitrary(&mut u).unwrap(); |
| 269 | + OutPoint::arbitrary(&mut u).unwrap(); |
| 270 | + transaction.compute_txid(); |
| 271 | + transaction.compute_wtxid(); |
| 272 | + transaction.version; |
| 273 | + Witness::arbitrary(&mut u).unwrap(); |
| 274 | + // ad: witness::Iter<'a>, |
| 275 | + }; |
| 276 | +} |
| 277 | + |
| 278 | +#[test] |
| 279 | +fn all_types_implement_send_sync() { |
| 280 | + fn assert_send<T: Send>() {} |
| 281 | + fn assert_sync<T: Sync>() {} |
| 282 | + |
| 283 | + // Types are `Send` and `Sync` where possible (C-SEND-SYNC). |
| 284 | + assert_send::<Structs>(); |
| 285 | + assert_sync::<Structs>(); |
| 286 | + assert_send::<Enums>(); |
| 287 | + assert_sync::<Enums>(); |
| 288 | + |
| 289 | + // Error types should implement the Send and Sync traits (C-GOOD-ERR). |
| 290 | + assert_send::<Errors>(); |
| 291 | + assert_sync::<Errors>(); |
| 292 | +} |
| 293 | + |
| 294 | +#[test] |
| 295 | +fn regression_default() { |
| 296 | + let got: Default = Default::default(); |
| 297 | + let want = Default { |
| 298 | + a: block::Version::NO_SOFT_FORK_SIGNALLING, |
| 299 | + b: Script::from_bytes(&[]), |
| 300 | + c: ScriptBuf::from_bytes(Vec::new()), |
| 301 | + d: Sequence::MAX, |
| 302 | + e: Witness::new(), |
| 303 | + }; |
| 304 | + assert_eq!(got, want); |
| 305 | +} |
| 306 | + |
| 307 | +#[test] |
| 308 | +// The only trait in this crate is `block::Validation` and it is not dyn compatible. |
| 309 | +fn dyn_compatible() {} |
0 commit comments