diff options
Diffstat (limited to 'third_party/rust/headers/src/disabled/util')
4 files changed, 746 insertions, 0 deletions
diff --git a/third_party/rust/headers/src/disabled/util/charset.rs b/third_party/rust/headers/src/disabled/util/charset.rs new file mode 100644 index 0000000000..5a3f462829 --- /dev/null +++ b/third_party/rust/headers/src/disabled/util/charset.rs @@ -0,0 +1,229 @@ +use std::fmt; +use std::str::FromStr; + +/// A Mime charset. +/// +/// The string representation is normalised to upper case. +/// +/// See [http://www.iana.org/assignments/character-sets/character-sets.xhtml][url]. +/// +/// [url]: http://www.iana.org/assignments/character-sets/character-sets.xhtml +#[derive(Clone, PartialEq)] +pub struct Charset(Charset_); + +impl Charset { + /// US ASCII + pub const US_ASCII: Charset = Charset(Charset_::Us_Ascii); + + /// ISO-8859-1 + pub const ISO_8859_1: Charset = Charset(Charset_::Iso_8859_1); + + /// ISO-8859-2 + pub const ISO_8859_2: Charset = Charset(Charset_::Iso_8859_2); + + /// ISO-8859-3 + pub const ISO_8859_3: Charset = Charset(Charset_::Iso_8859_3); + + /// ISO-8859-4 + pub const ISO_8859_4: Charset = Charset(Charset_::Iso_8859_4); + + /// ISO-8859-5 + pub const ISO_8859_5: Charset = Charset(Charset_::Iso_8859_5); + + /// ISO-8859-6 + pub const ISO_8859_6: Charset = Charset(Charset_::Iso_8859_6); + + /// ISO-8859-7 + pub const ISO_8859_7: Charset = Charset(Charset_::Iso_8859_7); + + /// ISO-8859-8 + pub const ISO_8859_8: Charset = Charset(Charset_::Iso_8859_8); + + /// ISO-8859-9 + pub const ISO_8859_9: Charset = Charset(Charset_::Iso_8859_9); + + /// ISO-8859-10 + pub const ISO_8859_10: Charset = Charset(Charset_::Iso_8859_10); + + /// Shift_JIS + pub const SHIFT_JIS: Charset = Charset(Charset_::Shift_Jis); + + /// EUC-JP + pub const EUC_JP: Charset = Charset(Charset_::Euc_Jp); + + /// ISO-2022-KR + pub const ISO_2022_KR: Charset = Charset(Charset_::Iso_2022_Kr); + + /// EUC-KR + pub const EUC_KR: Charset: Charset(Charset_::Euc_Kr); + + /// ISO-2022-JP + pub const ISO_2022_JP: Charset = Charset(Charset_::Iso_2022_Jp); + + /// ISO-2022-JP-2 + pub const ISO_2022_JP_2: Charset = Charset(Charset_::Iso_2022_Jp_2); + + /// ISO-8859-6-E + pub const ISO_8859_6_E: Charset = Charset(Charset_::Iso_8859_6_E); + + /// ISO-8859-6-I + pub const ISO_8859_6_I: Charset = Charset(Charset_::Iso_8859_6_I); + + /// ISO-8859-8-E + pub const ISO_8859_8_E: Charset = Charset(Charset_::Iso_8859_8_E); + + /// ISO-8859-8-I + pub const ISO_8859_8_I: Charset = Charset(Charset_::Iso_8859_8_I); + + /// GB2312 + pub const GB_2312: Charset = Charset(Charset_::Gb2312); + + /// Big5 + pub const BIG_5: Charset = Charset(Charset_::Big5); + + /// KOI8-R + pub const KOI8_R: Charset = Charset(Charset_::Koi8_R); +} + +#[derive(Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +enum Charset_ { + /// US ASCII + Us_Ascii, + /// ISO-8859-1 + Iso_8859_1, + /// ISO-8859-2 + Iso_8859_2, + /// ISO-8859-3 + Iso_8859_3, + /// ISO-8859-4 + Iso_8859_4, + /// ISO-8859-5 + Iso_8859_5, + /// ISO-8859-6 + Iso_8859_6, + /// ISO-8859-7 + Iso_8859_7, + /// ISO-8859-8 + Iso_8859_8, + /// ISO-8859-9 + Iso_8859_9, + /// ISO-8859-10 + Iso_8859_10, + /// Shift_JIS + Shift_Jis, + /// EUC-JP + Euc_Jp, + /// ISO-2022-KR + Iso_2022_Kr, + /// EUC-KR + Euc_Kr, + /// ISO-2022-JP + Iso_2022_Jp, + /// ISO-2022-JP-2 + Iso_2022_Jp_2, + /// ISO-8859-6-E + Iso_8859_6_E, + /// ISO-8859-6-I + Iso_8859_6_I, + /// ISO-8859-8-E + Iso_8859_8_E, + /// ISO-8859-8-I + Iso_8859_8_I, + /// GB2312 + Gb2312, + /// Big5 + Big5, + /// KOI8-R + Koi8_R, + + _Unknown, +} + +impl Charset { + fn name(&self) -> &'static str { + match self.0 { + Charset_::Us_Ascii => "US-ASCII", + Charset_::Iso_8859_1 => "ISO-8859-1", + Charset_::Iso_8859_2 => "ISO-8859-2", + Charset_::Iso_8859_3 => "ISO-8859-3", + Charset_::Iso_8859_4 => "ISO-8859-4", + Charset_::Iso_8859_5 => "ISO-8859-5", + Charset_::Iso_8859_6 => "ISO-8859-6", + Charset_::Iso_8859_7 => "ISO-8859-7", + Charset_::Iso_8859_8 => "ISO-8859-8", + Charset_::Iso_8859_9 => "ISO-8859-9", + Charset_::Iso_8859_10 => "ISO-8859-10", + Charset_::Shift_Jis => "Shift-JIS", + Charset_::Euc_Jp => "EUC-JP", + Charset_::Iso_2022_Kr => "ISO-2022-KR", + Charset_::Euc_Kr => "EUC-KR", + Charset_::Iso_2022_Jp => "ISO-2022-JP", + Charset_::Iso_2022_Jp_2 => "ISO-2022-JP-2", + Charset_::Iso_8859_6_E => "ISO-8859-6-E", + Charset_::Iso_8859_6_I => "ISO-8859-6-I", + Charset_::Iso_8859_8_E => "ISO-8859-8-E", + Charset_::Iso_8859_8_I => "ISO-8859-8-I", + Charset_::Gb2312 => "GB2312", + Charset_::Big5 => "5", + Charset_::Koi8_R => "KOI8-R", + Charset_::_Unknown => unreachable!("Charset::_Unknown"), + } + } +} + +impl fmt::Display for Charset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.name()) + } +} + +#[derive(Debug)] +pub struct CharsetFromStrError(()); + +impl FromStr for Charset { + type Err = CharsetFromStrError; + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Charset(match s.to_ascii_uppercase().as_ref() { + "US-ASCII" => Charset_::Us_Ascii, + "ISO-8859-1" => Charset_::Iso_8859_1, + "ISO-8859-2" => Charset_::Iso_8859_2, + "ISO-8859-3" => Charset_::Iso_8859_3, + "ISO-8859-4" => Charset_::Iso_8859_4, + "ISO-8859-5" => Charset_::Iso_8859_5, + "ISO-8859-6" => Charset_::Iso_8859_6, + "ISO-8859-7" => Charset_::Iso_8859_7, + "ISO-8859-8" => Charset_::Iso_8859_8, + "ISO-8859-9" => Charset_::Iso_8859_9, + "ISO-8859-10" => Charset_::Iso_8859_10, + "SHIFT-JIS" => Charset_::Shift_Jis, + "EUC-JP" => Charset_::Euc_Jp, + "ISO-2022-KR" => Charset_::Iso_2022_Kr, + "EUC-KR" => Charset_::Euc_Kr, + "ISO-2022-JP" => Charset_::Iso_2022_Jp, + "ISO-2022-JP-2" => Charset_::Iso_2022_Jp_2, + "ISO-8859-6-E" => Charset_::Iso_8859_6_E, + "ISO-8859-6-I" => Charset_::Iso_8859_6_I, + "ISO-8859-8-E" => Charset_::Iso_8859_8_E, + "ISO-8859-8-I" => Charset_::Iso_8859_8_I, + "GB2312" => Charset_::Gb2312, + "5" => Charset_::Big5, + "KOI8-R" => Charset_::Koi8_R, + _unknown => return Err(CharsetFromStrError(())), + })) + } +} + +#[test] +fn test_parse() { + assert_eq!(Charset::US_ASCII,"us-ascii".parse().unwrap()); + assert_eq!(Charset::US_ASCII,"US-Ascii".parse().unwrap()); + assert_eq!(Charset::US_ASCII,"US-ASCII".parse().unwrap()); + assert_eq!(Charset::SHIFT_JIS,"Shift-JIS".parse().unwrap()); + assert!("abcd".parse(::<Charset>().is_err()); +} + +#[test] +fn test_display() { + assert_eq!("US-ASCII", format!("{}", Charset::US_ASCII)); +} diff --git a/third_party/rust/headers/src/disabled/util/encoding.rs b/third_party/rust/headers/src/disabled/util/encoding.rs new file mode 100644 index 0000000000..fc972dd3c7 --- /dev/null +++ b/third_party/rust/headers/src/disabled/util/encoding.rs @@ -0,0 +1,57 @@ +use std::fmt; +use std::str; + +pub use self::Encoding::{Chunked, Brotli, Gzip, Deflate, Compress, Identity, EncodingExt, Trailers}; + +/// A value to represent an encoding used in `Transfer-Encoding` +/// or `Accept-Encoding` header. +#[derive(Clone, PartialEq, Debug)] +pub enum Encoding { + /// The `chunked` encoding. + Chunked, + /// The `br` encoding. + Brotli, + /// The `gzip` encoding. + Gzip, + /// The `deflate` encoding. + Deflate, + /// The `compress` encoding. + Compress, + /// The `identity` encoding. + Identity, + /// The `trailers` encoding. + Trailers, + /// Some other encoding that is less common, can be any String. + EncodingExt(String) +} + +impl fmt::Display for Encoding { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match *self { + Chunked => "chunked", + Brotli => "br", + Gzip => "gzip", + Deflate => "deflate", + Compress => "compress", + Identity => "identity", + Trailers => "trailers", + EncodingExt(ref s) => s.as_ref() + }) + } +} + +impl str::FromStr for Encoding { + type Err = ::Error; + fn from_str(s: &str) -> ::Result<Encoding> { + match s { + "chunked" => Ok(Chunked), + "br" => Ok(Brotli), + "deflate" => Ok(Deflate), + "gzip" => Ok(Gzip), + "compress" => Ok(Compress), + "identity" => Ok(Identity), + "trailers" => Ok(Trailers), + _ => Ok(EncodingExt(s.to_owned())) + } + } +} diff --git a/third_party/rust/headers/src/disabled/util/extended_value.rs b/third_party/rust/headers/src/disabled/util/extended_value.rs new file mode 100644 index 0000000000..0098f6270c --- /dev/null +++ b/third_party/rust/headers/src/disabled/util/extended_value.rs @@ -0,0 +1,192 @@ +/// An extended header parameter value (i.e., tagged with a character set and optionally, +/// a language), as defined in [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2). +#[derive(Clone, Debug, PartialEq)] +pub struct ExtendedValue { + /// The character set that is used to encode the `value` to a string. + pub charset: Charset, + /// The human language details of the `value`, if available. + pub language_tag: Option<LanguageTag>, + /// The parameter value, as expressed in octets. + pub value: Vec<u8>, +} + +/// Parses extended header parameter values (`ext-value`), as defined in +/// [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2). +/// +/// Extended values are denoted by parameter names that end with `*`. +/// +/// ## ABNF +/// +/// ```text +/// ext-value = charset "'" [ language ] "'" value-chars +/// ; like RFC 2231's <extended-initial-value> +/// ; (see [RFC2231], Section 7) +/// +/// charset = "UTF-8" / "ISO-8859-1" / mime-charset +/// +/// mime-charset = 1*mime-charsetc +/// mime-charsetc = ALPHA / DIGIT +/// / "!" / "#" / "$" / "%" / "&" +/// / "+" / "-" / "^" / "_" / "`" +/// / "{" / "}" / "~" +/// ; as <mime-charset> in Section 2.3 of [RFC2978] +/// ; except that the single quote is not included +/// ; SHOULD be registered in the IANA charset registry +/// +/// language = <Language-Tag, defined in [RFC5646], Section 2.1> +/// +/// value-chars = *( pct-encoded / attr-char ) +/// +/// pct-encoded = "%" HEXDIG HEXDIG +/// ; see [RFC3986], Section 2.1 +/// +/// attr-char = ALPHA / DIGIT +/// / "!" / "#" / "$" / "&" / "+" / "-" / "." +/// / "^" / "_" / "`" / "|" / "~" +/// ; token except ( "*" / "'" / "%" ) +/// ``` +pub fn parse_extended_value(val: &str) -> ::Result<ExtendedValue> { + + // Break into three pieces separated by the single-quote character + let mut parts = val.splitn(3,'\''); + + // Interpret the first piece as a Charset + let charset: Charset = match parts.next() { + None => return Err(::Error::Header), + Some(n) => try!(FromStr::from_str(n)), + }; + + // Interpret the second piece as a language tag + let lang: Option<LanguageTag> = match parts.next() { + None => return Err(::Error::Header), + Some("") => None, + Some(s) => match s.parse() { + Ok(lt) => Some(lt), + Err(_) => return Err(::Error::Header), + } + }; + + // Interpret the third piece as a sequence of value characters + let value: Vec<u8> = match parts.next() { + None => return Err(::Error::Header), + Some(v) => percent_encoding::percent_decode(v.as_bytes()).collect(), + }; + + Ok(ExtendedValue { + charset: charset, + language_tag: lang, + value: value, + }) +} + + +impl Display for ExtendedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let encoded_value = + percent_encoding::percent_encode(&self.value[..], self::percent_encoding_http::HTTP_VALUE); + if let Some(ref lang) = self.language_tag { + write!(f, "{}'{}'{}", self.charset, lang, encoded_value) + } else { + write!(f, "{}''{}", self.charset, encoded_value) + } + } +} + +/// Percent encode a sequence of bytes with a character set defined in +/// [https://tools.ietf.org/html/rfc5987#section-3.2][url] +/// +/// [url]: https://tools.ietf.org/html/rfc5987#section-3.2 +pub fn http_percent_encode(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result { + let encoded = percent_encoding::percent_encode(bytes, self::percent_encoding_http::HTTP_VALUE); + fmt::Display::fmt(&encoded, f) +} + +mod percent_encoding_http { + use percent_encoding; + + // internal module because macro is hard-coded to make a public item + // but we don't want to public export this item + define_encode_set! { + // This encode set is used for HTTP header values and is defined at + // https://tools.ietf.org/html/rfc5987#section-3.2 + pub HTTP_VALUE = [percent_encoding::SIMPLE_ENCODE_SET] | { + ' ', '"', '%', '\'', '(', ')', '*', ',', '/', ':', ';', '<', '-', '>', '?', + '[', '\\', ']', '{', '}' + } + } +} + +#[cfg(test)] +mod tests { + use shared::Charset; + use super::{ExtendedValue, parse_extended_value}; + use language_tags::LanguageTag; + + #[test] + fn test_parse_extended_value_with_encoding_and_language_tag() { + let expected_language_tag = "en".parse::<LanguageTag>().unwrap(); + // RFC 5987, Section 3.2.2 + // Extended notation, using the Unicode character U+00A3 (POUND SIGN) + let result = parse_extended_value("iso-8859-1'en'%A3%20rates"); + assert!(result.is_ok()); + let extended_value = result.unwrap(); + assert_eq!(Charset::Iso_8859_1, extended_value.charset); + assert!(extended_value.language_tag.is_some()); + assert_eq!(expected_language_tag, extended_value.language_tag.unwrap()); + assert_eq!(vec![163, b' ', b'r', b'a', b't', b'e', b's'], extended_value.value); + } + + #[test] + fn test_parse_extended_value_with_encoding() { + // RFC 5987, Section 3.2.2 + // Extended notation, using the Unicode characters U+00A3 (POUND SIGN) + // and U+20AC (EURO SIGN) + let result = parse_extended_value("UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"); + assert!(result.is_ok()); + let extended_value = result.unwrap(); + assert_eq!(Charset::Ext("UTF-8".to_string()), extended_value.charset); + assert!(extended_value.language_tag.is_none()); + assert_eq!(vec![194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a', b't', b'e', b's'], extended_value.value); + } + + #[test] + fn test_parse_extended_value_missing_language_tag_and_encoding() { + // From: https://greenbytes.de/tech/tc2231/#attwithfn2231quot2 + let result = parse_extended_value("foo%20bar.html"); + assert!(result.is_err()); + } + + #[test] + fn test_parse_extended_value_partially_formatted() { + let result = parse_extended_value("UTF-8'missing third part"); + assert!(result.is_err()); + } + + #[test] + fn test_parse_extended_value_partially_formatted_blank() { + let result = parse_extended_value("blank second part'"); + assert!(result.is_err()); + } + + #[test] + fn test_fmt_extended_value_with_encoding_and_language_tag() { + let extended_value = ExtendedValue { + charset: Charset::Iso_8859_1, + language_tag: Some("en".parse().expect("Could not parse language tag")), + value: vec![163, b' ', b'r', b'a', b't', b'e', b's'], + }; + assert_eq!("ISO-8859-1'en'%A3%20rates", format!("{}", extended_value)); + } + + #[test] + fn test_fmt_extended_value_with_encoding() { + let extended_value = ExtendedValue { + charset: Charset::Ext("UTF-8".to_string()), + language_tag: None, + value: vec![194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a', + b't', b'e', b's'], + }; + assert_eq!("UTF-8''%C2%A3%20and%20%E2%82%AC%20rates", + format!("{}", extended_value)); + } +} diff --git a/third_party/rust/headers/src/disabled/util/quality_value.rs b/third_party/rust/headers/src/disabled/util/quality_value.rs new file mode 100644 index 0000000000..bcc797280d --- /dev/null +++ b/third_party/rust/headers/src/disabled/util/quality_value.rs @@ -0,0 +1,268 @@ +#[allow(unused, deprecated)] +use std::ascii::AsciiExt; +use std::cmp; +use std::default::Default; +use std::fmt; +use std::str; + +#[cfg(test)] +use self::internal::IntoQuality; + +/// Represents a quality used in quality values. +/// +/// Can be created with the `q` function. +/// +/// # Implementation notes +/// +/// The quality value is defined as a number between 0 and 1 with three decimal places. This means +/// there are 1001 possible values. Since floating point numbers are not exact and the smallest +/// floating point data type (`f32`) consumes four bytes, hyper uses an `u16` value to store the +/// quality internally. For performance reasons you may set quality directly to a value between +/// 0 and 1000 e.g. `Quality(532)` matches the quality `q=0.532`. +/// +/// [RFC7231 Section 5.3.1](https://tools.ietf.org/html/rfc7231#section-5.3.1) +/// gives more information on quality values in HTTP header fields. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct Quality(u16); + +impl Default for Quality { + fn default() -> Quality { + Quality(1000) + } +} + +/// Represents an item with a quality value as defined in +/// [RFC7231](https://tools.ietf.org/html/rfc7231#section-5.3.1). +#[derive(Clone, PartialEq, Debug)] +pub struct QualityValue<T> { + /// The actual contents of the field. + value: T, + /// The quality (client or server preference) for the value. + quality: Quality, +} + +impl<T> QualityValue<T> { + /// Creates a new `QualityValue` from an item and a quality. + pub fn new(value: T, quality: Quality) -> QualityValue<T> { + QualityValue { + value, + quality, + } + } + + /* + /// Convenience function to set a `Quality` from a float or integer. + /// + /// Implemented for `u16` and `f32`. + /// + /// # Panic + /// + /// Panics if value is out of range. + pub fn with_q<Q: IntoQuality>(mut self, q: Q) -> QualityValue<T> { + self.quality = q.into_quality(); + self + } + */ +} + +impl<T> From<T> for QualityValue<T> { + fn from(value: T) -> QualityValue<T> { + QualityValue { + value, + quality: Quality::default(), + } + } +} + +impl<T: PartialEq> cmp::PartialOrd for QualityValue<T> { + fn partial_cmp(&self, other: &QualityValue<T>) -> Option<cmp::Ordering> { + self.quality.partial_cmp(&other.quality) + } +} + +impl<T: fmt::Display> fmt::Display for QualityValue<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.value, f)?; + match self.quality.0 { + 1000 => Ok(()), + 0 => f.write_str("; q=0"), + x => write!(f, "; q=0.{}", format!("{:03}", x).trim_right_matches('0')) + } + } +} + +impl<T: str::FromStr> str::FromStr for QualityValue<T> { + type Err = ::Error; + fn from_str(s: &str) -> ::Result<QualityValue<T>> { + // Set defaults used if parsing fails. + let mut raw_item = s; + let mut quality = 1f32; + + let parts: Vec<&str> = s.rsplitn(2, ';').map(|x| x.trim()).collect(); + if parts.len() == 2 { + if parts[0].len() < 2 { + return Err(::Error::invalid()); + } + if parts[0].starts_with("q=") || parts[0].starts_with("Q=") { + let q_part = &parts[0][2..parts[0].len()]; + if q_part.len() > 5 { + return Err(::Error::invalid()); + } + match q_part.parse::<f32>() { + Ok(q_value) => { + if 0f32 <= q_value && q_value <= 1f32 { + quality = q_value; + raw_item = parts[1]; + } else { + return Err(::Error::invalid()); + } + }, + Err(_) => { + return Err(::Error::invalid()) + }, + } + } + } + match raw_item.parse::<T>() { + // we already checked above that the quality is within range + Ok(item) => Ok(QualityValue::new(item, from_f32(quality))), + Err(_) => { + Err(::Error::invalid()) + }, + } + } +} + +#[inline] +fn from_f32(f: f32) -> Quality { + // this function is only used internally. A check that `f` is within range + // should be done before calling this method. Just in case, this + // debug_assert should catch if we were forgetful + debug_assert!(f >= 0f32 && f <= 1f32, "q value must be between 0.0 and 1.0"); + Quality((f * 1000f32) as u16) +} + +#[cfg(test)] +fn q<T: IntoQuality>(val: T) -> Quality { + val.into_quality() +} + +mod internal { + use super::Quality; + + // TryFrom is probably better, but it's not stable. For now, we want to + // keep the functionality of the `q` function, while allowing it to be + // generic over `f32` and `u16`. + // + // `q` would panic before, so keep that behavior. `TryFrom` can be + // introduced later for a non-panicking conversion. + + pub trait IntoQuality: Sealed + Sized { + fn into_quality(self) -> Quality; + } + + impl IntoQuality for f32 { + fn into_quality(self) -> Quality { + assert!(self >= 0f32 && self <= 1f32, "float must be between 0.0 and 1.0"); + super::from_f32(self) + } + } + + impl IntoQuality for u16 { + fn into_quality(self) -> Quality { + assert!(self <= 1000, "u16 must be between 0 and 1000"); + Quality(self) + } + } + + + pub trait Sealed {} + impl Sealed for u16 {} + impl Sealed for f32 {} +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_quality_item_fmt_q_1() { + let x = QualityValue::from("foo"); + assert_eq!(format!("{}", x), "foo"); + } + #[test] + fn test_quality_item_fmt_q_0001() { + let x = QualityValue::new("foo", Quality(1)); + assert_eq!(format!("{}", x), "foo; q=0.001"); + } + #[test] + fn test_quality_item_fmt_q_05() { + let x = QualityValue::new("foo", Quality(500)); + assert_eq!(format!("{}", x), "foo; q=0.5"); + } + + #[test] + fn test_quality_item_fmt_q_0() { + let x = QualityValue::new("foo", Quality(0)); + assert_eq!(x.to_string(), "foo; q=0"); + } + + #[test] + fn test_quality_item_from_str1() { + let x: QualityValue<String> = "chunked".parse().unwrap(); + assert_eq!(x, QualityValue { value: "chunked".to_owned(), quality: Quality(1000), }); + } + #[test] + fn test_quality_item_from_str2() { + let x: QualityValue<String> = "chunked; q=1".parse().unwrap(); + assert_eq!(x, QualityValue { value: "chunked".to_owned(), quality: Quality(1000), }); + } + #[test] + fn test_quality_item_from_str3() { + let x: QualityValue<String> = "gzip; q=0.5".parse().unwrap(); + assert_eq!(x, QualityValue { value: "gzip".to_owned(), quality: Quality(500), }); + } + #[test] + fn test_quality_item_from_str4() { + let x: QualityValue<String> = "gzip; q=0.273".parse().unwrap(); + assert_eq!(x, QualityValue { value: "gzip".to_owned(), quality: Quality(273), }); + } + #[test] + fn test_quality_item_from_str5() { + assert!("gzip; q=0.2739999".parse::<QualityValue<String>>().is_err()); + } + + #[test] + fn test_quality_item_from_str6() { + assert!("gzip; q=2".parse::<QualityValue<String>>().is_err()); + } + #[test] + fn test_quality_item_ordering() { + let x: QualityValue<String> = "gzip; q=0.5".parse().unwrap(); + let y: QualityValue<String> = "gzip; q=0.273".parse().unwrap(); + assert!(x > y) + } + + #[test] + fn test_quality() { + assert_eq!(q(0.5), Quality(500)); + } + + #[test] + #[should_panic] + fn test_quality_invalid() { + q(-1.0); + } + + #[test] + #[should_panic] + fn test_quality_invalid2() { + q(2.0); + } + + #[test] + fn test_fuzzing_bugs() { + assert!("99999;".parse::<QualityValue<String>>().is_err()); + assert!("\x0d;;;=\u{d6aa}==".parse::<QualityValue<String>>().is_ok()) + } +} |