rustfmt the codebase (#36)
This will ensure that we are properly formatting this library code according to rust standards
This commit is contained in:
parent
62cef4a773
commit
86e1d46507
8 changed files with 802 additions and 651 deletions
18
README.md
18
README.md
|
|
@ -22,7 +22,11 @@ use imap::client::Client;
|
|||
// See: https://support.google.com/accounts/answer/6010255?hl=en
|
||||
// Look at the gmail_oauth2.rs example on how to connect to a gmail server securely.
|
||||
fn main() {
|
||||
let mut imap_socket = Client::secure_connect(("imap.gmail.com", 993), "imap.gmail.com", SslConnectorBuilder::new(SslMethod::tls()).unwrap().build()).unwrap();
|
||||
let domain = "imap.gmail.com";
|
||||
let port = 993;
|
||||
let socket_addr = (domain, port);
|
||||
let ssl_connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
|
||||
let mut imap_socket = Client::secure_connect(socket_addr, domain, ssl_connector).unwrap();
|
||||
|
||||
imap_socket.login("username", "password").unwrap();
|
||||
|
||||
|
|
@ -31,15 +35,15 @@ fn main() {
|
|||
for capability in capabilities.iter() {
|
||||
println!("{}", capability);
|
||||
}
|
||||
},
|
||||
Err(e) => println!("Error parsing capability: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error parsing capability: {}", e),
|
||||
};
|
||||
|
||||
match imap_socket.select("INBOX") {
|
||||
Ok(mailbox) => {
|
||||
println!("{}", mailbox);
|
||||
},
|
||||
Err(e) => println!("Error selecting INBOX: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error selecting INBOX: {}", e),
|
||||
};
|
||||
|
||||
match imap_socket.fetch("2", "body[text]") {
|
||||
|
|
@ -47,8 +51,8 @@ fn main() {
|
|||
for line in lines.iter() {
|
||||
print!("{}", line);
|
||||
}
|
||||
},
|
||||
Err(e) => println!("Error Fetching email 2: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error Fetching email 2: {}", e),
|
||||
};
|
||||
|
||||
imap_socket.logout().unwrap();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ use imap::client::Client;
|
|||
// See: https://support.google.com/accounts/answer/6010255?hl=en
|
||||
// Look at the gmail_oauth2.rs example on how to connect to a gmail server securely.
|
||||
fn main() {
|
||||
let mut imap_socket = Client::secure_connect(("imap.gmail.com", 993), "imap.gmail.com", SslConnectorBuilder::new(SslMethod::tls()).unwrap().build()).unwrap();
|
||||
let domain = "imap.gmail.com";
|
||||
let port = 993;
|
||||
let socket_addr = (domain, port);
|
||||
let ssl_connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
|
||||
let mut imap_socket = Client::secure_connect(socket_addr, domain, ssl_connector).unwrap();
|
||||
|
||||
imap_socket.login("username", "password").unwrap();
|
||||
|
||||
|
|
@ -17,15 +21,15 @@ fn main() {
|
|||
for capability in capabilities.iter() {
|
||||
println!("{}", capability);
|
||||
}
|
||||
},
|
||||
Err(e) => println!("Error parsing capability: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error parsing capability: {}", e),
|
||||
};
|
||||
|
||||
match imap_socket.select("INBOX") {
|
||||
Ok(mailbox) => {
|
||||
println!("{}", mailbox);
|
||||
},
|
||||
Err(e) => println!("Error selecting INBOX: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error selecting INBOX: {}", e),
|
||||
};
|
||||
|
||||
match imap_socket.fetch("2", "body[text]") {
|
||||
|
|
@ -33,8 +37,8 @@ fn main() {
|
|||
for line in lines.iter() {
|
||||
print!("{}", line);
|
||||
}
|
||||
},
|
||||
Err(e) => println!("Error Fetching email 2: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error Fetching email 2: {}", e),
|
||||
};
|
||||
|
||||
imap_socket.logout().unwrap();
|
||||
|
|
|
|||
|
|
@ -3,34 +3,44 @@ extern crate openssl;
|
|||
extern crate base64;
|
||||
|
||||
use openssl::ssl::{SslConnectorBuilder, SslMethod};
|
||||
use base64::{encode};
|
||||
use base64::encode;
|
||||
use imap::client::Client;
|
||||
use imap::authenticator::Authenticator;
|
||||
|
||||
struct GmailOAuth2 {
|
||||
user: String,
|
||||
access_token: String
|
||||
access_token: String,
|
||||
}
|
||||
|
||||
impl Authenticator for GmailOAuth2 {
|
||||
#[allow(unused_variables)]
|
||||
fn process(&self, data: String) -> String {
|
||||
encode(format!("user={}\x01auth=Bearer {}\x01\x01", self.user, self.access_token).as_bytes())
|
||||
encode(
|
||||
format!(
|
||||
"user={}\x01auth=Bearer {}\x01\x01",
|
||||
self.user,
|
||||
self.access_token
|
||||
).as_bytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let gmail_auth = GmailOAuth2{
|
||||
let gmail_auth = GmailOAuth2 {
|
||||
user: String::from("sombody@gmail.com"),
|
||||
access_token: String::from("<access_token>")
|
||||
access_token: String::from("<access_token>"),
|
||||
};
|
||||
let mut imap_socket = Client::secure_connect(("imap.gmail.com", 993), "imap.gmail.com", SslConnectorBuilder::new(SslMethod::tls()).unwrap().build()).unwrap();
|
||||
let domain = "imap.gmail.com";
|
||||
let port = 993;
|
||||
let socket_addr = (domain, port);
|
||||
let ssl_connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
|
||||
let mut imap_socket = Client::secure_connect(socket_addr, domain, ssl_connector).unwrap();
|
||||
|
||||
imap_socket.authenticate("XOAUTH2", gmail_auth).unwrap();
|
||||
|
||||
match imap_socket.select("INBOX") {
|
||||
Ok(mailbox) => println!("{}", mailbox),
|
||||
Err(e) => println!("Error selecting INBOX: {}", e)
|
||||
Err(e) => println!("Error selecting INBOX: {}", e),
|
||||
};
|
||||
|
||||
match imap_socket.fetch("2", "body[text]") {
|
||||
|
|
@ -38,8 +48,8 @@ fn main() {
|
|||
for line in lines.iter() {
|
||||
print!("{}", line);
|
||||
}
|
||||
},
|
||||
Err(e) => println!("Error Fetching email 2: {}", e)
|
||||
}
|
||||
Err(e) => println!("Error Fetching email 2: {}", e),
|
||||
};
|
||||
|
||||
imap_socket.logout().unwrap();
|
||||
|
|
|
|||
292
src/client.rs
292
src/client.rs
|
|
@ -5,7 +5,8 @@ use std::time::Duration;
|
|||
|
||||
use super::mailbox::Mailbox;
|
||||
use super::authenticator::Authenticator;
|
||||
use super::parse::{parse_response_ok, parse_capability, parse_select_or_examine, parse_response, parse_authenticate_response};
|
||||
use super::parse::{parse_response_ok, parse_capability, parse_select_or_examine, parse_response,
|
||||
parse_authenticate_response};
|
||||
use super::error::{Error, Result};
|
||||
|
||||
static TAG_PREFIX: &'static str = "a";
|
||||
|
|
@ -17,7 +18,7 @@ const LF: u8 = 0x0a;
|
|||
pub struct Client<T> {
|
||||
stream: T,
|
||||
tag: u32,
|
||||
pub debug: bool
|
||||
pub debug: bool,
|
||||
}
|
||||
|
||||
/// `IdleHandle` allows a client to block waiting for changes to the remote mailbox.
|
||||
|
|
@ -122,8 +123,8 @@ impl<'a, T: SetReadTimeout + Read + Write + 'a> IdleHandle<'a, T> {
|
|||
// though it need only "poll" at half hour intervals.
|
||||
try!(self.client.stream.set_read_timeout(Some(self.keepalive)));
|
||||
match self.wait() {
|
||||
Err(Error::Io(ref e)) if e.kind() == io::ErrorKind::TimedOut ||
|
||||
e.kind() == io::ErrorKind::WouldBlock => {
|
||||
Err(Error::Io(ref e))
|
||||
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock => {
|
||||
// we need to refresh the IDLE connection
|
||||
try!(self.terminate());
|
||||
try!(self.init());
|
||||
|
|
@ -147,7 +148,8 @@ impl<'a, T: SetReadTimeout + Read + Write + 'a> IdleHandle<'a, T> {
|
|||
|
||||
impl<'a, T: Read + Write + 'a> Drop for IdleHandle<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.terminate().expect("IDLE connection did not terminate cleanly");
|
||||
self.terminate()
|
||||
.expect("IDLE connection did not terminate cleanly");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +161,9 @@ impl<'a> SetReadTimeout for TcpStream {
|
|||
|
||||
impl<'a> SetReadTimeout for SslStream<TcpStream> {
|
||||
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
||||
self.get_ref().set_read_timeout(timeout).map_err(|e| Error::Io(e))
|
||||
self.get_ref()
|
||||
.set_read_timeout(timeout)
|
||||
.map_err(|e| Error::Io(e))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,18 +176,22 @@ impl Client<TcpStream> {
|
|||
|
||||
try!(socket.read_greeting());
|
||||
Ok(socket)
|
||||
},
|
||||
Err(e) => Err(Error::Io(e))
|
||||
}
|
||||
Err(e) => Err(Error::Io(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// This will upgrade a regular TCP connection to use SSL.
|
||||
///
|
||||
/// Use the domain parameter for openssl's SNI and hostname verification.
|
||||
pub fn secure(mut self, domain: &str,ssl_connector: SslConnector) -> Result<Client<SslStream<TcpStream>>> {
|
||||
pub fn secure(
|
||||
mut self,
|
||||
domain: &str,
|
||||
ssl_connector: SslConnector,
|
||||
) -> Result<Client<SslStream<TcpStream>>> {
|
||||
// TODO This needs to be tested
|
||||
self.run_command_and_check_ok("STARTTLS")?;
|
||||
SslConnector::connect(&ssl_connector,domain, self.stream)
|
||||
SslConnector::connect(&ssl_connector, domain, self.stream)
|
||||
.map(Client::new)
|
||||
.map_err(Error::Ssl)
|
||||
}
|
||||
|
|
@ -191,37 +199,46 @@ impl Client<TcpStream> {
|
|||
|
||||
impl Client<SslStream<TcpStream>> {
|
||||
/// Creates a client with an SSL wrapper.
|
||||
pub fn secure_connect<A: ToSocketAddrs>(addr: A, domain: &str,ssl_connector: SslConnector) -> Result<Client<SslStream<TcpStream>>> {
|
||||
pub fn secure_connect<A: ToSocketAddrs>(
|
||||
addr: A,
|
||||
domain: &str,
|
||||
ssl_connector: SslConnector,
|
||||
) -> Result<Client<SslStream<TcpStream>>> {
|
||||
match TcpStream::connect(addr) {
|
||||
Ok(stream) => {
|
||||
let ssl_stream = match SslConnector::connect(&ssl_connector, domain,stream) {
|
||||
let ssl_stream = match SslConnector::connect(&ssl_connector, domain, stream) {
|
||||
Ok(s) => s,
|
||||
Err(e) => return Err(Error::Ssl(e))
|
||||
Err(e) => return Err(Error::Ssl(e)),
|
||||
};
|
||||
let mut socket = Client::new(ssl_stream);
|
||||
|
||||
try!(socket.read_greeting());
|
||||
Ok(socket)
|
||||
},
|
||||
Err(e) => Err(Error::Io(e))
|
||||
}
|
||||
Err(e) => Err(Error::Io(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read+Write> Client<T> {
|
||||
|
||||
impl<T: Read + Write> Client<T> {
|
||||
/// Creates a new client with the underlying stream.
|
||||
pub fn new(stream: T) -> Client<T> {
|
||||
Client{
|
||||
Client {
|
||||
stream: stream,
|
||||
tag: INITIAL_TAG,
|
||||
debug: false
|
||||
debug: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Authenticate will authenticate with the server, using the authenticator given.
|
||||
pub fn authenticate<A: Authenticator>(&mut self, auth_type: &str, authenticator: A) -> Result<()> {
|
||||
try!(self.run_command(&format!("AUTHENTICATE {}", auth_type).to_string()));
|
||||
pub fn authenticate<A: Authenticator>(
|
||||
&mut self,
|
||||
auth_type: &str,
|
||||
authenticator: A,
|
||||
) -> Result<()> {
|
||||
try!(self.run_command(
|
||||
&format!("AUTHENTICATE {}", auth_type).to_string()
|
||||
));
|
||||
self.do_auth_handshake(authenticator)
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +249,9 @@ impl<T: Read+Write> Client<T> {
|
|||
let line = try!(self.readline());
|
||||
|
||||
if line.starts_with(b"+") {
|
||||
let data = try!(parse_authenticate_response(String::from_utf8(line).unwrap()));
|
||||
let data = try!(parse_authenticate_response(
|
||||
String::from_utf8(line).unwrap()
|
||||
));
|
||||
let auth_response = authenticator.process(data);
|
||||
|
||||
try!(self.write_line(auth_response.into_bytes().as_slice()))
|
||||
|
|
@ -250,23 +269,23 @@ impl<T: Read+Write> Client<T> {
|
|||
}
|
||||
|
||||
/// Log in to the IMAP server.
|
||||
pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
|
||||
pub fn login(&mut self, username: &str, password: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
|
||||
}
|
||||
|
||||
/// Selects a mailbox
|
||||
pub fn select(&mut self, mailbox_name: &str) -> Result<Mailbox> {
|
||||
let lines = try!(
|
||||
self.run_command_and_read_response(&format!("SELECT {}", mailbox_name).to_string())
|
||||
);
|
||||
let lines = try!(self.run_command_and_read_response(
|
||||
&format!("SELECT {}", mailbox_name).to_string()
|
||||
));
|
||||
parse_select_or_examine(lines)
|
||||
}
|
||||
|
||||
/// Examine is identical to Select, but the selected mailbox is identified as read-only
|
||||
pub fn examine(&mut self, mailbox_name: &str) -> Result<Mailbox> {
|
||||
let lines = try!(
|
||||
self.run_command_and_read_response(&format!("EXAMINE {}", mailbox_name).to_string())
|
||||
);
|
||||
let lines = try!(self.run_command_and_read_response(
|
||||
&format!("EXAMINE {}", mailbox_name).to_string()
|
||||
));
|
||||
parse_select_or_examine(lines)
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +320,11 @@ impl<T: Read+Write> Client<T> {
|
|||
|
||||
/// Rename changes the name of a mailbox.
|
||||
pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
|
||||
self.run_command_and_check_ok(&format!(
|
||||
"RENAME {} {}",
|
||||
current_mailbox_name,
|
||||
new_mailbox_name
|
||||
).to_string())
|
||||
}
|
||||
|
||||
/// Subscribe adds the specified mailbox name to the server's set of "active" or "subscribed"
|
||||
|
|
@ -310,17 +333,17 @@ impl<T: Read+Write> Client<T> {
|
|||
self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
|
||||
}
|
||||
|
||||
/// Unsubscribe removes the specified mailbox name from the server's set of "active" or "subscribed"
|
||||
/// mailboxes as returned by the LSUB command.
|
||||
/// Unsubscribe removes the specified mailbox name from the server's set of
|
||||
/// "active" or "subscribed mailboxes as returned by the LSUB command.
|
||||
pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
|
||||
}
|
||||
|
||||
/// Capability requests a listing of capabilities that the server supports.
|
||||
pub fn capability(&mut self) -> Result<Vec<String>> {
|
||||
let lines = try!(
|
||||
self.run_command_and_read_response(&format!("CAPABILITY").to_string())
|
||||
);
|
||||
let lines = try!(self.run_command_and_read_response(
|
||||
&format!("CAPABILITY").to_string()
|
||||
));
|
||||
parse_capability(lines)
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +375,8 @@ impl<T: Read+Write> Client<T> {
|
|||
|
||||
/// Copy copies the specified message to the end of the specified destination mailbox.
|
||||
pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
|
||||
self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
|
||||
self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name)
|
||||
.to_string())
|
||||
}
|
||||
|
||||
pub fn uid_copy(&mut self, uid_set: &str, mailbox_name: &str) -> Result<()> {
|
||||
|
|
@ -361,14 +385,30 @@ impl<T: Read+Write> Client<T> {
|
|||
|
||||
/// The LIST command returns a subset of names from the complete set
|
||||
/// of all names available to the client.
|
||||
pub fn list(&mut self, reference_name: &str, mailbox_search_pattern: &str) -> Result<Vec<String>> {
|
||||
self.run_command_and_parse(&format!("LIST {} {}", reference_name, mailbox_search_pattern))
|
||||
pub fn list(
|
||||
&mut self,
|
||||
reference_name: &str,
|
||||
mailbox_search_pattern: &str,
|
||||
) -> Result<Vec<String>> {
|
||||
self.run_command_and_parse(&format!(
|
||||
"LIST {} {}",
|
||||
reference_name,
|
||||
mailbox_search_pattern
|
||||
))
|
||||
}
|
||||
|
||||
/// The LSUB command returns a subset of names from the set of names
|
||||
/// that the user has declared as being "active" or "subscribed".
|
||||
pub fn lsub(&mut self, reference_name: &str, mailbox_search_pattern: &str) -> Result<Vec<String>> {
|
||||
self.run_command_and_parse(&format!("LSUB {} {}", reference_name, mailbox_search_pattern))
|
||||
pub fn lsub(
|
||||
&mut self,
|
||||
reference_name: &str,
|
||||
mailbox_search_pattern: &str,
|
||||
) -> Result<Vec<String>> {
|
||||
self.run_command_and_parse(&format!(
|
||||
"LSUB {} {}",
|
||||
reference_name,
|
||||
mailbox_search_pattern
|
||||
))
|
||||
}
|
||||
|
||||
/// The STATUS command requests the status of the indicated mailbox.
|
||||
|
|
@ -384,7 +424,9 @@ impl<T: Read+Write> Client<T> {
|
|||
|
||||
/// The APPEND command adds a mail to a mailbox.
|
||||
pub fn append(&mut self, folder: &str, content: &[u8]) -> Result<Vec<String>> {
|
||||
try!(self.run_command(&format!("APPEND \"{}\" {{{}}}", folder, content.len())));
|
||||
try!(self.run_command(
|
||||
&format!("APPEND \"{}\" {{{}}}", folder, content.len())
|
||||
));
|
||||
let line = try!(self.readline());
|
||||
if !line.starts_with(b"+") {
|
||||
return Err(Error::Append);
|
||||
|
|
@ -441,7 +483,9 @@ impl<T: Read+Write> Client<T> {
|
|||
|
||||
fn readline(&mut self) -> Result<Vec<u8>> {
|
||||
let mut line_buffer: Vec<u8> = Vec::new();
|
||||
while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != LF && line_buffer[line_buffer.len()-2] != CR) {
|
||||
while line_buffer.len() < 2 ||
|
||||
(line_buffer[line_buffer.len() - 1] != LF && line_buffer[line_buffer.len() - 2] != CR)
|
||||
{
|
||||
let byte_buffer: &mut [u8] = &mut [0];
|
||||
let n = try!(self.stream.read(byte_buffer));
|
||||
if n > 0 {
|
||||
|
|
@ -452,7 +496,7 @@ impl<T: Read+Write> Client<T> {
|
|||
if self.debug {
|
||||
let mut line = line_buffer.clone();
|
||||
// Remove CRLF
|
||||
line.truncate(line_buffer.len()-2);
|
||||
line.truncate(line_buffer.len() - 2);
|
||||
print!("S: {}\n", String::from_utf8(line).unwrap());
|
||||
}
|
||||
|
||||
|
|
@ -489,7 +533,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response.as_bytes().to_vec());
|
||||
let mut client = Client::new(mock_stream);
|
||||
let actual_response = client.read_response().unwrap();
|
||||
assert!(expected_response == actual_response, "expected response doesn't equal actual");
|
||||
assert!(
|
||||
expected_response == actual_response,
|
||||
"expected response doesn't equal actual"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -528,11 +575,17 @@ mod tests {
|
|||
|
||||
let expected_command = format!("a1 {}", base_command);
|
||||
let command = imap_stream.create_command(String::from(base_command));
|
||||
assert!(command == expected_command, "expected command doesn't equal actual command");
|
||||
assert!(
|
||||
command == expected_command,
|
||||
"expected command doesn't equal actual command"
|
||||
);
|
||||
|
||||
let expected_command2 = format!("a2 {}", base_command);
|
||||
let command2 = imap_stream.create_command(String::from(base_command));
|
||||
assert!(command2 == expected_command2, "expected command doesn't equal actual command");
|
||||
assert!(
|
||||
command2 == expected_command2,
|
||||
"expected command doesn't equal actual command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -544,7 +597,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.login(username, password).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid login command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid login command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -554,7 +610,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.logout().unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid logout command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid logout command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -562,11 +621,20 @@ mod tests {
|
|||
let response = b"a1 OK RENAME completed\r\n".to_vec();
|
||||
let current_mailbox_name = "INBOX";
|
||||
let new_mailbox_name = "NEWINBOX";
|
||||
let command = format!("a1 RENAME {} {}\r\n", current_mailbox_name, new_mailbox_name);
|
||||
let command = format!(
|
||||
"a1 RENAME {} {}\r\n",
|
||||
current_mailbox_name,
|
||||
new_mailbox_name
|
||||
);
|
||||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.rename(current_mailbox_name, new_mailbox_name).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid rename command");
|
||||
client
|
||||
.rename(current_mailbox_name, new_mailbox_name)
|
||||
.unwrap();
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid rename command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -577,7 +645,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.subscribe(mailbox).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid subscribe command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid subscribe command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -588,7 +659,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.unsubscribe(mailbox).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid unsubscribe command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid unsubscribe command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -597,7 +671,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.expunge().unwrap();
|
||||
assert!(client.stream.written_buf == b"a1 EXPUNGE\r\n".to_vec(), "Invalid expunge command");
|
||||
assert!(
|
||||
client.stream.written_buf == b"a1 EXPUNGE\r\n".to_vec(),
|
||||
"Invalid expunge command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -606,7 +683,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.check().unwrap();
|
||||
assert!(client.stream.written_buf == b"a1 CHECK\r\n".to_vec(), "Invalid check command");
|
||||
assert!(
|
||||
client.stream.written_buf == b"a1 CHECK\r\n".to_vec(),
|
||||
"Invalid check command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -618,7 +698,8 @@ mod tests {
|
|||
* OK [UNSEEN 1] First unseen.\r\n\
|
||||
* OK [UIDVALIDITY 1257842737] UIDs valid\r\n\
|
||||
* OK [UIDNEXT 2] Predicted next UID\r\n\
|
||||
a1 OK [READ-ONLY] Select completed.\r\n".to_vec();
|
||||
a1 OK [READ-ONLY] Select completed.\r\n"
|
||||
.to_vec();
|
||||
let expected_mailbox = Mailbox {
|
||||
flags: String::from("(\\Answered \\Flagged \\Deleted \\Seen \\Draft)"),
|
||||
exists: 1,
|
||||
|
|
@ -626,14 +707,17 @@ mod tests {
|
|||
unseen: Some(1),
|
||||
permanent_flags: Some(String::from("()")),
|
||||
uid_next: Some(2),
|
||||
uid_validity: Some(1257842737)
|
||||
uid_validity: Some(1257842737),
|
||||
};
|
||||
let mailbox_name = "INBOX";
|
||||
let command = format!("a1 EXAMINE {}\r\n", mailbox_name);
|
||||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
let mailbox = client.examine(mailbox_name).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid examine command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid examine command"
|
||||
);
|
||||
assert!(mailbox == expected_mailbox, "Unexpected mailbox returned");
|
||||
}
|
||||
|
||||
|
|
@ -646,35 +730,48 @@ mod tests {
|
|||
* OK [UNSEEN 1] First unseen.\r\n\
|
||||
* OK [UIDVALIDITY 1257842737] UIDs valid\r\n\
|
||||
* OK [UIDNEXT 2] Predicted next UID\r\n\
|
||||
a1 OK [READ-ONLY] Select completed.\r\n".to_vec();
|
||||
a1 OK [READ-ONLY] Select completed.\r\n"
|
||||
.to_vec();
|
||||
let expected_mailbox = Mailbox {
|
||||
flags: String::from("(\\Answered \\Flagged \\Deleted \\Seen \\Draft)"),
|
||||
exists: 1,
|
||||
recent: 1,
|
||||
unseen: Some(1),
|
||||
permanent_flags: Some(String::from("(\\* \\Answered \\Flagged \\Deleted \\Draft \\Seen)")),
|
||||
permanent_flags: Some(String::from(
|
||||
"(\\* \\Answered \\Flagged \\Deleted \\Draft \\Seen)",
|
||||
)),
|
||||
uid_next: Some(2),
|
||||
uid_validity: Some(1257842737)
|
||||
uid_validity: Some(1257842737),
|
||||
};
|
||||
let mailbox_name = "INBOX";
|
||||
let command = format!("a1 SELECT {}\r\n", mailbox_name);
|
||||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
let mailbox = client.select(mailbox_name).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid select command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid select command"
|
||||
);
|
||||
assert!(mailbox == expected_mailbox, "Unexpected mailbox returned");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capability() {
|
||||
let response = b"* CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n\
|
||||
a1 OK CAPABILITY completed\r\n".to_vec();
|
||||
a1 OK CAPABILITY completed\r\n"
|
||||
.to_vec();
|
||||
let expected_capabilities = vec!["IMAP4rev1", "STARTTLS", "AUTH=GSSAPI", "LOGINDISABLED"];
|
||||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
let capabilities = client.capability().unwrap();
|
||||
assert!(client.stream.written_buf == b"a1 CAPABILITY\r\n".to_vec(), "Invalid capability command");
|
||||
assert!(capabilities == expected_capabilities, "Unexpected capabilities response");
|
||||
assert!(
|
||||
client.stream.written_buf == b"a1 CAPABILITY\r\n".to_vec(),
|
||||
"Invalid capability command"
|
||||
);
|
||||
assert!(
|
||||
capabilities == expected_capabilities,
|
||||
"Unexpected capabilities response"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -685,7 +782,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.create(mailbox_name).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid create command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid create command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -696,7 +796,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.delete(mailbox_name).unwrap();
|
||||
assert!(client.stream.written_buf == command.as_bytes().to_vec(), "Invalid delete command");
|
||||
assert!(
|
||||
client.stream.written_buf == command.as_bytes().to_vec(),
|
||||
"Invalid delete command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -705,7 +808,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.noop().unwrap();
|
||||
assert!(client.stream.written_buf == b"a1 NOOP\r\n".to_vec(), "Invalid noop command");
|
||||
assert!(
|
||||
client.stream.written_buf == b"a1 NOOP\r\n".to_vec(),
|
||||
"Invalid noop command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -714,7 +820,10 @@ mod tests {
|
|||
let mock_stream = MockStream::new(response);
|
||||
let mut client = Client::new(mock_stream);
|
||||
client.close().unwrap();
|
||||
assert!(client.stream.written_buf == b"a1 CLOSE\r\n".to_vec(), "Invalid close command");
|
||||
assert!(
|
||||
client.stream.written_buf == b"a1 CLOSE\r\n".to_vec(),
|
||||
"Invalid close command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -728,21 +837,16 @@ mod tests {
|
|||
}
|
||||
|
||||
fn generic_store<F, T>(prefix: &str, op: F)
|
||||
where F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T> {
|
||||
where
|
||||
F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T>,
|
||||
{
|
||||
|
||||
let res = "* 2 FETCH (FLAGS (\\Deleted \\Seen))\r\n\
|
||||
* 3 FETCH (FLAGS (\\Deleted))\r\n\
|
||||
* 4 FETCH (FLAGS (\\Deleted \\Flagged \\Seen))\r\n\
|
||||
a1 OK STORE completed\r\n";
|
||||
|
||||
generic_with_uid(
|
||||
res,
|
||||
"STORE",
|
||||
"2.4",
|
||||
"+FLAGS (\\Deleted)",
|
||||
prefix,
|
||||
op,
|
||||
);
|
||||
generic_with_uid(res, "STORE", "2.4", "+FLAGS (\\Deleted)", prefix, op);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -756,7 +860,9 @@ mod tests {
|
|||
}
|
||||
|
||||
fn generic_copy<F, T>(prefix: &str, op: F)
|
||||
where F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T> {
|
||||
where
|
||||
F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T>,
|
||||
{
|
||||
|
||||
generic_with_uid(
|
||||
"OK COPY completed\r\n",
|
||||
|
|
@ -779,31 +885,25 @@ mod tests {
|
|||
}
|
||||
|
||||
fn generic_fetch<F, T>(prefix: &str, op: F)
|
||||
where F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T> {
|
||||
where
|
||||
F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T>,
|
||||
{
|
||||
|
||||
generic_with_uid(
|
||||
"OK FETCH completed\r\n",
|
||||
"FETCH",
|
||||
"1",
|
||||
"BODY[]",
|
||||
prefix,
|
||||
op
|
||||
);
|
||||
generic_with_uid("OK FETCH completed\r\n", "FETCH", "1", "BODY[]", prefix, op);
|
||||
}
|
||||
|
||||
fn generic_with_uid<F, T>(
|
||||
res: &str,
|
||||
cmd: &str,
|
||||
seq: &str,
|
||||
query: &str,
|
||||
prefix: &str,
|
||||
op: F) where F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T>,
|
||||
fn generic_with_uid<F, T>(res: &str, cmd: &str, seq: &str, query: &str, prefix: &str, op: F)
|
||||
where
|
||||
F: FnOnce(&mut Client<MockStream>, &str, &str) -> Result<T>,
|
||||
{
|
||||
|
||||
let resp = format!("a1 {}\r\n", res).as_bytes().to_vec();
|
||||
let line = format!("a1{}{} {} {}\r\n", prefix, cmd, seq, query);
|
||||
let mut client = Client::new(MockStream::new(resp));
|
||||
let _ = op(&mut client, seq, query);
|
||||
assert!(client.stream.written_buf == line.as_bytes().to_vec(), "Invalid command");
|
||||
assert!(
|
||||
client.stream.written_buf == line.as_bytes().to_vec(),
|
||||
"Invalid command"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
src/error.rs
10
src/error.rs
|
|
@ -22,7 +22,7 @@ pub enum Error {
|
|||
// Error parsing a server response.
|
||||
Parse(ParseError),
|
||||
// Error appending a mail
|
||||
Append
|
||||
Append,
|
||||
}
|
||||
|
||||
impl From<IoError> for Error {
|
||||
|
|
@ -55,7 +55,7 @@ impl StdError for Error {
|
|||
Error::Parse(ref e) => e.description(),
|
||||
Error::BadResponse(_) => "Bad Response",
|
||||
Error::NoResponse(_) => "No Response",
|
||||
Error::Append => "Could not append mail to mailbox"
|
||||
Error::Append => "Could not append mail to mailbox",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ pub enum ParseError {
|
|||
// Error parsing the cabability response.
|
||||
Capability(Vec<String>),
|
||||
// Authentication errors.
|
||||
Authentication(String)
|
||||
Authentication(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseError {
|
||||
|
|
@ -91,13 +91,13 @@ impl StdError for ParseError {
|
|||
match *self {
|
||||
ParseError::StatusResponse(_) => "Unable to parse status response",
|
||||
ParseError::Capability(_) => "Unable to parse capability response",
|
||||
ParseError::Authentication(_) => "Unable to parse authentication response"
|
||||
ParseError::Authentication(_) => "Unable to parse authentication response",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&StdError> {
|
||||
match *self {
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Eq,PartialEq)]
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct Mailbox {
|
||||
pub flags: String,
|
||||
pub exists: u32,
|
||||
|
|
@ -8,7 +8,7 @@ pub struct Mailbox {
|
|||
pub unseen: Option<u32>,
|
||||
pub permanent_flags: Option<String>,
|
||||
pub uid_next: Option<u32>,
|
||||
pub uid_validity: Option<u32>
|
||||
pub uid_validity: Option<u32>,
|
||||
}
|
||||
|
||||
impl Default for Mailbox {
|
||||
|
|
@ -20,13 +20,24 @@ impl Default for Mailbox {
|
|||
unseen: None,
|
||||
permanent_flags: None,
|
||||
uid_next: None,
|
||||
uid_validity: None
|
||||
uid_validity: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Mailbox {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "flags: {}, exists: {}, recent: {}, unseen: {:?}, permanent_flags: {:?}, uid_next: {:?}, uid_validity: {:?}", self.flags, self.exists, self.recent, self.unseen, self.permanent_flags, self.uid_next, self.uid_validity)
|
||||
write!(
|
||||
f,
|
||||
"flags: {}, exists: {}, recent: {}, unseen: {:?}, permanent_flags: {:?},\
|
||||
uid_next: {:?}, uid_validity: {:?}",
|
||||
self.flags,
|
||||
self.exists,
|
||||
self.recent,
|
||||
self.unseen,
|
||||
self.permanent_flags,
|
||||
self.uid_next,
|
||||
self.uid_validity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,32 +6,32 @@ pub struct MockStream {
|
|||
read_pos: usize,
|
||||
pub written_buf: Vec<u8>,
|
||||
err_on_read: bool,
|
||||
read_delay: usize
|
||||
read_delay: usize,
|
||||
}
|
||||
|
||||
impl MockStream {
|
||||
pub fn new(read_buf: Vec<u8>) -> MockStream {
|
||||
MockStream{
|
||||
MockStream {
|
||||
read_buf: read_buf,
|
||||
read_pos: 0,
|
||||
written_buf: Vec::new(),
|
||||
err_on_read: false,
|
||||
read_delay: 0
|
||||
read_delay: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_err() -> MockStream {
|
||||
MockStream{
|
||||
MockStream {
|
||||
read_buf: Vec::new(),
|
||||
read_pos: 0,
|
||||
written_buf: Vec::new(),
|
||||
err_on_read: true,
|
||||
read_delay: 0
|
||||
read_delay: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_read_delay(read_buf: Vec<u8>) -> MockStream {
|
||||
MockStream{
|
||||
MockStream {
|
||||
read_buf: read_buf,
|
||||
read_pos: 0,
|
||||
written_buf: Vec::new(),
|
||||
|
|
@ -42,16 +42,16 @@ impl MockStream {
|
|||
}
|
||||
|
||||
impl Read for MockStream {
|
||||
fn read(&mut self, buf: &mut[u8]) -> Result<usize> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
if self.read_delay > 0 {
|
||||
self.read_delay -= 1;
|
||||
return Ok(0)
|
||||
return Ok(0);
|
||||
}
|
||||
if self.err_on_read {
|
||||
return Err(Error::new(ErrorKind::Other, "MockStream Error"))
|
||||
return Err(Error::new(ErrorKind::Other, "MockStream Error"));
|
||||
}
|
||||
if self.read_pos >= self.read_buf.len() {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "EOF"))
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "EOF"));
|
||||
}
|
||||
let write_len = min(buf.len(), self.read_buf.len() - self.read_pos);
|
||||
let max_pos = self.read_pos + write_len;
|
||||
|
|
|
|||
46
src/parse.rs
46
src/parse.rs
|
|
@ -7,7 +7,7 @@ pub fn parse_authenticate_response(line: String) -> Result<String> {
|
|||
let authenticate_regex = Regex::new("^+(.*)\r\n").unwrap();
|
||||
|
||||
for cap in authenticate_regex.captures_iter(line.as_str()) {
|
||||
let data = cap.get(1).map(|x|x.as_str()).unwrap_or("");
|
||||
let data = cap.get(1).map(|x| x.as_str()).unwrap_or("");
|
||||
return Ok(String::from(data));
|
||||
}
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ pub fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
|
|||
//Check Ok
|
||||
match parse_response_ok(lines.clone()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => return Err(e)
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
for line in lines.iter() {
|
||||
|
|
@ -37,7 +37,7 @@ pub fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
|
|||
pub fn parse_response_ok(lines: Vec<String>) -> Result<()> {
|
||||
match parse_response(lines) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => return Err(e)
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,11 +45,11 @@ pub fn parse_response(lines: Vec<String>) -> Result<Vec<String>> {
|
|||
let regex = Regex::new(r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)").unwrap();
|
||||
let last_line = match lines.last() {
|
||||
Some(l) => l,
|
||||
None => return Err(Error::Parse(ParseError::StatusResponse(lines.clone())))
|
||||
None => return Err(Error::Parse(ParseError::StatusResponse(lines.clone()))),
|
||||
};
|
||||
|
||||
for cap in regex.captures_iter(last_line) {
|
||||
let response_type = cap.get(2).map(|x|x.as_str()).unwrap_or("");
|
||||
let response_type = cap.get(2).map(|x| x.as_str()).unwrap_or("");
|
||||
match response_type {
|
||||
"OK" => return Ok(lines.clone()),
|
||||
"BAD" => return Err(Error::BadResponse(lines.clone())),
|
||||
|
|
@ -79,7 +79,7 @@ pub fn parse_select_or_examine(lines: Vec<String>) -> Result<Mailbox> {
|
|||
//Check Ok
|
||||
match parse_response_ok(lines.clone()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => return Err(e)
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let mut mailbox = Mailbox::default();
|
||||
|
|
@ -118,22 +118,41 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn parse_capability_test() {
|
||||
let expected_capabilities = vec![String::from("IMAP4rev1"), String::from("STARTTLS"), String::from("AUTH=GSSAPI"), String::from("LOGINDISABLED")];
|
||||
let lines = vec![String::from("* CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"), String::from("a1 OK CAPABILITY completed\r\n")];
|
||||
let expected_capabilities = vec![
|
||||
String::from("IMAP4rev1"),
|
||||
String::from("STARTTLS"),
|
||||
String::from("AUTH=GSSAPI"),
|
||||
String::from("LOGINDISABLED"),
|
||||
];
|
||||
let lines = vec![
|
||||
String::from(
|
||||
"* CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n",
|
||||
),
|
||||
String::from("a1 OK CAPABILITY completed\r\n"),
|
||||
];
|
||||
let capabilities = parse_capability(lines).unwrap();
|
||||
assert!(capabilities == expected_capabilities, "Unexpected capabilities parse response");
|
||||
assert!(
|
||||
capabilities == expected_capabilities,
|
||||
"Unexpected capabilities parse response"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn parse_capability_invalid_test() {
|
||||
let lines = vec![String::from("* JUNK IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"), String::from("a1 OK CAPABILITY completed\r\n")];
|
||||
let lines = vec![
|
||||
String::from("* JUNK IMAP4rev1 STARTTLS AUTH=GSSAPI LOGINDISABLED\r\n"),
|
||||
String::from("a1 OK CAPABILITY completed\r\n"),
|
||||
];
|
||||
parse_capability(lines).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_response_test() {
|
||||
let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 OK List completed.\r\n")];
|
||||
let lines = vec![
|
||||
String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"),
|
||||
String::from("a2 OK List completed.\r\n"),
|
||||
];
|
||||
let expected_lines = lines.clone();
|
||||
let actual_lines = parse_response(lines).unwrap();
|
||||
assert!(expected_lines == actual_lines, "Unexpected parse response");
|
||||
|
|
@ -142,7 +161,10 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn parse_response_invalid_test() {
|
||||
let lines = vec![String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"), String::from("a2 BAD broken.\r\n")];
|
||||
let lines = vec![
|
||||
String::from("* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"),
|
||||
String::from("a2 BAD broken.\r\n"),
|
||||
];
|
||||
parse_response(lines).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue