From c345a5b53165df90e8db7700fd37a172fc02b466 Mon Sep 17 00:00:00 2001 From: altugbakan Date: Thu, 9 Mar 2023 20:34:06 +0300 Subject: [PATCH] Add packet tests --- src/message.rs | 11 +-- src/packet.rs | 232 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 236 insertions(+), 7 deletions(-) diff --git a/src/message.rs b/src/message.rs index ed89460..32014db 100644 --- a/src/message.rs +++ b/src/message.rs @@ -9,7 +9,7 @@ pub struct Message; impl Message { pub fn send_data(socket: &UdpSocket, data: &[u8]) -> Result<(), Box> { - let buf = [&[0x00, Opcode::Data as u8], data].concat(); + let buf = [&Opcode::Data.as_bytes()[..], data].concat(); socket.send(&buf)?; @@ -17,7 +17,7 @@ impl Message { } pub fn send_ack(socket: &UdpSocket, block: u16) -> Result<(), Box> { - let buf = [&[0x00, Opcode::Ack as u8], &block.to_be_bytes()[..]].concat(); + let buf = [Opcode::Ack.as_bytes(), block.to_be_bytes()].concat(); socket.send(&buf)?; @@ -45,7 +45,7 @@ impl Message { socket: &UdpSocket, options: &Vec, ) -> Result<(), Box> { - let mut buf = vec![0x00, Opcode::Oack as u8]; + let mut buf = Opcode::Oack.as_bytes().to_vec(); for option in options { buf = [buf, option.as_bytes()].concat(); @@ -70,8 +70,9 @@ impl Message { fn get_error_buf(code: ErrorCode, msg: &str) -> Vec { [ - &[0x00, Opcode::Error as u8, 0x00, code as u8], - msg.as_bytes(), + &Opcode::Error.as_bytes()[..], + &code.as_bytes()[..], + &msg.as_bytes()[..], &[0x00], ] .concat() diff --git a/src/packet.rs b/src/packet.rs index 1791396..f377103 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -37,6 +37,8 @@ impl<'a> Packet<'a> { } } +#[repr(u16)] +#[derive(PartialEq)] pub enum Opcode { Rrq = 0x0001, Wrq = 0x0002, @@ -58,8 +60,13 @@ impl Opcode { _ => Err("invalid opcode"), } } + + pub fn as_bytes(self) -> [u8; 2] { + return (self as u16).to_be_bytes(); + } } +#[derive(Debug, PartialEq)] pub struct TransferOption { pub option: OptionType, pub value: usize, @@ -77,6 +84,7 @@ impl TransferOption { } } +#[derive(Debug, PartialEq)] pub enum OptionType { BlockSize, TransferSize, @@ -92,6 +100,10 @@ impl OptionType { } } + fn as_bytes(&self) -> &[u8] { + self.as_str().as_bytes() + } + fn from_str(value: &str) -> Result { match value { "blksize" => Ok(OptionType::BlockSize), @@ -103,7 +115,7 @@ impl OptionType { } #[repr(u16)] -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum ErrorCode { NotDefined = 0, FileNotFound = 1, @@ -129,6 +141,10 @@ impl ErrorCode { _ => Err("invalid error code"), } } + + pub fn as_bytes(self) -> [u8; 2] { + return (self as u16).to_be_bytes(); + } } fn parse_rq(buf: &[u8], opcode: Opcode) -> Result> { @@ -172,7 +188,7 @@ fn parse_rq(buf: &[u8], opcode: Opcode) -> Result> { fn parse_data(buf: &[u8]) -> Result> { Ok(Packet::Data { block_num: Convert::to_u16(&buf[2..])?, - data: &buf[2..], + data: &buf[4..], }) } @@ -189,4 +205,216 @@ fn parse_error(buf: &[u8]) -> Result> { #[cfg(test)] mod tests { use super::*; + + #[test] + fn parses_read_request() { + let buf = [ + &Opcode::Rrq.as_bytes()[..], + &"test.png".as_bytes(), + &[0x00], + &"octet".as_bytes(), + &[0x00], + ] + .concat(); + + if let Ok(Packet::Rrq { + filename, + mode, + options, + }) = parse_rq(&buf, Opcode::Rrq) + { + assert_eq!(filename, "test.png"); + assert_eq!(mode, "octet"); + assert_eq!(options.len(), 0); + } else { + panic!("cannot parse read request") + } + } + + #[test] + fn parses_read_request_with_options() { + let buf = [ + &Opcode::Rrq.as_bytes()[..], + &"test.png".as_bytes(), + &[0x00], + &"octet".as_bytes(), + &[0x00], + &OptionType::TransferSize.as_bytes(), + &[0x00], + &"0".as_bytes(), + &[0x00], + &OptionType::Timeout.as_bytes(), + &[0x00], + &"5".as_bytes(), + &[0x00], + ] + .concat(); + + if let Ok(Packet::Rrq { + filename, + mode, + options, + }) = parse_rq(&buf, Opcode::Rrq) + { + assert_eq!(filename, "test.png"); + assert_eq!(mode, "octet"); + assert_eq!(options.len(), 2); + assert_eq!( + options[0], + TransferOption { + option: OptionType::TransferSize, + value: 0 + } + ); + assert_eq!( + options[1], + TransferOption { + option: OptionType::Timeout, + value: 5 + } + ); + } else { + panic!("cannot parse read request with options") + } + } + + #[test] + fn parses_write_request() { + let buf = [ + &Opcode::Wrq.as_bytes()[..], + &"test.png".as_bytes(), + &[0x00], + &"octet".as_bytes(), + &[0x00], + ] + .concat(); + + if let Ok(Packet::Wrq { + filename, + mode, + options, + }) = parse_rq(&buf, Opcode::Wrq) + { + assert_eq!(filename, "test.png"); + assert_eq!(mode, "octet"); + assert_eq!(options.len(), 0); + } else { + panic!("cannot parse write request") + } + } + + #[test] + fn parses_write_request_with_options() { + let buf = [ + &Opcode::Wrq.as_bytes()[..], + &"test.png".as_bytes(), + &[0x00], + &"octet".as_bytes(), + &[0x00], + &OptionType::TransferSize.as_bytes(), + &[0x00], + &"12341234".as_bytes(), + &[0x00], + &OptionType::BlockSize.as_bytes(), + &[0x00], + &"1024".as_bytes(), + &[0x00], + ] + .concat(); + + if let Ok(Packet::Wrq { + filename, + mode, + options, + }) = parse_rq(&buf, Opcode::Wrq) + { + assert_eq!(filename, "test.png"); + assert_eq!(mode, "octet"); + assert_eq!(options.len(), 2); + assert_eq!( + options[0], + TransferOption { + option: OptionType::TransferSize, + value: 12341234 + } + ); + assert_eq!( + options[1], + TransferOption { + option: OptionType::BlockSize, + value: 1024 + } + ); + } else { + panic!("cannot parse write request with options") + } + } + + #[test] + fn parses_data() { + let buf = [ + &Opcode::Data.as_bytes()[..], + &5u16.to_be_bytes(), + &[ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ], + ] + .concat(); + + if let Ok(Packet::Data { block_num, data }) = parse_data(&buf) { + assert_eq!(block_num, 5); + assert_eq!( + data, + [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C] + ); + } else { + panic!("cannot parse data") + } + } + + #[test] + fn parses_ack() { + let buf = [&Opcode::Ack.as_bytes()[..], &12u16.to_be_bytes()].concat(); + + if let Ok(Packet::Ack(block_num)) = parse_ack(&buf) { + assert_eq!(block_num, 12); + } else { + panic!("cannot parse ack") + } + } + + #[test] + fn parses_error() { + let buf = [ + &Opcode::Error.as_bytes()[..], + &ErrorCode::FileExists.as_bytes(), + "file already exists".as_bytes(), + &[0x00], + ] + .concat(); + + if let Ok(Packet::Error { code, msg }) = parse_error(&buf) { + assert_eq!(code, ErrorCode::FileExists); + assert_eq!(msg, "file already exists"); + } else { + panic!("cannot parse error") + } + } + + #[test] + fn parses_error_without_message() { + let buf = [ + &Opcode::Error.as_bytes()[..], + &ErrorCode::FileExists.as_bytes(), + &[0x00], + ] + .concat(); + + if let Ok(Packet::Error { code, msg }) = parse_error(&buf) { + assert_eq!(code, ErrorCode::FileExists); + assert_eq!(msg, ""); + } else { + panic!("cannot parse error") + } + } }