Repository: launchbadge/sqlx
File: tests/sqlite/sqlite.rs (Rust)

Code before:
    Ok(())
}

#[sqlx_macros::test]
async fn test_multiple_set_progress_handler_calls_drop_old_handler() -> anyhow::Result<()> {
    static OBJECTS_DROPPED: AtomicUsize = AtomicUsize::new(0);

    struct Handler(pub &'static str);
    impl FnOnce<()> for Handler {
        type Output = bool;

        extern "rust-call" fn call_once(mut self, args: ()) -> bool {
            self.call_mut(args)
        }
    }
    impl FnMut<()> for Handler {
        extern "rust-call" fn call_mut(&mut self, _args: ()) -> bool {
            assert_eq!(3, self.0.len());
            false
        }
    }
    impl Drop for Handler {
        fn drop(&mut self) {
            OBJECTS_DROPPED.fetch_add(1, Ordering::Relaxed);
        }
    }

    {
        let mut conn = new::<Sqlite>().await?;

        conn.lock_handle()
            .await?
            .set_progress_handler(1, Handler("foo"));
        conn.lock_handle()
            .await?
            .set_progress_handler(1, Handler("bar"));
        conn.lock_handle()
            .await?
            .set_progress_handler(1, Handler("baz"));

        match sqlx::query("SELECT 'hello' AS title")
            .fetch_all(&mut conn)
            .await
        {
            Err(sqlx::Error::Database(err)) => {
                assert_eq!(err.message(), String::from("interrupted"))
            }
            _ => panic!("expected an interrupt"),
        }

        conn.lock_handle().await?.remove_progress_handler();

Review comment (suggestion):
This is unnecessary: we don't want to require nightly just to run this test. 

Just have a simple type that counts the number of times it was dropped and capture that in a normal closure, please.

Code after:
#[sqlx_macros::test]
async fn test_multiple_set_progress_handler_calls_drop_old_handler() -> anyhow::Result<()> {
    let ref_counted_object = Arc::new(0);
    assert_eq!(1, Arc::strong_count(&ref_counted_object));

    {
        let mut conn = new::<Sqlite>().await?;

        let o = ref_counted_object.clone();
        conn.lock_handle().await?.set_progress_handler(1, move || {
            println!("{:?}", o);
            false
        });
        assert_eq!(2, Arc::strong_count(&ref_counted_object));

        let o = ref_counted_object.clone();
        conn.lock_handle().await?.set_progress_handler(1, move || {
            println!("{:?}", o);
            false
        });
        assert_eq!(2, Arc::strong_count(&ref_counted_object));

        let o = ref_counted_object.clone();
        conn.lock_handle().await?.set_progress_handler(1, move || {
            println!("{:?}", o);
            false
        });
        assert_eq!(2, Arc::strong_count(&ref_counted_object));

        match sqlx::query("SELECT 'hello' AS title")
            .fetch_all(&mut conn)
            .await
        {
            Err(sqlx::Error::Database(err)) => {
                assert_eq!(err.message(), String::from("interrupted"))
            }
            _ => panic!("expected an interrupt"),
        }

        conn.lock_handle().await?.remove_progress_handler();
    }

    assert_eq!(1, Arc::strong_count(&ref_counted_object));
    Ok(())
}