use std::{
cell::Cell,
io,
rc::Rc,
};
use qubit_function::{
BoxRunnableOnce,
CallableOnce,
RunnableOnce,
SupplierOnce,
};
#[derive(Clone)]
struct ClonedRunnableOnce {
flag: Rc<Cell<bool>>,
}
impl RunnableOnce<io::Error> for ClonedRunnableOnce {
fn run(self) -> Result<(), io::Error> {
self.flag.set(true);
Ok(())
}
}
#[test]
fn test_runnable_once_closure_run_returns_success() {
let flag = Rc::new(Cell::new(false));
let captured = Rc::clone(&flag);
let task = move || {
captured.set(true);
Ok::<(), io::Error>(())
};
task.run().expect("runnable-once closure should succeed");
assert!(flag.get());
}
#[test]
fn test_runnable_once_closure_run_returns_error() {
let task = || Err::<(), _>(io::Error::other("failed"));
let error = task.run().expect_err("runnable-once closure should fail");
assert_eq!(error.kind(), io::ErrorKind::Other);
assert_eq!(error.to_string(), "failed");
}
#[test]
fn test_runnable_once_closure_into_box_executes_once() {
let task = || Ok::<(), io::Error>(());
let boxed = RunnableOnce::into_box(task);
boxed.run().expect("boxed runnable-once should succeed");
}
#[test]
fn test_runnable_once_closure_into_fn_returns_fn_once() {
let task = || Ok::<(), io::Error>(());
let function = RunnableOnce::into_fn(task);
function().expect("runnable-once function should succeed");
}
#[test]
fn test_runnable_once_to_box_clones_runnable() {
let flag = Rc::new(Cell::new(false));
let task = ClonedRunnableOnce {
flag: Rc::clone(&flag),
};
let first = task.to_box();
first.run().expect("boxed clone should succeed");
assert!(flag.get());
flag.set(false);
let second = task.to_box();
second
.run()
.expect("original runnable should remain reusable");
assert!(flag.get());
}
#[test]
fn test_runnable_once_to_fn_clones_runnable() {
let flag = Rc::new(Cell::new(false));
let task = ClonedRunnableOnce {
flag: Rc::clone(&flag),
};
let function = task.to_fn();
function().expect("cloned runnable should succeed");
assert!(flag.get());
}
#[test]
fn test_runnable_once_default_into_callable_returns_unit() {
let flag = Rc::new(Cell::new(false));
let task = ClonedRunnableOnce {
flag: Rc::clone(&flag),
};
let callable = RunnableOnce::into_callable(task);
callable.call().expect("unit callable should succeed");
assert!(flag.get());
}
#[test]
fn test_box_runnable_once_new_and_run() {
let flag = Rc::new(Cell::new(false));
let captured = Rc::clone(&flag);
let task = BoxRunnableOnce::new(move || {
captured.set(true);
Ok::<(), io::Error>(())
});
task.run().expect("box runnable-once should succeed");
assert!(flag.get());
}
#[test]
fn test_box_runnable_once_name_management() {
let mut task = BoxRunnableOnce::<io::Error>::new_with_name("cleanup", || Ok(()));
assert_eq!(task.name(), Some("cleanup"));
assert_eq!(task.to_string(), "BoxRunnableOnce(cleanup)");
assert!(format!("{task:?}").contains("cleanup"));
task.set_name("renamed");
assert_eq!(task.name(), Some("renamed"));
task.clear_name();
assert_eq!(task.name(), None);
assert_eq!(task.to_string(), "BoxRunnableOnce");
}
#[test]
fn test_box_runnable_once_into_box_returns_self() {
let task = BoxRunnableOnce::new(|| Ok::<(), io::Error>(()));
let boxed = RunnableOnce::into_box(task);
boxed
.run()
.expect("boxed runnable conversion should succeed");
}
#[test]
fn test_box_runnable_once_into_fn_extracts_function() {
let task = BoxRunnableOnce::new(|| Ok::<(), io::Error>(()));
let function = RunnableOnce::into_fn(task);
function().expect("runnable-once function should succeed");
}
#[test]
fn test_box_runnable_once_implements_supplier_once() {
let task = BoxRunnableOnce::new(|| Ok::<(), io::Error>(()));
let result = SupplierOnce::get(task);
result.expect("supplier once runnable should succeed");
}
#[test]
fn test_box_runnable_once_and_then_runs_next_on_success() {
let events = Rc::new(Cell::new(0));
let first_events = Rc::clone(&events);
let second_events = Rc::clone(&events);
let first = BoxRunnableOnce::new(move || {
first_events.set(1);
Ok::<(), io::Error>(())
});
let second = move || {
second_events.set(2);
Ok::<(), io::Error>(())
};
let chained = first.and_then(second);
chained.run().expect("chained runnable-once should succeed");
assert_eq!(events.get(), 2);
}
#[test]
fn test_box_runnable_once_and_then_skips_next_on_error() {
let events = Rc::new(Cell::new(0));
let second_events = Rc::clone(&events);
let first = BoxRunnableOnce::new(|| Err::<(), _>(io::Error::other("stop")));
let second = move || {
second_events.set(2);
Ok::<(), io::Error>(())
};
let chained = first.and_then(second);
assert_eq!(
chained
.run()
.expect_err("chained runnable should preserve error")
.to_string(),
"stop",
);
assert_eq!(events.get(), 0);
}
#[test]
fn test_box_runnable_once_then_callable_runs_callable_on_success() {
let task = BoxRunnableOnce::new_with_name("prepare", || Ok::<(), io::Error>(()));
let callable = || Ok::<i32, io::Error>(42);
let chained = task.then_callable(callable);
assert_eq!(chained.name(), Some("prepare"));
assert_eq!(chained.call().expect("callable should succeed"), 42);
}
#[test]
fn test_box_runnable_once_into_callable() {
let task = BoxRunnableOnce::new_with_name("cleanup", || Ok::<(), io::Error>(()));
let callable = task.into_callable();
assert_eq!(callable.name(), Some("cleanup"));
callable.call().expect("unit callable should succeed");
}
#[derive(Clone)]
struct TextRunnableOnce {
events: Rc<Cell<u32>>,
}
impl RunnableOnce<&'static str> for TextRunnableOnce {
fn run(self) -> Result<(), &'static str> {
self.events.set(self.events.get() + 1);
Ok(())
}
}
#[test]
fn test_runnable_once_default_conversions_with_text_error_type() {
let events = Rc::new(Cell::new(0));
let task = TextRunnableOnce {
events: Rc::clone(&events),
};
let boxed = RunnableOnce::into_box(task.clone());
boxed.run().expect("into_box should succeed");
let function = RunnableOnce::into_fn(task.clone());
function().expect("into_fn should succeed");
let boxed_from_ref = task.to_box();
boxed_from_ref.run().expect("to_box should succeed");
let function_from_ref = task.to_fn();
function_from_ref().expect("to_fn should succeed");
let callable = RunnableOnce::into_callable(task);
callable.call().expect("into_callable should succeed");
assert_eq!(events.get(), 5);
}
#[test]
fn test_box_runnable_once_from_supplier_with_text_error_type() {
let task = BoxRunnableOnce::from_supplier(|| Ok::<(), &'static str>(()));
task.run().expect("from_supplier should succeed");
}
#[test]
fn test_box_runnable_once_combinators_with_text_error_type() {
let events = Rc::new(Cell::new(0));
let first_events = Rc::clone(&events);
let second_events = Rc::clone(&events);
let first = BoxRunnableOnce::new(move || {
first_events.set(first_events.get() + 1);
Ok::<(), &'static str>(())
});
let second = move || {
second_events.set(second_events.get() + 1);
Ok::<(), &'static str>(())
};
let chained = first.and_then(second);
chained.run().expect("and_then should succeed");
assert_eq!(events.get(), 2);
let runnable = BoxRunnableOnce::new(|| Ok::<(), &'static str>(()));
let callable = runnable.then_callable(|| Ok::<i32, &'static str>(9));
assert_eq!(callable.call().expect("then_callable should succeed"), 9);
}