bouzuya.hatenablog.com

ぼうずやのにっき

catch_unwind で beforeEach/afterEach みたいな何か

bouzuya/rust-examples 。 test で beforeEach / afterEach が欲しいと言われたので catch_unwind を調べた。

std::panic::catch_unwind で一部の panic は catch できる。

fn test3_setup() {
    println!("test3 setup")
}

fn test3_teardown() {
    println!("test3 teardown");
}

fn run_test3<F, R>(f: F)
where
    F: FnOnce() -> R + std::panic::UnwindSafe,
{
    test3_setup();
    let result = std::panic::catch_unwind(f);
    test3_teardown();
    assert!(result.is_ok());
}

#[test]
#[should_panic]
fn test3() {
    run_test3(|| {
        assert_eq!(2 + 2, 5);
    });
}

あとは crates:futuresfutures:FutureExt::catch_unwind で async のときも。

async fn test6_setup() {
    println!("test6 setup")
}

async fn test6_teardown() {
    println!("test6 teardown");
}

async fn run_test6<R>(
    f: impl std::future::Future<Output = R> + Sized + std::panic::UnwindSafe,
) {
    test6_setup().await;
    let result = futures::FutureExt::catch_unwind(f).await;
    test6_teardown().await;
    assert!(result.is_ok());
}

#[tokio::test]
#[should_panic]
async fn test6() {
    run_test6(async {
        assert_eq!(2 + 2, 5);
    })
    .await
}

普段使っている crates:anyhow と組み合わせて……。

async fn test8_setup() -> anyhow::Result<()> {
    println!("test8 setup");
    Ok(())
}

async fn test8_teardown() -> anyhow::Result<()> {
    println!("test8 teardown");
    Ok(())
}

async fn run_test8<F, FutS, FutT, S, T>(f: F, setup: S, teardown: T) -> anyhow::Result<()>
where
    F: std::future::Future<Output = anyhow::Result<()>> + Sized + std::panic::UnwindSafe,
    FutS: std::future::Future<Output = anyhow::Result<()>>,
    FutT: std::future::Future<Output = anyhow::Result<()>>,
    S: Fn() -> FutS,
    T: Fn() -> FutT,
{
    setup().await?;
    let result = futures::FutureExt::catch_unwind(f).await;
    teardown().await?;
    result.unwrap()
}

#[tokio::test]
async fn test8() -> anyhow::Result<()> {
    run_test8(
        async {
            assert_eq!(2 + 2, 4);
            Ok(())
        },
        test8_setup,
        test8_teardown,
    )
    .await
}

今日のコミット。