refactor(hyper): add tests and refactor to increase coverage

This commit is contained in:
Pyfisch
2015-05-01 14:31:53 +02:00
parent 7f5e0382d9
commit ff346f147f
7 changed files with 49 additions and 54 deletions

View File

@@ -16,12 +16,15 @@ header! {
#[doc="# Example values"] #[doc="# Example values"]
#[doc="* `bytes`"] #[doc="* `bytes`"]
#[doc="* `none`"] #[doc="* `none`"]
#[doc="* `unknown-unit`"]
#[doc="```"] #[doc="```"]
(AcceptRanges, "Accept-Ranges") => (RangeUnit)+ (AcceptRanges, "Accept-Ranges") => (RangeUnit)+
test_acccept_ranges { test_acccept_ranges {
test_header!(test1, vec![b"bytes"]); test_header!(test1, vec![b"bytes"]);
test_header!(test2, vec![b"none"]); test_header!(test2, vec![b"none"]);
test_header!(test3, vec![b"unknown-unit"]);
test_header!(test4, vec![b"bytes, unknown-unit"]);
} }
} }

View File

@@ -1,34 +1,9 @@
use header::{Header, HeaderFormat};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::str::FromStr; use std::str::FromStr;
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
use unicase::UniCase; use unicase::UniCase;
pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader}; pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
/// `Connection` header, defined in [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.1)
///
/// The `Connection` header field allows the sender to indicate desired
/// control options for the current connection. In order to avoid
/// confusing downstream recipients, a proxy or gateway MUST remove or
/// replace any received connection options before forwarding the
/// message.
///
/// # ABNF
/// ```plain
/// Connection = 1#connection-option
/// connection-option = token
/// ```
///
/// # Example values
/// * `close`
/// * `upgrade`
/// * `keep-alive`
#[derive(Clone, PartialEq, Debug)]
pub struct Connection(pub Vec<ConnectionOption>);
deref!(Connection => Vec<ConnectionOption>);
/// Values that can be in the `Connection` header. /// Values that can be in the `Connection` header.
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum ConnectionOption { pub enum ConnectionOption {
@@ -50,11 +25,11 @@ pub enum ConnectionOption {
impl FromStr for ConnectionOption { impl FromStr for ConnectionOption {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<ConnectionOption, ()> { fn from_str(s: &str) -> Result<ConnectionOption, ()> {
Ok(match s { match s {
"keep-alive" => KeepAlive, "keep-alive" => Ok(KeepAlive),
"close" => Close, "close" => Ok(Close),
s => ConnectionHeader(UniCase(s.to_string())), s => Ok(ConnectionHeader(UniCase(s.to_string())))
}) }
} }
} }
@@ -63,25 +38,36 @@ impl Display for ConnectionOption {
f.write_str(match *self { f.write_str(match *self {
KeepAlive => "keep-alive", KeepAlive => "keep-alive",
Close => "close", Close => "close",
ConnectionHeader(UniCase(ref s)) => s, ConnectionHeader(UniCase(ref s)) => s.as_ref()
}) })
} }
} }
impl Header for Connection { header! {
fn header_name() -> &'static str { #[doc="`Connection` header, defined in"]
"Connection" #[doc="[RFC7230](http://tools.ietf.org/html/rfc7230#section-6.1)"]
} #[doc=""]
#[doc="The `Connection` header field allows the sender to indicate desired"]
#[doc="control options for the current connection. In order to avoid"]
#[doc="confusing downstream recipients, a proxy or gateway MUST remove or"]
#[doc="replace any received connection options before forwarding the"]
#[doc="message."]
#[doc=""]
#[doc="# ABNF"]
#[doc="```plain"]
#[doc="Connection = 1#connection-option"]
#[doc="connection-option = token"]
#[doc=""]
#[doc="# Example values"]
#[doc="* `close`"]
#[doc="* `keep-alive`"]
#[doc="* `upgrade`"]
(Connection, "Connection") => (ConnectionOption)+
fn parse_header(raw: &[Vec<u8>]) -> Option<Connection> { test_connection {
from_comma_delimited(raw).map(|vec| Connection(vec)) test_header!(test1, vec![b"close"]);
} test_header!(test2, vec![b"keep-alive"]);
} test_header!(test3, vec![b"upgrade"]);
impl HeaderFormat for Connection {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Connection(ref parts) = *self;
fmt_comma_delimited(f, &parts[..])
} }
} }

View File

@@ -65,9 +65,11 @@ impl Display for IfRange {
} }
#[cfg(test)] #[cfg(test)]
mod test_range { mod test_if_range {
use std::str;
use header::*; use header::*;
use super::IfRange as HeaderField; use super::IfRange as HeaderField;
test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]);
test_header!(test2, vec![b"\"xyzzy\""]); test_header!(test2, vec![b"\"xyzzy\""]);
test_header!(test3, vec![b"this-is-invalid"], None::<IfRange>);
} }

View File

@@ -256,8 +256,6 @@ macro_rules! header {
if raw.len() == 1 { if raw.len() == 1 {
if raw[0] == b"*" { if raw[0] == b"*" {
return Some($id::Any) return Some($id::Any)
} else if raw[0] == b"" {
return None
} }
} }
$crate::header::parsing::from_comma_delimited(raw).map(|vec| $id::Items(vec)) $crate::header::parsing::from_comma_delimited(raw).map(|vec| $id::Items(vec))

View File

@@ -6,13 +6,8 @@ use std::fmt::{self, Display};
// 2. in the range %x23 to %x7E, or // 2. in the range %x23 to %x7E, or
// 3. in the range %x80 to %xFF // 3. in the range %x80 to %xFF
fn check_slice_validity(slice: &str) -> bool { fn check_slice_validity(slice: &str) -> bool {
for c in slice.bytes() { slice.bytes().all(|c|
match c { c == b'\x21' || (c >= b'\x23' && c <= b'\x7e') | (c >= b'\x80' && c <= b'\xff'))
b'\x21' | b'\x23' ... b'\x7e' | b'\x80' ... b'\xff' => (),
_ => { return false; }
}
}
true
} }
/// An entity tag, defined in [RFC7232](https://tools.ietf.org/html/rfc7232#section-2.3) /// An entity tag, defined in [RFC7232](https://tools.ietf.org/html/rfc7232#section-2.3)

View File

@@ -83,4 +83,9 @@ mod tests {
fn test_asctime() { fn test_asctime() {
assert_eq!("Sun Nov 7 08:48:37 1994".parse(), Ok(NOV_07)); assert_eq!("Sun Nov 7 08:48:37 1994".parse(), Ok(NOV_07));
} }
#[test]
fn test_no_date() {
assert_eq!("this-is-no-date".parse(), Err::<HttpDate, ()>(()));
}
} }

View File

@@ -129,6 +129,7 @@ impl fmt::Display for Method {
mod tests { mod tests {
use std::collections::HashMap; use std::collections::HashMap;
use std::str::FromStr; use std::str::FromStr;
use error::Error;
use super::Method; use super::Method;
use super::Method::{Get, Post, Put, Extension}; use super::Method::{Get, Post, Put, Extension};
@@ -150,6 +151,11 @@ mod tests {
assert_eq!(Get, FromStr::from_str("GET").unwrap()); assert_eq!(Get, FromStr::from_str("GET").unwrap());
assert_eq!(Extension("MOVE".to_string()), assert_eq!(Extension("MOVE".to_string()),
FromStr::from_str("MOVE").unwrap()); FromStr::from_str("MOVE").unwrap());
let x: Result<Method, _> = FromStr::from_str("");
if let Err(Error::Method) = x {
} else {
panic!("An empty method is invalid!")
}
} }
#[test] #[test]