From efd6c96a3cf152b49b672ac87e225e45ab87a477 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sun, 26 Apr 2015 12:30:06 +0200 Subject: [PATCH 1/5] test(headers): Allow tests inside list header macros, add tests. Adds test cases from the relevant RFCs for a few headers. See also: #468, do we want the test cases rendered as examples in the docs? --- src/header/common/accept.rs | 57 +++++++++++++++----------- src/header/common/accept_charset.rs | 4 ++ src/header/common/accept_language.rs | 4 ++ src/header/common/content_encoding.rs | 2 + src/header/common/mod.rs | 33 ++++++++++++++- src/header/common/transfer_encoding.rs | 10 +++++ src/header/common/upgrade.rs | 12 ++++++ 7 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/header/common/accept.rs b/src/header/common/accept.rs index 02522dea..c991cab4 100644 --- a/src/header/common/accept.rs +++ b/src/header/common/accept.rs @@ -27,32 +27,39 @@ header! { #[doc="* Using always Mime types to represent `media-range` differs from the ABNF."] #[doc="* **FIXME**: `accept-ext` is not supported."] (Accept, "Accept") => (QualityItem)+ -} -#[cfg(test)] -mod tests { - use mime::*; - - use header::{Header, Quality, QualityItem, qitem}; - - use super::Accept; - - #[test] - fn test_parse_header_no_quality() { - let a: Accept = Header::parse_header([b"text/plain; charset=utf-8".to_vec()].as_ref()).unwrap(); - let b = Accept(vec![ - qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])), - ]); - assert_eq!(a, b); - } - - #[test] - fn test_parse_header_with_quality() { - let a: Accept = Header::parse_header([b"text/plain; charset=utf-8; q=0.5".to_vec()].as_ref()).unwrap(); - let b = Accept(vec![ - QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]), Quality(500)), - ]); - assert_eq!(a, b); + test_accept { + // Tests from the RFC + // FIXME: Test fails, first value containing a "*" fails to parse + // test_header!( + // test1, + // vec![b"audio/*; q=0.2, audio/basic"], + // Some(HeaderField(vec![ + // QualityItem::new(Mime(TopLevel::Audio, SubLevel::Star, vec![]), Quality(200)), + // qitem(Mime(TopLevel::Audio, SubLevel::Ext("basic".to_string()), vec![])), + // ]))); + test_header!( + test2, + vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"], + Some(HeaderField(vec![ + QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), Quality(500)), + qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])), + QualityItem::new(Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_string()), vec![]), Quality(800)), + qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_string()), vec![])), + ]))); + // Custom tests + test_header!( + test3, + vec![b"text/plain; charset=utf-8"], + Some(Accept(vec![ + qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])), + ]))); + test_header!( + test4, + vec![b"text/plain; charset=utf-8; q=0.5"], + Some(Accept(vec![ + QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]), Quality(500)), + ]))); } } diff --git a/src/header/common/accept_charset.rs b/src/header/common/accept_charset.rs index 7b36bd9d..53ae264c 100644 --- a/src/header/common/accept_charset.rs +++ b/src/header/common/accept_charset.rs @@ -16,6 +16,10 @@ header! { #[doc="Accept-Charset = 1#( ( charset / \"*\" ) [ weight ] )"] #[doc="```"] (AcceptCharset, "Accept-Charset") => (QualityItem)+ + + test_accept_charset { + test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]); + } } diff --git a/src/header/common/accept_language.rs b/src/header/common/accept_language.rs index 3cc95c52..ef478c4c 100644 --- a/src/header/common/accept_language.rs +++ b/src/header/common/accept_language.rs @@ -49,6 +49,10 @@ header! { #[doc="language-range = "] #[doc="```"] (AcceptLanguage, "Accept-Language") => (QualityItem)+ + + test_accept_language { + test_header!(test1, vec![b"da, en-gb;q=0.8, en;q=0.7"]); + } } #[cfg(test)] diff --git a/src/header/common/content_encoding.rs b/src/header/common/content_encoding.rs index beab9654..d4570125 100644 --- a/src/header/common/content_encoding.rs +++ b/src/header/common/content_encoding.rs @@ -17,6 +17,8 @@ header! { #[doc="Content-Encoding = 1#content-coding"] #[doc="```"] (ContentEncoding, "Content-Encoding") => (Encoding)+ + + test_content_encoding {} } bench_header!(single, ContentEncoding, { vec![b"gzip".to_vec()] }); diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 8168d965..68ff14c8 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -94,6 +94,29 @@ macro_rules! deref( } ); +macro_rules! test_header { + ($id:ident, $test:expr) => { + #[test] + fn $id() { + let a: Vec> = $test.iter().map(|x| x.to_vec()).collect(); + HeaderField::parse_header(&a[..]).unwrap(); + } + }; + ($id:ident, $raw:expr, $typed:expr) => { + #[test] + fn $id() { + use std::str; + let a: Vec> = $raw.iter().map(|x| x.to_vec()).collect(); + let val = HeaderField::parse_header(&a[..]); + // Test parsing + assert_eq!(val, $typed); + // Test formatting + let res: &str = str::from_utf8($raw[0]).unwrap(); + assert_eq!(format!("{}", $typed.unwrap()), res); + } + } +} + #[macro_export] macro_rules! header { // $a:meta: Attributes associated with the header item (usually docs) @@ -129,7 +152,7 @@ macro_rules! header { }; // List header, one or more items - ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => { + ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => { $(#[$a])* #[derive(Clone, Debug, PartialEq)] pub struct $id(pub Vec<$item>); @@ -153,6 +176,14 @@ macro_rules! header { self.fmt_header(f) } } + + #[allow(unused_imports)] + mod $tm{ + use $crate::header::*; + use $crate::mime::*; + use super::$id as HeaderField; + $($tf)* + } }; // Single value header ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => { diff --git a/src/header/common/transfer_encoding.rs b/src/header/common/transfer_encoding.rs index 4e8db0e9..18ea3f26 100644 --- a/src/header/common/transfer_encoding.rs +++ b/src/header/common/transfer_encoding.rs @@ -14,6 +14,16 @@ header! { #[doc="Transfer-Encoding = 1#transfer-coding"] #[doc="```"] (TransferEncoding, "Transfer-Encoding") => (Encoding)+ + + transfer_encoding { + test_header!( + test1, + vec![b"gzip, chunked"], + Some(HeaderField( + vec![Encoding::Gzip, Encoding::Chunked] + ))); + + } } bench_header!(normal, TransferEncoding, { vec![b"chunked, gzip".to_vec()] }); diff --git a/src/header/common/upgrade.rs b/src/header/common/upgrade.rs index b8071994..b47d2c2e 100644 --- a/src/header/common/upgrade.rs +++ b/src/header/common/upgrade.rs @@ -26,6 +26,18 @@ header! { #[doc="protocol-version = token"] #[doc="```"] (Upgrade, "Upgrade") => (Protocol)+ + + test_upgrade { + test_header!( + test1, + vec![b"HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11"], + Some(HeaderField(vec![ + Protocol::ProtocolExt("HTTP/2.0".to_string()), + Protocol::ProtocolExt("SHTTP/1.3".to_string()), + Protocol::ProtocolExt("IRC/6.9".to_string()), + Protocol::ProtocolExt("RTA/x11".to_string()), + ]))); + } } /// Protocol values that can appear in the Upgrade header. From 18f717fcf177b270a3340ddb445c1881a3c41a13 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sun, 26 Apr 2015 14:06:46 +0200 Subject: [PATCH 2/5] test(headers): Add tests for headers with "*" value --- src/header/common/if_match.rs | 31 ++++++++++++++---------------- src/header/common/if_none_match.rs | 8 ++++++++ src/header/common/mod.rs | 10 ++++++++-- src/header/common/vary.rs | 4 ++++ 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/header/common/if_match.rs b/src/header/common/if_match.rs index 58f55955..9d74dbe3 100644 --- a/src/header/common/if_match.rs +++ b/src/header/common/if_match.rs @@ -21,24 +21,21 @@ header! { #[doc="If-Match = \"*\" / 1#entity-tag"] #[doc="```"] (IfMatch, "If-Match") => {Any / (EntityTag)+} -} -#[test] -fn test_parse_header() { - use header::Header; - { - let a: IfMatch = Header::parse_header( - [b"*".to_vec()].as_ref()).unwrap(); - assert_eq!(a, IfMatch::Any); - } - { - let a: IfMatch = Header::parse_header( - [b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"".to_vec()].as_ref()).unwrap(); - let b = IfMatch::Items( - vec![EntityTag::new(false, "xyzzy".to_string()), - EntityTag::new(false, "r2d2xxxx".to_string()), - EntityTag::new(false, "c3piozzzz".to_string())]); - assert_eq!(a, b); + test_if_match { + test_header!( + test1, + vec![b"\"xyzzy\""], + Some(HeaderField::Items( + vec![EntityTag::new(false, "xyzzy".to_string())]))); + test_header!( + test2, + vec![b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""], + Some(HeaderField::Items( + vec![EntityTag::new(false, "xyzzy".to_string()), + EntityTag::new(false, "r2d2xxxx".to_string()), + EntityTag::new(false, "c3piozzzz".to_string())]))); + test_header!(test3, vec![b"*"], Some(IfMatch::Any)); } } diff --git a/src/header/common/if_none_match.rs b/src/header/common/if_none_match.rs index 4a388b0d..697cd7d2 100644 --- a/src/header/common/if_none_match.rs +++ b/src/header/common/if_none_match.rs @@ -20,6 +20,14 @@ header! { #[doc="If-None-Match = \"*\" / 1#entity-tag"] #[doc="```"] (IfNoneMatch, "If-None-Match") => {Any / (EntityTag)+} + + test_if_none_match { + test_header!(test1, vec![b"\"xyzzy\""]); + test_header!(test2, vec![b"W/\"xyzzy\""]); + test_header!(test3, vec![b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""]); + test_header!(test4, vec![b"W/\"xyzzy\", W/\"r2d2xxxx\", W/\"c3piozzzz\""]); + test_header!(test5, vec![b"*"]); + } } #[cfg(test)] diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 68ff14c8..0f88c501 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -176,7 +176,6 @@ macro_rules! header { self.fmt_header(f) } } - #[allow(unused_imports)] mod $tm{ use $crate::header::*; @@ -211,7 +210,7 @@ macro_rules! header { } }; // List header, one or more items with "*" option - ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => { + ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => { $(#[$a])* #[derive(Clone, Debug, PartialEq)] pub enum $id { @@ -250,6 +249,13 @@ macro_rules! header { self.fmt_header(f) } } + #[allow(unused_imports)] + mod $tm{ + use $crate::header::*; + use $crate::mime::*; + use super::$id as HeaderField; + $($tf)* + } }; } diff --git a/src/header/common/vary.rs b/src/header/common/vary.rs index e2b7ffef..9d90f106 100644 --- a/src/header/common/vary.rs +++ b/src/header/common/vary.rs @@ -15,6 +15,10 @@ header! { #[doc="Vary = \"*\" / 1#field-name"] #[doc="```"] (Vary, "Vary") => {Any / (UniCase)+} + + test_vary { + test_header!(test1, vec![b"accept-encoding, accept-language"]); + } } #[cfg(test)] From 76a4a013488d67b870df821a6a0a8e10b026a0c3 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sun, 26 Apr 2015 14:32:10 +0200 Subject: [PATCH 3/5] test(headers): Add tests for possibly empty list headers. --- src/header/common/accept_encoding.rs | 8 ++++ .../common/access_control_allow_headers.rs | 4 +- .../common/access_control_allow_methods.rs | 2 + .../common/access_control_request_headers.rs | 2 + .../common/access_control_request_method.rs | 2 +- src/header/common/allow.rs | 42 ++++++++++++------- src/header/common/mod.rs | 12 +++++- 7 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/header/common/accept_encoding.rs b/src/header/common/accept_encoding.rs index 03a254f5..8b7a9a60 100644 --- a/src/header/common/accept_encoding.rs +++ b/src/header/common/accept_encoding.rs @@ -16,6 +16,14 @@ header! { #[doc="codings = content-coding / \"identity\" / \"*\""] #[doc="```"] (AcceptEncoding, "Accept-Encoding") => (QualityItem)* + + test_accept_encoding { + test_header!(test1, vec![b"compress, gzip".to_vec()]); + test_header!(test2, vec![b"".to_vec()]); + test_header!(test3, vec![b"*".to_vec()]); + test_header!(test4, vec![b"compress;q=0.5, gzip;q=1.0".to_vec()]); + test_header!(test5, vec![b"gzip;q=1.0, identity; q=0.5, *;q=0".to_vec()]); + } } #[cfg(test)] diff --git a/src/header/common/access_control_allow_headers.rs b/src/header/common/access_control_allow_headers.rs index da5dea08..a5cc169d 100644 --- a/src/header/common/access_control_allow_headers.rs +++ b/src/header/common/access_control_allow_headers.rs @@ -8,4 +8,6 @@ header! { #[doc="response to a preflight request, which header field names can be used"] #[doc="during the actual request."] (AccessControlAllowHeaders, "Access-Control-Allow-Headers") => (UniCase)* -} \ No newline at end of file + + test_access_control_allow_headers {} +} diff --git a/src/header/common/access_control_allow_methods.rs b/src/header/common/access_control_allow_methods.rs index 8d12de38..da22eb45 100644 --- a/src/header/common/access_control_allow_methods.rs +++ b/src/header/common/access_control_allow_methods.rs @@ -8,4 +8,6 @@ header! { #[doc="response to a preflight request, which methods can be used during the"] #[doc="actual request."] (AccessControlAllowMethods, "Access-Control-Allow-Methods") => (Method)* + + test_access_control_allow_methods {} } diff --git a/src/header/common/access_control_request_headers.rs b/src/header/common/access_control_request_headers.rs index 79f57d21..0bb09377 100644 --- a/src/header/common/access_control_request_headers.rs +++ b/src/header/common/access_control_request_headers.rs @@ -8,4 +8,6 @@ header! { #[doc="be used in the actual request as part of the preflight request."] #[doc="during the actual request."] (AccessControlRequestHeaders, "Access-Control-Request-Headers") => (UniCase)* + + test_access_control_request_headers {} } diff --git a/src/header/common/access_control_request_method.rs b/src/header/common/access_control_request_method.rs index 5706dfee..de97ec18 100644 --- a/src/header/common/access_control_request_method.rs +++ b/src/header/common/access_control_request_method.rs @@ -7,4 +7,4 @@ header! { #[doc="The `Access-Control-Request-Method` header indicates which method will be"] #[doc="used in the actual request as part of the preflight request."] (AccessControlRequestMethod, "Access-Control-Request-Method") => [Method] -} \ No newline at end of file +} diff --git a/src/header/common/allow.rs b/src/header/common/allow.rs index 41464388..778a807a 100644 --- a/src/header/common/allow.rs +++ b/src/header/common/allow.rs @@ -13,23 +13,33 @@ header! { #[doc="Allow = #method"] #[doc="```"] (Allow, "Allow") => (Method)* -} -#[cfg(test)] -mod tests { - use super::Allow; - use header::Header; - use method::Method::{self, Options, Get, Put, Post, Delete, Head, Trace, Connect, Patch, Extension}; - - #[test] - fn test_allow() { - let mut allow: Option; - - allow = Header::parse_header([b"OPTIONS,GET,PUT,POST,DELETE,HEAD,TRACE,CONNECT,PATCH,fOObAr".to_vec()].as_ref()); - assert_eq!(allow, Some(Allow(vec![Options, Get, Put, Post, Delete, Head, Trace, Connect, Patch, Extension("fOObAr".to_string())]))); - - allow = Header::parse_header([b"".to_vec()].as_ref()); - assert_eq!(allow, Some(Allow(Vec::::new()))); + test_allow { + // From the RFC + test_header!( + test1, + vec![b"GET, HEAD, PUT"], + Some(HeaderField(vec![Method::Get, Method::Head, Method::Put]))); + // Own tests + test_header!( + test2, + vec![b"OPTIONS, GET, PUT, POST, DELETE, HEAD, TRACE, CONNECT, PATCH, fOObAr"], + Some(HeaderField(vec![ + Method::Options, + Method::Get, + Method::Put, + Method::Post, + Method::Delete, + Method::Head, + Method::Trace, + Method::Connect, + Method::Patch, + Method::Extension("fOObAr".to_string())]))); + // FIXME: Formatting fails + // test_header!( + // test3, + // vec![b""], + // Some(HeaderField(Vec::::new()))); } } diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 0f88c501..530df936 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -125,7 +125,7 @@ macro_rules! header { // $nn:expr: Nice name of the header // List header, zero or more items - ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)*) => { + ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => { $(#[$a])* #[derive(Clone, Debug, PartialEq)] pub struct $id(pub Vec<$item>); @@ -149,6 +149,14 @@ macro_rules! header { self.fmt_header(f) } } + #[allow(unused_imports)] + mod $tm{ + use $crate::header::*; + use $crate::mime::*; + use $crate::method::Method; + use super::$id as HeaderField; + $($tf)* + } }; // List header, one or more items @@ -180,6 +188,7 @@ macro_rules! header { mod $tm{ use $crate::header::*; use $crate::mime::*; + use $crate::method::Method; use super::$id as HeaderField; $($tf)* } @@ -253,6 +262,7 @@ macro_rules! header { mod $tm{ use $crate::header::*; use $crate::mime::*; + use $crate::method::Method; use super::$id as HeaderField; $($tf)* } From 6d34448043f233721fd499a6dd7e494a86fde963 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sun, 26 Apr 2015 15:49:34 +0200 Subject: [PATCH 4/5] test(headers): Test if formatting gives back the same header --- src/header/common/accept_encoding.rs | 13 ++++++++----- src/header/common/mod.rs | 17 +++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/header/common/accept_encoding.rs b/src/header/common/accept_encoding.rs index 8b7a9a60..ff9d4751 100644 --- a/src/header/common/accept_encoding.rs +++ b/src/header/common/accept_encoding.rs @@ -18,11 +18,14 @@ header! { (AcceptEncoding, "Accept-Encoding") => (QualityItem)* test_accept_encoding { - test_header!(test1, vec![b"compress, gzip".to_vec()]); - test_header!(test2, vec![b"".to_vec()]); - test_header!(test3, vec![b"*".to_vec()]); - test_header!(test4, vec![b"compress;q=0.5, gzip;q=1.0".to_vec()]); - test_header!(test5, vec![b"gzip;q=1.0, identity; q=0.5, *;q=0".to_vec()]); + // From the RFC + test_header!(test1, vec![b"compress, gzip"]); + test_header!(test2, vec![b""]); + test_header!(test3, vec![b"*"]); + // Note: Removed quality 1 from gzip + test_header!(test4, vec![b"compress;q=0.5, gzip"]); + // FIXME: Formatting of 0 as quality value + // test_header!(test5, vec![b"gzip;q=1.0, identity; q=0.5, *;q=0"]); } } diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 530df936..b69e54e7 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -95,17 +95,23 @@ macro_rules! deref( ); macro_rules! test_header { - ($id:ident, $test:expr) => { + ($id:ident, $raw:expr) => { #[test] fn $id() { - let a: Vec> = $test.iter().map(|x| x.to_vec()).collect(); - HeaderField::parse_header(&a[..]).unwrap(); + use std::ascii::AsciiExt; + let raw = $raw; + let a: Vec> = raw.iter().map(|x| x.to_vec()).collect(); + let value = HeaderField::parse_header(&a[..]); + let result = format!("{}", value.unwrap()); + let expected = String::from_utf8(raw[0].to_vec()).unwrap(); + let result_cmp: Vec = result.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect(); + let expected_cmp: Vec = expected.to_ascii_lowercase().split(' ').map(|x| x.to_string()).collect(); + assert_eq!(result_cmp.concat(), expected_cmp.concat()); } }; ($id:ident, $raw:expr, $typed:expr) => { #[test] fn $id() { - use std::str; let a: Vec> = $raw.iter().map(|x| x.to_vec()).collect(); let val = HeaderField::parse_header(&a[..]); // Test parsing @@ -151,6 +157,7 @@ macro_rules! header { } #[allow(unused_imports)] mod $tm{ + use std::str; use $crate::header::*; use $crate::mime::*; use $crate::method::Method; @@ -186,6 +193,7 @@ macro_rules! header { } #[allow(unused_imports)] mod $tm{ + use std::str; use $crate::header::*; use $crate::mime::*; use $crate::method::Method; @@ -260,6 +268,7 @@ macro_rules! header { } #[allow(unused_imports)] mod $tm{ + use std::str; use $crate::header::*; use $crate::mime::*; use $crate::method::Method; From a27e6812b9db98fd8f375f2b4b497e4bafc1871e Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sun, 26 Apr 2015 19:16:44 +0200 Subject: [PATCH 5/5] test(headers): Add tests for single value headers. --- src/header/common/accept_charset.rs | 14 -------------- src/header/common/access_control_max_age.rs | 4 +++- src/header/common/access_control_request_method.rs | 2 ++ src/header/common/content_length.rs | 5 +++++ src/header/common/content_type.rs | 9 +++++++++ src/header/common/date.rs | 4 ++++ src/header/common/etag.rs | 6 ++++++ src/header/common/expires.rs | 5 +++++ src/header/common/if_modified_since.rs | 5 +++++ src/header/common/if_unmodified_since.rs | 5 +++++ src/header/common/last_modified.rs | 4 ++++ src/header/common/location.rs | 6 ++++++ src/header/common/mod.rs | 11 ++++++++++- src/header/common/referer.rs | 5 +++++ src/header/common/server.rs | 5 +++++ src/header/common/user_agent.rs | 5 +++++ 16 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/header/common/accept_charset.rs b/src/header/common/accept_charset.rs index 53ae264c..1fc044ae 100644 --- a/src/header/common/accept_charset.rs +++ b/src/header/common/accept_charset.rs @@ -21,17 +21,3 @@ header! { test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]); } } - - -#[test] -fn test_parse_header() { - use header::{self, q}; - let a: AcceptCharset = header::Header::parse_header( - [b"iso-8859-5, iso-8859-6;q=0.8".to_vec()].as_ref()).unwrap(); - let b = AcceptCharset(vec![ - QualityItem { item: Charset::Iso_8859_5, quality: q(1.0) }, - QualityItem { item: Charset::Iso_8859_6, quality: q(0.8) }, - ]); - assert_eq!(format!("{}", a), format!("{}", b)); - assert_eq!(a, b); -} diff --git a/src/header/common/access_control_max_age.rs b/src/header/common/access_control_max_age.rs index b5a9aec2..036f14e1 100644 --- a/src/header/common/access_control_max_age.rs +++ b/src/header/common/access_control_max_age.rs @@ -5,4 +5,6 @@ header! { #[doc="The `Access-Control-Max-Age` header indicates how long the results of a"] #[doc="preflight request can be cached in a preflight result cache."] (AccessControlMaxAge, "Access-Control-Max-Age") => [u32] -} \ No newline at end of file + + test_access_control_max_age {} +} diff --git a/src/header/common/access_control_request_method.rs b/src/header/common/access_control_request_method.rs index de97ec18..30f0c152 100644 --- a/src/header/common/access_control_request_method.rs +++ b/src/header/common/access_control_request_method.rs @@ -7,4 +7,6 @@ header! { #[doc="The `Access-Control-Request-Method` header indicates which method will be"] #[doc="used in the actual request as part of the preflight request."] (AccessControlRequestMethod, "Access-Control-Request-Method") => [Method] + + test_access_control_request_method {} } diff --git a/src/header/common/content_length.rs b/src/header/common/content_length.rs index ac630880..4c9d3946 100644 --- a/src/header/common/content_length.rs +++ b/src/header/common/content_length.rs @@ -16,6 +16,11 @@ header! { #[doc="Content-Length = 1*DIGIT"] #[doc="```"] (ContentLength, "Content-Length") => [u64] + + test_content_length { + // Testcase from RFC + test_header!(test1, vec![b"3495"], Some(HeaderField(3495))); + } } bench_header!(bench, ContentLength, { vec![b"42349984".to_vec()] }); diff --git a/src/header/common/content_type.rs b/src/header/common/content_type.rs index 427de5ee..89f4bff3 100644 --- a/src/header/common/content_type.rs +++ b/src/header/common/content_type.rs @@ -17,6 +17,15 @@ header! { #[doc="Content-Type = media-type"] #[doc="```"] (ContentType, "Content-Type") => [Mime] + + test_content_type { + test_header!( + test1, + // FIXME: Should be b"text/html; charset=ISO-8859-4" but mime crate lowercases + // the whole value so parsing and formatting the value gives a different result + vec![b"text/html; charset=iso-8859-4"], + Some(HeaderField(Mime(TopLevel::Text, SubLevel::Html, vec![(Attr::Charset, Value::Ext("iso-8859-4".to_string()))])))); + } } bench_header!(bench, ContentType, { vec![b"application/json; charset=utf-8".to_vec()] }); diff --git a/src/header/common/date.rs b/src/header/common/date.rs index 70fcb5fe..8bba6769 100644 --- a/src/header/common/date.rs +++ b/src/header/common/date.rs @@ -11,6 +11,10 @@ header! { #[doc="Date = HTTP-date"] #[doc="```"] (Date, "Date") => [HttpDate] + + test_date { + test_header!(test1, vec![b"Tue, 15 Nov 1994 08:12:31 GMT"]); + } } bench_header!(imf_fixdate, Date, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); diff --git a/src/header/common/etag.rs b/src/header/common/etag.rs index 7d30041f..fbd65e29 100644 --- a/src/header/common/etag.rs +++ b/src/header/common/etag.rs @@ -18,6 +18,12 @@ header! { #[doc="ETag = entity-tag"] #[doc="```"] (ETag, "ETag") => [EntityTag] + + test_etag { + test_header!(test1, vec![b"\"xyzzy\""], Some(HeaderField(EntityTag::new(false, "xyzzy".to_string())))); + test_header!(test2, vec![b"W/\"xyzzy\""], Some(HeaderField(EntityTag::new(true, "xyzzy".to_string())))); + test_header!(test3, vec![b"\"\""], Some(HeaderField(EntityTag::new(false, "".to_string())))); + } } #[cfg(test)] diff --git a/src/header/common/expires.rs b/src/header/common/expires.rs index 613ef6a0..aa080d5e 100644 --- a/src/header/common/expires.rs +++ b/src/header/common/expires.rs @@ -15,6 +15,11 @@ header! { #[doc="Expires = HTTP-date"] #[doc="```"] (Expires, "Expires") => [HttpDate] + + test_expires { + // Testcase from RFC + test_header!(test1, vec![b"Thu, 01 Dec 1994 16:00:00 GMT"]); + } } bench_header!(imf_fixdate, Expires, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); diff --git a/src/header/common/if_modified_since.rs b/src/header/common/if_modified_since.rs index b8453203..67241b84 100644 --- a/src/header/common/if_modified_since.rs +++ b/src/header/common/if_modified_since.rs @@ -15,6 +15,11 @@ header! { #[doc="If-Unmodified-Since = HTTP-date"] #[doc="```"] (IfModifiedSince, "If-Modified-Since") => [HttpDate] + + test_if_modified_since { + // Testcase from RFC + test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); + } } bench_header!(imf_fixdate, IfModifiedSince, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); diff --git a/src/header/common/if_unmodified_since.rs b/src/header/common/if_unmodified_since.rs index 200d030d..9fd3afbd 100644 --- a/src/header/common/if_unmodified_since.rs +++ b/src/header/common/if_unmodified_since.rs @@ -15,6 +15,11 @@ header! { #[doc="If-Unmodified-Since = HTTP-date"] #[doc="```"] (IfUnmodifiedSince, "If-Unmodified-Since") => [HttpDate] + + test_if_unmodified_since { + // Testcase from RFC + test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); + } } bench_header!(imf_fixdate, IfUnmodifiedSince, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); diff --git a/src/header/common/last_modified.rs b/src/header/common/last_modified.rs index cf3f0cf5..e203b20b 100644 --- a/src/header/common/last_modified.rs +++ b/src/header/common/last_modified.rs @@ -13,6 +13,10 @@ header! { #[doc="Expires = HTTP-date"] #[doc="```"] (LastModified, "Last-Modified") => [HttpDate] + + test_last_modified { + // Testcase from RFC + test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]);} } bench_header!(imf_fixdate, LastModified, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); diff --git a/src/header/common/location.rs b/src/header/common/location.rs index f5d23023..4ff45fdf 100644 --- a/src/header/common/location.rs +++ b/src/header/common/location.rs @@ -14,6 +14,12 @@ header! { // TODO: Use URL (Location, "Location") => [String] + test_location { + // Testcase from RFC + test_header!(test1, vec![b"/People.html#tim"]); + test_header!(test2, vec![b"http://www.example.net/index.html"]); + } + } bench_header!(bench, Location, { vec![b"http://foo.com/hello:3000".to_vec()] }); diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index b69e54e7..f1218f43 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -202,7 +202,7 @@ macro_rules! header { } }; // Single value header - ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => { + ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty] $tm:ident{$($tf:item)*}) => { $(#[$a])* #[derive(Clone, Debug, PartialEq)] pub struct $id(pub $value); @@ -225,6 +225,15 @@ macro_rules! header { ::std::fmt::Display::fmt(&**self, f) } } + #[allow(unused_imports)] + mod $tm{ + use std::str; + use $crate::header::*; + use $crate::mime::*; + use $crate::method::Method; + use super::$id as HeaderField; + $($tf)* + } }; // List header, one or more items with "*" option ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => { diff --git a/src/header/common/referer.rs b/src/header/common/referer.rs index ab720537..06dbeeff 100644 --- a/src/header/common/referer.rs +++ b/src/header/common/referer.rs @@ -14,6 +14,11 @@ header! { #[doc="```"] // TODO: Use URL (Referer, "Referer") => [String] + + test_referer { + // Testcase from the RFC + test_header!(test1, vec![b"http://www.example.org/hypertext/Overview.html"]); + } } bench_header!(bench, Referer, { vec![b"http://foo.com/hello:3000".to_vec()] }); diff --git a/src/header/common/server.rs b/src/header/common/server.rs index 476d4bc0..9f795c68 100644 --- a/src/header/common/server.rs +++ b/src/header/common/server.rs @@ -15,6 +15,11 @@ header! { #[doc="```"] // TODO: Maybe parse as defined in the spec? (Server, "Server") => [String] + + test_server { + // Testcase from RFC + test_header!(test1, vec![b"CERN/3.0 libwww/2.17"]); + } } bench_header!(bench, Server, { vec![b"Some String".to_vec()] }); diff --git a/src/header/common/user_agent.rs b/src/header/common/user_agent.rs index 2a481e9b..2592bcda 100644 --- a/src/header/common/user_agent.rs +++ b/src/header/common/user_agent.rs @@ -18,6 +18,11 @@ header! { #[doc="```"] // TODO: Maybe write parsing according to the spec? (Split the String) (UserAgent, "User-Agent") => [String] + + test_user_agent { + // Testcase from RFC + test_header!(test1, vec![b"CERN-LineMode/2.15 libwww/2.17b3"]); + } } #[test] fn test_format() {