#![cfg(feature = "expensive_tests")]
use std::collections::HashMap;
use proptest::{collection::vec, prelude::*};
use snapper_box::CryptoBox;
use tempfile::tempdir;
#[derive(Clone, Debug)]
enum Command {
Insert {
namespace: usize,
key: u16,
value: i64,
},
Drop,
}
#[derive(Clone, Debug)]
struct CommandList {
namespace_count: usize,
commands: Vec<Command>,
}
impl CommandList {
pub fn to_hashmaps(&self) -> HashMap<String, HashMap<u16, i64>> {
let mut hashes: HashMap<String, HashMap<u16, i64>> = HashMap::new();
for i in 0..self.namespace_count {
hashes.insert(i.to_string(), HashMap::new());
}
for command in &self.commands {
match command {
Command::Insert {
namespace,
key,
value,
} => {
let namespace = namespace.to_string();
let map = hashes.get_mut(&namespace).expect("Invalid command");
map.insert(*key, *value);
}
Command::Drop => continue,
}
}
for name in hashes.keys().cloned().collect::<Vec<_>>() {
if hashes.get(&name).map(|x| x.is_empty()).unwrap_or(true) {
hashes.remove(&name);
}
}
hashes
}
}
prop_compose! {
fn command(max_namespaces: usize, drop_interval: u8)
(namespace in 0..max_namespaces,
key in any::<u16>(),
value in any::<i64>(),
drop in 0_u8..drop_interval) -> Command {
if drop == 0 {
Command::Drop
} else {
Command::Insert { namespace, key, value }
}
}
}
prop_compose! {
fn command_list_raw(namespaces: usize, drop_interval: u8, command_list_max_len: usize)
(commands in vec(command(namespaces, drop_interval), 0..command_list_max_len)) -> CommandList {
CommandList { namespace_count: namespaces, commands }
}
}
prop_compose! {
fn command_list_small()
(command_list in command_list_raw(10, 10, 50)) -> CommandList {
command_list
}
}
proptest! {
#![proptest_config(ProptestConfig {
cases: 150,
..ProptestConfig::default()
})]
#[test]
fn smoke_test_small(command_list in command_list_small()) {
println!("{:#?}", command_list);
let tempdir = tempdir().expect("Failed to get tempdir");
let path = tempdir.path().join("box");
let mut crypto_box =
CryptoBox::init(&path, None, None, "testing").expect("Failed to init box");
let target = command_list.to_hashmaps();
for command in command_list.commands {
match command {
Command::Insert {
namespace,
key,
value,
} => {
let name = namespace.to_string();
if !crypto_box.namespace_exists(&name) {
crypto_box
.create_namespace(name.clone())
.expect("Failed to create namespace");
}
crypto_box
.insert(&key, &value, &name)
.expect("Failed to insert pair");
}
Command::Drop => {
crypto_box.flush().expect("Failed to flush");
std::mem::drop(crypto_box);
crypto_box = CryptoBox::open(&path, "testing").expect("Failed to reopen box");
}
}
}
let mut output: HashMap<String, HashMap<u16, i64>> = HashMap::new();
for name in crypto_box.namespaces() {
let namespace = crypto_box
.to_hashmap(&name)
.expect("Failed to dump namespace");
output.insert(name, namespace);
}
assert_eq!(output, target);
}
}