Skip to content

Commit f268ca2

Browse files
committed
hashes: Add api test file
As we did for `units` and as part of the stabalization effort. Add an `api` test module that verifies the public API for the `hashes` crate.
1 parent b4326f0 commit f268ca2

1 file changed

Lines changed: 225 additions & 0 deletions

File tree

hashes/tests/api.rs

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Test the API surface of `units`.
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+
12+
// Import using module style e.g., `sha256::Hash`.
13+
use bitcoin_hashes::{
14+
hash160, hash_newtype, hkdf, hmac, ripemd160, sha1, sha256, sha256d, sha256t, sha256t_tag,
15+
sha384, sha512, sha512_256, siphash24, FromSliceError, Hash, HashEngine,
16+
};
17+
// Import using type alias style e.g., `Sha256`.
18+
use bitcoin_hashes::{
19+
Hash160, Hkdf, Hmac, HmacEngine, Ripemd160, Sha1, Sha256, Sha256d, Sha256t, Sha384, Sha512,
20+
Sha512_256, Siphash24,
21+
};
22+
23+
// Arbitrary midstate value; taken from as sha256t unit tests.
24+
const TEST_MIDSTATE: [u8; 32] = [
25+
156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108,
26+
71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201,
27+
];
28+
29+
sha256t_tag! {
30+
/// Test tag so we don't have to use generics.
31+
#[derive(Debug)]
32+
struct Tag = raw(TEST_MIDSTATE, 64);
33+
}
34+
hash_newtype! {
35+
/// A concrete sha256t hash type so we don't have to use generics.
36+
#[derive(Debug)]
37+
struct TaggedHash(sha256t::Hash<Tag>);
38+
}
39+
40+
/// All the hash types excluding `Hkdf`.
41+
// `Hkdf` only implements `Copy` and `Clone` ATM - by design.
42+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] // C-COMMON-TRAITS
43+
// We check `Hkdf` implements `Debug` in the non-empty debug test below.
44+
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
45+
struct Hashes<T: Hash> {
46+
a: hash160::Hash,
47+
c: Hmac<T>,
48+
d: ripemd160::Hash,
49+
e: sha1::Hash,
50+
f: sha256::Hash,
51+
g: sha256d::Hash,
52+
h: TaggedHash,
53+
i: sha384::Hash,
54+
j: sha512::Hash,
55+
k: sha512_256::Hash,
56+
l: siphash24::Hash,
57+
}
58+
59+
impl Hashes<Sha256> {
60+
fn new_sha256() -> Self {
61+
let hmac = HmacEngine::<sha256::HashEngine>::new(&[]).finalize();
62+
// `TaggedHash` is not a general hash but `Sha256<Tag>` is.
63+
let tagged = TaggedHash::from_byte_array(Sha256t::<Tag>::hash(&[]).to_byte_array());
64+
let siphash = Siphash24::from_engine(siphash24::HashEngine::with_keys(0, 0));
65+
66+
Hashes {
67+
a: Hash160::hash(&[]),
68+
// b: hkdf,
69+
c: hmac,
70+
d: Ripemd160::hash(&[]),
71+
e: Sha1::hash(&[]),
72+
f: Sha256::hash(&[]),
73+
g: Sha256d::hash(&[]),
74+
h: tagged,
75+
i: Sha384::hash(&[]),
76+
j: Sha512::hash(&[]),
77+
k: Sha512_256::hash(&[]),
78+
l: siphash,
79+
}
80+
}
81+
}
82+
83+
/// All the hash engines.
84+
#[derive(Clone)] // C-COMMON-TRAITS
85+
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
86+
struct Engines {
87+
a: hash160::HashEngine,
88+
// We cannot derive `Debug` on a generic `HmacEngine<T>` engine.
89+
b: hmac::HmacEngine<sha256::HashEngine>,
90+
c: ripemd160::HashEngine,
91+
d: sha1::HashEngine,
92+
e: sha256::HashEngine,
93+
f: sha256d::HashEngine,
94+
g: sha256t::HashEngine<Tag>,
95+
h: sha384::HashEngine,
96+
i: sha512::HashEngine,
97+
j: sha512_256::HashEngine,
98+
k: siphash24::HashEngine,
99+
}
100+
101+
impl Engines {
102+
fn new_sha256() -> Self {
103+
Engines {
104+
a: hash160::HashEngine::new(),
105+
b: hmac::HmacEngine::<sha256::HashEngine>::new(&[]),
106+
c: ripemd160::HashEngine::new(),
107+
d: sha1::HashEngine::new(),
108+
e: sha256::HashEngine::new(),
109+
f: sha256d::HashEngine::new(),
110+
g: sha256t::Hash::<Tag>::engine(),
111+
h: sha384::HashEngine::new(),
112+
i: sha512::HashEngine::new(),
113+
j: sha512_256::HashEngine::new(),
114+
k: siphash24::HashEngine::with_keys(0, 0),
115+
}
116+
}
117+
}
118+
119+
/// Public structs that are not hashes, engines, or errors.
120+
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] // C-COMMON-TRAITS
121+
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
122+
struct OtherStructs {
123+
a: sha256::Midstate,
124+
// There is no way to construct a `siphash24::State` so we cannot directly
125+
// test it but `siphash24::HashEngine` includes one so `Engines` implicitly
126+
// tests it (e.g. `Debug` and `Clone`).
127+
//
128+
// b: siphash24::State,
129+
130+
// Don't worry about including a tag because its tested in `primitives`.
131+
}
132+
133+
impl OtherStructs {
134+
fn new() -> Self { Self { a: sha256::Midstate::new(TEST_MIDSTATE, 0) } }
135+
}
136+
137+
/// All hash engine types that implement `Default`.
138+
#[derive(Default)]
139+
struct Default {
140+
a: hash160::HashEngine,
141+
b: ripemd160::HashEngine,
142+
c: sha1::HashEngine,
143+
d: sha256::HashEngine,
144+
e: sha256d::HashEngine,
145+
f: sha256t::HashEngine<Tag>,
146+
g: sha384::HashEngine,
147+
h: sha512::HashEngine,
148+
i: sha512_256::HashEngine,
149+
}
150+
151+
/// Hash types that require a key.
152+
struct Keyed<T: Hash> {
153+
a: Hmac<T>,
154+
l: siphash24::Hash,
155+
}
156+
157+
/// A struct that includes all public error types.
158+
// These derives are the policy of `rust-bitcoin` not Rust API guidelines.
159+
#[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG).
160+
struct Errors {
161+
a: FromSliceError,
162+
b: hkdf::MaxLengthError,
163+
c: sha256::MidstateError,
164+
}
165+
166+
#[test]
167+
fn api_can_use_modules_from_crate_root() {
168+
use bitcoin_hashes::{
169+
hash160, hkdf, hmac, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256,
170+
siphash24,
171+
};
172+
}
173+
174+
#[test]
175+
fn api_can_use_alias_from_crate_root() {
176+
use bitcoin_hashes::{
177+
Hash160, Hkdf, Hmac, Ripemd160, Sha1, Sha256, Sha256d, Sha256t, Sha384, Sha512, Sha512_256,
178+
Siphash24,
179+
};
180+
}
181+
182+
// `Debug` representation is never empty (C-DEBUG-NONEMPTY).
183+
#[test]
184+
fn api_all_non_error_types_have_non_empty_debug() {
185+
macro_rules! check_debug {
186+
($t:tt; $($field:tt),* $(,)?) => {
187+
$(
188+
let debug = format!("{:?}", $t.$field);
189+
assert!(!debug.is_empty());
190+
)*
191+
}
192+
}
193+
194+
let t = Hashes::<Sha256>::new_sha256();
195+
check_debug!(t; a, c, d, e, f, g, h, i, j, k, l);
196+
197+
// This tests `Debug` on `Hkdf` but not for all `T: GeneralHash`.
198+
let t = Hkdf::<sha256::HashEngine>::new(&[], &[]);
199+
let debug = format!("{:?}", t);
200+
assert!(!debug.is_empty());
201+
202+
let t = Engines::new_sha256();
203+
check_debug!(t; a, c, d, e, f, g, h, i, j, k);
204+
205+
let t = OtherStructs::new();
206+
check_debug!(t; a);
207+
}
208+
209+
#[test]
210+
fn all_types_implement_send_sync() {
211+
fn assert_send<T: Send>() {}
212+
fn assert_sync<T: Sync>() {}
213+
214+
// Types are `Send` and `Sync` where possible (C-SEND-SYNC).
215+
assert_send::<Hashes<Sha256>>();
216+
assert_sync::<Hashes<Sha256>>();
217+
assert_send::<Engines>();
218+
assert_sync::<Engines>();
219+
assert_send::<OtherStructs>();
220+
assert_sync::<OtherStructs>();
221+
222+
// Error types should implement the Send and Sync traits (C-GOOD-ERR).
223+
assert_send::<Errors>();
224+
assert_sync::<Errors>();
225+
}

0 commit comments

Comments
 (0)