mod context_directory_data;
mod tally_directory_data;
use super::VerificationDirectoryTrait;
use super::{
file_group::FileGroupFileIter, ContextDirectoryTrait, FileStructureError,
FileStructureErrorImpl,
};
use crate::{
data_structures::{VerifierDataDecode, VerifierDataToTypeTrait},
verification::VerificationPeriod,
};
pub(crate) use context_directory_data::MockContextDirectory;
use std::{collections::HashMap, path::Path, sync::Arc};
pub(crate) use tally_directory_data::MockTallyDirectory;
pub(crate) struct MockVerificationDirectory {
context: MockContextDirectory,
tally: Option<MockTallyDirectory>,
}
impl VerificationDirectoryTrait for MockVerificationDirectory {
type ContextDirType = MockContextDirectory;
type TallyDirType = MockTallyDirectory;
fn unwrap_tally(&self) -> &MockTallyDirectory {
match &self.tally {
Some(t) => t,
None => panic!("called `unwrap_tally()` on a `Setup` value"),
}
}
fn context(&self) -> &Self::ContextDirType {
&self.context
}
fn path(&self) -> &Path {
self.context().dir.location().parent().unwrap()
}
}
impl MockVerificationDirectory {
pub fn new(period: &VerificationPeriod, location: &Path) -> Self {
let context = MockContextDirectory::new(location);
match period {
VerificationPeriod::Setup => MockVerificationDirectory {
context,
tally: None,
},
VerificationPeriod::Tally => MockVerificationDirectory {
context,
tally: Some(MockTallyDirectory::new(location)),
},
}
}
pub fn context_mut(&mut self) -> &mut MockContextDirectory {
&mut self.context
}
#[allow(dead_code)]
pub fn unwrap_tally_mut(&mut self) -> &mut MockTallyDirectory {
match &mut self.tally {
Some(t) => t,
None => panic!("called `unwrap_tally()` on a `Setup` value"),
}
}
}
macro_rules! impl_mock_methods_for_mocked_data {
($data_name: ident, $data_type: ident) => {
paste! {
#[allow(dead_code)]
#[doc = "Mock `$data_name`"]
pub fn [<mock_ $data_name>](
&mut self,
mut closure: impl FnMut(&mut $data_type),
) {
let orig_payload = match self.dir.[<$data_name>]() {
Ok(p) => p.as_ref().clone(),
Err(_) => return
};
let mut payload = match self.[<mocked_ $data_name>].as_ref() {
Some(p) => match p.as_ref() {
MockedDataType::Data(p) => Some(p.clone()),
_ => None
}
None => None
}.unwrap_or_else(|| orig_payload);
closure(
&mut payload
);
self.[<mocked_ $data_name>] = Some(Box::new(MockedDataType::Data(payload.clone())));
}
#[doc = "Mock `$data_name` with error"]
#[allow(dead_code)]
pub fn [<mock_ $data_name _error>](
&mut self,
error: FileStructureError,
) {
self.[<mocked_ $data_name>] = Some(Box::new(MockedDataType::Error(error.to_string())))
}
#[doc = "Reset the original data for `$data_name`"]
#[allow(dead_code)]
pub fn [<mock_ $data_name _reset>](&mut self) {
self.[<mocked_ $data_name>] = None;
}
}
};
}
use impl_mock_methods_for_mocked_data;
macro_rules! impl_trait_get_method_for_mocked_data {
($data_name: ident, $data_type: ident) => {
paste! {
fn $data_name(
&self,
) -> Result<Arc<$data_type>, FileStructureError> {
match &self.[<mocked_ $data_name>] {
None => self.dir.$data_name(),
Some(e) => match e.as_ref() {
MockedDataType::Data(d) => Ok(Arc::new(d.clone())),
MockedDataType::Error(e) => Err(FileStructureError::from(FileStructureErrorImpl::Mock(e.to_string()))),
MockedDataType::Deleted => Err(FileStructureError::from(FileStructureErrorImpl::Mock("Something wrong. Data cannot be deleted".to_string())))
}
}
}
}
};
}
use impl_trait_get_method_for_mocked_data;
macro_rules! impl_mock_methods_for_mocked_group {
($data_name: ident, $data_type: ident) => {
paste! {
#[allow(dead_code)]
pub fn [<mock_ $data_name>](
&mut self,
pos: usize,
mut closure: impl FnMut(&mut $data_type),
) {
let orig_payload = match self.dir.[<$data_name _iter>]().find(|(i, _)| i == &pos) {
Some((_, res)) => match res {
Ok(p) => p.as_ref().clone(),
Err(_) => return
},
None => return
};
let mut payload = match self.[<mocked_ $data_name>].get(&pos) {
Some(p) => match &p.element_type {
MockedDataType::Data(p) => Some(p.clone()),
_ => None
}
None => None
}.unwrap_or_else(|| orig_payload);
closure(
&mut payload
);
let _ = self.[<mocked_ $data_name>].insert(pos, Box::new(MockFileGroupElement::new(
MockedDataType::Data(payload.clone()))));
}
#[allow(dead_code)]
pub fn [<mock_ $data_name _as_deleted>](&mut self, pos: usize) {
let _ = self.[<mocked_ $data_name>].insert(pos, Box::new(MockFileGroupElement::new(
MockedDataType::Deleted)));
}
#[allow(dead_code)]
pub fn [<mock_ $data_name _error>](
&mut self,
pos: usize,
error: FileStructureError,
) {
let _ = self.[<mocked_ $data_name>].insert(pos, Box::new(MockFileGroupElement::new(
MockedDataType::Error(error.to_string()))));
}
#[allow(dead_code)]
pub fn [<mock_ $data_name _reset>](&mut self, pos: usize) {
let _ = self.[<mocked_ $data_name>].remove(&pos);
}
}
};
}
use impl_mock_methods_for_mocked_group;
macro_rules! impl_trait_get_method_for_mocked_group {
($data_name: ident, $data_type: ident) => {
paste! {
fn [<$data_name _iter>](
&self,
) -> impl Iterator<
Item = (
usize,
Result<Arc<$data_type>, FileStructureError>,
),
> {
MockFileGroupDataIter::new(FileGroupFileIter::new(
&self.dir.[<$data_name _group>]()), &self.[<mocked_ $data_name>])
}
}
};
}
use impl_trait_get_method_for_mocked_group;
#[derive(Clone)]
pub enum MockedDataType<D>
where
D: VerifierDataDecode + VerifierDataToTypeTrait,
{
Data(D),
Deleted,
Error(String),
}
#[derive(Clone)]
pub struct MockFileGroupElement<D>
where
D: VerifierDataDecode + VerifierDataToTypeTrait + Clone,
{
element_type: MockedDataType<D>,
}
impl<D> MockFileGroupElement<D>
where
D: VerifierDataDecode + VerifierDataToTypeTrait + Clone,
{
fn to_data_res(&self) -> Option<Result<D, FileStructureError>> {
match &self.element_type {
MockedDataType::Data(d) => Some(Ok(d.clone())),
MockedDataType::Deleted => None,
MockedDataType::Error(e) => Some(Err(FileStructureError::from(
FileStructureErrorImpl::Mock(e.to_string()),
))),
}
}
}
impl<D> MockFileGroupElement<D>
where
D: VerifierDataDecode + VerifierDataToTypeTrait + Clone,
{
pub fn new(element_type: MockedDataType<D>) -> Self {
MockFileGroupElement { element_type }
}
}
pub struct MockFileGroupDataIter<'a, D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> {
pub file_group_iter: FileGroupFileIter<D>,
pub mocked: &'a HashMap<usize, Box<MockFileGroupElement<D>>>,
}
impl<'a, D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> MockFileGroupDataIter<'a, D> {
pub fn new(
file_group_iter: FileGroupFileIter<D>,
mocked: &'a HashMap<usize, Box<MockFileGroupElement<D>>>,
) -> Self {
Self {
file_group_iter,
mocked,
}
}
}
impl<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> Iterator
for MockFileGroupDataIter<'_, D>
{
type Item = (usize, Result<Arc<D>, FileStructureError>);
fn next(&mut self) -> Option<Self::Item> {
let (pos, file_res) = self.file_group_iter.next()?;
match self.mocked.get(&pos) {
Some(m) => match m.to_data_res() {
Some(res) => Some((pos, res.map(Arc::new))),
None => self.next(),
},
None => Some((pos, file_res.decode_verifier_data())),
}
}
}