use std::cell::RefCell;
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::rc::Rc;
use adaptite::Reactor;
#[test]
fn the_signal_writes_documented_as_panicking_do_panic() {
let reactor = Reactor::new();
let value = reactor.signal(1u32);
let hook = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| {}));
type Case = (&'static str, Box<dyn Fn()>);
let cases: Vec<Case> = vec![
("set inside with", {
let value = value.clone();
Box::new(move || value.with(|_| _ = value.set(2)))
}),
("replace inside with", {
let value = value.clone();
Box::new(move || value.with(|_| _ = value.replace(3)))
}),
("set inside with_peek", {
let value = value.clone();
Box::new(move || value.with_peek(|_| _ = value.set(4)))
}),
("replace inside with_peek", {
let value = value.clone();
Box::new(move || value.with_peek(|_| _ = value.replace(5)))
}),
("set inside update", {
let value = value.clone();
Box::new(move || value.update(|_| _ = value.set(6)))
}),
("replace inside update", {
let value = value.clone();
Box::new(move || value.update(|_| _ = value.replace(7)))
}),
];
let mut failures = Vec::new();
for (name, case) in cases {
if catch_unwind(AssertUnwindSafe(case)).is_ok() {
failures.push(name);
}
}
std::panic::set_hook(hook);
assert!(
failures.is_empty(),
"documented under `# Panics`, but returned normally: {failures:?}"
);
}
#[test]
fn a_comparator_that_writes_the_signal_it_compares_panics() {
thread_local! {
static SELF_WRITER: RefCell<Option<adaptite::Signal<Reentrant>>> =
const { RefCell::new(None) };
}
#[derive(Clone)]
struct Reentrant(u32);
impl PartialEq for Reentrant {
fn eq(&self, other: &Self) -> bool {
SELF_WRITER.with(|slot| {
if let Some(signal) = slot.borrow().as_ref() {
let _ = signal.replace(Reentrant(99));
}
});
self.0 == other.0
}
}
let reactor = Reactor::new();
let value = reactor.signal(Reentrant(0));
SELF_WRITER.with(|slot| *slot.borrow_mut() = Some(value.clone()));
let hook = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| {}));
let outcome = catch_unwind(AssertUnwindSafe(|| _ = value.set(Reentrant(1))));
std::panic::set_hook(hook);
SELF_WRITER.with(|slot| *slot.borrow_mut() = None);
outcome.expect_err("a comparator that writes the signal under comparison must panic");
}
#[test]
fn a_watch_handler_may_write_the_watched_source_and_flush() {
let seen = Rc::new(RefCell::new(Vec::new()));
let reactor = Reactor::new();
let value = reactor.signal(0i32);
let handle = reactor.watch(
{
let value = value.clone();
move || value.get()
},
{
let seen = Rc::clone(&seen);
let value = value.clone();
let reactor = reactor.clone();
move |new: &i32, old: Option<&i32>| {
seen.borrow_mut().push((old.copied(), *new));
if *new < 2 {
value.set(*new + 1);
reactor.flush_now();
}
}
},
);
reactor.flush_now();
handle.leak();
assert_eq!(&*seen.borrow(), &[(None, 0), (Some(0), 1), (Some(1), 2)]);
}