Make test utilities available under a test-dependencies feature.
This commit is contained in:
parent
7331a8f458
commit
e19446f8fd
|
@ -14,6 +14,10 @@ categories = ["algorithms", "data-structures"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
proptest = { version = "1.0.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest = "1"
|
proptest = "1.0.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
test-dependencies = ["proptest"]
|
||||||
|
|
|
@ -1105,8 +1105,10 @@ mod tests {
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::{apply_operation, arb_operation};
|
use crate::{
|
||||||
use crate::{Frontier, Tree};
|
testing::{apply_operation, arb_operation},
|
||||||
|
Frontier, Tree,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nonempty_frontier_root() {
|
fn nonempty_frontier_root() {
|
||||||
|
|
383
src/lib.rs
383
src/lib.rs
|
@ -412,17 +412,180 @@ pub trait Tree<H> {
|
||||||
fn garbage_collect(&mut self);
|
fn garbage_collect(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(bench, test, feature = "test-dependencies"))]
|
||||||
|
pub mod testing {
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
|
use proptest::prelude::*;
|
||||||
|
use std::hash::{Hasher, SipHasher};
|
||||||
|
|
||||||
|
use super::{Hashable, Level, Position, Tree};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Types and utilities for shared example tests.
|
||||||
|
//
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub(crate) struct SipHashable(pub(crate) u64);
|
||||||
|
|
||||||
|
impl Hashable for SipHashable {
|
||||||
|
fn empty_leaf() -> Self {
|
||||||
|
SipHashable(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combine(_level: Level, a: &Self, b: &Self) -> Self {
|
||||||
|
let mut hasher = SipHasher::new();
|
||||||
|
hasher.write_u64(a.0);
|
||||||
|
hasher.write_u64(b.0);
|
||||||
|
SipHashable(hasher.finish())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hashable for String {
|
||||||
|
fn empty_leaf() -> Self {
|
||||||
|
"_".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combine(_: Level, a: &Self, b: &Self) -> Self {
|
||||||
|
a.to_string() + b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Operations
|
||||||
|
//
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Operation<A> {
|
||||||
|
Append(A),
|
||||||
|
CurrentPosition,
|
||||||
|
CurrentLeaf,
|
||||||
|
Mark,
|
||||||
|
MarkedLeaf(Position),
|
||||||
|
MarkedPositions,
|
||||||
|
Unmark(Position),
|
||||||
|
Checkpoint,
|
||||||
|
Rewind,
|
||||||
|
Authpath(Position, usize),
|
||||||
|
GarbageCollect,
|
||||||
|
}
|
||||||
|
|
||||||
|
use Operation::*;
|
||||||
|
|
||||||
|
impl<H: Hashable> Operation<H> {
|
||||||
|
pub fn apply<T: Tree<H>>(&self, tree: &mut T) -> Option<(Position, Vec<H>)> {
|
||||||
|
match self {
|
||||||
|
Append(a) => {
|
||||||
|
assert!(tree.append(a), "append failed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
CurrentPosition => None,
|
||||||
|
CurrentLeaf => None,
|
||||||
|
Mark => {
|
||||||
|
assert!(tree.mark().is_some(), "mark failed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
MarkedLeaf(_) => None,
|
||||||
|
MarkedPositions => None,
|
||||||
|
Unmark(p) => {
|
||||||
|
assert!(tree.remove_mark(*p), "remove mark failed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Checkpoint => {
|
||||||
|
tree.checkpoint();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Rewind => {
|
||||||
|
assert!(tree.rewind(), "rewind failed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Authpath(p, d) => tree
|
||||||
|
.root(*d)
|
||||||
|
.and_then(|root| tree.witness(*p, &root))
|
||||||
|
.map(|xs| (*p, xs)),
|
||||||
|
GarbageCollect => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_all<T: Tree<H>>(
|
||||||
|
ops: &[Operation<H>],
|
||||||
|
tree: &mut T,
|
||||||
|
) -> Option<(Position, Vec<H>)> {
|
||||||
|
let mut result = None;
|
||||||
|
for op in ops {
|
||||||
|
result = op.apply(tree);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arb_operation<G: Strategy + Clone>(
|
||||||
|
item_gen: G,
|
||||||
|
pos_gen: impl Strategy<Value = usize> + Clone,
|
||||||
|
) -> impl Strategy<Value = Operation<G::Value>>
|
||||||
|
where
|
||||||
|
G::Value: Clone + 'static,
|
||||||
|
{
|
||||||
|
prop_oneof![
|
||||||
|
item_gen.prop_map(Operation::Append),
|
||||||
|
Just(Operation::Mark),
|
||||||
|
prop_oneof![
|
||||||
|
Just(Operation::CurrentLeaf),
|
||||||
|
Just(Operation::CurrentPosition),
|
||||||
|
Just(Operation::MarkedPositions),
|
||||||
|
],
|
||||||
|
Just(Operation::GarbageCollect),
|
||||||
|
pos_gen
|
||||||
|
.clone()
|
||||||
|
.prop_map(|i| Operation::MarkedLeaf(Position(i))),
|
||||||
|
pos_gen.clone().prop_map(|i| Operation::Unmark(Position(i))),
|
||||||
|
Just(Operation::Checkpoint),
|
||||||
|
Just(Operation::Rewind),
|
||||||
|
pos_gen.prop_flat_map(
|
||||||
|
|i| (0usize..10).prop_map(move |depth| Operation::Authpath(Position(i), depth))
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_operation<H, T: Tree<H>>(tree: &mut T, op: Operation<H>) {
|
||||||
|
match op {
|
||||||
|
Append(value) => {
|
||||||
|
tree.append(&value);
|
||||||
|
}
|
||||||
|
Mark => {
|
||||||
|
tree.mark();
|
||||||
|
}
|
||||||
|
Unmark(position) => {
|
||||||
|
tree.remove_mark(position);
|
||||||
|
}
|
||||||
|
Checkpoint => {
|
||||||
|
tree.checkpoint();
|
||||||
|
}
|
||||||
|
Rewind => {
|
||||||
|
tree.rewind();
|
||||||
|
}
|
||||||
|
CurrentPosition => {}
|
||||||
|
CurrentLeaf => {}
|
||||||
|
Authpath(_, _) => {}
|
||||||
|
MarkedLeaf(_) => {}
|
||||||
|
MarkedPositions => {}
|
||||||
|
GarbageCollect => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
#![allow(deprecated)]
|
use proptest::prelude::*;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hasher;
|
|
||||||
use std::hash::SipHasher;
|
|
||||||
|
|
||||||
use super::bridgetree::BridgeTree;
|
use super::{
|
||||||
use super::sample::{lazy_root, CompleteTree};
|
bridgetree::BridgeTree,
|
||||||
use super::{Address, Hashable, Level, Position, Source, Tree};
|
sample::{lazy_root, CompleteTree},
|
||||||
|
testing::{arb_operation, Operation, Operation::*, SipHashable},
|
||||||
|
Address, Hashable, Level, Position, Source, Tree,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn position_is_complete_subtree() {
|
fn position_is_complete_subtree() {
|
||||||
|
@ -519,36 +682,6 @@ pub(crate) mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Types and utilities for shared example tests.
|
|
||||||
//
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub(crate) struct SipHashable(pub(crate) u64);
|
|
||||||
|
|
||||||
impl Hashable for SipHashable {
|
|
||||||
fn empty_leaf() -> Self {
|
|
||||||
SipHashable(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn combine(_level: Level, a: &Self, b: &Self) -> Self {
|
|
||||||
let mut hasher = SipHasher::new();
|
|
||||||
hasher.write_u64(a.0);
|
|
||||||
hasher.write_u64(b.0);
|
|
||||||
SipHashable(hasher.finish())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hashable for String {
|
|
||||||
fn empty_leaf() -> Self {
|
|
||||||
"_".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn combine(_: Level, a: &Self, b: &Self) -> Self {
|
|
||||||
a.to_string() + b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Shared example tests
|
// Shared example tests
|
||||||
//
|
//
|
||||||
|
@ -835,6 +968,18 @@ pub(crate) mod tests {
|
||||||
assert_eq!(t.root(0).unwrap(), "ab______________");
|
assert_eq!(t.root(0).unwrap(), "ab______________");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn append(x: &str) -> Operation<String> {
|
||||||
|
Operation::Append(x.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmark(pos: usize) -> Operation<String> {
|
||||||
|
Operation::Unmark(Position(pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn witness(pos: usize, depth: usize) -> Operation<String> {
|
||||||
|
Operation::Authpath(Position(pos), depth)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn check_rewind_remove_mark<T: Tree<String>, F: Fn(usize) -> T>(new_tree: F) {
|
pub(crate) fn check_rewind_remove_mark<T: Tree<String>, F: Fn(usize) -> T>(new_tree: F) {
|
||||||
let mut tree = new_tree(100);
|
let mut tree = new_tree(100);
|
||||||
tree.append(&"e".to_string());
|
tree.append(&"e".to_string());
|
||||||
|
@ -1024,86 +1169,6 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Operations
|
|
||||||
//
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum Operation<A> {
|
|
||||||
Append(A),
|
|
||||||
CurrentPosition,
|
|
||||||
CurrentLeaf,
|
|
||||||
Mark,
|
|
||||||
MarkedLeaf(Position),
|
|
||||||
MarkedPositions,
|
|
||||||
Unmark(Position),
|
|
||||||
Checkpoint,
|
|
||||||
Rewind,
|
|
||||||
Authpath(Position, usize),
|
|
||||||
GarbageCollect,
|
|
||||||
}
|
|
||||||
|
|
||||||
use Operation::*;
|
|
||||||
|
|
||||||
fn append(x: &str) -> Operation<String> {
|
|
||||||
Operation::Append(x.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unmark(pos: usize) -> Operation<String> {
|
|
||||||
Operation::Unmark(Position(pos))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn authpath(pos: usize, depth: usize) -> Operation<String> {
|
|
||||||
Operation::Authpath(Position(pos), depth)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: Hashable> Operation<H> {
|
|
||||||
pub fn apply<T: Tree<H>>(&self, tree: &mut T) -> Option<(Position, Vec<H>)> {
|
|
||||||
match self {
|
|
||||||
Append(a) => {
|
|
||||||
assert!(tree.append(a), "append failed");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
CurrentPosition => None,
|
|
||||||
CurrentLeaf => None,
|
|
||||||
Mark => {
|
|
||||||
assert!(tree.mark().is_some(), "mark failed");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
MarkedLeaf(_) => None,
|
|
||||||
MarkedPositions => None,
|
|
||||||
Unmark(p) => {
|
|
||||||
assert!(tree.remove_mark(*p), "remove mark failed");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Checkpoint => {
|
|
||||||
tree.checkpoint();
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Rewind => {
|
|
||||||
assert!(tree.rewind(), "rewind failed");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Authpath(p, d) => tree
|
|
||||||
.root(*d)
|
|
||||||
.and_then(|root| tree.witness(*p, &root))
|
|
||||||
.map(|xs| (*p, xs)),
|
|
||||||
GarbageCollect => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_all<T: Tree<H>>(
|
|
||||||
ops: &[Operation<H>],
|
|
||||||
tree: &mut T,
|
|
||||||
) -> Option<(Position, Vec<H>)> {
|
|
||||||
let mut result = None;
|
|
||||||
for op in ops {
|
|
||||||
result = op.apply(tree);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn compute_root_from_witness<H: Hashable>(
|
pub(crate) fn compute_root_from_witness<H: Hashable>(
|
||||||
value: H,
|
value: H,
|
||||||
position: Position,
|
position: Position,
|
||||||
|
@ -1181,16 +1246,16 @@ pub(crate) mod tests {
|
||||||
fn test_witness_consistency() {
|
fn test_witness_consistency() {
|
||||||
let samples = vec![
|
let samples = vec![
|
||||||
// Reduced examples
|
// Reduced examples
|
||||||
vec![append("a"), append("b"), Checkpoint, Mark, authpath(0, 1)],
|
vec![append("a"), append("b"), Checkpoint, Mark, witness(0, 1)],
|
||||||
vec![append("c"), append("d"), Mark, Checkpoint, authpath(1, 1)],
|
vec![append("c"), append("d"), Mark, Checkpoint, witness(1, 1)],
|
||||||
vec![append("e"), Checkpoint, Mark, append("f"), authpath(0, 1)],
|
vec![append("e"), Checkpoint, Mark, append("f"), witness(0, 1)],
|
||||||
vec![
|
vec![
|
||||||
append("g"),
|
append("g"),
|
||||||
Mark,
|
Mark,
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
unmark(0),
|
unmark(0),
|
||||||
append("h"),
|
append("h"),
|
||||||
authpath(0, 0),
|
witness(0, 0),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("i"),
|
append("i"),
|
||||||
|
@ -1198,7 +1263,7 @@ pub(crate) mod tests {
|
||||||
Mark,
|
Mark,
|
||||||
unmark(0),
|
unmark(0),
|
||||||
append("j"),
|
append("j"),
|
||||||
authpath(0, 0),
|
witness(0, 0),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("i"),
|
append("i"),
|
||||||
|
@ -1206,7 +1271,7 @@ pub(crate) mod tests {
|
||||||
append("j"),
|
append("j"),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
append("k"),
|
append("k"),
|
||||||
authpath(0, 1),
|
witness(0, 1),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("l"),
|
append("l"),
|
||||||
|
@ -1215,9 +1280,9 @@ pub(crate) mod tests {
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
append("m"),
|
append("m"),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
authpath(0, 2),
|
witness(0, 2),
|
||||||
],
|
],
|
||||||
vec![Checkpoint, append("n"), Mark, authpath(0, 1)],
|
vec![Checkpoint, append("n"), Mark, witness(0, 1)],
|
||||||
vec![
|
vec![
|
||||||
append("a"),
|
append("a"),
|
||||||
Mark,
|
Mark,
|
||||||
|
@ -1225,7 +1290,7 @@ pub(crate) mod tests {
|
||||||
unmark(0),
|
unmark(0),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
append("b"),
|
append("b"),
|
||||||
authpath(0, 1),
|
witness(0, 1),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("a"),
|
append("a"),
|
||||||
|
@ -1233,7 +1298,7 @@ pub(crate) mod tests {
|
||||||
append("b"),
|
append("b"),
|
||||||
unmark(0),
|
unmark(0),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
authpath(0, 0),
|
witness(0, 0),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("a"),
|
append("a"),
|
||||||
|
@ -1243,7 +1308,7 @@ pub(crate) mod tests {
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
Rewind,
|
Rewind,
|
||||||
append("b"),
|
append("b"),
|
||||||
authpath(0, 0),
|
witness(0, 0),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("a"),
|
append("a"),
|
||||||
|
@ -1253,7 +1318,7 @@ pub(crate) mod tests {
|
||||||
Rewind,
|
Rewind,
|
||||||
append("a"),
|
append("a"),
|
||||||
unmark(0),
|
unmark(0),
|
||||||
authpath(0, 1),
|
witness(0, 1),
|
||||||
],
|
],
|
||||||
// Unreduced examples
|
// Unreduced examples
|
||||||
vec![
|
vec![
|
||||||
|
@ -1263,7 +1328,7 @@ pub(crate) mod tests {
|
||||||
append("q"),
|
append("q"),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
unmark(1),
|
unmark(1),
|
||||||
authpath(1, 1),
|
witness(1, 1),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("r"),
|
append("r"),
|
||||||
|
@ -1273,7 +1338,7 @@ pub(crate) mod tests {
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
unmark(2),
|
unmark(2),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
authpath(2, 2),
|
witness(2, 2),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
append("u"),
|
append("u"),
|
||||||
|
@ -1285,7 +1350,7 @@ pub(crate) mod tests {
|
||||||
append("x"),
|
append("x"),
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
Checkpoint,
|
Checkpoint,
|
||||||
authpath(0, 3),
|
witness(0, 3),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1338,62 +1403,6 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use proptest::prelude::*;
|
|
||||||
|
|
||||||
pub fn arb_operation<G: Strategy + Clone>(
|
|
||||||
item_gen: G,
|
|
||||||
pos_gen: impl Strategy<Value = usize> + Clone,
|
|
||||||
) -> impl Strategy<Value = Operation<G::Value>>
|
|
||||||
where
|
|
||||||
G::Value: Clone + 'static,
|
|
||||||
{
|
|
||||||
prop_oneof![
|
|
||||||
item_gen.prop_map(Operation::Append),
|
|
||||||
Just(Operation::Mark),
|
|
||||||
prop_oneof![
|
|
||||||
Just(Operation::CurrentLeaf),
|
|
||||||
Just(Operation::CurrentPosition),
|
|
||||||
Just(Operation::MarkedPositions),
|
|
||||||
],
|
|
||||||
Just(Operation::GarbageCollect),
|
|
||||||
pos_gen
|
|
||||||
.clone()
|
|
||||||
.prop_map(|i| Operation::MarkedLeaf(Position(i))),
|
|
||||||
pos_gen.clone().prop_map(|i| Operation::Unmark(Position(i))),
|
|
||||||
Just(Operation::Checkpoint),
|
|
||||||
Just(Operation::Rewind),
|
|
||||||
pos_gen.prop_flat_map(
|
|
||||||
|i| (0usize..10).prop_map(move |depth| Operation::Authpath(Position(i), depth))
|
|
||||||
),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_operation<H, T: Tree<H>>(tree: &mut T, op: Operation<H>) {
|
|
||||||
match op {
|
|
||||||
Append(value) => {
|
|
||||||
tree.append(&value);
|
|
||||||
}
|
|
||||||
Mark => {
|
|
||||||
tree.mark();
|
|
||||||
}
|
|
||||||
Unmark(position) => {
|
|
||||||
tree.remove_mark(position);
|
|
||||||
}
|
|
||||||
Checkpoint => {
|
|
||||||
tree.checkpoint();
|
|
||||||
}
|
|
||||||
Rewind => {
|
|
||||||
tree.rewind();
|
|
||||||
}
|
|
||||||
CurrentPosition => {}
|
|
||||||
CurrentLeaf => {}
|
|
||||||
Authpath(_, _) => {}
|
|
||||||
MarkedLeaf(_) => {}
|
|
||||||
MarkedPositions => {}
|
|
||||||
GarbageCollect => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_operations<H: Hashable + Ord + Clone + Debug>(
|
fn check_operations<H: Hashable + Ord + Clone + Debug>(
|
||||||
ops: &[Operation<H>],
|
ops: &[Operation<H>],
|
||||||
) -> Result<(), TestCaseError> {
|
) -> Result<(), TestCaseError> {
|
||||||
|
|
|
@ -251,11 +251,12 @@ pub(crate) fn lazy_root<H: Hashable + Clone>(mut leaves: Vec<H>) -> H {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::tests::{compute_root_from_witness, SipHashable};
|
|
||||||
use crate::{Hashable, Level, Position, Tree};
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use super::CompleteTree;
|
use super::CompleteTree;
|
||||||
|
use crate::{
|
||||||
|
testing::SipHashable, tests::compute_root_from_witness, Hashable, Level, Position, Tree,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_empty_root() {
|
fn correct_empty_root() {
|
||||||
|
|
Loading…
Reference in New Issue