diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 013f6a576..4e3c153a0 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -325,6 +325,15 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hamcrest" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hex" version = "0.2.0" @@ -666,9 +675,32 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -688,6 +720,17 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.1.43" @@ -781,6 +824,7 @@ dependencies = [ "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "expectest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hamcrest 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)", "indextree 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1807,6 +1851,7 @@ dependencies = [ "checksum futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "0c84b40c7e2de99ffd70602db314a7a8c26b2b3d830e6f7f7a142a8860ab3ca4" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum hamcrest 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a70d66db6fd5a50b704eb55ce979bc5509d3a919d764bddec92f72a3e06ed7f6" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58" "checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" @@ -1847,8 +1892,11 @@ dependencies = [ "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" diff --git a/rust/pact_matching/Cargo.toml b/rust/pact_matching/Cargo.toml index 12b90914e..d92c1736b 100644 --- a/rust/pact_matching/Cargo.toml +++ b/rust/pact_matching/Cargo.toml @@ -44,3 +44,4 @@ default-features = false quickcheck = "0.4.1" expectest = "0.9.1" env_logger = "0.4.3" +hamcrest = "0.1.5" diff --git a/rust/pact_matching/src/generator_tests.rs b/rust/pact_matching/src/generator_tests.rs index 02f3ee4cc..d0db234b5 100644 --- a/rust/pact_matching/src/generator_tests.rs +++ b/rust/pact_matching/src/generator_tests.rs @@ -4,6 +4,7 @@ use models::{Request, Response, OptionalBody, DetectedContentType}; use models::generators::{JsonHandler, ContentTypeHandler}; use std::str::FromStr; use serde_json::Value; +use hamcrest::prelude::*; #[test] fn returns_original_response_if_there_are_no_generators() { @@ -299,3 +300,30 @@ fn applies_the_generator_to_the_object_graph_with_wildcard() { expect!(&json_handler.value["b"]).to(be_equal_to(&json!("B"))); expect!(&json_handler.value["c"]).to(be_equal_to(&json!("C"))); } + +#[test] +fn date_generator_test() { + let generated = Generator::Date(None).generate_value(&"".to_string()); + assert_that!(&generated.unwrap(), matches_regex(r"^\d{4}-\d{2}-\d{2}$")); + + let generated2 = Generator::Date(Some("yyyy-MM-ddZ".into())).generate_value(&"".to_string()); + assert_that!(&generated2.unwrap(), matches_regex(r"^\d{4}-\d{2}-\d{2}[-+]\d{4}$")); +} + +#[test] +fn time_generator_test() { + let generated = Generator::Time(None).generate_value(&"".to_string()); + assert_that!(&generated.unwrap(), matches_regex(r"^\d{2}:\d{2}:\d{2}$")); + + let generated2 = Generator::Time(Some("HH:mm:ssZ".into())).generate_value(&"".to_string()); + assert_that!(&generated2.unwrap(), matches_regex(r"^\d{2}:\d{2}:\d{2}[-+]\d+$")); +} + +#[test] +fn datetime_generator_test() { + let generated = Generator::DateTime(None).generate_value(&"".to_string()); + assert_that!(&generated.unwrap(), matches_regex(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[-+]\d+$")); + + let generated2 = Generator::DateTime(Some("yyyy-MM-dd HH:mm:ssZ".into())).generate_value(&"".to_string()); + assert_that!(&generated2.unwrap(), matches_regex(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[-+]\d+$")); +} diff --git a/rust/pact_matching/src/lib.rs b/rust/pact_matching/src/lib.rs index d07d434ff..37390b037 100644 --- a/rust/pact_matching/src/lib.rs +++ b/rust/pact_matching/src/lib.rs @@ -1045,6 +1045,7 @@ extern crate expectest; extern crate quickcheck; #[cfg(test)] extern crate env_logger; +#[cfg(test)] #[macro_use] extern crate hamcrest; #[cfg(test)] mod tests; diff --git a/rust/pact_matching/src/models/generators.rs b/rust/pact_matching/src/models/generators.rs index ecf1c6a94..c9ffce5a8 100644 --- a/rust/pact_matching/src/models/generators.rs +++ b/rust/pact_matching/src/models/generators.rs @@ -17,6 +17,9 @@ use sxd_document::dom::Document; use path_exp::*; use itertools::Itertools; use indextree::{Arena, NodeId}; +use chrono::prelude::*; +use time_utils::{parse_pattern, to_chrono_pattern}; +use nom::types::CompleteStr; /// Trait to represent a generator #[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Eq, Hash)] @@ -38,7 +41,7 @@ pub enum Generator { /// Generates a random time that matches either the provided format or the ISO format Time(Option), /// Generates a random timestamp that matches either the provided format or the ISO format - Timestamp(Option), + DateTime(Option), /// Generates a random boolean value RandomBoolean } @@ -61,9 +64,9 @@ impl Generator { &Some(ref format) => json!({ "type": "Time", "format": format }), &None => json!({ "type": "Time" }) }, - &Generator::Timestamp(ref format) => match format { - &Some(ref format) => json!({ "type": "Timestamp", "format": format }), - &None => json!({ "type": "Timestamp" }) + &Generator::DateTime(ref format) => match format { + &Some(ref format) => json!({ "type": "DateTime", "format": format }), + &None => json!({ "type": "DateTime" }) }, &Generator::RandomBoolean => json!({ "type": "RandomBoolean" }) } @@ -84,7 +87,7 @@ impl Generator { "Regex" => map.get("regex").map(|val| Generator::Regex(json_to_string(val))), "Date" => Some(Generator::Date(map.get("format").map(|f| json_to_string(f)))), "Time" => Some(Generator::Time(map.get("format").map(|f| json_to_string(f)))), - "Timestamp" => Some(Generator::Timestamp(map.get("format").map(|f| json_to_string(f)))), + "DateTime" => Some(Generator::DateTime(map.get("format").map(|f| json_to_string(f)))), "RandomBoolean" => Some(Generator::RandomBoolean), _ => { warn!("'{}' is not a valid generator type", gen_type); @@ -139,17 +142,35 @@ impl GenerateValue for Generator { warn!("Regex generator is not implemented"); None }, - &Generator::Date(ref _format) => { - warn!("Date generator is not implemented"); - None + &Generator::Date(ref format) => match format { + Some(pattern) => match parse_pattern(CompleteStr(pattern)) { + Ok(tokens) => Some(Local::now().date().format(&to_chrono_pattern(&tokens.1)).to_string()), + Err(err) => { + warn!("Date format {} is not valid - {}", pattern, err); + None + } + }, + None => Some(Local::now().naive_local().date().to_string()) }, - &Generator::Time(ref _format) => { - warn!("Time generator is not implemented"); - None + &Generator::Time(ref format) => match format { + Some(pattern) => match parse_pattern(CompleteStr(pattern)) { + Ok(tokens) => Some(Local::now().format(&to_chrono_pattern(&tokens.1)).to_string()), + Err(err) => { + warn!("Time format {} is not valid - {}", pattern, err); + None + } + }, + None => Some(Local::now().time().format("%H:%M:%S").to_string()) }, - &Generator::Timestamp(ref _format) => { - warn!("Timestamp generator is not implemented"); - None + &Generator::DateTime(ref format) => match format { + Some(pattern) => match parse_pattern(CompleteStr(pattern)) { + Ok(tokens) => Some(Local::now().format(&to_chrono_pattern(&tokens.1)).to_string()), + Err(err) => { + warn!("DateTime format {} is not valid - {}", pattern, err); + None + } + }, + None => Some(Local::now().format("%Y-%m-%dT%H:%M:%S.%3f%z").to_string()) }, &Generator::RandomBoolean => Some(format!("{}", rnd.gen::())) } @@ -191,17 +212,35 @@ impl GenerateValue for Generator { warn!("Regex generator is not implemented"); None }, - &Generator::Date(ref _format) => { - warn!("Date generator is not implemented"); - None + &Generator::Date(ref format) => match format { + Some(pattern) => match parse_pattern(CompleteStr(pattern)) { + Ok(tokens) => Some(json!(Local::now().date().format(&to_chrono_pattern(&tokens.1)).to_string())), + Err(err) => { + warn!("Date format {} is not valid - {}", pattern, err); + None + } + }, + None => Some(json!(Local::now().naive_local().date().to_string())) }, - &Generator::Time(ref _format) => { - warn!("Time generator is not implemented"); - None + &Generator::Time(ref format) => match format { + Some(pattern) => match parse_pattern(CompleteStr(pattern)) { + Ok(tokens) => Some(json!(Local::now().format(&to_chrono_pattern(&tokens.1)).to_string())), + Err(err) => { + warn!("Time format {} is not valid - {}", pattern, err); + None + } + }, + None => Some(json!(Local::now().time().format("%H:%M:%S").to_string())) }, - &Generator::Timestamp(ref _format) => { - warn!("Timestamp generator is not implemented"); - None + &Generator::DateTime(ref format) => match format { + Some(pattern) => match parse_pattern(CompleteStr(pattern)) { + Ok(tokens) => Some(json!(Local::now().format(&to_chrono_pattern(&tokens.1)).to_string())), + Err(err) => { + warn!("DateTime format {} is not valid - {}", pattern, err); + None + } + }, + None => Some(json!(Local::now().format("%Y-%m-%dT%H:%M:%S.%3f%z").to_string())) }, &Generator::RandomBoolean => Some(json!(rand::thread_rng().gen::())) } @@ -752,11 +791,11 @@ mod tests { } #[test] - fn timestamp_generator_from_json_test() { - expect!(Generator::from_map(&s!("Timestamp"), &serde_json::Map::new())).to(be_some().value(Generator::Timestamp(None))); - expect!(Generator::from_map(&s!("Timestamp"), &json!({ "min": 5 }).as_object().unwrap())).to(be_some().value(Generator::Timestamp(None))); - expect!(Generator::from_map(&s!("Timestamp"), &json!({ "format": "yyyy-MM-dd" }).as_object().unwrap())).to(be_some().value(Generator::Timestamp(Some(s!("yyyy-MM-dd"))))); - expect!(Generator::from_map(&s!("Timestamp"), &json!({ "format": 5 }).as_object().unwrap())).to(be_some().value(Generator::Timestamp(Some(s!("5"))))); + fn datetime_generator_from_json_test() { + expect!(Generator::from_map(&s!("DateTime"), &serde_json::Map::new())).to(be_some().value(Generator::DateTime(None))); + expect!(Generator::from_map(&s!("DateTime"), &json!({ "min": 5 }).as_object().unwrap())).to(be_some().value(Generator::DateTime(None))); + expect!(Generator::from_map(&s!("DateTime"), &json!({ "format": "yyyy-MM-dd" }).as_object().unwrap())).to(be_some().value(Generator::DateTime(Some(s!("yyyy-MM-dd"))))); + expect!(Generator::from_map(&s!("DateTime"), &json!({ "format": 5 }).as_object().unwrap())).to(be_some().value(Generator::DateTime(Some(s!("5"))))); } #[test] @@ -803,12 +842,12 @@ mod tests { expect!(Generator::Time(None).to_json()).to(be_equal_to(json!({ "type": "Time" }))); - expect!(Generator::Timestamp(Some(s!("yyyyMMdd"))).to_json()).to(be_equal_to(json!({ - "type": "Timestamp", + expect!(Generator::DateTime(Some(s!("yyyyMMdd"))).to_json()).to(be_equal_to(json!({ + "type": "DateTime", "format": "yyyyMMdd" }))); - expect!(Generator::Timestamp(None).to_json()).to(be_equal_to(json!({ - "type": "Timestamp" + expect!(Generator::DateTime(None).to_json()).to(be_equal_to(json!({ + "type": "DateTime" }))); } } diff --git a/rust/pact_matching/src/time_utils.rs b/rust/pact_matching/src/time_utils.rs index 8f6789f8e..4c6a42db6 100644 --- a/rust/pact_matching/src/time_utils.rs +++ b/rust/pact_matching/src/time_utils.rs @@ -6,14 +6,14 @@ use itertools::Itertools; pub enum DateTimePatternToken { Era, Year(usize), - Month, + Month(usize), Text(Vec), WeekInYear, WeekInMonth, DayInYear, DayInMonth, DayOfWeekInMonth, - DayName, + DayName(usize), DayOfWeek, AmPm, Hour24, @@ -102,10 +102,10 @@ named!(week_in_month_pattern , value!(DateTim named!(day_in_year_pattern , value!(DateTimePatternToken::DayInYear, many1!(char!('D')))); named!(day_in_month_pattern , value!(DateTimePatternToken::DayInMonth, many1!(char!('d')))); named!(day_of_week_in_month_pattern , value!(DateTimePatternToken::DayOfWeekInMonth, many1!(char!('F')))); -named!(day_name_pattern , value!(DateTimePatternToken::DayName, many1!(char!('E')))); +named!(day_name_pattern , do_parse!(d: is_a!("E") >> (DateTimePatternToken::DayName(d.len())))); named!(day_of_week_pattern , value!(DateTimePatternToken::DayOfWeek, many1!(char!('u')))); named!(year_pattern , do_parse!(y: is_a!("yY") >> (DateTimePatternToken::Year(y.len())) )); -named!(month_pattern , value!(DateTimePatternToken::Month, many1!(is_a!("ML")))); +named!(month_pattern , do_parse!(m: is_a!("ML") >> (DateTimePatternToken::Month(m.len())))); named!(text_pattern , do_parse!( t: many1!(none_of!("GyYMLwWdDFEu'akKhHmsSzZX")) >> (DateTimePatternToken::Text(t)) @@ -129,7 +129,7 @@ named!(millisecond_pattern , value!(DateTimeP named!(timezone_pattern , value!(DateTimePatternToken::Timezone, many1!(char!('z')))); named!(rfc_timezone_pattern , value!(DateTimePatternToken::Rfc822Timezone, many1!(char!('Z')))); named!(iso_timezone_pattern , value!(DateTimePatternToken::Iso8601Timezone, many1!(char!('X')))); -named!(parse_pattern >, do_parse!( +named!(pub parse_pattern >, do_parse!( v: many0!(alt!( era_pattern | year_pattern | @@ -217,10 +217,10 @@ fn validate_datetime_string<'a>(value: &String, pattern_tokens: &Vec week_in_month(buffer), DateTimePatternToken::DayInYear => day_in_year(buffer), DateTimePatternToken::DayInMonth => day_in_month(buffer), - DateTimePatternToken::Month => month(buffer), + DateTimePatternToken::Month(_m) => month(buffer), DateTimePatternToken::Text(t) => text(buffer, t), DateTimePatternToken::DayOfWeekInMonth => digit1(buffer), - DateTimePatternToken::DayName => day_of_week_name(buffer), + DateTimePatternToken::DayName(_d) => day_of_week_name(buffer), DateTimePatternToken::DayOfWeek => day_of_week(buffer), DateTimePatternToken::Hour24 => hour_24(buffer), DateTimePatternToken::Hour24ZeroBased => hour_24_0(buffer), @@ -251,13 +251,49 @@ pub fn validate_datetime(value: &String, format: &String) -> Result<(), String> } } +pub fn to_chrono_pattern(tokens: &Vec) -> String { + let mut buffer = String::new(); + + for token in tokens { + buffer.push_str(match token { + DateTimePatternToken::Era => "AD".into(), + DateTimePatternToken::Year(d) => if *d == 2 { "%y".into() } else { "%Y".into() }, + DateTimePatternToken::WeekInYear => "%U".into(), + DateTimePatternToken::WeekInMonth => { + warn!("Chono does not support week in month"); + "".into() + }, + DateTimePatternToken::DayInYear => "%j".into(), + DateTimePatternToken::DayInMonth => "%d".into(), + DateTimePatternToken::Month(d) => if *d <= 2 { "%m".into() } else if *d > 3 { "%B".into() } else { "%b".into() }, + DateTimePatternToken::Text(t) => t.iter().join("").replace("%", "%%").to_owned(), + DateTimePatternToken::DayOfWeekInMonth => { + warn!("Chono does not support day of week in month"); + "".into() + }, + DateTimePatternToken::DayName(d) => if *d > 3 { "%A".into() } else { "%a".into() }, + DateTimePatternToken::DayOfWeek => "%u".into(), + DateTimePatternToken::Hour24 => "%H".into(), + DateTimePatternToken::Hour24ZeroBased => "%H".into(), + DateTimePatternToken::Hour12 => "%I".into(), + DateTimePatternToken::Hour12ZeroBased => "%I".into(), + DateTimePatternToken::Minute => "%M".into(), + DateTimePatternToken::Second => "%S".into(), + DateTimePatternToken::Millisecond => "%3f".into(), + DateTimePatternToken::Timezone => "%:z".into(), + DateTimePatternToken::Rfc822Timezone => "%z".into(), + DateTimePatternToken::Iso8601Timezone => "%:z".into(), + DateTimePatternToken::AmPm => "%p".into() + }.as_str()); + } + + buffer +} + #[cfg(test)] mod tests { use super::*; use expectest::prelude::*; - use chrono::prelude::*; - use chrono::TimeZone; - use chrono_tz::Tz; #[test] fn parse_date_and_time() { @@ -334,11 +370,11 @@ mod tests { #[test] fn parse_month() { expect!(parse_pattern(CompleteStr("M"))).to( - be_ok().value((CompleteStr(""), vec![DateTimePatternToken::Month]))); + be_ok().value((CompleteStr(""), vec![DateTimePatternToken::Month(1)]))); expect!(parse_pattern(CompleteStr("MM"))).to( - be_ok().value((CompleteStr(""), vec![DateTimePatternToken::Month]))); + be_ok().value((CompleteStr(""), vec![DateTimePatternToken::Month(2)]))); expect!(parse_pattern(CompleteStr("LLL"))).to( - be_ok().value((CompleteStr(""), vec![DateTimePatternToken::Month]))); + be_ok().value((CompleteStr(""), vec![DateTimePatternToken::Month(3)]))); expect!(validate_datetime(&"jan".into(), &"M".into())).to(be_ok()); expect!(validate_datetime(&"october".into(), &"MMM".into())).to(be_ok()); @@ -403,7 +439,7 @@ mod tests { expect!(parse_pattern(CompleteStr("F"))).to( be_ok().value((CompleteStr(""), vec![DateTimePatternToken::DayOfWeekInMonth]))); expect!(parse_pattern(CompleteStr("EE"))).to( - be_ok().value((CompleteStr(""), vec![DateTimePatternToken::DayName]))); + be_ok().value((CompleteStr(""), vec![DateTimePatternToken::DayName(2)]))); expect!(parse_pattern(CompleteStr("u"))).to( be_ok().value((CompleteStr(""), vec![DateTimePatternToken::DayOfWeek]))); @@ -492,7 +528,21 @@ mod tests { expect!(validate_datetime(&"GMT-24:00".into(), &"z".into())).to(be_err()); expect!(validate_datetime(&"GMT+23:61".into(), &"z".into())).to(be_err()); expect!(validate_datetime(&"GMT+2351".into(), &"z".into())).to(be_err()); + } + #[test] + fn to_chrono_pattern_test() { + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("yyyy-MM-dd")).unwrap().1)).to(be_equal_to("%Y-%m-%d")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("yyyy-MM-dd HH:mm:ss")).unwrap().1)).to(be_equal_to("%Y-%m-%d %H:%M:%S")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("EEE, MMM d, ''yy")).unwrap().1)).to(be_equal_to("%a, %b %d, \'%y")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("h:mm a")).unwrap().1)).to(be_equal_to("%I:%M %p")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("hh 'o''clock' a, z")).unwrap().1)).to(be_equal_to("%I o'clock %p, %:z")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("yyyyy.MMMMM.dd GGG hh:mm aaa")).unwrap().1)).to(be_equal_to("%Y.%B.%d AD %I:%M %p")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("EEE, d MMM yyyy HH:mm:ss Z")).unwrap().1)).to(be_equal_to("%a, %d %b %Y %H:%M:%S %z")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("yyMMddHHmmssZ")).unwrap().1)).to(be_equal_to("%y%m%d%H%M%S%z")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).unwrap().1)).to(be_equal_to("%Y-%m-%dT%H:%M:%S.%3f%z")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")).unwrap().1)).to(be_equal_to("%Y-%m-%dT%H:%M:%S.%3f%:z")); + expect!(to_chrono_pattern(&parse_pattern(CompleteStr("YYYY-'W'ww-u")).unwrap().1)).to(be_equal_to("%Y-W%U-%u")); } }