//! Single call and synchronous return value.

mod common;

use std::convert::Infallible;

use debounce_promise::Debounce;

use common::{sleep, Counter};

#[tokio::test]
async fn returns_the_result_of_a_single_operation() {
    let debounced =
        Debounce::latest(|value: &'static str| async move { Ok::<_, Infallible>(value) })
            .wait_ms(100)
            .build();
    let result = debounced.call("foo").await;
    assert_eq!(result, Ok("foo"));
}

#[tokio::test]
async fn converts_the_return_value_to_a_result() {
    // The function returns a ready value with no async work, the wrapper still
    // coalesces a burst into one run.
    let calls = Counter::new();
    let c = calls.clone();
    let debounced = Debounce::latest(move |_: i32| {
        let c = c.clone();
        async move { Ok::<_, Infallible>(c.bump() + 1) }
    })
    .wait_ms(10)
    .build();

    debounced.call(1);
    debounced.call(2);
    let _ = debounced.call(3).await;

    assert_eq!(calls.get(), 1);
}

#[tokio::test]
async fn non_promise_return_value_resolves_in_trailing_mode() {
    // A7: rounds out the count check above with a value assertion.
    let debounced = Debounce::latest(|n: i32| async move { Ok::<_, Infallible>(n * 2) })
        .wait_ms(10)
        .build();

    let a = debounced.call(1);
    let b = debounced.call(5);
    sleep(20).await;
    assert_eq!(a.await, Ok(10));
    assert_eq!(b.await, Ok(10));
}
