Add packet tests

This commit is contained in:
altugbakan 2023-03-09 20:34:06 +03:00
parent 68d05e3a11
commit c345a5b531
2 changed files with 236 additions and 7 deletions

View file

@ -9,7 +9,7 @@ pub struct Message;
impl Message {
pub fn send_data(socket: &UdpSocket, data: &[u8]) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
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<TransferOption>,
) -> Result<(), Box<dyn Error>> {
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<u8> {
[
&[0x00, Opcode::Error as u8, 0x00, code as u8],
msg.as_bytes(),
&Opcode::Error.as_bytes()[..],
&code.as_bytes()[..],
&msg.as_bytes()[..],
&[0x00],
]
.concat()

View file

@ -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<Self, &'static str> {
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<Packet, Box<dyn Error>> {
@ -172,7 +188,7 @@ fn parse_rq(buf: &[u8], opcode: Opcode) -> Result<Packet, Box<dyn Error>> {
fn parse_data(buf: &[u8]) -> Result<Packet, Box<dyn Error>> {
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<Packet, Box<dyn Error>> {
#[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")
}
}
}