I'm currently working on a personal project with Rust to learn the language, which basically consists on translating a project I did in college in C to Rust. The project basically consists in a (very) simplified file system based on ext2, and I want to test a part of code responsible of creating a "virtual device" (a file) and read/write to it, but I don't know what's the best approach to test it. This is the code I want to test:
pub struct FileSystem {
v_device: File,
size: usize
}
impl FileSystem {
pub fn new(path: &str) -> Result<Self, io::Error> {
let v_device = File::create(path)?;
v_device.set_permissions(fs::Permissions::from_mode(0o666))
.expect("TODO: panic message");
Ok (Self { v_device, size: 0 })
}
pub fn write_block(&mut self, block_number: u64, buffer: &[u8; BLOCKSIZE as usize]) -> Result<usize, io::Error> {
let offset = BLOCKSIZE * block_number;
let bytes_written = self.v_device.write_at(buffer, offset)?;
self.size += bytes_written;
Ok(bytes_written)
}
pub fn read_block(&self, block_number: u64, buffer: &mut [u8; BLOCKSIZE as usize]) -> Result<(), io::Error> {
let offset = BLOCKSIZE * block_number;
self.v_device.read_exact_at(buffer, offset)?;
Ok(())
}
}
My idea is to test the creation of the file, that the correct number of bytes are written, that the correct number of bytes can be read, etc., but this would mean I'd have to create several real files only to test the program. Is there a way to test it without having to create a bunch of files? If not, how's the best approach to test this code?
PS: any advice regarding the code I posted is also welcome!
Since read_block
and write_block
operations that you want to test do not actually require v_device
to be a file, but something that implements Read
, Write
and Seek
traits, you can make the FileSystem
generic:
pub struct FileSystem<T: Read + Write + Seek> {
v_device: T,
size: usize
}
Then create another constructor in addition to new
which accepts argument of type T
. In the tests, instead of a File
you can use Cursor
which also implements Read + Write + Seek
and can operate on the in-memory Vec
if you construct it with Cursor::new(Vec::new())
.