use proptest::collection::{btree_map, vec};
use proptest::prelude::*;
use wacore_binary::marshal::{marshal, unmarshal_ref};
use wacore_binary::node::{Attrs, Node, NodeContent, NodeValue};
const MAX_DEPTH: u32 = 4;
const MAX_CHILDREN: usize = 4;
const MAX_ATTRS: usize = 4;
const MAX_BYTES: usize = 64;
fn safe_string() -> impl Strategy<Value = String> {
prop::string::string_regex("[^@]{0,16}").expect("valid regex")
}
fn nibble_string() -> impl Strategy<Value = String> {
prop::string::string_regex("[0-9.-]{1,16}").expect("valid regex")
}
fn attrs_strategy() -> impl Strategy<Value = Attrs> {
btree_map(safe_string(), safe_string(), 0..=MAX_ATTRS).prop_map(|map| {
let mut attrs = Attrs::new();
for (k, v) in map {
attrs.push(k, NodeValue::String(v.into()));
}
attrs
})
}
fn node_strategy() -> impl Strategy<Value = Node> {
let leaf_content = prop_oneof![
Just(None),
nibble_string().prop_map(|s| Some(NodeContent::String(s.into()))),
vec(any::<u8>(), 0..=MAX_BYTES).prop_map(|b| Some(NodeContent::Bytes(b))),
];
let leaf = (safe_string(), attrs_strategy(), leaf_content)
.prop_map(|(tag, attrs, content)| Node::new(tag, attrs, content));
leaf.prop_recursive(MAX_DEPTH, 64, MAX_CHILDREN as u32, move |inner| {
(
safe_string(),
attrs_strategy(),
vec(inner, 1..=MAX_CHILDREN),
)
.prop_map(|(tag, attrs, children)| {
Node::new(tag, attrs, Some(NodeContent::Nodes(children)))
})
})
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(2048))]
#[test]
fn marshal_unmarshal_roundtrip(node in node_strategy()) {
let bytes = marshal(&node).expect("marshal must succeed for a valid node");
let decoded = unmarshal_ref(&bytes[1..])
.expect("decoding our own encoder output must succeed")
.to_owned();
prop_assert_eq!(decoded, node);
}
}