#![cfg(test)]
use super::{BranchSearch, Config, start_branch_search};
use crate::trie;
use rand::distributions::{Distribution as _, Uniform};
#[test]
fn fuzzing() {
fn uniform_sample(min: u8, max: u8) -> u8 {
Uniform::new_inclusive(min, max).sample(&mut rand::thread_rng())
}
for _ in 0..2048 {
let mut trie = trie::trie_structure::TrieStructure::<()>::new();
let mut list = vec![Vec::new()];
for elem in list.clone().into_iter() {
for _ in 0..uniform_sample(0, 4) {
let mut elem = elem.clone();
for _ in 0..uniform_sample(0, 3) {
elem.push(uniform_sample(0, 255));
}
list.push(elem);
}
}
for elem in list {
match trie.node(trie::bytes_to_nibbles(elem.iter().copied())) {
trie::trie_structure::Entry::Vacant(e) => {
e.insert_storage_value().insert((), ());
}
trie::trie_structure::Entry::Occupied(
trie::trie_structure::NodeAccess::Branch(e),
) => {
e.insert_storage_value();
}
trie::trie_structure::Entry::Occupied(
trie::trie_structure::NodeAccess::Storage(_),
) => {}
}
}
for _ in 0..256 {
let search_params = {
let mut prefix = Vec::new();
for _ in 0..uniform_sample(0, 2) {
prefix.push(trie::Nibble::try_from(uniform_sample(0, 15)).unwrap());
}
Config {
key_before: {
let mut key = prefix.clone();
for _ in 0..uniform_sample(0, 2) {
key.push(trie::Nibble::try_from(uniform_sample(0, 15)).unwrap());
}
key
},
no_branch_search: rand::random(),
or_equal: rand::random(),
prefix,
}
};
let expected = {
trie.iter_ordered().find_map(|node_index| {
if !trie.is_storage(node_index) && search_params.no_branch_search {
return None;
}
let full_key = trie
.node_full_key_by_index(node_index)
.unwrap()
.collect::<Vec<_>>();
if full_key < search_params.key_before {
return None;
}
if full_key == search_params.key_before && !search_params.or_equal {
return None;
}
if !full_key.starts_with(&search_params.prefix) {
return None;
}
Some(full_key)
})
};
let obtained = {
let mut search = BranchSearch::NextKey(start_branch_search(Config {
key_before: search_params.key_before.iter().copied(),
or_equal: search_params.or_equal,
no_branch_search: search_params.no_branch_search,
prefix: search_params.prefix.iter().copied(),
}));
loop {
match search {
BranchSearch::Found {
branch_trie_node_key,
} => break branch_trie_node_key.map(|k| k.collect::<Vec<_>>()),
BranchSearch::NextKey(req) => {
let key = trie.iter_ordered().find_map(|node_index| {
if !trie.is_storage(node_index) {
return None;
}
let full_key = trie
.node_full_key_by_index(node_index)
.unwrap()
.collect::<Vec<_>>();
if full_key
< trie::bytes_to_nibbles(req.key_before()).collect::<Vec<_>>()
{
return None;
}
if full_key
== trie::bytes_to_nibbles(req.key_before()).collect::<Vec<_>>()
&& !req.or_equal()
{
return None;
}
if !full_key.starts_with(
&trie::bytes_to_nibbles(req.prefix()).collect::<Vec<_>>(),
) {
return None;
}
assert!(full_key.len() % 2 == 0);
Some(full_key)
});
search = req.inject(
key.map(|k| trie::nibbles_to_bytes_suffix_extend(k.into_iter())),
);
}
}
}
};
if expected != obtained {
panic!(
"\nexpected: {:?}\nobtained: {:?}\nsearch_params: {:?}\ntrie: {:?}",
expected, obtained, search_params, trie
);
}
}
}
}