use const_table::const_table;
use std::error::Error;
use std::fmt;
use crate::utils::*;
#[derive(Clone, Copy, Debug)]
pub(crate) enum MessageError {
Empty,
WrongSource,
NoCommand,
}
impl fmt::Display for MessageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MessageError::Empty => write!(f, "Message is empty"),
MessageError::WrongSource => write!(f, "Wrong source syntax"),
MessageError::NoCommand => write!(f, "No command"),
}
}
}
impl Error for MessageError {}
#[derive(PartialEq, Eq, Debug)]
pub(crate) struct Message<'a> {
source: Option<&'a str>,
command: &'a str,
params: Vec<&'a str>,
}
impl<'a> Message<'a> {
pub(crate) fn from_shared_str(input: &'a str) -> Result<Self, MessageError> {
let trimmed = input.trim_start();
if !trimmed.is_empty() {
let start_pos = if trimmed.bytes().next() == Some(b':') {
1
} else {
0
};
let (rest, last_param) = if let Some((rest, lp)) = trimmed[start_pos..].split_once(':')
{
(&trimmed[0..rest.len() + start_pos], Some(lp))
} else {
(trimmed, None)
};
let mut rest_words = rest.split_ascii_whitespace();
let source = if rest.bytes().next() == Some(b':') {
let s = &rest_words.next().unwrap()[1..];
if !validate_source(s) {
return Err(MessageError::WrongSource);
}
Some(s) } else {
None
};
let command = if let Some(cmd) = rest_words.next() {
cmd
} else {
return Err(MessageError::NoCommand);
};
let mut params = rest_words.collect::<Vec<_>>();
if let Some(lp) = last_param {
params.push(lp); }
Ok(Message {
source,
command,
params,
})
} else {
Err(MessageError::Empty)
}
}
pub(crate) fn to_string_with_source(&self, source: &str) -> String {
let mut out = ":".to_string();
out += source;
out.push(' ');
out += self.command;
if !self.params.is_empty() {
self.params[..self.params.len() - 1].iter().for_each(|s| {
out.push(' ');
out += s;
});
let last = self.params[self.params.len() - 1];
if last.find(|c| c == ':' || c == ' ' || c == '\t').is_some() || last.is_empty() {
out += " :";
} else {
out.push(' ');
}
out += last;
}
out
}
}
#[allow(clippy::enum_variant_names)]
#[const_table]
pub(crate) enum CommandId {
CommandName {
pub(crate) name: &'static str,
},
CAPId = CommandName { name: "CAP" },
_AUTHENTICATEId = CommandName {
name: "AUTHENTICATE",
},
PASSId = CommandName { name: "PASS" },
NICKId = CommandName { name: "NICK" },
USERId = CommandName { name: "USER" },
PINGId = CommandName { name: "PING" },
PONGId = CommandName { name: "PONG" },
OPERId = CommandName { name: "OPER" },
_QUITId = CommandName { name: "QUIT" },
JOINId = CommandName { name: "JOIN" },
PARTId = CommandName { name: "PART" },
TOPICId = CommandName { name: "TOPIC" },
NAMESId = CommandName { name: "NAMES" },
LISTId = CommandName { name: "LIST" },
INVITEId = CommandName { name: "INVITE" },
KICKId = CommandName { name: "KICK" },
MOTDId = CommandName { name: "MOTD" },
VERSIONId = CommandName { name: "VERSION" },
ADMINId = CommandName { name: "ADMIN" },
CONNECTId = CommandName { name: "CONNECT" },
_LUSERSId = CommandName { name: "LUSERS" },
TIMEId = CommandName { name: "TIME" },
STATSId = CommandName { name: "STATS" },
LINKSId = CommandName { name: "LINKS" },
_HELPId = CommandName { name: "HELP" },
_INFOId = CommandName { name: "INFO" },
MODEId = CommandName { name: "MODE" },
PRIVMSGId = CommandName { name: "PRIVMSG" },
NOTICEId = CommandName { name: "NOTICE" },
WHOId = CommandName { name: "WHO" },
WHOISId = CommandName { name: "WHOIS" },
WHOWASId = CommandName { name: "WHOWAS" },
KILLId = CommandName { name: "KILL" },
_REHASHId = CommandName { name: "REHASH" },
_RESTARTId = CommandName { name: "RESTART" },
SQUITId = CommandName { name: "SQUIT" },
_AWAYId = CommandName { name: "AWAY" },
USERHOSTId = CommandName { name: "USERHOST" },
WALLOPSId = CommandName { name: "WALLOPS" },
ISONId = CommandName { name: "ISON" },
_DIEId = CommandName { name: "DIE" },
}
use CommandId::*;
#[derive(Clone, Debug)]
pub(crate) enum CommandError {
UnknownCommand(String),
UnknownSubcommand(CommandId, String),
NeedMoreParams(CommandId),
ParameterDoesntMatch(CommandId, usize),
WrongParameter(CommandId, usize),
UnknownMode(usize, char, String),
UnknownUModeFlag(usize),
InvalidModeParam {
target: String,
modechar: char,
param: String,
description: String,
},
}
use CommandError::*;
impl fmt::Display for CommandError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnknownCommand(s) => write!(f, "Unknown command '{}'", s),
UnknownSubcommand(cmd, scmd) => {
write!(f, "Unknown subcommand '{}' in command '{}'", scmd, cmd.name)
}
NeedMoreParams(s) => write!(f, "Command '{}' needs more parameters", s.name),
ParameterDoesntMatch(s, i) => {
write!(f, "Parameter {} doesn't match for command '{}'", i, s.name)
}
WrongParameter(s, i) => write!(f, "Wrong parameter {} in command '{}'", i, s.name),
UnknownMode(i, c, ch) => write!(f, "Unknown mode {} in parameter {} for {}", c, i, ch),
UnknownUModeFlag(i) => write!(f, "Unknown umode flag in parameter {}", i),
InvalidModeParam {
modechar,
param,
target,
description,
} => write!(
f,
"Invalid mode parameter: {} {} {} {}",
target, modechar, param, description
),
}
}
}
impl Error for CommandError {}
#[allow(clippy::upper_case_acronyms)]
#[derive(PartialEq, Eq, Debug)]
pub(crate) enum CapCommand {
LS,
LIST,
REQ,
END,
}
#[allow(clippy::upper_case_acronyms)]
#[derive(PartialEq, Eq, Debug)]
pub(crate) enum Command<'a> {
CAP {
subcommand: CapCommand,
caps: Option<Vec<&'a str>>,
version: Option<u32>,
},
AUTHENTICATE {},
PASS {
password: &'a str,
},
NICK {
nickname: &'a str,
},
USER {
username: &'a str,
hostname: &'a str,
servername: &'a str,
realname: &'a str,
},
PING {
token: &'a str,
},
PONG {
token: &'a str,
},
OPER {
name: &'a str,
password: &'a str,
},
QUIT {},
JOIN {
channels: Vec<&'a str>,
keys: Option<Vec<&'a str>>,
},
PART {
channels: Vec<&'a str>,
reason: Option<&'a str>,
},
TOPIC {
channel: &'a str,
topic: Option<&'a str>,
},
NAMES {
channels: Vec<&'a str>,
},
LIST {
channels: Vec<&'a str>,
server: Option<&'a str>,
},
INVITE {
nickname: &'a str,
channel: &'a str,
},
KICK {
channel: &'a str,
users: Vec<&'a str>,
comment: Option<&'a str>,
},
MOTD {
target: Option<&'a str>,
},
VERSION {
target: Option<&'a str>,
},
ADMIN {
target: Option<&'a str>,
},
CONNECT {
target_server: &'a str,
port: Option<u16>,
remote_server: Option<&'a str>,
},
LUSERS {},
TIME {
server: Option<&'a str>,
},
STATS {
query: char,
server: Option<&'a str>,
},
LINKS {
remote_server: Option<&'a str>,
server_mask: Option<&'a str>,
},
HELP {
subject: Option<&'a str>,
},
INFO {},
MODE {
target: &'a str,
modes: Vec<(&'a str, Vec<&'a str>)>,
},
PRIVMSG {
targets: Vec<&'a str>,
text: &'a str,
},
NOTICE {
targets: Vec<&'a str>,
text: &'a str,
},
WHO {
mask: &'a str,
},
WHOIS {
target: Option<&'a str>,
nickmasks: Vec<&'a str>,
},
WHOWAS {
nickname: &'a str,
count: Option<usize>,
server: Option<&'a str>,
},
KILL {
nickname: &'a str,
comment: &'a str,
},
REHASH {},
RESTART {},
SQUIT {
server: &'a str,
comment: &'a str,
},
AWAY {
text: Option<&'a str>,
},
USERHOST {
nicknames: Vec<&'a str>,
},
WALLOPS {
text: &'a str,
},
ISON {
nicknames: Vec<&'a str>,
},
DIE {
message: Option<&'a str>,
},
}
use Command::*;
pub(crate) const NUM_COMMANDS: usize = 41;
impl<'a> Command<'a> {
pub(crate) fn index(&self) -> usize {
match self {
CAP { .. } => 0,
AUTHENTICATE { .. } => 1,
PASS { .. } => 2,
NICK { .. } => 3,
USER { .. } => 4,
PING { .. } => 5,
PONG { .. } => 6,
OPER { .. } => 7,
QUIT { .. } => 8,
JOIN { .. } => 9,
PART { .. } => 10,
TOPIC { .. } => 11,
NAMES { .. } => 12,
LIST { .. } => 13,
INVITE { .. } => 14,
KICK { .. } => 15,
MOTD { .. } => 16,
VERSION { .. } => 17,
ADMIN { .. } => 18,
CONNECT { .. } => 19,
LUSERS { .. } => 20,
TIME { .. } => 21,
STATS { .. } => 22,
LINKS { .. } => 23,
HELP { .. } => 24,
INFO { .. } => 25,
MODE { .. } => 26,
PRIVMSG { .. } => 27,
NOTICE { .. } => 28,
WHO { .. } => 29,
WHOIS { .. } => 30,
WHOWAS { .. } => 31,
KILL { .. } => 32,
REHASH { .. } => 33,
RESTART { .. } => 34,
SQUIT { .. } => 35,
AWAY { .. } => 36,
USERHOST { .. } => 37,
WALLOPS { .. } => 38,
ISON { .. } => 39,
DIE { .. } => 40,
}
}
fn parse_from_message(message: &Message<'a>) -> Result<Self, CommandError> {
match message.command.to_ascii_uppercase().as_str() {
"CAP" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let subcommand = match param_it.next().unwrap().to_ascii_uppercase().as_str() {
"LS" => CapCommand::LS,
"LIST" => CapCommand::LIST,
"REQ" => CapCommand::REQ,
"END" => CapCommand::END,
_ => return Err(UnknownSubcommand(CAPId, message.params[0].to_string())),
};
let (caps, version) = if subcommand == CapCommand::REQ {
(
param_it
.next()
.map(|x| x.split_ascii_whitespace().collect::<Vec<_>>()),
None,
)
} else if subcommand == CapCommand::LS {
let v = if let Some(s) = param_it.next() {
if let Ok(value) = s.parse() {
Some(value)
} else {
return Err(WrongParameter(CAPId, 1));
}
} else {
None
};
(None, v)
} else {
(None, None)
};
Ok(CAP {
subcommand,
caps,
version,
})
} else {
Err(NeedMoreParams(CAPId))
}
}
"AUTHENTICATE" => Ok(AUTHENTICATE {}),
"PASS" => {
if !message.params.is_empty() {
Ok(PASS {
password: message.params[0],
})
} else {
Err(NeedMoreParams(PASSId))
}
}
"NICK" => {
if !message.params.is_empty() {
Ok(NICK {
nickname: message.params[0],
})
} else {
Err(NeedMoreParams(NICKId))
}
}
"USER" => {
if message.params.len() >= 4 {
Ok(USER {
username: message.params[0],
hostname: message.params[1],
servername: message.params[2],
realname: message.params[3],
})
} else {
Err(NeedMoreParams(USERId))
}
}
"PING" => {
if !message.params.is_empty() {
Ok(PING {
token: message.params[0],
})
} else {
Err(NeedMoreParams(PINGId))
}
}
"PONG" => {
if !message.params.is_empty() {
Ok(PONG {
token: message.params[0],
})
} else {
Err(NeedMoreParams(PONGId))
}
}
"OPER" => {
if message.params.len() >= 2 {
Ok(OPER {
name: message.params[0],
password: message.params[1],
})
} else {
Err(NeedMoreParams(OPERId))
}
}
"QUIT" => Ok(QUIT {}),
"JOIN" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let channels = param_it.next().unwrap().split(',').collect::<Vec<_>>();
let keys_opt = param_it.next().map(|x| x.split(',').collect::<Vec<_>>());
if let Some(ref keys) = keys_opt {
if keys.len() != channels.len() {
return Err(ParameterDoesntMatch(JOINId, 1));
}
}
Ok(JOIN {
channels,
keys: keys_opt,
})
} else {
Err(NeedMoreParams(JOINId))
}
}
"PART" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let channels = param_it.next().unwrap().split(',').collect::<Vec<_>>();
let reason = param_it.next().copied();
Ok(PART { channels, reason })
} else {
Err(NeedMoreParams(PARTId))
}
}
"TOPIC" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let channel = param_it.next().unwrap();
let topic = param_it.next().copied();
Ok(TOPIC { channel, topic })
} else {
Err(NeedMoreParams(TOPICId))
}
}
"NAMES" => {
if !message.params.is_empty() {
Ok(NAMES {
channels: message.params[0].split(',').collect::<Vec<_>>(),
})
} else {
Ok(NAMES { channels: vec![] })
}
}
"LIST" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let channels = param_it.next().unwrap().split(',').collect::<Vec<_>>();
let server = param_it.next().copied();
Ok(LIST { channels, server })
} else {
Ok(LIST {
channels: vec![],
server: None,
})
}
}
"INVITE" => {
if message.params.len() >= 2 {
Ok(INVITE {
nickname: message.params[0],
channel: message.params[1],
})
} else {
Err(NeedMoreParams(INVITEId))
}
}
"KICK" => {
if message.params.len() >= 2 {
let mut param_it = message.params.iter();
let channel = param_it.next().unwrap();
let users = param_it.next().unwrap().split(',').collect::<Vec<_>>();
let comment = param_it.next().copied();
Ok(KICK {
channel,
users,
comment,
})
} else {
Err(NeedMoreParams(KICKId))
}
}
"MOTD" => Ok(MOTD {
target: message.params.get(0).copied(),
}),
"VERSION" => Ok(VERSION {
target: message.params.get(0).copied(),
}),
"ADMIN" => Ok(ADMIN {
target: message.params.get(0).copied(),
}),
"CONNECT" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let target_server = param_it.next().unwrap();
let port = param_it.next().map(|x| x.parse()).transpose();
let remote_server = param_it.next().copied();
match port {
Err(_) => Err(WrongParameter(CONNECTId, 1)),
Ok(p) => Ok(CONNECT {
target_server,
port: p,
remote_server,
}),
}
} else {
Err(NeedMoreParams(CONNECTId))
}
}
"LUSERS" => Ok(LUSERS {}),
"TIME" => Ok(TIME {
server: message.params.get(0).copied(),
}),
"STATS" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let query_str = param_it.next().unwrap();
let server = param_it.next().copied();
if query_str.len() == 1 {
Ok(STATS {
query: query_str.chars().next().unwrap(),
server,
})
} else {
Err(WrongParameter(STATSId, 0))
}
} else {
Err(NeedMoreParams(STATSId))
}
}
"LINKS" => {
if message.params.len() == 2 {
Ok(LINKS {
remote_server: Some(message.params[0]),
server_mask: Some(message.params[1]),
})
} else if message.params.len() == 1 {
Ok(LINKS {
remote_server: None,
server_mask: Some(message.params[0]),
})
} else {
Ok(LINKS {
remote_server: None,
server_mask: None,
})
}
}
"HELP" => {
if !message.params.is_empty() {
Ok(HELP {
subject: Some(message.params[0]),
})
} else {
Ok(HELP { subject: None })
}
}
"INFO" => Ok(INFO {}),
"MODE" => {
if !message.params.is_empty() {
let mut modes = vec![];
let mut param_it = message.params.iter();
let target = param_it.next().unwrap();
if let Some(s) = param_it.next() {
if s.starts_with('+') || s.starts_with('-') {
let mut modestring = *s;
let mut mode_args = vec![];
for s in param_it {
if s.starts_with('+') || s.starts_with('-') {
modes.push((modestring, mode_args));
modestring = *s;
mode_args = vec![];
} else {
mode_args.push(*s);
}
}
modes.push((modestring, mode_args));
} else {
return Err(WrongParameter(MODEId, 1));
}
}
Ok(MODE { target, modes })
} else {
Err(NeedMoreParams(MODEId))
}
}
"PRIVMSG" => {
if message.params.len() >= 2 {
Ok(PRIVMSG {
targets: message.params[0].split(',').collect::<Vec<_>>(),
text: message.params[1],
})
} else {
Err(NeedMoreParams(PRIVMSGId))
}
}
"NOTICE" => {
if message.params.len() >= 2 {
Ok(NOTICE {
targets: message.params[0].split(',').collect::<Vec<_>>(),
text: message.params[1],
})
} else {
Err(NeedMoreParams(NOTICEId))
}
}
"WHO" => {
if !message.params.is_empty() {
Ok(WHO {
mask: message.params[0],
})
} else {
Err(NeedMoreParams(WHOId))
}
}
"WHOIS" => {
if !message.params.is_empty() {
if message.params.len() >= 2 {
Ok(WHOIS {
target: Some(message.params[0]),
nickmasks: message.params[1].split(',').collect::<Vec<_>>(),
})
} else {
Ok(WHOIS {
target: None,
nickmasks: message.params[0].split(',').collect::<Vec<_>>(),
})
}
} else {
Err(NeedMoreParams(WHOISId))
}
}
"WHOWAS" => {
if !message.params.is_empty() {
let mut param_it = message.params.iter();
let nickname = param_it.next().unwrap();
let count = param_it.next().map(|x| x.parse()).transpose();
let server = param_it.next().copied();
match count {
Err(_) => Err(WrongParameter(WHOWASId, 1)),
Ok(c) => Ok(WHOWAS {
nickname,
count: c,
server,
}),
}
} else {
Err(NeedMoreParams(WHOWASId))
}
}
"KILL" => {
if message.params.len() >= 2 {
Ok(KILL {
nickname: message.params[0],
comment: message.params[1],
})
} else {
Err(NeedMoreParams(KILLId))
}
}
"REHASH" => Ok(REHASH {}),
"RESTART" => Ok(RESTART {}),
"SQUIT" => {
if message.params.len() >= 2 {
Ok(SQUIT {
server: message.params[0],
comment: message.params[1],
})
} else {
Err(NeedMoreParams(SQUITId))
}
}
"AWAY" => Ok(AWAY {
text: message.params.get(0).copied(),
}),
"USERHOST" => {
if !message.params.is_empty() {
Ok(USERHOST {
nicknames: message.params.clone(),
})
} else {
Err(NeedMoreParams(USERHOSTId))
}
}
"WALLOPS" => {
if !message.params.is_empty() {
Ok(WALLOPS {
text: message.params[0],
})
} else {
Err(NeedMoreParams(WALLOPSId))
}
}
"ISON" => {
if !message.params.is_empty() {
Ok(ISON {
nicknames: message.params.clone(),
})
} else {
Err(NeedMoreParams(ISONId))
}
}
"DIE" => {
if !message.params.is_empty() {
Ok(DIE {
message: Some(message.params[0]),
})
} else {
Ok(DIE { message: None })
}
}
s => Err(UnknownCommand(s.to_string())),
}
}
pub(crate) fn from_message(message: &Message<'a>) -> Result<Self, CommandError> {
match Self::parse_from_message(message) {
Ok(x) => {
match x.validate() {
Ok(()) => Ok(x),
Err(e) => Err(e),
}
}
Err(e) => Err(e),
}
}
fn validate(&self) -> Result<(), CommandError> {
match self {
CAP { version, .. } => {
if let Some(v) = version {
if *v < 302 {
Err(WrongParameter(CAPId, 1))
} else {
Ok(())
}
} else {
Ok(())
}
}
NICK { nickname } => validate_username(nickname).map_err(|_| WrongParameter(NICKId, 0)),
USER { username, .. } => {
validate_username(username).map_err(|_| WrongParameter(USERId, 0))
}
OPER { name, .. } => validate_username(name).map_err(|_| WrongParameter(OPERId, 0)),
JOIN { channels, .. } => channels
.iter()
.try_for_each(|ch| validate_channel(ch))
.map_err(|_| WrongParameter(JOINId, 0)),
PART { channels, .. } => channels
.iter()
.try_for_each(|ch| validate_channel(ch))
.map_err(|_| WrongParameter(PARTId, 0)),
TOPIC { channel, .. } => {
validate_channel(channel).map_err(|_| WrongParameter(TOPICId, 0))
}
NAMES { channels } => channels
.iter()
.try_for_each(|ch| validate_channel(ch))
.map_err(|_| WrongParameter(NAMESId, 0)),
LIST { channels, server } => {
channels
.iter()
.try_for_each(|ch| validate_channel(ch))
.map_err(|_| WrongParameter(LISTId, 0))?;
if let Some(srv) = server {
validate_server(srv, WrongParameter(LISTId, 1))?;
}
Ok(())
}
INVITE { nickname, channel } => {
validate_username(nickname).map_err(|_| WrongParameter(INVITEId, 0))?;
validate_channel(channel).map_err(|_| WrongParameter(INVITEId, 1))
}
KICK { channel, users, .. } => {
validate_channel(channel).map_err(|_| WrongParameter(KICKId, 0))?;
users
.iter()
.try_for_each(|u| validate_username(u))
.map_err(|_| WrongParameter(KICKId, 1))
}
MOTD { target } => {
if let Some(t) = target {
validate_server_mask(t, WrongParameter(MOTDId, 0))?;
}
Ok(())
}
VERSION { target } => {
if let Some(t) = target {
validate_server_mask(t, WrongParameter(VERSIONId, 0))?;
}
Ok(())
}
ADMIN { target } => {
if let Some(t) = target {
validate_server_mask(t, WrongParameter(ADMINId, 0))?;
}
Ok(())
}
CONNECT {
target_server,
remote_server,
..
} => {
validate_server(target_server, WrongParameter(CONNECTId, 0))?;
if let Some(s) = remote_server {
validate_server(s, WrongParameter(CONNECTId, 1))?;
}
Ok(())
}
TIME { server } => {
if let Some(s) = server {
validate_server(s, WrongParameter(TIMEId, 0))?;
}
Ok(())
}
STATS { query, server } => {
match query {
'c' | 'h' | 'i' | 'k' | 'l' | 'm' | 'o' | 'u' | 'y' => {
if let Some(s) = server {
validate_server(s, WrongParameter(STATSId, 1))?;
}
}
_ => return Err(WrongParameter(STATSId, 0)),
};
Ok(())
}
LINKS {
remote_server,
server_mask,
} => {
if let Some(s) = remote_server {
validate_server(s, WrongParameter(LINKSId, 0))?;
if let Some(sm) = server_mask {
validate_server_mask(sm, WrongParameter(LINKSId, 1))?;
}
} else if let Some(sm) = server_mask {
validate_server_mask(sm, WrongParameter(LINKSId, 0))?;
}
Ok(())
}
MODE { target, modes } => {
if validate_channel(target).is_ok() {
validate_channelmodes(target, modes)
} else if validate_username(target).is_ok() {
validate_usermodes(modes)
} else {
Err(WrongParameter(MODEId, 0))
}
}
PRIVMSG { targets, .. } => {
targets.iter().try_for_each(|n| {
validate_username(n)
.map_err(|_| WrongParameter(PRIVMSGId, 0))
.or_else(|_| validate_prefixed_channel(n, WrongParameter(PRIVMSGId, 0)))
})
}
NOTICE { targets, .. } => {
targets.iter().try_for_each(|n| {
validate_username(n)
.map_err(|_| WrongParameter(NOTICEId, 0))
.or_else(|_| validate_prefixed_channel(n, WrongParameter(NOTICEId, 0)))
})
}
WHOIS { target, nickmasks } => {
let next_param_idx = if let Some(t) = target {
validate_server(t, WrongParameter(WHOISId, 0))?;
1
} else {
0
};
nickmasks
.iter()
.try_for_each(|n| validate_username(n))
.map_err(|_| WrongParameter(WHOISId, next_param_idx))
}
WHOWAS {
nickname, server, ..
} => {
validate_username(nickname).map_err(|_| WrongParameter(WHOWASId, 0))?;
if let Some(s) = server {
validate_server(s, WrongParameter(WHOWASId, 2))?;
}
Ok(())
}
KILL { nickname, .. } => {
validate_username(nickname).map_err(|_| WrongParameter(KILLId, 0))
}
SQUIT { server, .. } => {
validate_server(server, WrongParameter(SQUITId, 0))?;
Ok(())
}
USERHOST { nicknames } => nicknames.iter().enumerate().try_for_each(|(i, n)| {
validate_username(n).map_err(|_| WrongParameter(USERHOSTId, i))
}),
_ => Ok(()),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_message_from_shared_str() {
assert_eq!(
Ok(Message {
source: None,
command: "QUIT",
params: vec![]
}),
Message::from_shared_str("QUIT").map_err(|e| e.to_string())
);
assert_eq!(
Ok(Message {
source: None,
command: "QUIT",
params: vec![]
}),
Message::from_shared_str(" QUIT").map_err(|e| e.to_string())
);
assert_eq!(
Ok(Message {
source: Some("source"),
command: "QUIT",
params: vec![]
}),
Message::from_shared_str(":source QUIT").map_err(|e| e.to_string())
);
assert_eq!(
Ok(Message {
source: None,
command: "USER",
params: vec!["guest", "0", "*", "Ronnie Reagan"]
}),
Message::from_shared_str("USER guest 0 * :Ronnie Reagan").map_err(|e| e.to_string())
);
assert_eq!(
Ok(Message {
source: None,
command: "USER",
params: vec!["guest", "0", "*", "Benny"]
}),
Message::from_shared_str("USER guest 0 * Benny").map_err(|e| e.to_string())
);
assert_eq!(
Ok(Message {
source: None,
command: "PRIVMSG",
params: vec!["bobby", ":-). Hello guy!"]
}),
Message::from_shared_str("PRIVMSG bobby ::-). Hello guy!").map_err(|e| e.to_string())
);
assert_eq!(
Ok(Message {
source: Some("mati!mat@gg.com"),
command: "QUIT",
params: vec![]
}),
Message::from_shared_str(":mati!mat@gg.com QUIT").map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong source syntax".to_string()),
Message::from_shared_str(":mati@mat!gg.com QUIT").map_err(|e| e.to_string())
);
}
#[test]
fn test_command_from_message() {
assert_eq!(
Ok(CAP {
subcommand: CapCommand::LS,
caps: None,
version: None
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LS"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CAP {
subcommand: CapCommand::LS,
caps: None,
version: Some(302)
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LS", "302"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CAP {
subcommand: CapCommand::LS,
caps: None,
version: Some(303)
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LS", "303"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'CAP'".to_string()),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LS", "301"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'CAP'".to_string()),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LS", "xxx"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CAP {
subcommand: CapCommand::LIST,
caps: None,
version: None
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LIST"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CAP {
subcommand: CapCommand::REQ,
version: None,
caps: Some(vec!["multi-prefix", "tls"])
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["REQ", "multi-prefix tls"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CAP {
subcommand: CapCommand::END,
caps: None,
version: None
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["END"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CAP {
subcommand: CapCommand::REQ,
version: None,
caps: Some(vec!["multi-prefix", "tlsx"])
}),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["REQ", "multi-prefix tlsx"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Unknown subcommand 'LSS' in command 'CAP'".to_string()),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec!["LSS"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'CAP' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "CAP",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(AUTHENTICATE {}),
Command::from_message(&Message {
source: None,
command: "AUTHENTICATE",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PASS { password: "secret" }),
Command::from_message(&Message {
source: None,
command: "PASS",
params: vec!["secret"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'PASS' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "PASS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(NICK { nickname: "lucky" }),
Command::from_message(&Message {
source: None,
command: "NICK",
params: vec!["lucky"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'NICK'".to_string()),
Command::from_message(&Message {
source: None,
command: "NICK",
params: vec!["luc.ky"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'NICK'".to_string()),
Command::from_message(&Message {
source: None,
command: "NICK",
params: vec!["luc,ky"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'NICK'".to_string()),
Command::from_message(&Message {
source: None,
command: "NICK",
params: vec!["luc:ky"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'NICK' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "NICK",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(USER {
username: "chris",
hostname: "0",
servername: "*",
realname: "Chris Wood"
}),
Command::from_message(&Message {
source: None,
command: "USER",
params: vec!["chris", "0", "*", "Chris Wood"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'USER'".to_string()),
Command::from_message(&Message {
source: None,
command: "USER",
params: vec!["chr:is", "0", "*", "Chris Wood"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'USER' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "USER",
params: vec!["chris", "0", "*"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PING { token: "xxxaaa" }),
Command::from_message(&Message {
source: None,
command: "PING",
params: vec!["xxxaaa"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'PING' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "PING",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(OPER {
name: "guru",
password: "mythebestday"
}),
Command::from_message(&Message {
source: None,
command: "OPER",
params: vec!["guru", "mythebestday"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'OPER'".to_string()),
Command::from_message(&Message {
source: None,
command: "OPER",
params: vec!["gu:ru", "mythebestday"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'OPER' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "OPER",
params: vec!["guru"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(QUIT {}),
Command::from_message(&Message {
source: None,
command: "QUIT",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(JOIN {
channels: vec!["#cats", "&fruits", "#software"],
keys: None
}),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,&fruits,#software"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(JOIN {
channels: vec!["#cats", "&fruits", "#software"],
keys: Some(vec!["mycat", "apple", "wesnoth"])
}),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,&fruits,#software", "mycat,apple,wesnoth"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'JOIN'".to_string()),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,&fru:its,#software"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'JOIN'".to_string()),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,fruits,#software"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(JOIN {
channels: vec!["#cats", "&fru.its", "#software"],
keys: None
}),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,&fru.its,#software"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Parameter 1 doesn't match for command 'JOIN'".to_string()),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,&fruits,#software,#countries", "mycat,apple,wesnoth"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Parameter 1 doesn't match for command 'JOIN'".to_string()),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec!["#cats,&fruits,#software", "mycat,apple,wesnoth,zizi"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'JOIN' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "JOIN",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PART {
channels: vec!["#dogs", "&juices", "#hardware"],
reason: None
}),
Command::from_message(&Message {
source: None,
command: "PART",
params: vec!["#dogs,&juices,#hardware"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PART {
channels: vec!["#dogs", "&juices", "#hardware"],
reason: Some("I don't like these channels")
}),
Command::from_message(&Message {
source: None,
command: "PART",
params: vec!["#dogs,&juices,#hardware", "I don't like these channels"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'PART'".to_string()),
Command::from_message(&Message {
source: None,
command: "PART",
params: vec!["#dogs,&juices,#har:dware", "I don't like these channels"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'PART' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "PART",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(TOPIC {
channel: "#gizmo",
topic: None
}),
Command::from_message(&Message {
source: None,
command: "TOPIC",
params: vec!["#gizmo"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(TOPIC {
channel: "#gizmo",
topic: Some("Some creatures")
}),
Command::from_message(&Message {
source: None,
command: "TOPIC",
params: vec!["#gizmo", "Some creatures"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'TOPIC'".to_string()),
Command::from_message(&Message {
source: None,
command: "TOPIC",
params: vec!["#giz:mo"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'TOPIC' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "TOPIC",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(NAMES {
channels: vec!["#dogs", "&juices", "#hardware"]
}),
Command::from_message(&Message {
source: None,
command: "NAMES",
params: vec!["#dogs,&juices,#hardware"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(NAMES { channels: vec![] }),
Command::from_message(&Message {
source: None,
command: "NAMES",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'NAMES'".to_string()),
Command::from_message(&Message {
source: None,
command: "NAMES",
params: vec!["#dogs,&juices,#hard:ware"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LIST {
channels: vec!["#dogs", "&juices", "#hardware"],
server: None
}),
Command::from_message(&Message {
source: None,
command: "LIST",
params: vec!["#dogs,&juices,#hardware"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LIST {
channels: vec!["#dogs", "&juices", "#hardware"],
server: Some("funny.checkbox.org")
}),
Command::from_message(&Message {
source: None,
command: "LIST",
params: vec!["#dogs,&juices,#hardware", "funny.checkbox.org"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LIST {
channels: vec![],
server: None
}),
Command::from_message(&Message {
source: None,
command: "LIST",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'LIST'".to_string()),
Command::from_message(&Message {
source: None,
command: "LIST",
params: vec!["#dogs,&juices,#har:dware", "funny.checkbox.org"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'LIST'".to_string()),
Command::from_message(&Message {
source: None,
command: "LIST",
params: vec!["#dogs,&juices,#hardware", "fnny"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(INVITE {
nickname: "greg",
channel: "#plants"
}),
Command::from_message(&Message {
source: None,
command: "INVITE",
params: vec!["greg", "#plants"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'INVITE'".to_string()),
Command::from_message(&Message {
source: None,
command: "INVITE",
params: vec!["gr:eg", "#plants"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'INVITE'".to_string()),
Command::from_message(&Message {
source: None,
command: "INVITE",
params: vec!["greg", "_plants"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'INVITE' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "INVITE",
params: vec!["greg"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(KICK {
channel: "#toolkits",
users: vec!["mickey"],
comment: None
}),
Command::from_message(&Message {
source: None,
command: "KICK",
params: vec!["#toolkits", "mickey"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(KICK {
channel: "#toolkits",
users: vec!["mickey", "lola"],
comment: None
}),
Command::from_message(&Message {
source: None,
command: "KICK",
params: vec!["#toolkits", "mickey,lola"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(KICK {
channel: "#toolkits",
users: vec!["mickey"],
comment: Some("Mickey is not polite")
}),
Command::from_message(&Message {
source: None,
command: "KICK",
params: vec!["#toolkits", "mickey", "Mickey is not polite"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'KICK'".to_string()),
Command::from_message(&Message {
source: None,
command: "KICK",
params: vec!["@toolkits", "mickey"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'KICK'".to_string()),
Command::from_message(&Message {
source: None,
command: "KICK",
params: vec!["#toolkits", "mic:key"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'KICK' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "KICK",
params: vec!["#toolkits"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MOTD { target: None }),
Command::from_message(&Message {
source: None,
command: "MOTD",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MOTD {
target: Some("bubu.com")
}),
Command::from_message(&Message {
source: None,
command: "MOTD",
params: vec!["bubu.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MOTD {
target: Some("*com")
}),
Command::from_message(&Message {
source: None,
command: "MOTD",
params: vec!["*com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'MOTD'".to_string()),
Command::from_message(&Message {
source: None,
command: "MOTD",
params: vec!["bubucom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(VERSION { target: None }),
Command::from_message(&Message {
source: None,
command: "VERSION",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(VERSION {
target: Some("bubu.com")
}),
Command::from_message(&Message {
source: None,
command: "VERSION",
params: vec!["bubu.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(VERSION {
target: Some("*com")
}),
Command::from_message(&Message {
source: None,
command: "VERSION",
params: vec!["*com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'VERSION'".to_string()),
Command::from_message(&Message {
source: None,
command: "VERSION",
params: vec!["bubucom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(ADMIN { target: None }),
Command::from_message(&Message {
source: None,
command: "ADMIN",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(ADMIN {
target: Some("bubu.com")
}),
Command::from_message(&Message {
source: None,
command: "ADMIN",
params: vec!["bubu.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(ADMIN {
target: Some("*com")
}),
Command::from_message(&Message {
source: None,
command: "ADMIN",
params: vec!["*com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'ADMIN'".to_string()),
Command::from_message(&Message {
source: None,
command: "ADMIN",
params: vec!["bubucom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CONNECT {
target_server: "chat.purple.com",
port: None,
remote_server: None
}),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec!["chat.purple.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CONNECT {
target_server: "chat.purple.com",
port: Some(6670),
remote_server: None
}),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec!["chat.purple.com", "6670"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(CONNECT {
target_server: "chat.purple.com",
port: Some(6670),
remote_server: Some("chat.broker.com")
}),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec!["chat.purple.com", "6670", "chat.broker.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'CONNECT'".to_string()),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec!["chatpurplecom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'CONNECT'".to_string()),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec!["chat.purple.com", "xxxaa"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'CONNECT'".to_string()),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec!["chat.purple.com", "6670", "chatbrokercom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'CONNECT' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "CONNECT",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LUSERS {}),
Command::from_message(&Message {
source: None,
command: "LUSERS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(TIME { server: None }),
Command::from_message(&Message {
source: None,
command: "TIME",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(TIME {
server: Some("bubu.com")
}),
Command::from_message(&Message {
source: None,
command: "TIME",
params: vec!["bubu.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'TIME'".to_string()),
Command::from_message(&Message {
source: None,
command: "TIME",
params: vec!["*com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'TIME'".to_string()),
Command::from_message(&Message {
source: None,
command: "TIME",
params: vec!["bubucom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(STATS {
query: 'c',
server: None
}),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec!["c"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(STATS {
query: 'l',
server: None
}),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec!["l"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(STATS {
query: 'o',
server: None
}),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec!["o"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(STATS {
query: 'o',
server: Some("chat.fruits.com")
}),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec!["o", "chat.fruits.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'STATS'".to_string()),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec!["z"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'STATS'".to_string()),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec!["o", "chatfruitscom"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'STATS' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "STATS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LINKS {
remote_server: None,
server_mask: Some("*.gigo.net")
}),
Command::from_message(&Message {
source: None,
command: "LINKS",
params: vec!["*.gigo.net"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LINKS {
remote_server: Some("first.proxy.net"),
server_mask: Some("*.gigo.net")
}),
Command::from_message(&Message {
source: None,
command: "LINKS",
params: vec!["first.proxy.net", "*.gigo.net"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'LINKS'".to_string()),
Command::from_message(&Message {
source: None,
command: "LINKS",
params: vec!["gigonet"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'LINKS'".to_string()),
Command::from_message(&Message {
source: None,
command: "LINKS",
params: vec!["first.proxy.net", "gigonet"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'LINKS'".to_string()),
Command::from_message(&Message {
source: None,
command: "LINKS",
params: vec!["firstproxynet", "*.gigo.net"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(LINKS {
remote_server: None,
server_mask: None
}),
Command::from_message(&Message {
source: None,
command: "LINKS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(HELP {
subject: Some("PING Message")
}),
Command::from_message(&Message {
source: None,
command: "HELP",
params: vec!["PING Message"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(HELP {
subject: Some("PONG Message")
}),
Command::from_message(&Message {
source: None,
command: "HELP",
params: vec!["PONG Message"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(HELP { subject: None }),
Command::from_message(&Message {
source: None,
command: "HELP",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(INFO {}),
Command::from_message(&Message {
source: None,
command: "INFO",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "andy",
modes: vec![]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["andy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#engines",
modes: vec![]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#engines"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "andy",
modes: vec![("+ow", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["andy", "+ow"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "andy",
modes: vec![("+oOr-iw", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["andy", "+oOr-iw"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "andy",
modes: vec![("+oOr", vec![]), ("-iw", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["andy", "+oOr", "-iw"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Unknown umode flag in parameter 1".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["teddy", "+otOr"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Unknown umode flag in parameter 1".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["teddy", "+otOr", "bbb"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+ntsm", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+ntsm"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+b", vec!["*@192.168.1.7"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+b", "*@192.168.1.7"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-b", vec!["*@192.168.1.7"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-b", "*@192.168.1.7"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![
("+b", vec!["*@192.168.1.7"]),
("+e", vec!["*@192.168.1.3"]),
("+I", vec!["*@192.168.1.9"])
]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec![
"#chasis",
"+b",
"*@192.168.1.7",
"+e",
"*@192.168.1.3",
"+I",
"*@192.168.1.9"
]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![
("-b", vec!["*@192.168.1.7"]),
("-e", vec!["*@192.168.1.3"]),
("-I", vec!["*@192.168.1.9"])
]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec![
"#chasis",
"-b",
"*@192.168.1.7",
"-e",
"*@192.168.1.3",
"-I",
"*@192.168.1.9"
]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![
("-mb", vec!["*@192.168.1.7"]),
("-ne", vec!["*@192.168.1.3"]),
("-tI", vec!["*@192.168.1.9"])
]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec![
"#chasis",
"-mb",
"*@192.168.1.7",
"-ne",
"*@192.168.1.3",
"-tI",
"*@192.168.1.9"
]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+b", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+b"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+l", vec!["123"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+l", "123"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-l", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-l"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+k", vec!["secret"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+k", "secret"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-k", vec![])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-k"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-bl+i", vec!["*@192.168.0.1"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-bl+i", "*@192.168.0.1"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+o", vec!["barry"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+o", "barry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-o", vec!["barry"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-o", "barry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+h", vec!["barry"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+h", "barry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-h", vec!["barry"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-h", "barry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("+v", vec!["barry"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+v", "barry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "#chasis",
modes: vec![("-v", vec!["barry"])]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-v", "barry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(MODE {
target: "andy",
modes: vec![]
}),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["andy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis l No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+l"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis k No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+k"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis o No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+o"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis o No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-o"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis h No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+h"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis h No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-h"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis v No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+v"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis v No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-v"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err(
"Invalid mode parameter: #chasis l xxx invalid digit found in \
string"
.to_string()
),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "+l", "xxx"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis l 145 \
Unexpected argument"
.to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-l", "145"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis k 145 \
Unexpected argument"
.to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-k", "145"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Invalid mode parameter: #chasis o No argument".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec!["#chasis", "-bl+oi", "*@192.168.0.1"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'MODE' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "MODE",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["bobby", "andy"],
text: "Hello, guys"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["bobby,andy", "Hello, guys"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["#graphics", "&musics"],
text: "Hello, guys"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["#graphics,&musics", "Hello, guys"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["#graphics", "&musics", "jimmy"],
text: "Hello, cruel world!"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["#graphics,&musics,jimmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["%#graphics", "~&musics", "jimmy"],
text: "Hello, cruel world!"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["%#graphics,~&musics,jimmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["@#graphics", "&&musics", "jimmy"],
text: "Hello, cruel world!"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["@#graphics,&&musics,jimmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["@+#graphics", "&&musics", "jimmy"],
text: "Hello, cruel world!"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["@+#graphics,&&musics,jimmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(PRIVMSG {
targets: vec!["+#graphics", "+&musics", "jimmy"],
text: "Hello, cruel world!"
}),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["+#graphics,+&musics,jimmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'PRIVMSG'".to_string()),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["#graphics,&musics,ji.mmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'PRIVMSG' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "PRIVMSG",
params: vec!["#graphics,&musics,jimmy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(NOTICE {
targets: vec!["bobby", "andy"],
text: "Hello, guys"
}),
Command::from_message(&Message {
source: None,
command: "NOTICE",
params: vec!["bobby,andy", "Hello, guys"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(NOTICE {
targets: vec!["#graphics", "&musics"],
text: "Hello, guys"
}),
Command::from_message(&Message {
source: None,
command: "NOTICE",
params: vec!["#graphics,&musics", "Hello, guys"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(NOTICE {
targets: vec!["#graphics", "&musics", "jimmy"],
text: "Hello, cruel world!"
}),
Command::from_message(&Message {
source: None,
command: "NOTICE",
params: vec!["#graphics,&musics,jimmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'NOTICE'".to_string()),
Command::from_message(&Message {
source: None,
command: "NOTICE",
params: vec!["#graphics,&musics,ji.mmy", "Hello, cruel world!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'NOTICE' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "NOTICE",
params: vec!["#graphics,&musics,jimmy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WHO { mask: "bla*bla" }),
Command::from_message(&Message {
source: None,
command: "WHO",
params: vec!["bla*bla"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'WHO' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "WHO",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WHOIS {
target: None,
nickmasks: vec!["alice", "eliz", "garry"]
}),
Command::from_message(&Message {
source: None,
command: "WHOIS",
params: vec!["alice,eliz,garry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WHOIS {
target: Some("coco.net"),
nickmasks: vec!["alice", "eliz", "garry"]
}),
Command::from_message(&Message {
source: None,
command: "WHOIS",
params: vec!["coco.net", "alice,eliz,garry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'WHOIS'".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOIS",
params: vec!["alice,el:iz,garry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'WHOIS'".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOIS",
params: vec!["coconet", "alice,eliz,garry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'WHOIS'".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOIS",
params: vec!["coco.net", "alice,eliz,ga:rry"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'WHOIS' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOIS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WHOWAS {
nickname: "mat",
count: None,
server: None
}),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec!["mat"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WHOWAS {
nickname: "mat",
count: Some(10),
server: None
}),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec!["mat", "10"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WHOWAS {
nickname: "mat",
count: Some(10),
server: Some("some.where.net")
}),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec!["mat", "10", "some.where.net"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'WHOWAS'".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec!["mat:"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'WHOWAS'".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec!["mat", "XX"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 2 in command 'WHOWAS'".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec!["mat", "10", "somewherenet"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'WHOWAS' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "WHOWAS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(KILL {
nickname: "bobby",
comment: "Killed!"
}),
Command::from_message(&Message {
source: None,
command: "KILL",
params: vec!["bobby", "Killed!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'KILL'".to_string()),
Command::from_message(&Message {
source: None,
command: "KILL",
params: vec!["bob:by", "Killed!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'KILL' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "KILL",
params: vec!["bobby"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(REHASH {}),
Command::from_message(&Message {
source: None,
command: "REHASH",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(RESTART {}),
Command::from_message(&Message {
source: None,
command: "RESTART",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(SQUIT {
server: "somewhere.dot.com",
comment: "Killed!"
}),
Command::from_message(&Message {
source: None,
command: "SQUIT",
params: vec!["somewhere.dot.com", "Killed!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'SQUIT'".to_string()),
Command::from_message(&Message {
source: None,
command: "SQUIT",
params: vec!["bobxxx", "Killed!"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'SQUIT' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "SQUIT",
params: vec!["somewhere.dot.com"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(AWAY { text: None }),
Command::from_message(&Message {
source: None,
command: "AWAY",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(AWAY {
text: Some("I will make rest")
}),
Command::from_message(&Message {
source: None,
command: "AWAY",
params: vec!["I will make rest"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(USERHOST {
nicknames: vec!["bobby"]
}),
Command::from_message(&Message {
source: None,
command: "USERHOST",
params: vec!["bobby"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(USERHOST {
nicknames: vec!["bobby", "jimmy"]
}),
Command::from_message(&Message {
source: None,
command: "USERHOST",
params: vec!["bobby", "jimmy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 0 in command 'USERHOST'".to_string()),
Command::from_message(&Message {
source: None,
command: "USERHOST",
params: vec!["bo:bby", "jimmy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 1 in command 'USERHOST'".to_string()),
Command::from_message(&Message {
source: None,
command: "USERHOST",
params: vec!["bobby", "ji:mmy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Wrong parameter 2 in command 'USERHOST'".to_string()),
Command::from_message(&Message {
source: None,
command: "USERHOST",
params: vec!["bobby", "damon", "ji:mmy"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'USERHOST' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "USERHOST",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(WALLOPS {
text: "This is some message"
}),
Command::from_message(&Message {
source: None,
command: "WALLOPS",
params: vec!["This is some message"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Err("Command 'WALLOPS' needs more parameters".to_string()),
Command::from_message(&Message {
source: None,
command: "WALLOPS",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(DIE {
message: Some("This is some message")
}),
Command::from_message(&Message {
source: None,
command: "DIE",
params: vec!["This is some message"]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(DIE { message: None }),
Command::from_message(&Message {
source: None,
command: "DIE",
params: vec![]
})
.map_err(|e| e.to_string())
);
assert_eq!(
Ok(RESTART {}),
Command::from_message(&Message {
source: None,
command: "reStaRt",
params: vec![]
})
.map_err(|e| e.to_string())
);
}
#[test]
fn test_message_to_string_with_source() {
assert_eq!(
":buru USER guest 0 * :Ronnie Reagan".to_string(),
Message {
source: None,
command: "USER",
params: vec!["guest", "0", "*", "Ronnie Reagan"]
}
.to_string_with_source("buru")
);
assert_eq!(
":buru USER guest 0 * :".to_string(),
Message {
source: None,
command: "USER",
params: vec!["guest", "0", "*", ""]
}
.to_string_with_source("buru")
);
assert_eq!(
":sonny INVITE mati1 #xxx".to_string(),
Message {
source: Some("xxxx"),
command: "INVITE",
params: vec!["mati1", "#xxx"]
}
.to_string_with_source("sonny")
);
}
}