Add another test for for idempotency

This commit is contained in:
Jeremy Wall 2022-08-02 03:01:27 -04:00
parent b8f3d9c630
commit be789a2fee
4 changed files with 92 additions and 0 deletions

View File

@ -8,3 +8,10 @@ license = "Apache License 2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.proptest]
version = "1.0.0"
optional = true
[features]
default = []

View File

@ -23,6 +23,8 @@ mod node;
pub enum EdgeError {
NoSuchDependents,
}
// TODO(jwall): In order to avoid copies it is probably smart to have some concept of
// a node pool.
/// A Merkle-DAG implementation. This is a modification on the standard Merkle Tree data structure
/// but instead of a tree it is a DAG and as a result can have multiple roots. A merkle-dag specifies
@ -114,3 +116,6 @@ where
#[cfg(test)]
mod test;
#[cfg(all(test, feature = "proptest"))]
mod proptest;

58
src/proptest.rs Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2022 Jeremy Wall (Jeremy@marzhilsltudios.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use proptest::prelude::*;
use std::collections::{hash_map::DefaultHasher, BTreeMap, BTreeSet};
use crate::DAG;
fn edge_strategy(nodes_count: usize) -> impl Strategy<Value = (Vec<String>, BTreeSet<usize>)> {
prop::collection::vec(".*", 4..nodes_count).prop_flat_map(|payloads| {
let nodes_len = payloads.len();
// TODO(jwall): Generate valid DAGs
// select a random set of payloads to be roots.
// select a random set of non root payloads to be dependencies
(
// our total list of nodes.
Just(payloads),
// our random list of roots.
prop::collection::btree_set(1..nodes_len, 1..(nodes_len / 2)),
)
})
}
proptest! {
#[test]
fn test_dag_add_node_properties((nodes, parent_idxs) in edge_strategy(100)) {
// TODO implement the tests now
let mut dag = DAG::<String, DefaultHasher, 8>::new();
let parent_count = parent_idxs.len();
let mut dependents = BTreeMap::new();
for (idx, n) in nodes.iter().cloned().enumerate() {
if !parent_idxs.contains(&idx) {
let node_id = dag.add_node(n, BTreeSet::new()).unwrap();
let parent = idx % parent_count;
if dependents.contains_key(&parent) {
dependents.get_mut(&parent).map(|v: &mut BTreeSet<[u8; 8]>| v.insert(node_id));
} else {
dependents.insert(parent, BTreeSet::from([node_id]));
}
}
}
for (pidx, dep_ids) in dependents {
dag.add_node(nodes[pidx].clone(), dep_ids).unwrap();
}
assert!(dag.get_roots().len() <= parent_count);
assert!(dag.get_nodes().len() <= nodes.len());
}
}

View File

@ -61,3 +61,25 @@ fn test_adding_nodes_is_idempotent() {
assert_eq!(root_size, dag.get_roots().len());
assert_eq!(nodes_size, dag.get_nodes().len());
}
#[test]
fn test_adding_nodes_is_idempotent_regardless_of_dep_order() {
let mut dag = DAG::<&str, DefaultHasher, 8>::new();
let quake_node_id = dag.add_node("quake", BTreeSet::new()).unwrap();
let qualm_node_id = dag.add_node("qualm", BTreeSet::new()).unwrap();
let quell_node_id = dag.add_node("quell", BTreeSet::new()).unwrap();
let dep_ids = BTreeSet::from([quake_node_id, qualm_node_id, quell_node_id]);
dag.add_node("foo", dep_ids).unwrap();
let root_size = dag.get_roots().len();
let nodes_size = dag.get_nodes().len();
let dep_ids = BTreeSet::from([quell_node_id, quake_node_id, qualm_node_id]);
dag.add_node("foo", dep_ids).unwrap();
assert_eq!(root_size, dag.get_roots().len());
assert_eq!(nodes_size, dag.get_nodes().len());
let dep_ids = BTreeSet::from([qualm_node_id, quell_node_id, quake_node_id]);
dag.add_node("foo", dep_ids).unwrap();
assert_eq!(root_size, dag.get_roots().len());
assert_eq!(nodes_size, dag.get_nodes().len());
}