liteboxfs 0.1.0

A modern POSIX filesystem in a SQLite database
Documentation
use xpct::{be_empty, be_err, be_ok, contain_element, contain_elements, equal, expect, have_len};

use super::{BlockStoreTestExt, DataBlock};
use crate::{
    block::{
        store::BlockStore,
        types::{Block, FileId},
    },
    errors::InternalError,
    testing::MemoryBlockStore,
};

#[test]
fn list_blocks_when_file_does_not_exist() {
    let store = MemoryBlockStore::new();

    expect!(store.list_blocks(FileId::from(1)))
        .to(be_err())
        .to(equal(
            InternalError::FileNotFound {
                id: FileId::from(1),
            }
            .into(),
        ));
}

#[test]
fn insert_and_read_block() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: block_id,
        bytes: expected_bytes,
        signature: expected_signature,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let mut actual_bytes = Vec::new();
    let read_block = expect!(store.read_block(block_id, &mut actual_bytes))
        .to(be_ok())
        .into_inner();

    expect!(actual_bytes).to(equal(expected_bytes));
    expect!(read_block.signature).to(equal(expected_signature));
}

#[test]
fn replace_single_block() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: initial_block_id,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: new_block_id,
        bytes: new_bytes,
        signature: new_signature,
        ..
    } = expect!(store.replace_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    expect!(new_block_id).to_not(equal(initial_block_id));

    let mut actual_bytes = Vec::new();
    let read_block = expect!(store.read_block(new_block_id, &mut actual_bytes))
        .to(be_ok())
        .into_inner();

    expect!(actual_bytes).to(equal(new_bytes));
    expect!(read_block.signature).to(equal(new_signature));
}

#[test]
fn append_block_to_end() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: first_block_id,
        signature: first_signature,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: second_block_id,
        signature: second_signature,
        ..
    } = expect!(store.insert_data(file_id, 1))
        .to(be_ok())
        .into_inner();

    let block_list = expect!(store.list_blocks(file_id))
        .to(be_ok())
        .into_inner()
        .into_iter()
        .collect::<Vec<_>>();

    expect!(&block_list).to(have_len(2));
    expect!(block_list).to(contain_elements([
        Block {
            id: first_block_id,
            signature: first_signature,
        },
        Block {
            id: second_block_id,
            signature: second_signature,
        },
    ]));
}

#[test]
fn prepend_block_to_front() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: second_block_id,
        signature: second_signature,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: first_block_id,
        signature: first_signature,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let block_list = expect!(store.list_blocks(file_id))
        .to(be_ok())
        .into_inner()
        .into_iter()
        .collect::<Vec<_>>();

    expect!(&block_list).to(have_len(2));
    expect!(block_list).to(contain_elements([
        Block {
            id: first_block_id,
            signature: first_signature,
        },
        Block {
            id: second_block_id,
            signature: second_signature,
        },
    ]));
}

#[test]
fn insert_block_in_middle() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: first_block_id,
        signature: first_signature,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: third_block_id,
        signature: third_signature,
        ..
    } = expect!(store.insert_data(file_id, 1))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: second_block_id,
        signature: second_signature,
        ..
    } = expect!(store.insert_data(file_id, 1))
        .to(be_ok())
        .into_inner();

    let block_list = expect!(store.list_blocks(file_id))
        .to(be_ok())
        .into_inner()
        .into_iter()
        .collect::<Vec<_>>();

    expect!(&block_list).to(have_len(3));
    expect!(block_list).to(contain_elements([
        Block {
            id: first_block_id,
            signature: first_signature,
        },
        Block {
            id: second_block_id,
            signature: second_signature,
        },
        Block {
            id: third_block_id,
            signature: third_signature,
        },
    ]));
}

#[test]
fn remove_single_block() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock { id: block_id, .. } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let removed_block_ids = expect!(store.remove_blocks(file_id, 0..1))
        .to(be_ok())
        .into_inner();

    expect!(&removed_block_ids).to(have_len(1));
    expect!(removed_block_ids).to(contain_element(block_id));

    let block_list = expect!(store.list_blocks(file_id))
        .to(be_ok())
        .into_inner()
        .into_iter()
        .collect::<Vec<_>>();

    expect!(&block_list).to(be_empty());
}

#[test]
fn remove_all_blocks() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: first_block_id, ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: second_block_id,
        ..
    } = expect!(store.insert_data(file_id, 1))
        .to(be_ok())
        .into_inner();

    let removed_block_ids = expect!(store.remove_blocks(file_id, 0..2))
        .to(be_ok())
        .into_inner();

    expect!(&removed_block_ids).to(have_len(2));
    expect!(removed_block_ids).to(contain_elements([first_block_id, second_block_id]));

    let block_list = expect!(store.list_blocks(file_id))
        .to(be_ok())
        .into_inner()
        .into_iter()
        .collect::<Vec<_>>();

    expect!(&block_list).to(be_empty());
}

#[test]
fn remove_middle_block() {
    let mut store = MemoryBlockStore::new();
    let file_id = FileId::from(1);

    let DataBlock {
        id: first_block_id,
        signature: first_block_signature,
        ..
    } = expect!(store.insert_data(file_id, 0))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: second_block_id,
        ..
    } = expect!(store.insert_data(file_id, 1))
        .to(be_ok())
        .into_inner();

    let DataBlock {
        id: third_block_id,
        signature: third_block_signature,
        ..
    } = expect!(store.insert_data(file_id, 2))
        .to(be_ok())
        .into_inner();

    let removed_block_ids = expect!(store.remove_blocks(file_id, 1..2))
        .to(be_ok())
        .into_inner();

    expect!(&removed_block_ids).to(have_len(1));
    expect!(removed_block_ids).to(contain_element(second_block_id));

    let block_list = expect!(store.list_blocks(file_id))
        .to(be_ok())
        .into_inner()
        .into_iter()
        .collect::<Vec<_>>();

    expect!(&block_list).to(have_len(2));
    expect!(block_list).to(contain_elements([
        Block {
            id: first_block_id,
            signature: first_block_signature,
        },
        Block {
            id: third_block_id,
            signature: third_block_signature,
        },
    ]));
}