primitives: Add an API test module
In preparation for 1.0-ing `primitives` add an `api` test module that makes an effort to verify the API surface. This is similar to what is in `units` and what is in development for `hashes` (in #4017).
This commit is contained in:
parent
8ec2d353c9
commit
e2d9a8a0d8
|
@ -0,0 +1,309 @@
|
|||
// 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: <https://rust-lang.github.io/api-guidelines/about.html>
|
||||
|
||||
#![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<Checked>,
|
||||
b: block::Block<Unchecked>,
|
||||
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<Checked>,
|
||||
b: block::Block<Unchecked>,
|
||||
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<Checked>,
|
||||
b: block::Block<Unchecked>,
|
||||
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<Checked>,
|
||||
// b: block::Block<Unchecked>,
|
||||
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::IncompatibleHeightError,
|
||||
c: relative::IncompatibleTimeError,
|
||||
d: relative::IncompatibleHeightError,
|
||||
e: relative::IncompatibleTimeError,
|
||||
f: relative::DisabledLockTimeError,
|
||||
g: relative::DisabledLockTimeError,
|
||||
h: script::RedeemScriptSizeError,
|
||||
i: 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, IncompatibleHeightError, IncompatibleTimeError, 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::<Unchecked>::arbitrary(&mut u).unwrap().assume_checked(None);
|
||||
block::Block::<Unchecked>::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<T: Send>() {}
|
||||
fn assert_sync<T: Sync>() {}
|
||||
|
||||
// Types are `Send` and `Sync` where possible (C-SEND-SYNC).
|
||||
assert_send::<Structs>();
|
||||
assert_sync::<Structs>();
|
||||
assert_send::<Enums>();
|
||||
assert_sync::<Enums>();
|
||||
|
||||
// Error types should implement the Send and Sync traits (C-GOOD-ERR).
|
||||
assert_send::<Errors>();
|
||||
assert_sync::<Errors>();
|
||||
}
|
||||
|
||||
#[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() {}
|
Loading…
Reference in New Issue