/* use std::any::TypeId; use common::protocol::{ hint::{KnownFactory, MockHintWalker}, value::MockValueVisitor, }; use effectful::bound::Dynamic; use effectful::SendSync; use effectful::blocking::BlockingSpin; use mockall::predicate::eq; use treaty::{ any::{AnyTrait, BorrowedStatic, OwnedStatic, TempBorrowedMutStatic}, protocol::{ visitor::{visit_value, Value, ValueKnown, VisitResult}, walker::hint::Hint, DynVisitor, }, Flow, }; mod common; /// Tests support for custom type support in the value protocol. /// /// This is a core feature of treaty so it better work. #[test] fn custom_value_type() { // The value we want to visit in the value visitor. #[derive(PartialEq, Debug, Clone, SendSync)] struct MyValue; let mut mock = MockValueVisitor::, BlockingSpin>::new(); // Expect the visit method to be called once with the custom type. mock.expect_visit() .times(2) .with(eq(OwnedStatic(MyValue))) .return_const(VisitResult::Control(Flow::Done)); // Cast to a trait object for the value protocol. // This shows the visit method is going through the trait. let visitor: &mut dyn Value, BlockingSpin> = &mut mock; // Visit the value. let result = visitor.visit(OwnedStatic(MyValue)).into_value(); // The mock returns that it is done. assert_eq!(result, VisitResult::Control(Flow::Done)); let visitor: &mut dyn AnyTrait = &mut mock; assert_eq!( visit_value::<_, BlockingSpin>(DynVisitor(visitor), OwnedStatic(MyValue)).into_value(), VisitResult::Control(Flow::Done) ); } /// Tests that a value with a lifetime can be given to the value protocol. /// /// This allows for treaty's zero copy capabilities. /// Also this is what allows treaty to short circuit things like structs and enums if the visitor /// supports it. #[test] fn borrowed_value() { // A value with a lifetime longer than the visitor. let context = String::from("test"); // Scope that doesn't live as long as the context. { // We borrow the context, this is what we pass to the visitor. let value = &context; let mut mock = MockValueVisitor::, BlockingSpin>::new(); // Expect the visit method to be called once with the borrowed value. mock.expect_visit() .times(2) .withf(|BorrowedStatic(value)| *value == "test") .return_const(VisitResult::Control(Flow::Done)); // Cast to a trait object for the value protocol. let visitor: &mut dyn Value, BlockingSpin> = &mut mock; // Visit the borrowed value. assert_eq!( visitor.visit(BorrowedStatic(value)).into_value(), Flow::Done.into() ); let visitor: &mut dyn AnyTrait = &mut mock; assert_eq!( visit_value::<_, BlockingSpin>(DynVisitor(visitor), BorrowedStatic(value)).into_value(), VisitResult::Control(Flow::Done) ); } // Make sure the compiler doesn't do anything funny with the lifetime. assert_eq!(context, "test"); } /// Tests that a value with a temp lifetime can be given to the value protocol. /// /// This is useful for passing borrows of things inside a walker to a visitor. /// The visitor can't keep the borrow as the temp lifetime is shorter than the context. /// /// If you replaced the [`TempBorrowedMutStaticHrt`] with [`BorrowedMutStaticHrt`] /// this would fail to compile. #[test] fn temp_borrowed_value() { // A value with a lifetime longer than the visitor. let mut context = String::from("test"); // Scope that doesn't live as long as the context. { // We borrow the context, this is what we pass to the visitor. let value = &mut context; let mut mock = MockValueVisitor::, BlockingSpin>::new(); // Expect the visit method to be called once with the borrowed value. mock.expect_visit() .times(2) .withf(|TempBorrowedMutStatic(value)| *value == "test") .return_const(VisitResult::Control(Flow::Done)); // Cast to a trait object for the value protocol. // We definitly need this for this test so the lifetime is invariant. let visitor: &mut dyn Value, BlockingSpin> = &mut mock; // Visit the context to show we can shorten the lifetime. // This would also force the lifetime to be to long if this wasn't the Temp form. assert_eq!( visitor.visit(TempBorrowedMutStatic(value)).into_value(), Flow::Done.into() ); // Temporary scope (smaller than the context we set above). { // A temporary value. let mut value = String::from("test"); // Visit the temp value. assert_eq!( visitor .visit(TempBorrowedMutStatic(&mut value)) .into_value(), Flow::Done.into() ); } // Force the visitor to outlive the temporary scope. let _ = visitor; } // Make sure the compiler doesn't do anything funny with the lifetime. assert_eq!(context, "test"); } /// Tests for the control flow returns the value protocol visit can return. #[test] fn all_visit_results() { let mut mock = MockValueVisitor::, BlockingSpin>::new(); mock.expect_visit() .once() .with(eq(OwnedStatic(0))) .return_const(VisitResult::Control(Flow::Done)); mock.expect_visit() .once() .with(eq(OwnedStatic(1))) .return_const(VisitResult::Control(Flow::Err)); mock.expect_visit() .once() .with(eq(OwnedStatic(2))) .return_const(VisitResult::Control(Flow::Continue)); mock.expect_visit() .once() .with(eq(OwnedStatic(3))) .return_const(VisitResult::Skipped(())); let visitor: &mut dyn Value, BlockingSpin> = &mut mock; // Visit can return a done. assert_eq!( visitor.visit(OwnedStatic(0)).into_value(), VisitResult::Control(Flow::Done) ); // Visit can return an error signal. assert_eq!( visitor.visit(OwnedStatic(1)).into_value(), VisitResult::Control(Flow::Err) ); // Visit can return a continue. assert_eq!( visitor.visit(OwnedStatic(2)).into_value(), VisitResult::Control(Flow::Continue) ); // A visit can be skipped. // This is for runtime visit support checking. // The value should be given back, but that's not forced. assert_eq!( visitor.visit(OwnedStatic(3)).into_value(), VisitResult::Skipped(Dynamic(OwnedStatic(3))) ); } /// Tests that the higher ranked name for the value protocol exists. #[test] fn value_proto() { // The type id of the higher ranked type. let id = TypeId::of::, BlockingSpin>>(); // The type id for the lifetime containing value protocol trait object. let name_id = TypeNameId::of_lower::, BlockingSpin>, BlockingSpin>(); // They should be the same. assert_eq!(id, name_id.into_type_id()); } /// Tests that the value protocol can be given as a hint to a walker. /// /// The value protocol allows a hint of a preview of the value. #[test] fn as_hint() { { let mut mock = MockHintWalker::, BlockingSpin>>::new(); mock.expect_known().once().return_const( (|_, _hint| { Ok(ValueKnown { preview: Some(Dynamic(&OwnedStatic(42))), }) }) as KnownFactory, BlockingSpin>>, ); let walker: &mut dyn Hint, BlockingSpin>> = &mut mock; // The value protocol has no hint data, and it has no known data. assert_eq!( walker.known(&()).into_value(), Ok(ValueKnown { preview: Some(Dynamic(&OwnedStatic(42))) }) ); } { let mut mock = MockHintWalker::, BlockingSpin>>::new(); mock.expect_known().once().return_const( (|_, _hint| { Ok(ValueKnown { preview: Some(Dynamic(&BorrowedStatic(&42))), }) }) as KnownFactory, BlockingSpin>>, ); let walker: &mut dyn Hint, BlockingSpin>> = &mut mock; // The value protocol has no hint data, and it has no known data. assert_eq!( walker.known(&()).into_value(), Ok(ValueKnown { preview: Some(Dynamic(&BorrowedStatic(&42))) }) ); } { let mut mock = MockHintWalker::, BlockingSpin>>::new(); mock.expect_known().once().return_const( (|_, _hint| Ok(ValueKnown { preview: None })) as KnownFactory, BlockingSpin>>, ); let walker: &mut dyn Hint, BlockingSpin>> = &mut mock; // The value protocol has no hint data, and it has no known data. assert_eq!( walker.known(&()).into_value(), Ok(ValueKnown { preview: None }) ); } } */