async-spooled-tempfile 0.1.0

Asynchronous spooled temporary file
Documentation
use std::io::SeekFrom;

use async_spooled_tempfile::{SpooledData, SpooledTempFile};
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};

#[tokio::test]
async fn test_implicit_rollover() {
    let mut sf = SpooledTempFile::new(5);
    let mut read_buffer = Vec::new();

    assert!(!sf.is_rolled());
    assert!(!sf.is_poisoned());
    assert!(std::matches!(sf.stream_position().await, Ok(0)));
    sf.read_to_end(&mut read_buffer).await.unwrap();
    assert_eq!(read_buffer.len(), 0);

    let first_data_written = b"1234";
    sf.write_all(first_data_written).await.unwrap();

    assert!(!sf.is_rolled());
    assert!(!sf.is_poisoned());
    let res_cur_pos = sf.stream_position().await;
    assert!(std::matches!(res_cur_pos, Ok(4)));
    let cur_pos = res_cur_pos.unwrap();
    sf.seek(SeekFrom::Start(0)).await.unwrap();
    sf.read_to_end(&mut read_buffer).await.unwrap();
    assert_eq!(read_buffer.as_slice(), first_data_written);
    read_buffer.clear();

    sf.seek(SeekFrom::Start(cur_pos)).await.unwrap();

    let second_data_written = b"5678";
    sf.write_all(second_data_written).await.unwrap();

    assert!(sf.is_rolled());
    assert!(!sf.is_poisoned());
    assert!(std::matches!(sf.stream_position().await, Ok(8)));

    sf.seek(SeekFrom::Start(0)).await.unwrap();
    sf.read_to_end(&mut read_buffer).await.unwrap();

    assert_eq!(
        read_buffer,
        [
            first_data_written.as_slice(),
            second_data_written.as_slice()
        ]
        .concat()
    );

    assert!(std::matches!(
        sf.into_inner().await,
        Ok(SpooledData::OnDisk(..))
    ));
}

#[tokio::test]
async fn test_explicit_rollover() {
    let mut sf = SpooledTempFile::new(5);
    let mut read_buffer = Vec::new();

    let first_data_written = b"123";
    sf.write_all(first_data_written).await.unwrap();

    assert!(!sf.is_rolled());
    assert!(!sf.is_poisoned());
    assert!(std::matches!(sf.stream_position().await, Ok(3)));

    sf.seek(SeekFrom::Start(0)).await.unwrap();

    sf.roll().await.unwrap();

    assert!(sf.is_rolled());
    assert!(!sf.is_poisoned());
    assert!(std::matches!(sf.stream_position().await, Ok(0)));

    sf.read_to_end(&mut read_buffer).await.unwrap();
    assert_eq!(read_buffer.as_slice(), first_data_written);
    assert!(std::matches!(
        sf.into_inner().await,
        Ok(SpooledData::OnDisk(..))
    ));
}

#[tokio::test]
async fn test_into_inner() {
    let mut sf1 = SpooledTempFile::new(10);

    let first_data_written = b"1234567";
    sf1.write_all(first_data_written).await.unwrap();

    assert!(!sf1.is_rolled());
    assert!(!sf1.is_poisoned());
    assert!(std::matches!(sf1.stream_position().await, Ok(7)));
    assert!(std::matches!(
        sf1.into_inner().await,
        Ok(SpooledData::InMemory(..))
    ));

    let mut sf2 = SpooledTempFile::with_max_size_and_capacity(10, 10);

    let second_data_written = b"123456789abcdef";
    sf2.write_all(second_data_written).await.unwrap();

    assert!(sf2.is_rolled());
    assert!(!sf2.is_poisoned());
    assert!(std::matches!(sf2.stream_position().await, Ok(15)));
    assert!(std::matches!(
        sf2.into_inner().await,
        Ok(SpooledData::OnDisk(..))
    ));
}

#[tokio::test]
async fn test_set_len() {
    let mut sf1 = SpooledTempFile::new(10);
    sf1.set_len(4).await.unwrap();

    let f1_buffer = match sf1.into_inner().await {
        Ok(SpooledData::InMemory(cur)) => cur.into_inner(),
        _ => panic!("the data of the first spooled file should be in memory"),
    };
    assert_eq!(f1_buffer.as_slice(), b"\x00\x00\x00\x00");

    let mut sf2 = SpooledTempFile::new(5);
    sf2.write_all(b"abc").await.unwrap();
    assert!(!sf2.is_rolled());
    assert!(!sf2.is_poisoned());
    sf2.set_len(10).await.unwrap();

    let mut sf2_file = match sf2.into_inner().await {
        Ok(SpooledData::OnDisk(file)) => file,
        _ => panic!("the data of the second spooled file should be located in a file"),
    };
    sf2_file.seek(SeekFrom::Start(0)).await.unwrap();
    let mut sf2_content = Vec::new();
    sf2_file.read_to_end(&mut sf2_content).await.unwrap();

    assert_eq!(sf2_content.as_slice(), b"abc\x00\x00\x00\x00\x00\x00\x00");
}