Add packet tests
This commit is contained in:
parent
68d05e3a11
commit
c345a5b531
2 changed files with 236 additions and 7 deletions
|
|
@ -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()
|
||||
|
|
|
|||
232
src/packet.rs
232
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<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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue