use fs_core::block::BlockRead;
use fs_core::error::{Error, Result};
use fs_core::CachingDevice;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
struct Bytes {
data: Vec<u8>,
reads: AtomicUsize,
}
impl Bytes {
fn reads(&self) -> usize {
self.reads.load(Ordering::SeqCst)
}
}
impl BlockRead for Bytes {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
self.reads.fetch_add(1, Ordering::SeqCst);
let start = usize::try_from(offset).unwrap_or(usize::MAX);
let end = start.saturating_add(buf.len());
if end > self.data.len() || start > self.data.len() {
return Err(Error::ShortRead {
offset,
want: buf.len(),
got: self.data.len().saturating_sub(start),
});
}
buf.copy_from_slice(&self.data[start..end]);
Ok(())
}
fn size_bytes(&self) -> u64 {
self.data.len() as u64
}
}
fn cache() -> (Arc<CachingDevice>, Arc<Bytes>) {
let inner = Arc::new(Bytes {
data: (0..4096u32).map(|i| i as u8).collect(),
reads: AtomicUsize::new(0),
});
(CachingDevice::read_only(inner.clone(), 512, 4), inner)
}
#[test]
fn a_read_at_the_very_top_of_the_address_space_is_refused() {
let (cache, dev) = cache();
let mut buf = [0xEEu8; 8];
let result = cache.read_at(u64::MAX, &mut buf);
match result {
Err(Error::ShortRead { offset, want, got }) => {
assert_eq!((offset, want, got), (u64::MAX, 8, 0));
}
other => panic!("expected ShortRead, got {other:?}"),
}
assert_eq!(
dev.reads(),
0,
"the cache forwarded the wild offset to the device instead of refusing it"
);
assert_eq!(buf, [0xEEu8; 8], "a refused read leaves the buffer alone");
}
#[test]
fn a_read_whose_end_wraps_past_the_top_is_refused() {
let (cache, dev) = cache();
let mut buf = [0xEEu8; 64];
let result = cache.read_at(u64::MAX - 4, &mut buf);
match result {
Err(Error::ShortRead { offset, want, got }) => {
assert_eq!((offset, want, got), (u64::MAX - 4, 64, 0));
}
other => panic!("expected ShortRead, got {other:?}"),
}
assert_eq!(
dev.reads(),
0,
"the cache forwarded the wrapping offset to the device instead of refusing it"
);
assert_eq!(buf, [0xEEu8; 64], "a refused read leaves the buffer alone");
}
#[test]
fn an_ordinary_read_consults_the_device() {
let (cache, dev) = cache();
let mut buf = [0u8; 8];
cache.read_at(16, &mut buf).expect("an ordinary read");
assert_eq!(buf, [16, 17, 18, 19, 20, 21, 22, 23]);
assert!(
dev.reads() >= 1,
"an ordinary read must reach the device, or the zero above proves nothing"
);
}