Move CombinedTree to incrementalmerkletree::testing
This commit is contained in:
parent
3f88ac3af2
commit
4e2883c707
|
@ -1,303 +1,35 @@
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::BridgeTree;
|
use crate::BridgeTree;
|
||||||
use incrementalmerkletree::{
|
use incrementalmerkletree::{
|
||||||
testing::{
|
testing::{
|
||||||
append_str, arb_operation, check_operations, complete_tree::CompleteTree, unmark,
|
arb_operation, check_operations, check_rewind_remove_mark,
|
||||||
witness, Operation::*, SipHashable, Tree,
|
check_rewind_remove_mark_consistency, complete_tree::CompleteTree, CombinedTree,
|
||||||
|
SipHashable,
|
||||||
},
|
},
|
||||||
Hashable, Position,
|
Hashable,
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
fn new_combined_tree<H: Hashable + Ord + Clone + Debug>(
|
||||||
// Types and utilities for cross-verification property tests
|
max_checkpoints: usize,
|
||||||
//
|
) -> CombinedTree<H, CompleteTree<H>, BridgeTree<H, 4>> {
|
||||||
|
CombinedTree::new(
|
||||||
#[derive(Clone)]
|
CompleteTree::new(4, max_checkpoints),
|
||||||
pub struct CombinedTree<H: Hashable + Ord, const DEPTH: u8> {
|
BridgeTree::<H, 4>::new(max_checkpoints),
|
||||||
inefficient: CompleteTree<H>,
|
)
|
||||||
efficient: BridgeTree<H, DEPTH>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: Hashable + Ord + Clone, const DEPTH: u8> CombinedTree<H, DEPTH> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CombinedTree {
|
|
||||||
inefficient: CompleteTree::new(DEPTH.into(), 100),
|
|
||||||
efficient: BridgeTree::new(100),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: Hashable + Ord + Clone + Debug, const DEPTH: u8> Tree<H> for CombinedTree<H, DEPTH> {
|
|
||||||
fn append(&mut self, value: &H) -> bool {
|
|
||||||
let a = self.inefficient.append(value);
|
|
||||||
let b = self.efficient.append(value);
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn root(&self, checkpoint_depth: usize) -> Option<H> {
|
|
||||||
let a = self.inefficient.root(checkpoint_depth);
|
|
||||||
let b = self.efficient.root(checkpoint_depth);
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_position(&self) -> Option<Position> {
|
|
||||||
let a = self.inefficient.current_position();
|
|
||||||
let b = self.efficient.current_position();
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_leaf(&self) -> Option<&H> {
|
|
||||||
let a = self.inefficient.current_leaf();
|
|
||||||
let b = self.efficient.current_leaf();
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_marked_leaf(&self, position: Position) -> Option<&H> {
|
|
||||||
let a = self.inefficient.get_marked_leaf(position);
|
|
||||||
let b = self.efficient.get_marked_leaf(position);
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark(&mut self) -> Option<Position> {
|
|
||||||
let a = self.inefficient.mark();
|
|
||||||
let b = self.efficient.mark();
|
|
||||||
assert_eq!(a, b);
|
|
||||||
let apos = self.inefficient.marked_positions();
|
|
||||||
let bpos = self.efficient.marked_positions();
|
|
||||||
assert_eq!(apos, bpos);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marked_positions(&self) -> BTreeSet<Position> {
|
|
||||||
let a = self.inefficient.marked_positions();
|
|
||||||
let b = self.efficient.marked_positions();
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn witness(&self, position: Position, as_of_root: &H) -> Option<Vec<H>> {
|
|
||||||
let a = self.inefficient.witness(position, as_of_root);
|
|
||||||
let b = self.efficient.witness(position, as_of_root);
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_mark(&mut self, position: Position) -> bool {
|
|
||||||
let a = self.inefficient.remove_mark(position);
|
|
||||||
let b = self.efficient.remove_mark(position);
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
fn checkpoint(&mut self) {
|
|
||||||
self.inefficient.checkpoint();
|
|
||||||
self.efficient.checkpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rewind(&mut self) -> bool {
|
|
||||||
let a = self.inefficient.rewind();
|
|
||||||
let b = self.efficient.rewind();
|
|
||||||
assert_eq!(a, b);
|
|
||||||
a
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_witness_consistency() {
|
fn test_rewind_remove_mark() {
|
||||||
let samples = vec![
|
check_rewind_remove_mark(new_combined_tree);
|
||||||
// Reduced examples
|
|
||||||
vec![
|
|
||||||
append_str("a"),
|
|
||||||
append_str("b"),
|
|
||||||
Checkpoint,
|
|
||||||
Mark,
|
|
||||||
witness(0, 1),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("c"),
|
|
||||||
append_str("d"),
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
witness(1, 1),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("e"),
|
|
||||||
Checkpoint,
|
|
||||||
Mark,
|
|
||||||
append_str("f"),
|
|
||||||
witness(0, 1),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("g"),
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
unmark(0),
|
|
||||||
append_str("h"),
|
|
||||||
witness(0, 0),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("i"),
|
|
||||||
Checkpoint,
|
|
||||||
Mark,
|
|
||||||
unmark(0),
|
|
||||||
append_str("j"),
|
|
||||||
witness(0, 0),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("i"),
|
|
||||||
Mark,
|
|
||||||
append_str("j"),
|
|
||||||
Checkpoint,
|
|
||||||
append_str("k"),
|
|
||||||
witness(0, 1),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("l"),
|
|
||||||
Checkpoint,
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
append_str("m"),
|
|
||||||
Checkpoint,
|
|
||||||
witness(0, 2),
|
|
||||||
],
|
|
||||||
vec![Checkpoint, append_str("n"), Mark, witness(0, 1)],
|
|
||||||
vec![
|
|
||||||
append_str("a"),
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
unmark(0),
|
|
||||||
Checkpoint,
|
|
||||||
append_str("b"),
|
|
||||||
witness(0, 1),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("a"),
|
|
||||||
Mark,
|
|
||||||
append_str("b"),
|
|
||||||
unmark(0),
|
|
||||||
Checkpoint,
|
|
||||||
witness(0, 0),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("a"),
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
unmark(0),
|
|
||||||
Checkpoint,
|
|
||||||
Rewind,
|
|
||||||
append_str("b"),
|
|
||||||
witness(0, 0),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("a"),
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
Checkpoint,
|
|
||||||
Rewind,
|
|
||||||
append_str("a"),
|
|
||||||
unmark(0),
|
|
||||||
witness(0, 1),
|
|
||||||
],
|
|
||||||
// Unreduced examples
|
|
||||||
vec![
|
|
||||||
append_str("o"),
|
|
||||||
append_str("p"),
|
|
||||||
Mark,
|
|
||||||
append_str("q"),
|
|
||||||
Checkpoint,
|
|
||||||
unmark(1),
|
|
||||||
witness(1, 1),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("r"),
|
|
||||||
append_str("s"),
|
|
||||||
append_str("t"),
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
unmark(2),
|
|
||||||
Checkpoint,
|
|
||||||
witness(2, 2),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("u"),
|
|
||||||
Mark,
|
|
||||||
append_str("v"),
|
|
||||||
append_str("w"),
|
|
||||||
Checkpoint,
|
|
||||||
unmark(0),
|
|
||||||
append_str("x"),
|
|
||||||
Checkpoint,
|
|
||||||
Checkpoint,
|
|
||||||
witness(0, 3),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
for (i, sample) in samples.iter().enumerate() {
|
|
||||||
let tree = CombinedTree::<String, 4>::new();
|
|
||||||
let result = check_operations(tree, 4, sample);
|
|
||||||
assert!(
|
|
||||||
matches!(result, Ok(())),
|
|
||||||
"Reference/Test mismatch at index {}: {:?}",
|
|
||||||
i,
|
|
||||||
result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These check_operations tests cover errors where the test framework itself previously did not
|
|
||||||
// correctly handle chain state restoration.
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rewind_remove_mark_consistency() {
|
fn test_rewind_remove_mark_consistency() {
|
||||||
let samples = vec![
|
check_rewind_remove_mark_consistency(new_combined_tree);
|
||||||
vec![append_str("x"), Checkpoint, Mark, Rewind, unmark(0)],
|
|
||||||
vec![
|
|
||||||
append_str("d"),
|
|
||||||
Checkpoint,
|
|
||||||
Mark,
|
|
||||||
unmark(0),
|
|
||||||
Rewind,
|
|
||||||
unmark(0),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("o"),
|
|
||||||
Checkpoint,
|
|
||||||
Mark,
|
|
||||||
Checkpoint,
|
|
||||||
unmark(0),
|
|
||||||
Rewind,
|
|
||||||
Rewind,
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
append_str("s"),
|
|
||||||
Mark,
|
|
||||||
append_str("m"),
|
|
||||||
Checkpoint,
|
|
||||||
unmark(0),
|
|
||||||
Rewind,
|
|
||||||
unmark(0),
|
|
||||||
unmark(0),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
for (i, sample) in samples.iter().enumerate() {
|
|
||||||
let tree = CombinedTree::<String, 4>::new();
|
|
||||||
let result = check_operations(tree, 4, sample);
|
|
||||||
assert!(
|
|
||||||
matches!(result, Ok(())),
|
|
||||||
"Reference/Test mismatch at index {}: {:?}",
|
|
||||||
i,
|
|
||||||
result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
|
@ -310,7 +42,7 @@ pub(crate) mod tests {
|
||||||
1..100
|
1..100
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
let tree = CombinedTree::<SipHashable, 4>::new();
|
let tree = new_combined_tree(100);
|
||||||
check_operations(tree, 4, &ops)?;
|
check_operations(tree, 4, &ops)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +53,7 @@ pub(crate) mod tests {
|
||||||
1..100
|
1..100
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
let tree = CombinedTree::<String, 4>::new();
|
let tree = new_combined_tree(100);
|
||||||
check_operations(tree, 4, &ops)?;
|
check_operations(tree, 4, &ops)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
//! Traits and types used to permit comparison testing between tree implementations.
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
@ -384,6 +387,106 @@ pub fn compute_root_from_witness<H: Hashable>(value: H, position: Position, path
|
||||||
cur
|
cur
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Types and utilities for cross-verification property tests
|
||||||
|
//
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CombinedTree<H, I: Tree<H>, E: Tree<H>> {
|
||||||
|
inefficient: I,
|
||||||
|
efficient: E,
|
||||||
|
_phantom: PhantomData<H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hashable + Ord + Clone + Debug, I: Tree<H>, E: Tree<H>> CombinedTree<H, I, E> {
|
||||||
|
pub fn new(inefficient: I, efficient: E) -> Self {
|
||||||
|
CombinedTree {
|
||||||
|
inefficient,
|
||||||
|
efficient,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hashable + Ord + Clone + Debug, I: Tree<H>, E: Tree<H>> Tree<H> for CombinedTree<H, I, E> {
|
||||||
|
fn append(&mut self, value: &H) -> bool {
|
||||||
|
let a = self.inefficient.append(value);
|
||||||
|
let b = self.efficient.append(value);
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn root(&self, checkpoint_depth: usize) -> Option<H> {
|
||||||
|
let a = self.inefficient.root(checkpoint_depth);
|
||||||
|
let b = self.efficient.root(checkpoint_depth);
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_position(&self) -> Option<Position> {
|
||||||
|
let a = self.inefficient.current_position();
|
||||||
|
let b = self.efficient.current_position();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_leaf(&self) -> Option<&H> {
|
||||||
|
let a = self.inefficient.current_leaf();
|
||||||
|
let b = self.efficient.current_leaf();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_marked_leaf(&self, position: Position) -> Option<&H> {
|
||||||
|
let a = self.inefficient.get_marked_leaf(position);
|
||||||
|
let b = self.efficient.get_marked_leaf(position);
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark(&mut self) -> Option<Position> {
|
||||||
|
let a = self.inefficient.mark();
|
||||||
|
let b = self.efficient.mark();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
let apos = self.inefficient.marked_positions();
|
||||||
|
let bpos = self.efficient.marked_positions();
|
||||||
|
assert_eq!(apos, bpos);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn marked_positions(&self) -> BTreeSet<Position> {
|
||||||
|
let a = self.inefficient.marked_positions();
|
||||||
|
let b = self.efficient.marked_positions();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn witness(&self, position: Position, as_of_root: &H) -> Option<Vec<H>> {
|
||||||
|
let a = self.inefficient.witness(position, as_of_root);
|
||||||
|
let b = self.efficient.witness(position, as_of_root);
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_mark(&mut self, position: Position) -> bool {
|
||||||
|
let a = self.inefficient.remove_mark(position);
|
||||||
|
let b = self.efficient.remove_mark(position);
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checkpoint(&mut self) {
|
||||||
|
self.inefficient.checkpoint();
|
||||||
|
self.efficient.checkpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewind(&mut self) -> bool {
|
||||||
|
let a = self.inefficient.rewind();
|
||||||
|
let b = self.efficient.rewind();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Shared example tests
|
// Shared example tests
|
||||||
//
|
//
|
||||||
|
@ -763,6 +866,188 @@ pub fn check_rewind_remove_mark<T: Tree<String>, F: Fn(usize) -> T>(new_tree: F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_witness_consistency<T: Tree<String>, F: Fn(usize) -> T>(new_tree: F) {
|
||||||
|
let samples = vec![
|
||||||
|
// Reduced examples
|
||||||
|
vec![
|
||||||
|
append_str("a"),
|
||||||
|
append_str("b"),
|
||||||
|
Checkpoint,
|
||||||
|
Mark,
|
||||||
|
witness(0, 1),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("c"),
|
||||||
|
append_str("d"),
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
witness(1, 1),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("e"),
|
||||||
|
Checkpoint,
|
||||||
|
Mark,
|
||||||
|
append_str("f"),
|
||||||
|
witness(0, 1),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("g"),
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
unmark(0),
|
||||||
|
append_str("h"),
|
||||||
|
witness(0, 0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("i"),
|
||||||
|
Checkpoint,
|
||||||
|
Mark,
|
||||||
|
unmark(0),
|
||||||
|
append_str("j"),
|
||||||
|
witness(0, 0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("i"),
|
||||||
|
Mark,
|
||||||
|
append_str("j"),
|
||||||
|
Checkpoint,
|
||||||
|
append_str("k"),
|
||||||
|
witness(0, 1),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("l"),
|
||||||
|
Checkpoint,
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
append_str("m"),
|
||||||
|
Checkpoint,
|
||||||
|
witness(0, 2),
|
||||||
|
],
|
||||||
|
vec![Checkpoint, append_str("n"), Mark, witness(0, 1)],
|
||||||
|
vec![
|
||||||
|
append_str("a"),
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
unmark(0),
|
||||||
|
Checkpoint,
|
||||||
|
append_str("b"),
|
||||||
|
witness(0, 1),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("a"),
|
||||||
|
Mark,
|
||||||
|
append_str("b"),
|
||||||
|
unmark(0),
|
||||||
|
Checkpoint,
|
||||||
|
witness(0, 0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("a"),
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
unmark(0),
|
||||||
|
Checkpoint,
|
||||||
|
Rewind,
|
||||||
|
append_str("b"),
|
||||||
|
witness(0, 0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("a"),
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
Checkpoint,
|
||||||
|
Rewind,
|
||||||
|
append_str("a"),
|
||||||
|
unmark(0),
|
||||||
|
witness(0, 1),
|
||||||
|
],
|
||||||
|
// Unreduced examples
|
||||||
|
vec![
|
||||||
|
append_str("o"),
|
||||||
|
append_str("p"),
|
||||||
|
Mark,
|
||||||
|
append_str("q"),
|
||||||
|
Checkpoint,
|
||||||
|
unmark(1),
|
||||||
|
witness(1, 1),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("r"),
|
||||||
|
append_str("s"),
|
||||||
|
append_str("t"),
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
unmark(2),
|
||||||
|
Checkpoint,
|
||||||
|
witness(2, 2),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("u"),
|
||||||
|
Mark,
|
||||||
|
append_str("v"),
|
||||||
|
append_str("w"),
|
||||||
|
Checkpoint,
|
||||||
|
unmark(0),
|
||||||
|
append_str("x"),
|
||||||
|
Checkpoint,
|
||||||
|
Checkpoint,
|
||||||
|
witness(0, 3),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, sample) in samples.iter().enumerate() {
|
||||||
|
let result = check_operations(new_tree(100), 4, sample);
|
||||||
|
assert!(
|
||||||
|
matches!(result, Ok(())),
|
||||||
|
"Reference/Test mismatch at index {}: {:?}",
|
||||||
|
i,
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_rewind_remove_mark_consistency<T: Tree<String>, F: Fn(usize) -> T>(new_tree: F) {
|
||||||
|
let samples = vec![
|
||||||
|
vec![append_str("x"), Checkpoint, Mark, Rewind, unmark(0)],
|
||||||
|
vec![
|
||||||
|
append_str("d"),
|
||||||
|
Checkpoint,
|
||||||
|
Mark,
|
||||||
|
unmark(0),
|
||||||
|
Rewind,
|
||||||
|
unmark(0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("o"),
|
||||||
|
Checkpoint,
|
||||||
|
Mark,
|
||||||
|
Checkpoint,
|
||||||
|
unmark(0),
|
||||||
|
Rewind,
|
||||||
|
Rewind,
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
append_str("s"),
|
||||||
|
Mark,
|
||||||
|
append_str("m"),
|
||||||
|
Checkpoint,
|
||||||
|
unmark(0),
|
||||||
|
Rewind,
|
||||||
|
unmark(0),
|
||||||
|
unmark(0),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
for (i, sample) in samples.iter().enumerate() {
|
||||||
|
let result = check_operations(new_tree(100), 4, sample);
|
||||||
|
assert!(
|
||||||
|
matches!(result, Ok(())),
|
||||||
|
"Reference/Test mismatch at index {}: {:?}",
|
||||||
|
i,
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
Loading…
Reference in New Issue