use proptest::prelude::*;
use super::super::*;
proptest! {
#[test]
fn prop_difficulty_conversion(expanded_seed in any::<block::Hash>()) {
let expanded_seed = ExpandedDifficulty::from_hash(&expanded_seed);
let hash_zero = block::Hash([0; 32]);
let hash_max = block::Hash([0xff; 32]);
prop_assert!(expanded_seed >= hash_zero);
prop_assert!(expanded_seed <= hash_max);
prop_assume!(expanded_seed != hash_zero);
let compact = expanded_seed.to_compact();
let expanded_trunc = compact.to_expanded();
let work = compact.to_work();
if let Some(expanded_trunc) = expanded_trunc {
prop_assert!(expanded_trunc > hash_zero);
prop_assert!(expanded_trunc < hash_max);
prop_assert!(expanded_trunc <= expanded_seed);
let compact_trip = expanded_trunc.to_compact();
prop_assert_eq!(compact, compact_trip);
let expanded_trip = compact_trip.to_expanded().expect("roundtrip expanded is valid");
prop_assert_eq!(expanded_trunc, expanded_trip);
let work = work.expect("every positive 256-bit target has representable work");
let work_trip = compact_trip
.to_work()
.expect("roundtrip positive target has representable work");
prop_assert_eq!(work, work_trip);
}
}
#[test]
fn prop_work_conversion(work in any::<Work>()) {
let work_zero = Work(U256::zero());
let work_max = Work(U256::MAX);
prop_assert!(work > work_zero);
prop_assert!(work < work_max);
let partial_work = PartialCumulativeWork::from(work);
prop_assert!(partial_work > PartialCumulativeWork::from(work_zero));
prop_assert!(partial_work < PartialCumulativeWork::from(work_max));
let zero_sum = PartialCumulativeWork::from(work_zero)
.checked_add(work_zero)
.expect("adding zero to zero is representable");
let max_sum = PartialCumulativeWork::from(work_max)
.checked_add(work_zero)
.expect("adding zero to the maximum is representable");
prop_assert!(partial_work > zero_sum);
prop_assert!(partial_work < max_sum);
}
#[test]
fn prop_expanded_cmp(expanded in any::<ExpandedDifficulty>()) {
let hash_zero = block::Hash([0; 32]);
let hash_max = block::Hash([0xff; 32]);
prop_assert!(expanded > hash_zero);
prop_assert!(expanded < hash_max);
}
#[test]
fn prop_hash_cmp(hash in any::<block::Hash>()) {
let ex_zero = ExpandedDifficulty(U256::zero());
let ex_one = ExpandedDifficulty(U256::one());
let ex_max = ExpandedDifficulty(U256::MAX);
prop_assert!(hash >= ex_zero);
prop_assert!(hash <= ex_max);
prop_assert!(hash >= ex_one || hash == ex_zero);
}
#[test]
#[allow(clippy::double_comparisons)]
fn prop_expanded_hash_cmp(expanded in any::<ExpandedDifficulty>(), hash in any::<block::Hash>()) {
prop_assert!(expanded < hash || expanded > hash || expanded == hash);
}
#[test]
#[allow(clippy::double_comparisons)]
fn prop_compact_roundtrip(compact1 in any::<CompactDifficulty>(), compact2 in any::<CompactDifficulty>()) {
prop_assert!(compact1 != compact2 || compact1 == compact2);
let expanded1 = compact1.to_expanded().expect("arbitrary compact values are valid");
let expanded2 = compact2.to_expanded().expect("arbitrary compact values are valid");
if expanded1 != expanded2 {
prop_assert!(compact1 != compact2);
} else {
prop_assert!(compact1 == compact2);
}
let compact1_trip = expanded1.to_compact();
let compact2_trip = expanded2.to_compact();
if compact1_trip != compact2_trip {
prop_assert!(compact1 != compact2);
} else {
prop_assert!(compact1 == compact2);
}
}
#[test]
fn prop_expanded_roundtrip(expanded1_seed in any::<block::Hash>(), expanded2_seed in any::<block::Hash>()) {
let expanded1_seed = ExpandedDifficulty::from_hash(&expanded1_seed);
let expanded2_seed = ExpandedDifficulty::from_hash(&expanded2_seed);
let expanded_zero = ExpandedDifficulty(U256::zero());
prop_assume!(expanded1_seed != expanded_zero);
prop_assume!(expanded2_seed != expanded_zero);
let compact1 = expanded1_seed.to_compact();
let compact2 = expanded2_seed.to_compact();
let expanded1_trunc = compact1.to_expanded();
let expanded2_trunc = compact2.to_expanded();
let work1 = compact1.to_work();
let work2 = compact2.to_work();
match expanded1_seed.cmp(&expanded2_seed) {
Ordering::Greater => {
prop_assert!(expanded1_trunc >= expanded2_trunc);
}
Ordering::Equal => {
prop_assert!(compact1 == compact2);
prop_assert!(expanded1_trunc == expanded2_trunc);
}
Ordering::Less => {
prop_assert!(expanded1_trunc <= expanded2_trunc);
}
}
if expanded1_trunc == expanded2_trunc {
prop_assert!(compact1 == compact2);
}
prop_assert!(work1.is_some());
prop_assert!(work2.is_some());
match expanded1_seed.cmp(&expanded2_seed) {
Ordering::Greater => {
prop_assert!(work1 <= work2);
}
Ordering::Equal => {
prop_assert!(work1 == work2);
}
Ordering::Less => {
prop_assert!(work1 >= work2);
}
}
match expanded1_trunc.cmp(&expanded2_trunc) {
Ordering::Greater => {
prop_assert!(work1 <= work2);
}
Ordering::Equal => {
prop_assert!(work1 == work2);
}
Ordering::Less => {
prop_assert!(work1 >= work2);
}
}
}
#[test]
fn prop_work_sum(work1 in any::<Work>(), work2 in any::<Work>()) {
if let Some(work_total) = PartialCumulativeWork::from(work1).checked_add(work2) {
prop_assert!(work_total >= PartialCumulativeWork::from(work1));
prop_assert!(work_total >= PartialCumulativeWork::from(work2));
prop_assert_eq!(work_total - work1, PartialCumulativeWork::from(work2));
prop_assert_eq!(work_total - work2, PartialCumulativeWork::from(work1));
}
if let Some(work_total) = PartialCumulativeWork::from(work1).checked_add(work1) {
prop_assert!(work_total >= PartialCumulativeWork::from(work1));
prop_assert_eq!(work_total - work1, PartialCumulativeWork::from(work1));
}
if let Some(work_total) = PartialCumulativeWork::from(work2).checked_add(work2) {
prop_assert!(work_total >= PartialCumulativeWork::from(work2));
prop_assert_eq!(work_total - work2, PartialCumulativeWork::from(work2));
}
}
}