use std::cell::{
Cell,
RefCell,
};
use std::rc::Rc;
use std::sync::{
Arc,
atomic::{
AtomicUsize,
Ordering,
},
};
use qubit_function::predicates::{
ArcStatefulPredicate,
BoxStatefulPredicate,
FnStatefulPredicateOps,
RcStatefulPredicate,
StatefulPredicate,
};
#[test]
fn test_stateful_predicate_default_conversions_allow_relaxed_generic_types() {
#[derive(Clone, Debug)]
struct BorrowedRc<'a> {
value: &'a str,
}
#[derive(Debug)]
struct BorrowedRcStatefulPredicate {
count: Cell<usize>,
}
impl Clone for BorrowedRcStatefulPredicate {
fn clone(&self) -> Self {
Self {
count: Cell::new(self.count.get()),
}
}
}
impl<'a> StatefulPredicate<BorrowedRc<'a>> for BorrowedRcStatefulPredicate {
fn test(&mut self, value: &BorrowedRc<'a>) -> bool {
self.count.set(self.count.get() + 1);
value.value == "left"
}
}
let text = String::from("left");
let value = BorrowedRc {
value: text.as_str(),
};
let predicate = BorrowedRcStatefulPredicate {
count: Cell::new(0),
};
assert!(predicate.clone().into_box().test(&value));
assert!(predicate.clone().into_rc().test(&value));
assert!(predicate.clone().into_arc().test(&value));
assert!(predicate.clone().into_fn()(&value));
assert!(predicate.to_box().test(&value));
assert!(predicate.to_rc().test(&value));
assert!(predicate.to_arc().test(&value));
assert!(predicate.to_fn()(&value));
}
#[test]
fn test_closure_implements_stateful_predicate() {
let mut calls = 0;
let mut predicate = |value: &i32| {
calls += 1;
calls % 2 == 0 && *value > 0
};
assert!(!predicate.test(&5));
assert!(predicate.test(&5));
assert!(!predicate.test(&-5));
}
#[test]
fn test_box_stateful_predicate_new_and_name_methods() {
let mut predicate = BoxStatefulPredicate::new_with_name("positive", |value: &i32| *value > 0);
assert_eq!(predicate.name(), Some("positive"));
assert!(predicate.test(&5));
assert!(!predicate.test(&-5));
predicate.set_name("renamed");
assert_eq!(predicate.name(), Some("renamed"));
}
#[test]
fn test_box_stateful_predicate_always_true_and_false() {
let mut always_true = BoxStatefulPredicate::<i32>::always_true();
let mut always_false = BoxStatefulPredicate::<i32>::always_false();
assert_eq!(always_true.name(), Some("always_true"));
assert_eq!(always_false.name(), Some("always_false"));
assert!(always_true.test(&0));
assert!(!always_false.test(&0));
}
#[test]
fn test_box_stateful_predicate_composition_preserves_state() {
let left_calls = Rc::new(RefCell::new(0));
let right_calls = Rc::new(RefCell::new(0));
let left_counter = Rc::clone(&left_calls);
let right_counter = Rc::clone(&right_calls);
let left = BoxStatefulPredicate::new(move |value: &i32| {
*left_counter.borrow_mut() += 1;
*value > 0
});
let right = BoxStatefulPredicate::new(move |value: &i32| {
*right_counter.borrow_mut() += 1;
value % 2 == 0
});
let mut combined = left.and(right);
assert!(combined.test(&4));
assert!(!combined.test(&3));
assert!(!combined.test(&-2));
assert_eq!(*left_calls.borrow(), 3);
assert_eq!(*right_calls.borrow(), 2);
}
#[test]
fn test_box_stateful_predicate_logical_operations_cover_all_branches() {
let mut and_pred =
BoxStatefulPredicate::new(|value: &i32| *value > 0).and(|value: &i32| value % 2 == 0);
assert!(and_pred.test(&4));
assert!(!and_pred.test(&3));
assert!(!and_pred.test(&-2));
let mut or_pred =
BoxStatefulPredicate::new(|value: &i32| *value > 0).or(|value: &i32| value % 2 == 0);
assert!(or_pred.test(&4));
assert!(or_pred.test(&-2));
assert!(!or_pred.test(&-3));
let mut nand_pred =
BoxStatefulPredicate::new(|value: &i32| *value > 0).nand(|value: &i32| value % 2 == 0);
assert!(!nand_pred.test(&4));
assert!(nand_pred.test(&3));
assert!(nand_pred.test(&-2));
let mut xor_pred =
BoxStatefulPredicate::new(|value: &i32| *value > 0).xor(|value: &i32| value % 2 == 0);
assert!(!xor_pred.test(&4));
assert!(xor_pred.test(&3));
assert!(xor_pred.test(&-2));
assert!(!xor_pred.test(&-3));
let mut nor_pred =
BoxStatefulPredicate::new(|value: &i32| *value > 0).nor(|value: &i32| value % 2 == 0);
assert!(!nor_pred.test(&4));
assert!(!nor_pred.test(&-2));
assert!(nor_pred.test(&-3));
}
#[test]
fn test_box_stateful_predicate_debug_and_display() {
let unnamed = BoxStatefulPredicate::new(|value: &i32| *value > 0);
assert!(format!("{unnamed:?}").contains("BoxStatefulPredicate"));
assert_eq!(format!("{unnamed}"), "BoxStatefulPredicate(unnamed)");
let named = BoxStatefulPredicate::new_with_name("positive", |value: &i32| *value > 0);
assert!(format!("{named:?}").contains("positive"));
assert_eq!(format!("{named}"), "BoxStatefulPredicate(positive)");
}
#[test]
fn test_box_stateful_predicate_into_conversions() {
let calls = Rc::new(RefCell::new(0));
let counter = Rc::clone(&calls);
let predicate = BoxStatefulPredicate::new(move |value: &i32| {
*counter.borrow_mut() += 1;
*value > 0
});
let mut rc = predicate.into_rc();
assert!(rc.test(&5));
assert_eq!(*calls.borrow(), 1);
let mut boxed = rc.into_box();
assert!(!boxed.test(&-5));
assert_eq!(*calls.borrow(), 2);
let mut function = boxed.into_fn();
assert!(function(&5));
assert_eq!(*calls.borrow(), 3);
}
#[test]
fn test_rc_stateful_predicate_common_methods_and_conversions() {
let mut always_true = RcStatefulPredicate::<i32>::always_true();
let mut always_false = RcStatefulPredicate::<i32>::always_false();
assert_eq!(always_true.name(), Some("always_true"));
assert_eq!(always_false.name(), Some("always_false"));
assert!(always_true.test(&0));
assert!(!always_false.test(&0));
let mut predicate = RcStatefulPredicate::new_with_name("positive", |value: &i32| *value > 0);
assert_eq!(predicate.name(), Some("positive"));
predicate.set_name("renamed");
assert_eq!(predicate.name(), Some("renamed"));
assert!(format!("{predicate:?}").contains("renamed"));
assert_eq!(format!("{predicate}"), "RcStatefulPredicate(renamed)");
let mut boxed = predicate.to_box();
let mut rc_clone = predicate.to_rc();
assert!(boxed.test(&1));
assert!(rc_clone.test(&1));
{
let mut function = predicate.to_fn();
assert!(function(&1));
}
let mut boxed_from_owned = predicate.clone().into_box();
let mut rc_from_owned = predicate.clone().into_rc();
let mut fn_from_owned = predicate.into_fn();
assert!(boxed_from_owned.test(&1));
assert!(rc_from_owned.test(&1));
assert!(fn_from_owned(&1));
}
#[test]
fn test_rc_stateful_predicate_clone_shares_state() {
let calls = Rc::new(RefCell::new(0));
let counter = Rc::clone(&calls);
let mut predicate = RcStatefulPredicate::new(move |value: &i32| {
*counter.borrow_mut() += 1;
*value > 0
});
let mut cloned = predicate.clone();
assert!(predicate.test(&1));
assert!(cloned.test(&2));
assert_eq!(*calls.borrow(), 2);
}
#[test]
fn test_rc_stateful_predicate_logical_operations_cover_all_branches() {
let positive = RcStatefulPredicate::new(|value: &i32| *value > 0);
let mut and_pred = positive.and(|value: &i32| value % 2 == 0);
assert!(and_pred.test(&4));
assert!(!and_pred.test(&3));
assert!(!and_pred.test(&-2));
let mut or_pred = positive.or(|value: &i32| value % 2 == 0);
assert!(or_pred.test(&4));
assert!(or_pred.test(&-2));
assert!(!or_pred.test(&-3));
let mut nand_pred = positive.nand(|value: &i32| value % 2 == 0);
assert!(!nand_pred.test(&4));
assert!(nand_pred.test(&3));
assert!(nand_pred.test(&-2));
let mut xor_pred = positive.xor(|value: &i32| value % 2 == 0);
assert!(!xor_pred.test(&4));
assert!(xor_pred.test(&3));
assert!(xor_pred.test(&-2));
assert!(!xor_pred.test(&-3));
let mut nor_pred = positive.nor(|value: &i32| value % 2 == 0);
assert!(!nor_pred.test(&4));
assert!(!nor_pred.test(&-2));
assert!(nor_pred.test(&-3));
}
#[test]
fn test_rc_stateful_predicate_self_composition_releases_borrow_between_calls() {
let calls = Rc::new(RefCell::new(0));
let counter = Rc::clone(&calls);
let predicate = RcStatefulPredicate::new(move |_value: &i32| {
*counter.borrow_mut() += 1;
true
});
let mut combined = predicate.and(predicate.clone());
assert!(combined.test(&1));
assert_eq!(*calls.borrow(), 2);
}
#[test]
fn test_arc_stateful_predicate_common_methods_and_conversions() {
let mut always_true = ArcStatefulPredicate::<i32>::always_true();
let mut always_false = ArcStatefulPredicate::<i32>::always_false();
assert_eq!(always_true.name(), Some("always_true"));
assert_eq!(always_false.name(), Some("always_false"));
assert!(always_true.test(&0));
assert!(!always_false.test(&0));
let mut predicate = ArcStatefulPredicate::new_with_name("positive", |value: &i32| *value > 0);
assert_eq!(predicate.name(), Some("positive"));
predicate.set_name("renamed");
assert_eq!(predicate.name(), Some("renamed"));
assert!(format!("{predicate:?}").contains("renamed"));
assert_eq!(format!("{predicate}"), "ArcStatefulPredicate(renamed)");
let mut boxed = predicate.to_box();
let mut rc = predicate.to_rc();
let mut arc_clone = predicate.to_arc();
assert!(boxed.test(&1));
assert!(rc.test(&1));
assert!(arc_clone.test(&1));
{
let mut function = predicate.to_fn();
assert!(function(&1));
}
let mut boxed_from_owned = predicate.clone().into_box();
let mut rc_from_owned = predicate.clone().into_rc();
let mut arc_from_owned = predicate.clone().into_arc();
let mut fn_from_owned = predicate.into_fn();
assert!(boxed_from_owned.test(&1));
assert!(rc_from_owned.test(&1));
assert!(arc_from_owned.test(&1));
assert!(fn_from_owned(&1));
}
#[test]
fn test_arc_stateful_predicate_clone_shares_state() {
let calls = Arc::new(AtomicUsize::new(0));
let counter = Arc::clone(&calls);
let mut predicate = ArcStatefulPredicate::new(move |value: &i32| {
counter.fetch_add(1, Ordering::Relaxed);
*value > 0
});
let mut cloned = predicate.clone();
assert!(predicate.test(&1));
assert!(cloned.test(&2));
assert_eq!(calls.load(Ordering::Relaxed), 2);
}
#[test]
fn test_arc_stateful_predicate_logical_operations_cover_all_branches() {
let positive = ArcStatefulPredicate::new(|value: &i32| *value > 0);
let mut and_pred = positive.and(|value: &i32| value % 2 == 0);
assert!(and_pred.test(&4));
assert!(!and_pred.test(&3));
assert!(!and_pred.test(&-2));
let mut or_pred = positive.or(|value: &i32| value % 2 == 0);
assert!(or_pred.test(&4));
assert!(or_pred.test(&-2));
assert!(!or_pred.test(&-3));
let mut nand_pred = positive.nand(|value: &i32| value % 2 == 0);
assert!(!nand_pred.test(&4));
assert!(nand_pred.test(&3));
assert!(nand_pred.test(&-2));
let mut xor_pred = positive.xor(|value: &i32| value % 2 == 0);
assert!(!xor_pred.test(&4));
assert!(xor_pred.test(&3));
assert!(xor_pred.test(&-2));
assert!(!xor_pred.test(&-3));
let mut nor_pred = positive.nor(|value: &i32| value % 2 == 0);
assert!(!nor_pred.test(&4));
assert!(!nor_pred.test(&-2));
assert!(nor_pred.test(&-3));
}
#[test]
fn test_arc_stateful_predicate_self_composition_releases_lock_between_calls() {
let calls = Arc::new(AtomicUsize::new(0));
let counter = Arc::clone(&calls);
let predicate = ArcStatefulPredicate::new(move |_value: &i32| {
counter.fetch_add(1, Ordering::Relaxed);
true
});
let mut combined = predicate.and(predicate.clone());
assert!(combined.test(&1));
assert_eq!(calls.load(Ordering::Relaxed), 2);
}
#[test]
fn test_stateful_predicate_not_operator() {
let mut boxed = !BoxStatefulPredicate::new(|value: &i32| *value > 0);
assert!(!boxed.test(&5));
assert!(boxed.test(&-5));
let rc = RcStatefulPredicate::new(|value: &i32| *value > 0);
let mut negated_rc = !&rc;
assert!(!negated_rc.test(&5));
assert!(negated_rc.test(&-5));
let mut owned_negated_rc = !rc;
assert!(!owned_negated_rc.test(&5));
assert!(owned_negated_rc.test(&-5));
let arc = ArcStatefulPredicate::new(|value: &i32| *value > 0);
let mut negated_arc = !&arc;
assert!(!negated_arc.test(&5));
assert!(negated_arc.test(&-5));
let mut owned_negated_arc = !arc;
assert!(!owned_negated_arc.test(&5));
assert!(owned_negated_arc.test(&-5));
}
#[test]
fn test_fn_stateful_predicate_ops_observable_behavior() {
fn assert_ops<F: FnStatefulPredicateOps<i32>>(_: &F) {}
let mut calls = 0;
let predicate = move |value: &i32| {
calls += 1;
calls % 2 == 0 && *value > 0
};
assert_ops(&predicate);
let mut composed = predicate.or(|value: &i32| *value == 0);
assert!(composed.test(&0));
assert!(composed.test(&5));
assert!(!composed.test(&-5));
}
#[test]
fn test_fn_stateful_predicate_ops_logical_operations_cover_all_branches() {
let mut and_pred = (|value: &i32| *value > 0).and(|value: &i32| value % 2 == 0);
assert!(and_pred.test(&4));
assert!(!and_pred.test(&3));
assert!(!and_pred.test(&-2));
let mut or_pred = (|value: &i32| *value > 0).or(|value: &i32| value % 2 == 0);
assert!(or_pred.test(&4));
assert!(or_pred.test(&-2));
assert!(!or_pred.test(&-3));
let mut not_pred = (|value: &i32| *value > 0).not();
assert!(!not_pred.test(&5));
assert!(not_pred.test(&-5));
let mut nand_pred = (|value: &i32| *value > 0).nand(|value: &i32| value % 2 == 0);
assert!(!nand_pred.test(&4));
assert!(nand_pred.test(&3));
assert!(nand_pred.test(&-2));
let mut xor_pred = (|value: &i32| *value > 0).xor(|value: &i32| value % 2 == 0);
assert!(!xor_pred.test(&4));
assert!(xor_pred.test(&3));
assert!(xor_pred.test(&-2));
assert!(!xor_pred.test(&-3));
let mut nor_pred = (|value: &i32| *value > 0).nor(|value: &i32| value % 2 == 0);
assert!(!nor_pred.test(&4));
assert!(!nor_pred.test(&-2));
assert!(nor_pred.test(&-3));
}