Skip to content

Commit aca2de1

Browse files
authored
Merge pull request #1777 from mina86/b
cosmwasm_std: remove dependency on DefaultHasher in tests
2 parents 0dae968 + a3c9597 commit aca2de1

File tree

7 files changed

+81
-104
lines changed

7 files changed

+81
-104
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/std/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,6 @@ cosmwasm-crypto = { path = "../crypto", version = "1.3.0-rc.0" }
6363
cosmwasm-schema = { path = "../schema" }
6464
# The chrono dependency is only used in an example, which Rust compiles for us. If this causes trouble, remove it.
6565
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
66+
crc32fast = "1.3.2"
6667
hex-literal = "0.3.1"
6768
serde_json = "1.0.81"

packages/std/src/addresses.rs

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -399,11 +399,9 @@ fn hash(ty: &str, key: &[u8]) -> Vec<u8> {
399399
#[cfg(test)]
400400
mod tests {
401401
use super::*;
402-
use crate::HexBinary;
402+
use crate::{assert_hash_works, HexBinary};
403403
use hex_literal::hex;
404-
use std::collections::hash_map::DefaultHasher;
405404
use std::collections::HashSet;
406-
use std::hash::{Hash, Hasher};
407405

408406
#[test]
409407
fn addr_unchecked_works() {
@@ -651,23 +649,9 @@ mod tests {
651649

652650
#[test]
653651
fn canonical_addr_implements_hash() {
654-
let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
655-
let mut hasher = DefaultHasher::new();
656-
alice1.hash(&mut hasher);
657-
let alice1_hash = hasher.finish();
658-
659-
let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
660-
let mut hasher = DefaultHasher::new();
661-
alice2.hash(&mut hasher);
662-
let alice2_hash = hasher.finish();
663-
652+
let alice = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
664653
let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
665-
let mut hasher = DefaultHasher::new();
666-
bob.hash(&mut hasher);
667-
let bob_hash = hasher.finish();
668-
669-
assert_eq!(alice1_hash, alice2_hash);
670-
assert_ne!(alice1_hash, bob_hash);
654+
assert_hash_works!(alice, bob);
671655
}
672656

673657
/// This requires Hash and Eq to be implemented

packages/std/src/binary.rs

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,10 @@ impl<'de> de::Visitor<'de> for Base64Visitor {
238238
#[cfg(test)]
239239
mod tests {
240240
use super::*;
241+
use crate::assert_hash_works;
241242
use crate::errors::StdError;
242243
use crate::serde::{from_slice, to_vec};
243-
use std::collections::hash_map::DefaultHasher;
244244
use std::collections::HashSet;
245-
use std::hash::{Hash, Hasher};
246245

247246
#[test]
248247
fn encode_decode() {
@@ -505,51 +504,17 @@ mod tests {
505504

506505
#[test]
507506
fn binary_implements_as_ref() {
508-
// Can use as_ref (this we already get via the Deref implementation)
509-
let data = Binary(vec![7u8, 35, 49, 101, 0, 255]);
510-
assert_eq!(data.as_ref(), &[7u8, 35, 49, 101, 0, 255]);
511-
512-
let data = Binary(vec![7u8, 35, 49, 101, 0, 255]);
513-
let data_ref = &data;
514-
assert_eq!(data_ref.as_ref(), &[7u8, 35, 49, 101, 0, 255]);
515-
516-
// Implements as ref
517-
518-
// This is a dummy function to mimic the signature of
519-
// https://docs.rs/sha2/0.10.6/sha2/trait.Digest.html#tymethod.digest
520-
fn hash(data: impl AsRef<[u8]>) -> u64 {
521-
let mut hasher = DefaultHasher::new();
522-
data.as_ref().hash(&mut hasher);
523-
hasher.finish()
524-
}
525-
526-
let data = Binary(vec![7u8, 35, 49, 101, 0, 255]);
527-
hash(data);
528-
529-
let data = Binary(vec![7u8, 35, 49, 101, 0, 255]);
530-
let data_ref = &data;
531-
hash(data_ref);
507+
let want = &[7u8, 35, 49, 101, 0, 255];
508+
let data = Binary(want.to_vec());
509+
assert_eq!(want, AsRef::<[u8]>::as_ref(&data));
510+
assert_eq!(want, AsRef::<[u8]>::as_ref(&&data));
532511
}
533512

534513
#[test]
535514
fn binary_implements_hash() {
536-
let a1 = Binary::from([0, 187, 61, 11, 250, 0]);
537-
let mut hasher = DefaultHasher::new();
538-
a1.hash(&mut hasher);
539-
let a1_hash = hasher.finish();
540-
541-
let a2 = Binary::from([0, 187, 61, 11, 250, 0]);
542-
let mut hasher = DefaultHasher::new();
543-
a2.hash(&mut hasher);
544-
let a2_hash = hasher.finish();
545-
515+
let a = Binary::from([0, 187, 61, 11, 250, 0]);
546516
let b = Binary::from([16, 21, 33, 0, 255, 9]);
547-
let mut hasher = DefaultHasher::new();
548-
b.hash(&mut hasher);
549-
let b_hash = hasher.finish();
550-
551-
assert_eq!(a1_hash, a2_hash);
552-
assert_ne!(a1_hash, b_hash);
517+
assert_hash_works!(a, b);
553518
}
554519

555520
/// This requires Hash and Eq to be implemented

packages/std/src/hex_binary.rs

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,8 @@ impl<'de> de::Visitor<'de> for HexVisitor {
247247
mod tests {
248248
use super::*;
249249

250-
use crate::{from_slice, to_vec, StdError};
251-
use std::collections::hash_map::DefaultHasher;
250+
use crate::{assert_hash_works, from_slice, to_vec, StdError};
252251
use std::collections::HashSet;
253-
use std::hash::{Hash, Hasher};
254252

255253
#[test]
256254
fn from_hex_works() {
@@ -569,51 +567,17 @@ mod tests {
569567

570568
#[test]
571569
fn hex_binary_implements_as_ref() {
572-
// Can use as_ref (this we already get via the Deref implementation)
573-
let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
574-
assert_eq!(data.as_ref(), &[7u8, 35, 49, 101, 0, 255]);
575-
576-
let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
577-
let data_ref = &data;
578-
assert_eq!(data_ref.as_ref(), &[7u8, 35, 49, 101, 0, 255]);
579-
580-
// Implements as ref
581-
582-
// This is a dummy function to mimic the signature of
583-
// https://docs.rs/sha2/0.10.6/sha2/trait.Digest.html#tymethod.digest
584-
fn hash(data: impl AsRef<[u8]>) -> u64 {
585-
let mut hasher = DefaultHasher::new();
586-
data.as_ref().hash(&mut hasher);
587-
hasher.finish()
588-
}
589-
590-
let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
591-
hash(data);
592-
593-
let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]);
594-
let data_ref = &data;
595-
hash(data_ref);
570+
let want = &[7u8, 35, 49, 101, 0, 255];
571+
let data = HexBinary(want.to_vec());
572+
assert_eq!(want, AsRef::<[u8]>::as_ref(&data));
573+
assert_eq!(want, AsRef::<[u8]>::as_ref(&&data));
596574
}
597575

598576
#[test]
599577
fn hex_binary_implements_hash() {
600-
let a1 = HexBinary::from([0, 187, 61, 11, 250, 0]);
601-
let mut hasher = DefaultHasher::new();
602-
a1.hash(&mut hasher);
603-
let a1_hash = hasher.finish();
604-
605-
let a2 = HexBinary::from([0, 187, 61, 11, 250, 0]);
606-
let mut hasher = DefaultHasher::new();
607-
a2.hash(&mut hasher);
608-
let a2_hash = hasher.finish();
609-
578+
let a = HexBinary::from([0, 187, 61, 11, 250, 0]);
610579
let b = HexBinary::from([16, 21, 33, 0, 255, 9]);
611-
let mut hasher = DefaultHasher::new();
612-
b.hash(&mut hasher);
613-
let b_hash = hasher.finish();
614-
615-
assert_eq!(a1_hash, a2_hash);
616-
assert_ne!(a1_hash, b_hash);
580+
assert_hash_works!(a, b);
617581
}
618582

619583
/// This requires Hash and Eq to be implemented

packages/std/src/testing/assertions.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::{Decimal, Uint128};
2+
#[cfg(test)]
3+
use core::hash::{Hash, Hasher};
24
use std::str::FromStr as _;
35

46
/// Asserts that two expressions are approximately equal to each other.
@@ -21,6 +23,25 @@ macro_rules! assert_approx_eq {
2123
}};
2224
}
2325

26+
/// Asserts that type `T` implements `Hash` trait correctly.
27+
///
28+
/// `left` and `right` must be unequal objects.
29+
///
30+
/// Some object pairs may produce the same hash causing test failure.
31+
/// In those cases try different objects. The test uses stable hasher
32+
/// so once working pair is identified, the test’s going to continue
33+
/// passing.
34+
#[macro_export]
35+
#[cfg(test)]
36+
macro_rules! assert_hash_works {
37+
($left:expr, $right:expr $(,)?) => {{
38+
$crate::testing::assert_hash_works_impl($left, $right, None);
39+
}};
40+
($left:expr, $right:expr, $($args:tt)+) => {{
41+
$crate::testing::assert_hash_works_impl($left, $right, Some(format!($($args)*)));
42+
}};
43+
}
44+
2445
/// Implementation for the [`cosmwasm_std::assert_approx_eq`] macro. This does not provide any
2546
/// stability guarantees and may change any time.
2647
#[track_caller]
@@ -50,6 +71,45 @@ pub fn assert_approx_eq_impl<U: Into<Uint128>>(
5071
}
5172
}
5273

74+
/// Tests that type `T` implements `Hash` trait correctly.
75+
///
76+
/// `left` and `right` must be unequal objects.
77+
///
78+
/// Some object pairs may produce the same hash causing test failure.
79+
/// In those cases try different objects. The test uses stable hasher
80+
/// so once working pair is identified, the test’s going to continue
81+
/// passing.
82+
#[track_caller]
83+
#[doc(hidden)]
84+
#[cfg(test)]
85+
pub fn assert_hash_works_impl<T: Clone + Hash>(left: T, right: T, panic_msg: Option<String>) {
86+
fn hash(value: &impl Hash) -> u64 {
87+
let mut hasher = crc32fast::Hasher::default();
88+
value.hash(&mut hasher);
89+
hasher.finish()
90+
}
91+
92+
// Check clone
93+
if hash(&left) != hash(&left.clone()) {
94+
match panic_msg {
95+
Some(panic_msg) => {
96+
panic!("assertion failed: `hash(left) == hash(left.clone())`\n: {panic_msg}")
97+
}
98+
None => panic!("assertion failed: `hash(left) == hash(left.clone())`"),
99+
}
100+
}
101+
102+
// Check different object
103+
if hash(&left) == hash(&right) {
104+
match panic_msg {
105+
Some(panic_msg) => {
106+
panic!("assertion failed: `hash(left) != hash(right)`\n: {panic_msg}")
107+
}
108+
None => panic!("assertion failed: `hash(left) != hash(right)`"),
109+
}
110+
}
111+
}
112+
53113
#[cfg(test)]
54114
mod tests {
55115
#[test]

packages/std/src/testing/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ mod mock;
88
mod shuffle;
99

1010
pub use assertions::assert_approx_eq_impl;
11+
#[cfg(test)]
12+
pub use assertions::assert_hash_works_impl;
1113

1214
#[cfg(feature = "cosmwasm_1_3")]
1315
pub use mock::DistributionQuerier;

0 commit comments

Comments
 (0)