use { core::{ cell::RefCell, fmt::{self, Debug, Display, Formatter}, }, fehler::{throw, throws}, market::*, never::Never, std::{ collections::VecDeque, sync::atomic::{AtomicU8, Ordering}, }, }; struct U8Consumer { goods: RefCell>, } impl Agent for U8Consumer { type Good = u8; } impl Consumer for U8Consumer { type Flaws = ConsumptionFlaws; #[throws(Failure)] fn consume(&self) -> Self::Good { self.goods .borrow_mut() .pop_front() .ok_or(self.failure(Fault::Insufficiency(EmptyStock::default())))? } } impl Display for U8Consumer { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "U8Consumer") } } impl From> for U8Consumer { fn from(goods: Vec) -> Self { Self { goods: RefCell::new(goods.into()), } } } #[derive(Clone, Copy, Debug, PartialEq)] struct MockDefect; impl Flaws for MockDefect { type Insufficiency = Never; type Defect = Self; } #[derive(Default)] struct U8Producer { goods: RefCell>, fail_on_call: Option<(u8, Fault>)>, calls: AtomicU8, } impl U8Producer { fn fail_on_produce_call(&mut self, call: u8, fault: Fault>) { self.fail_on_call = Some((call, fault)); } } impl Agent for U8Producer { type Good = u8; } impl Display for U8Producer { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "U8Producer") } } impl Producer for U8Producer { type Flaws = ProductionFlaws; #[throws(Recall)] fn produce(&self, good: Self::Good) { if let Some((call, fault)) = self.fail_on_call { if call == self.calls.fetch_add(1, Ordering::Relaxed) { throw!(self.recall(fault, good)); } } self.goods.borrow_mut().push(good); } } #[test] fn produce_goods_success() { let producer = U8Producer::default(); let goods = U8Consumer::from(vec![0, 1, 2]); assert_eq!(producer.produce_goods(&goods).unwrap(), ()); assert_eq!(producer.goods, RefCell::new(vec![0, 1, 2])) } #[test] fn produce_goods_insufficient_stock() { let mut producer = U8Producer::default(); let goods = U8Consumer::from(vec![0, 1, 2]); producer.fail_on_produce_call(0, Fault::Insufficiency(FullStock::default())); assert_eq!( producer.produce_goods(&goods).unwrap_err(), Blockage::Production(producer.recall(Fault::Insufficiency(FullStock::default()), 0)) ); assert_eq!(producer.goods, RefCell::new(vec![])); } #[test] fn produce_goods_fault() { let mut producer = U8Producer::default(); let goods = U8Consumer::from(vec![0, 1, 2]); let fault = Fault::Defect(MockDefect); producer.fail_on_produce_call(0, fault.clone()); assert_eq!( producer.produce_goods(&goods).unwrap_err(), Blockage::Production(producer.recall(fault, 0)) ); assert_eq!(producer.goods, RefCell::new(vec![])); } #[test] fn produce_goods_fault_middle() { let mut producer = U8Producer::default(); let goods = U8Consumer::from(vec![0, 1, 2]); let fault = Fault::Defect(MockDefect); producer.fail_on_produce_call(1, fault.clone()); assert_eq!( producer.produce_goods(&goods).unwrap_err(), Blockage::Production(producer.recall(fault, 1)) ); assert_eq!(producer.goods, RefCell::new(vec![0])); } #[test] fn force_success() { let producer = U8Producer::default(); assert_eq!(producer.force(0).unwrap(), ()); assert_eq!(producer.goods, RefCell::new(vec![0])); } #[test] fn force_insufficient_stock() { let mut producer = U8Producer::default(); producer.fail_on_produce_call(0, Fault::Insufficiency(FullStock::default())); assert_eq!(producer.force(0).unwrap(), ()); assert_eq!(producer.goods, RefCell::new(vec![0])); } #[test] fn force_fault() { let mut producer = U8Producer::default(); let fault = Fault::Defect(MockDefect); producer.fail_on_produce_call(0, fault.clone()); assert_eq!( producer.force(0).unwrap_err(), producer.recall(fault, 0).try_blame().unwrap() ); } #[test] fn force_goods_fault() { let mut producer = U8Producer::default(); let goods = U8Consumer::from(vec![0, 1, 2]); let fault = Fault::Defect(MockDefect); producer.fail_on_produce_call(0, fault.clone()); assert_eq!( producer.force_goods(&goods).unwrap_err(), Blockage::Production(producer.recall(fault, 0).try_blame().unwrap()) ); assert_eq!(producer.goods, RefCell::new(vec![])); } #[test] fn force_goods_fault_middle() { let mut producer = U8Producer::default(); let goods = U8Consumer::from(vec![0, 1, 2]); let fault = Fault::Defect(MockDefect); producer.fail_on_produce_call(1, fault.clone()); assert_eq!( producer.force_goods(&goods).unwrap_err(), Blockage::Production(producer.recall(fault, 1).try_blame().unwrap()) ); assert_eq!(producer.goods, RefCell::new(vec![0])); }