Use `proptest` instead of `quickcheck` for `zcash_history` tests.
This commit is contained in:
parent
47596b08ff
commit
5511bf3c92
|
@ -11,12 +11,16 @@ categories = ["cryptography::cryptocurrencies"]
|
|||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
quickcheck = "0.9"
|
||||
proptest = "1.0.0"
|
||||
|
||||
[dependencies]
|
||||
primitive-types = "0.11"
|
||||
byteorder = "1"
|
||||
blake2 = { package = "blake2b_simd", version = "1" }
|
||||
proptest = { version = "1.0.0", optional = true }
|
||||
|
||||
[features]
|
||||
test-dependencies = ["proptest"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
|
|
@ -216,39 +216,57 @@ impl V2 {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl quickcheck::Arbitrary for NodeData {
|
||||
fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
|
||||
let mut node_data = NodeData {
|
||||
consensus_branch_id: 0,
|
||||
..Default::default()
|
||||
};
|
||||
gen.fill_bytes(&mut node_data.subtree_commitment[..]);
|
||||
node_data.start_time = gen.next_u32();
|
||||
node_data.end_time = gen.next_u32();
|
||||
node_data.start_target = gen.next_u32();
|
||||
node_data.end_target = gen.next_u32();
|
||||
gen.fill_bytes(&mut node_data.start_sapling_root[..]);
|
||||
gen.fill_bytes(&mut node_data.end_sapling_root[..]);
|
||||
let mut number = [0u8; 32];
|
||||
gen.fill_bytes(&mut number[..]);
|
||||
node_data.subtree_total_work = U256::from_little_endian(&number[..]);
|
||||
node_data.start_height = gen.next_u64();
|
||||
node_data.end_height = gen.next_u64();
|
||||
node_data.sapling_tx = gen.next_u64();
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
pub mod testing {
|
||||
use primitive_types::U256;
|
||||
use proptest::array::uniform32;
|
||||
use proptest::prelude::{any, prop_compose};
|
||||
|
||||
node_data
|
||||
use super::NodeData;
|
||||
|
||||
prop_compose! {
|
||||
pub fn arb_node_data()(
|
||||
subtree_commitment in uniform32(any::<u8>()),
|
||||
start_time in any::<u32>(),
|
||||
end_time in any::<u32>(),
|
||||
start_target in any::<u32>(),
|
||||
end_target in any::<u32>(),
|
||||
start_sapling_root in uniform32(any::<u8>()),
|
||||
end_sapling_root in uniform32(any::<u8>()),
|
||||
subtree_total_work in uniform32(any::<u8>()),
|
||||
start_height in any::<u64>(),
|
||||
end_height in any::<u64>(),
|
||||
sapling_tx in any::<u64>(),
|
||||
) -> NodeData {
|
||||
NodeData {
|
||||
consensus_branch_id: 0,
|
||||
subtree_commitment,
|
||||
start_time,
|
||||
end_time,
|
||||
start_target,
|
||||
end_target,
|
||||
start_sapling_root,
|
||||
end_sapling_root,
|
||||
subtree_total_work: U256::from_little_endian(&subtree_total_work[..]),
|
||||
start_height,
|
||||
end_height,
|
||||
sapling_tx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NodeData;
|
||||
use quickcheck::{quickcheck, TestResult};
|
||||
use super::testing::arb_node_data;
|
||||
use proptest::prelude::*;
|
||||
|
||||
quickcheck! {
|
||||
fn serialization_round_trip(node_data: NodeData) -> TestResult {
|
||||
TestResult::from_bool(NodeData::from_bytes(0, node_data.to_bytes()).unwrap() == node_data)
|
||||
use super::NodeData;
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn serialization_round_trip(node_data in arb_node_data()) {
|
||||
assert_eq!(NodeData::from_bytes(0, node_data.to_bytes()).unwrap(), node_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,12 +325,11 @@ fn combine_nodes<'a, V: Version>(left: IndexedNode<'a, V>, right: IndexedNode<'a
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::{Entry, EntryKind, EntryLink, Tree};
|
||||
use crate::{node_data, NodeData, Version, V2};
|
||||
|
||||
use assert_matches::assert_matches;
|
||||
use quickcheck::{quickcheck, TestResult};
|
||||
use proptest::prelude::*;
|
||||
|
||||
fn leaf(height: u32) -> node_data::V2 {
|
||||
node_data::V2 {
|
||||
|
@ -640,100 +639,90 @@ mod tests {
|
|||
assert_eq!(tree.len(), 4083); // 4095 - log2(4096)
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn there_and_back(number: u32) -> TestResult {
|
||||
if number > 1024*1024 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let mut tree = initial();
|
||||
for i in 0..number {
|
||||
tree.append_leaf(leaf(i+3)).expect("Failed to append");
|
||||
}
|
||||
for _ in 0..number {
|
||||
tree.truncate_leaf().expect("Failed to truncate");
|
||||
}
|
||||
proptest! {
|
||||
#![proptest_config(ProptestConfig::with_cases(10))]
|
||||
|
||||
TestResult::from_bool(matches!(tree.root(), EntryLink::Stored(2)))
|
||||
#[test]
|
||||
fn prop_there_and_back(number in 0u32..=(1024*1024)) {
|
||||
let mut tree = initial();
|
||||
for i in 0..number {
|
||||
tree.append_leaf(leaf(i+3)).expect("Failed to append");
|
||||
}
|
||||
for _ in 0..number {
|
||||
tree.truncate_leaf().expect("Failed to truncate");
|
||||
}
|
||||
|
||||
assert_matches!(tree.root(), EntryLink::Stored(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prop_leaf_count(number in 3u32..=(1024*1024)) {
|
||||
let mut tree = initial();
|
||||
for i in 1..(number-1) {
|
||||
tree.append_leaf(leaf(i+2)).expect("Failed to append");
|
||||
}
|
||||
|
||||
assert_eq!(tree.root_node().expect("no root").node.leaf_count(), number as u64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prop_parity(number in 3u32..=(2048*2048)) {
|
||||
let mut tree = initial();
|
||||
for i in 1..(number-1) {
|
||||
tree.append_leaf(leaf(i+2)).expect("Failed to append");
|
||||
}
|
||||
|
||||
if number & (number - 1) == 0 {
|
||||
assert_matches!(tree.root(), EntryLink::Stored(_));
|
||||
} else {
|
||||
assert_matches!(tree.root(), EntryLink::Generated(_));
|
||||
}
|
||||
}
|
||||
|
||||
fn leaf_count(number: u32) -> TestResult {
|
||||
if !(3..=1024 * 1024).contains(&number) {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let mut tree = initial();
|
||||
for i in 1..(number-1) {
|
||||
tree.append_leaf(leaf(i+2)).expect("Failed to append");
|
||||
}
|
||||
|
||||
TestResult::from_bool(
|
||||
tree.root_node().expect("no root").node.leaf_count() == number as u64
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn parity(number: u32) -> TestResult {
|
||||
if !(3..=2048 * 2048).contains(&number) {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let mut tree = initial();
|
||||
for i in 1..(number-1) {
|
||||
tree.append_leaf(leaf(i+2)).expect("Failed to append");
|
||||
}
|
||||
|
||||
TestResult::from_bool(
|
||||
if number & (number - 1) == 0 {
|
||||
matches!(tree.root(), EntryLink::Stored(_))
|
||||
} else {
|
||||
matches!(tree.root(), EntryLink::Generated(_))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn parity_with_truncate(add: u32, delete: u32) -> TestResult {
|
||||
#[test]
|
||||
fn prop_parity_with_truncate(
|
||||
add_and_delete in (0u32..=(2048*2048)).prop_flat_map(
|
||||
|add| (Just(add), 0..=add)
|
||||
)
|
||||
) {
|
||||
let (add, delete) = add_and_delete;
|
||||
// First we add `add` number of leaves, then delete `delete` number of leaves
|
||||
// What is left should be consistent with generated-stored structure
|
||||
if add > 2048 * 2048 || add < delete {
|
||||
TestResult::discard()
|
||||
let mut tree = initial();
|
||||
for i in 0..add {
|
||||
tree.append_leaf(leaf(i+3)).expect("Failed to append");
|
||||
}
|
||||
for _ in 0..delete {
|
||||
tree.truncate_leaf().expect("Failed to truncate");
|
||||
}
|
||||
|
||||
let total = add - delete + 2;
|
||||
|
||||
if total & (total - 1) == 0 {
|
||||
assert_matches!(tree.root(), EntryLink::Stored(_));
|
||||
} else {
|
||||
let mut tree = initial();
|
||||
for i in 0..add {
|
||||
tree.append_leaf(leaf(i+3)).expect("Failed to append");
|
||||
}
|
||||
for _ in 0..delete {
|
||||
tree.truncate_leaf().expect("Failed to truncate");
|
||||
}
|
||||
|
||||
let total = add - delete + 2;
|
||||
|
||||
TestResult::from_bool(
|
||||
if total & (total - 1) == 0 {
|
||||
matches!(tree.root(), EntryLink::Stored(_))
|
||||
} else {
|
||||
matches!(tree.root(), EntryLink::Generated(_))
|
||||
}
|
||||
)
|
||||
assert_matches!(tree.root(), EntryLink::Generated(_));
|
||||
}
|
||||
}
|
||||
|
||||
// Length of tree is always less than number of leaves squared
|
||||
fn stored_length(add: u32, delete: u32) -> TestResult {
|
||||
if add > 2048 * 2048 || add < delete {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let mut tree = initial();
|
||||
for i in 0..add {
|
||||
tree.append_leaf(leaf(i+3)).expect("Failed to append");
|
||||
}
|
||||
for _ in 0..delete {
|
||||
tree.truncate_leaf().expect("Failed to truncate");
|
||||
}
|
||||
|
||||
let total = add - delete + 2;
|
||||
|
||||
TestResult::from_bool(total * total > tree.len())
|
||||
#[test]
|
||||
fn prop_stored_length(
|
||||
add_and_delete in (0u32..=(2048*2048)).prop_flat_map(
|
||||
|add| (Just(add), 0..=add)
|
||||
)
|
||||
) {
|
||||
let (add, delete) = add_and_delete;
|
||||
let mut tree = initial();
|
||||
for i in 0..add {
|
||||
tree.append_leaf(leaf(i+3)).expect("Failed to append");
|
||||
}
|
||||
for _ in 0..delete {
|
||||
tree.truncate_leaf().expect("Failed to truncate");
|
||||
}
|
||||
|
||||
let total = add - delete + 2;
|
||||
|
||||
assert!(total * total > tree.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue