sigwake 0.0.1

A thread-safe signal-based state management library that integrates with Rust's async programming model
Documentation
use assert_call::{CallRecorder, call};
use sigwake::time::spawn_at;
use sigwake::utils::Action;
use std::time::{Duration, Instant, SystemTime};
use tokio::{spawn, test, time::sleep};

async fn wait_sleep() {
    sleep(Duration::from_millis(200)).await;
}

#[test]
async fn spawn_at_instant() {
    let mut cr = CallRecorder::new();
    let at = Instant::now() + Duration::from_millis(50);
    let _task = spawn_at(Action::new(|| call!("called")), at);
    wait_sleep().await;
    cr.verify("called");
}

#[test]
async fn spawn_at_system_time() {
    let mut cr = CallRecorder::new();
    let at = SystemTime::now() + Duration::from_millis(50);
    let _task = spawn_at(Action::new(|| call!("called")), at);
    wait_sleep().await;
    cr.verify("called");
}

#[test]
async fn spawn_at_duration() {
    let mut cr = CallRecorder::new();
    let duration = Duration::from_millis(50);
    let _task = spawn_at(Action::new(|| call!("called")), duration);
    wait_sleep().await;
    cr.verify("called");
}

#[test]
async fn cancel_timer() {
    let mut cr = CallRecorder::new();
    let at = Instant::now() + Duration::from_millis(50);
    let task = spawn_at(Action::new(|| call!("called")), at);
    drop(task);
    wait_sleep().await;
    cr.verify(());
}

#[test]
async fn spawn_multiple_timers() {
    let mut cr = CallRecorder::new();
    let expected = 10;
    let mut tasks = Vec::new();

    for i in 0..expected {
        let task = spawn_at(
            Action::new(move || call!("timer{i}")),
            Duration::from_millis(50 + i * 10),
        );
        tasks.push(task);
    }
    wait_sleep().await;

    let expected = (0..expected)
        .map(|i| format!("timer{i}"))
        .collect::<Vec<_>>();
    cr.verify(expected);
}

#[test]
async fn timer_ordering() {
    let mut cr = CallRecorder::new();
    let _task1 = spawn_at(Action::new(|| call!("second")), Duration::from_millis(50));
    let _task2 = spawn_at(Action::new(|| call!("first")), Duration::from_millis(25));
    wait_sleep().await;
    cr.verify(vec!["first", "second"]);
}

#[test]
async fn sleep_duration() {
    let mut cr = CallRecorder::new();
    let duration = Duration::from_millis(50);
    let _task = spawn(async move {
        sigwake::time::sleep(duration).await;
        call!("woke up");
    });
    wait_sleep().await;
    cr.verify("woke up");
}

#[test]
async fn sleep_instant() {
    let mut cr = CallRecorder::new();
    let at = Instant::now() + Duration::from_millis(50);
    let _task = spawn(async move {
        sigwake::time::sleep(at).await;
        call!("woke up");
    });
    wait_sleep().await;
    cr.verify("woke up");
}

#[test]
async fn sleep_system_time() {
    let mut cr = CallRecorder::new();
    let at = SystemTime::now() + Duration::from_millis(50);
    let _task = spawn(async move {
        sigwake::time::sleep(at).await;
        call!("woke up");
    });
    wait_sleep().await;
    cr.verify("woke up");
}

#[test]
async fn sleep_multiple() {
    let mut cr = CallRecorder::new();
    let expected = 3;
    let mut tasks = Vec::new();

    for i in 0..expected {
        let task = spawn(async move {
            sigwake::time::sleep(Duration::from_millis(50 + i * 10)).await;
            call!("woke up {i}");
        });
        tasks.push(task);
    }
    wait_sleep().await;

    let expected = (0..expected)
        .map(|i| format!("woke up {i}"))
        .collect::<Vec<_>>();
    cr.verify(expected);
}

#[test]
async fn sleep_duration_elapsed() {
    let duration = Duration::from_millis(50);
    let start = Instant::now();
    sigwake::time::sleep(duration).await;
    let elapsed = start.elapsed();
    assert!(
        elapsed >= duration,
        "sleep should take at least the specified duration"
    );
}

#[test]
async fn sleep_instant_elapsed() {
    let target_duration = Duration::from_millis(50);
    let target_time = Instant::now() + target_duration;
    sigwake::time::sleep(target_time).await;
    assert!(
        Instant::now() >= target_time,
        "sleep should wait until the target time"
    );
}

#[test]
async fn sleep_system_time_elapsed() {
    let target_duration = Duration::from_millis(50);
    let target_time = SystemTime::now() + target_duration;
    sigwake::time::sleep(target_time).await;
    assert!(
        SystemTime::now() >= target_time,
        "sleep should wait until the target time"
    );
}