From ef28c2585d37419d1ae3bc467b42224509f26e3b Mon Sep 17 00:00:00 2001 From: altugbakan Date: Thu, 30 Mar 2023 19:54:46 +0300 Subject: [PATCH] Add Window tests and fixes --- .gitignore | 1 + src/packet.rs | 2 +- src/window.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ea8c4bf..787aa48 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/tmp diff --git a/src/packet.rs b/src/packet.rs index 8adaa8e..25d7ed9 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -177,7 +177,7 @@ impl TransferOption { /// ```rust /// use tftpd::OptionType; /// -/// assert_eq!(OptionType::BlockSize, OptionType::from_str("blksize").unwrap()); +/// assert_eq!(OptionType::BlockSize, "blksize".parse().unwrap()); /// assert_eq!("tsize", OptionType::TransferSize.as_str()); /// ``` #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/src/window.rs b/src/window.rs index 2d203d4..81c3fa0 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,5 +1,23 @@ use std::{collections::VecDeque, error::Error, fs::File, io::Read}; +/// Window `struct` is used to store chunks of data from a file. +/// It is used to store the data that is being sent or received for +/// Windowsize option. +/// +/// # Example +/// ```rust +/// use std::{fs::{self, OpenOptions, File}, io::Write}; +/// use tftpd::Window; +/// +/// let mut file = File::create("test.txt").unwrap(); +/// file.write_all(b"Hello, world!").unwrap(); +/// file.flush().unwrap(); +/// +/// let file = File::open("test.txt").unwrap(); +/// let mut window = Window::new(5, 512, file); +/// window.fill().unwrap(); +/// fs::remove_file("test.txt").unwrap(); +/// ``` pub struct Window { elements: VecDeque>, size: usize, @@ -8,6 +26,7 @@ pub struct Window { } impl Window { + /// Creates a new `Window` with the supplied size and chunk size. pub fn new(size: usize, chunk_size: usize, file: File) -> Window { Window { elements: VecDeque::new(), @@ -17,20 +36,25 @@ impl Window { } } + /// Fills the `Window` with chunks of data from the file. pub fn fill(&mut self) -> Result<(), Box> { for _ in self.elements.len()..self.size { let mut chunk = vec![0; self.chunk_size]; let size = self.file.read(&mut chunk)?; - self.elements.push_back(chunk); if size != self.chunk_size { + chunk.truncate(size); + self.elements.push_back(chunk); break; } + + self.elements.push_back(chunk); } Ok(()) } + /// Removes the first `amount` of elements from the `Window`. pub fn remove(&mut self, amount: usize) -> Result<(), Box> { if amount > self.elements.len() { return Err("amount cannot be larger than size".into()); @@ -41,3 +65,55 @@ impl Window { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use std::{fs, io::Write}; + + #[test] + fn fills_and_removes_from_window() { + let file = initialize(); + + let mut window = Window::new(2, 5, file); + window.fill().unwrap(); + assert_eq!(window.elements.len(), 2); + assert_eq!(window.elements[0], b"Hello"[..]); + assert_eq!(window.elements[1], b", wor"[..]); + + window.remove(1).unwrap(); + assert_eq!(window.elements.len(), 1); + assert_eq!(window.elements[0], b", wor"[..]); + + window.fill().unwrap(); + assert_eq!(window.elements.len(), 2); + assert_eq!(window.elements[0], b", wor"[..]); + assert_eq!(window.elements[1], b"ld!"[..]); + + clean(); + } + + fn initialize() -> File { + let dir_name = "tmp"; + let file_name = "tmp/test.txt"; + + if fs::metadata(dir_name).is_err() { + fs::create_dir(dir_name).unwrap(); + } + + if File::open(file_name).is_ok() { + fs::remove_file(file_name).unwrap(); + } + + let mut file = File::create(file_name).unwrap(); + file.write_all(b"Hello, world!").unwrap(); + file.flush().unwrap(); + + File::open(file_name).unwrap() + } + + fn clean() { + fs::remove_file("tmp/test.txt").unwrap(); + fs::remove_dir("tmp").unwrap(); + } +}