use super::{TEST_BLOCK_SIZE, random_buf};
use crate::{
block::{
logical::{LogicalBlockStore, LogicalBlockStoreAdapter},
store::{BlockStore, BlockStoreInput},
types::{BlockData, FileId},
},
testing::Case,
testing::MemoryBlockStore,
};
use xpct::{be_none, be_ok, be_some, equal, expect, have_len, match_pattern, pattern};
const LOGICAL_BLOCK_SIZE: usize = TEST_BLOCK_SIZE * 2;
#[cfg(test)]
mod get_block_at_index {
use super::*;
#[test]
fn single_physical_block_aligned() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
let data = random_buf(LOGICAL_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 0, data.as_slice().into())).to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(0, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
expect!(bytes).to(equal(&data));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn single_physical_block_partial() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
let data = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 0, data.as_slice().into())).to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(0, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
expect!(&bytes[..TEST_BLOCK_SIZE]).to(equal(&data[..]));
expect!(&bytes[TEST_BLOCK_SIZE..]).to(equal(&vec![0u8; TEST_BLOCK_SIZE][..]));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn logical_block_beyond_eof() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
let data = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 0, data.as_slice().into())).to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
expect!(adapter.get_block_at_index(5, &block_list))
.to(be_ok())
.to(be_none());
}
#[test]
fn multiple_blocks_in_single_logical() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
let data1 = random_buf(TEST_BLOCK_SIZE, Case::Lower);
let data2 = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 0, data1.as_slice().into())).to(be_ok());
expect!(block_store.insert_block(file_id, 1, data2.as_slice().into())).to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(0, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
expect!(&bytes[..TEST_BLOCK_SIZE]).to(equal(&data1[..]));
expect!(&bytes[TEST_BLOCK_SIZE..]).to(equal(&data2[..]));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn logical_block_middle_of_file() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
for i in 0..4 {
let data = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, i, data.as_slice().into())).to(be_ok());
}
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(1, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn entire_logical_block_is_hole() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
expect!(block_store.insert_block(
file_id,
0,
BlockStoreInput::Hole {
len: LOGICAL_BLOCK_SIZE as u64
}
))
.to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
expect!(adapter.get_block_at_index(0, &block_list))
.to(be_ok())
.to(be_some())
.into()
.to(match_pattern(
pattern!(BlockData::Hole { len } if *len == LOGICAL_BLOCK_SIZE as u64),
));
}
#[test]
fn logical_block_spans_data_and_hole() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
let data = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 0, data.as_slice().into())).to(be_ok());
expect!(block_store.insert_block(
file_id,
1,
BlockStoreInput::Hole {
len: TEST_BLOCK_SIZE as u64
}
))
.to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(0, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
expect!(&bytes[..TEST_BLOCK_SIZE]).to(equal(&data[..]));
expect!(&bytes[TEST_BLOCK_SIZE..]).to(equal(&vec![0u8; TEST_BLOCK_SIZE][..]));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn logical_block_spans_hole_and_data() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
expect!(block_store.insert_block(
file_id,
0,
BlockStoreInput::Hole {
len: TEST_BLOCK_SIZE as u64
}
))
.to(be_ok());
let data = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 1, data.as_slice().into())).to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(0, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
expect!(&bytes[..TEST_BLOCK_SIZE]).to(equal(&vec![0u8; TEST_BLOCK_SIZE][..]));
expect!(&bytes[TEST_BLOCK_SIZE..]).to(equal(&data[..]));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn logical_block_at_exact_boundary() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
for i in 0..4 {
let data = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, i, data.as_slice().into())).to(be_ok());
}
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(1, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
#[test]
fn logical_block_partial_at_eof() {
let mut block_store = MemoryBlockStore::new();
let file_id = FileId::from(1);
let data1 = random_buf(TEST_BLOCK_SIZE, Case::Lower);
let data2 = random_buf(TEST_BLOCK_SIZE, Case::Lower);
expect!(block_store.insert_block(file_id, 0, data1.as_slice().into())).to(be_ok());
expect!(block_store.insert_block(file_id, 1, data2.as_slice().into())).to(be_ok());
let data3 = random_buf(4, Case::Lower);
expect!(block_store.insert_block(file_id, 2, data3.as_slice().into())).to(be_ok());
let block_list = expect!(block_store.list_blocks(file_id))
.to(be_ok())
.into_inner();
let mut adapter = LogicalBlockStoreAdapter::new(block_store, LOGICAL_BLOCK_SIZE);
let result = expect!(adapter.get_block_at_index(1, &block_list))
.to(be_ok())
.to(be_some())
.into_inner();
match result.as_ref() {
BlockData::Data { bytes } => {
expect!(bytes).to(have_len(LOGICAL_BLOCK_SIZE));
expect!(&bytes[..4]).to(equal(&data3[..]));
expect!(&bytes[4..]).to(equal(&vec![0u8; 12][..]));
}
BlockData::Hole { .. } => panic!("Expected Data, got Hole"),
}
}
}