use crate::error::unexpected::Mappable; use crate::{origin, util}; pub struct Store where S: origin::Store + 'static, F: Fn(&origin::Descr) -> Option + Sync + Send, { mapping_fn: F, stores: Vec, } impl Store where S: origin::Store + 'static, F: Fn(&origin::Descr) -> Option + Sync + Send, { pub fn new(mapping_fn: F, stores: Vec) -> Store { Store { mapping_fn, stores } } } impl origin::Store for Store where S: origin::Store + 'static, F: Fn(&origin::Descr) -> Option + Sync + Send, { fn sync(&self, descr: &origin::Descr) -> Result<(), origin::SyncError> { (self.mapping_fn)(descr) .or_unexpected_while(format!("mapping {:?} to store", &descr))? .sync(descr) } fn all_descrs(&self) -> Result, origin::AllDescrsError> { let mut res = Vec::::new(); for store in self.stores.iter() { store.all_descrs()?.into_iter().collect_into(&mut res); } Ok(res) } fn get_file( &self, descr: &origin::Descr, path: &str, ) -> Result { (self.mapping_fn)(descr) .or_unexpected_while(format!("mapping {:?} to store", &descr))? .get_file(descr, path) } } #[cfg(test)] mod tests { use crate::origin; use std::sync; struct Harness { descr_a: origin::Descr, descr_b: origin::Descr, descr_unknown: origin::Descr, store_a: sync::Arc>, store_b: sync::Arc>, store: Box, } impl Harness { fn new() -> Harness { let descr_a = origin::Descr::Git { url: "A".to_string(), branch_name: "A".to_string(), }; let descr_b = origin::Descr::Git { url: "B".to_string(), branch_name: "B".to_string(), }; let store_a = origin::new_mock(); let store_b = origin::new_mock(); Harness { descr_a: descr_a.clone(), descr_b: descr_b.clone(), descr_unknown: origin::Descr::Git { url: "X".to_string(), branch_name: "X".to_string(), }, store_a: store_a.clone(), store_b: store_b.clone(), store: Box::from(super::Store::new( { let store_a = store_a.clone(); let store_b = store_b.clone(); move |descr| match descr { &origin::Descr::Git { ref url, .. } if url == "A" => { Some(store_a.clone()) } &origin::Descr::Git { ref url, .. } if url == "B" => { Some(store_b.clone()) } _ => None, } }, vec![store_a.clone(), store_b.clone()], )), } } } #[test] fn sync() { let h = Harness::new(); { let descr_a = h.descr_a.clone(); h.store_a .lock() .unwrap() .expect_sync() .withf(move |descr: &origin::Descr| descr == &descr_a) .times(1) .return_const(Ok::<(), origin::SyncError>(())); } assert_eq!(Ok(()), h.store.sync(&h.descr_a)); { let descr_b = h.descr_b.clone(); h.store_b .lock() .unwrap() .expect_sync() .withf(move |descr: &origin::Descr| descr == &descr_b) .times(1) .return_const(Ok::<(), origin::SyncError>(())); } assert_eq!(Ok(()), h.store.sync(&h.descr_b)); assert!(h.store.sync(&h.descr_unknown).is_err()); } #[test] fn all_descrs() { let h = Harness::new(); h.store_a .lock() .unwrap() .expect_all_descrs() .times(1) .return_const(Ok::, origin::AllDescrsError>(vec![h .descr_a .clone()])); h.store_b .lock() .unwrap() .expect_all_descrs() .times(1) .return_const(Ok::, origin::AllDescrsError>(vec![h .descr_b .clone()])); assert_eq!( Ok(vec![h.descr_a.clone(), h.descr_b.clone()]), h.store.all_descrs(), ) } }