use zebra_test::prelude::*;
use crate::{block, fmt::SummaryDebug, transaction::arbitrary::MAX_ARBITRARY_ITEMS, LedgerState};
use super::super::{
serialize::{parse_coinbase_height, write_coinbase_height},
Input,
};
use proptest::collection::vec;
#[test]
fn coinbase_has_height() -> Result<()> {
let _init_guard = zebra_test::init();
let strategy =
any::<block::Height>().prop_flat_map(|height| Input::arbitrary_with(Some(height)));
proptest!(|(input in strategy)| {
let is_coinbase = matches!(input, Input::Coinbase { .. });
prop_assert!(is_coinbase);
});
Ok(())
}
#[test]
fn input_coinbase_vecs_only_have_coinbase_input() -> Result<()> {
let _init_guard = zebra_test::init();
let strategy = LedgerState::coinbase_strategy(None, None, false)
.prop_flat_map(|ledger_state| Input::vec_strategy(&ledger_state, MAX_ARBITRARY_ITEMS));
proptest!(|(inputs in strategy.prop_map(SummaryDebug))| {
let len = inputs.len();
for (ind, input) in inputs.into_iter().enumerate() {
let is_coinbase = matches!(input, Input::Coinbase { .. });
if ind == 0 {
prop_assert!(is_coinbase);
prop_assert_eq!(1, len);
} else {
prop_assert!(!is_coinbase);
}
}
});
Ok(())
}
#[test]
fn coinbase_height_round_trip_from_random_input() -> Result<()> {
let _init_guard = zebra_test::init();
let strategy =
any::<block::Height>().prop_flat_map(|height| Input::arbitrary_with(Some(height)));
proptest!(|(input in strategy)| {
let (height, data) = match input {
Input::Coinbase { height, data, .. } => (height, data),
_ => unreachable!("all inputs will have coinbase height and data"),
};
let mut encoded = Vec::new();
write_coinbase_height(height, &data, &mut encoded)?;
let decoded = parse_coinbase_height(encoded)?;
prop_assert_eq!(height, decoded.0);
});
Ok(())
}
proptest! {
#[test]
fn coinbase_height_round_trip_from_random_bytes(mut height_bytes in vec(any::<u8>(), 1..5)) {
let mut encoded1 = vec![height_bytes.len() as u8];
encoded1.append(&mut height_bytes);
let decoded = parse_coinbase_height(encoded1.clone()).ok();
if decoded.is_some() {
let mut encoded2 = Vec::new();
write_coinbase_height(decoded.as_ref().unwrap().0, &decoded.unwrap().1, &mut encoded2)?;
prop_assert_eq!(encoded2, encoded1);
}
}
#[test]
fn coinbase_height_round_trip_from_random_byte(height_byte in vec(any::<u8>(), 1..2)) {
let encoded1 = height_byte;
let decoded = parse_coinbase_height(encoded1.clone()).ok();
if decoded.is_some() {
let mut encoded2 = Vec::new();
write_coinbase_height(decoded.as_ref().unwrap().0, &decoded.unwrap().1, &mut encoded2)?;
prop_assert_eq!(encoded2, encoded1);
}
}
}