diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3570335 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +# Contributing + +The `dtparse` crate is better for the contributions made by members of the open source community, +and seeks to make it easy to contribute back to the community it comes from. The goals are +fairly straight-forward, but here are the ways that would be most beneficial: + +## Bug Reports + +The testing suite for `dtparse` is built using tests derived from the [`dateutil`](https://github.com/dateutil/dateutil) +package in Python. Some Rust-specific behavior may show up though, for example in how +Rust handles nanoseconds where Python's standard library will only go to microseconds. + +If you believe that behavior is improper, you are encouraged to file an issue; there are no dumb +issues or suggestions, and the world is a better place for having your input. + +## Testing/Fuzzing + +`dtparse`'s history as a port of Python software has led to some behavior being shown in Rust +that would not otherwise be an issue in Python. Testing for these issues to prevent panics +is greatly appreciated, and some great work has already happened surrounding fuzzing. + +New test cases built either by fuzzers or humans are welcome. + +## Feature Requests + +Handling weird date formats and quirks is the name of the game. Any ideas on how to improve that +or utilities useful in handling the mapping of human time to computers is appreciated. + +Writing code to implement the feature is never mandatory (though always appreciated); if there's +something you believe `dtparse` should do that it doesn't currently support, let's make that happen. + +# Development Setup + +The setup requirements for `dtparse` should be fairly straightforward - the project can be built +and deployed using only the `cargo` tool in Rust. + +Much of the test coee is generated from Python code, and then the generated versions are stored +in version control. Thi is to ensure that all users can run the tests even without +installing Python or the other necessary packages. + +To regenerate the tests, please use Python 3.6 with the `dateutil` package installed, and run: + +- `python build_pycompat.py` +- `python build_pycompat_tokenizer.py` diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..344b4fe --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,6 @@ +This project benefits from the Rust and open source communities, but most specifically from these people: + +# Contributors: + +- [@messense](https://github.com/messense) +- [@mjmeehan](https://github.com/mjmeehan) \ No newline at end of file diff --git a/build_pycompat.py b/build_pycompat.py index a63cf54..4ea3ecb 100644 --- a/build_pycompat.py +++ b/build_pycompat.py @@ -222,7 +222,7 @@ fn parse_and_assert( fuzzy_with_tokens: bool, default: Option<&NaiveDateTime>, ignoretz: bool, - tzinfos: HashMap, + tzinfos: &HashMap, ) { let mut parser = Parser::new(info); @@ -272,7 +272,7 @@ fn parse_fuzzy_and_assert( fuzzy_with_tokens: bool, default: Option<&NaiveDateTime>, ignoretz: bool, - tzinfos: HashMap, + tzinfos: &HashMap, ) { let mut parser = Parser::new(info); @@ -316,7 +316,7 @@ fn test_parse_default{i}() {{ micros: {d.microsecond}, tzo: None }}; parse_and_assert(pdt, info, "{s}", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); }}\n''' TEST_PARSE_SIMPLE = ''' @@ -340,7 +340,7 @@ fn test_parse_tzinfo{i}() {{ micros: {d.microsecond}, tzo: Some({offset}), }}; parse_and_assert(pdt, info, "{s}", None, None, false, false, - None, false, rs_tzinfo_map!()); + None, false, &rs_tzinfo_map!()); }}\n''' TEST_PARSE_OFFSET = ''' @@ -353,7 +353,7 @@ fn test_parse_offset{i}() {{ micros: {d.microsecond}, tzo: Some({offset}), }}; parse_and_assert(pdt, info, "{s}", None, None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' TEST_PARSE_DAYFIRST = ''' @@ -366,7 +366,7 @@ fn test_parse_dayfirst{i}() {{ micros: {d.microsecond}, tzo: None, }}; parse_and_assert(pdt, info, "{s}", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' TEST_PARSE_YEARFIRST = ''' @@ -379,7 +379,7 @@ fn test_parse_yearfirst{i}() {{ micros: {d.microsecond}, tzo: None, }}; parse_and_assert(pdt, info, "{s}", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' TEST_PARSE_DFYF = ''' @@ -392,7 +392,7 @@ fn test_parse_dfyf{i}() {{ micros: {d.microsecond}, tzo: None, }}; parse_and_assert(pdt, info, "{s}", Some(true), Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' TEST_UNSPECIFIED_FALLBACK = ''' @@ -406,7 +406,7 @@ fn test_unspecified_fallback{i}() {{ micros: {d.microsecond}, tzo: None }}; parse_and_assert(pdt, info, "{s}", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); }}\n''' TEST_PARSE_IGNORETZ = ''' @@ -419,7 +419,7 @@ fn test_parse_ignoretz{i}() {{ micros: {d.microsecond}, tzo: None }}; parse_and_assert(pdt, info, "{s}", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); }}\n''' TEST_PARSE_DEFAULT_IGNORE = ''' @@ -434,7 +434,7 @@ fn test_parse_default_ignore{i}() {{ micros: {d.microsecond}, tzo: None }}; parse_and_assert(pdt, info, "{s}", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); }}\n''' TEST_FUZZY_TZINFO = ''' @@ -447,7 +447,7 @@ fn test_fuzzy_tzinfo{i}() {{ micros: {d.microsecond}, tzo: Some({offset}) }}; parse_fuzzy_and_assert(pdt, None, info, "{s}", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' TEST_FUZZY_TOKENS_TZINFO = ''' @@ -461,7 +461,7 @@ fn test_fuzzy_tokens_tzinfo{i}() {{ }}; let tokens = vec![{tokens}]; parse_fuzzy_and_assert(pdt, Some(tokens), info, "{s}", None, None, true, true, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' TEST_FUZZY_SIMPLE = ''' @@ -474,7 +474,7 @@ fn test_fuzzy_simple{i}() {{ micros: {d.microsecond}, tzo: None }}; parse_fuzzy_and_assert(pdt, None, info, "{s}", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); }}\n''' diff --git a/fuzz/.gitignore b/fuzz/.gitignore deleted file mode 100644 index dfeb7db..0000000 --- a/fuzz/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ - -target -libfuzzer -corpus -artifacts diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml deleted file mode 100644 index 0350800..0000000 --- a/fuzz/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ - -[package] -name = "dtparse-fuzz" -version = "0.0.1" -authors = ["Automatically generated"] -publish = false - -[package.metadata] -cargo-fuzz = true - -[dependencies.dtparse] -path = ".." -[dependencies.libfuzzer-sys] -git = "https://github.com/rust-fuzz/libfuzzer-sys.git" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[[bin]] -name = "fuzzer_script_1" -path = "fuzzers/fuzzer_script_1.rs" diff --git a/fuzz/fuzzers/fuzzer_script_1.rs b/fuzz/fuzzers/fuzzer_script_1.rs deleted file mode 100644 index 92cd04c..0000000 --- a/fuzz/fuzzers/fuzzer_script_1.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![no_main] -extern crate libfuzzer_sys; -extern crate dtparse; -use dtparse::parse; -#[export_name="rust_fuzzer_test_input"] -pub extern fn go(data: &[u8]) { - if let Ok(s) = std::str::from_utf8(data) { - parse(s); - } -} diff --git a/src/lib.rs b/src/lib.rs index 6589e89..fa21c7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,53 +39,34 @@ lazy_static! { static ref SIXTY: Decimal = Decimal::new(60, 0); } -#[derive(Debug, PartialEq)] -pub enum ParseInternalError { - // Errors that indicate internal bugs - YMDEarlyResolve, - YMDValueUnset(Vec), - ParseIndexError, - InvalidDecimal, - InvalidInteger, - - // Python-style errors - ValueError(String), -} - -impl From for ParseInternalError { - fn from(_err: DecimalError) -> Self { - ParseInternalError::InvalidDecimal +impl From for ParseError { + fn from(err: DecimalError) -> Self { + ParseError::InvalidNumeric(format!("{}", err)) } } -impl From for ParseInternalError { - fn from(_err: ParseIntError) -> Self { - ParseInternalError::InvalidInteger +impl From for ParseError { + fn from(err: ParseIntError) -> Self { + ParseError::InvalidNumeric(format!("{}", err)) } } #[derive(Debug, PartialEq)] pub enum ParseError { + AmbiguousYMD, AmbiguousWeekday, - InternalError(ParseInternalError), - InvalidMonth, - UnrecognizedToken(String), - InvalidParseResult(ParsingResult), AmPmWithoutHour, - TimezoneUnsupported, ImpossibleTimestamp(&'static str), -} - -impl From for ParseError { - fn from(err: ParseInternalError) -> Self { - ParseError::InternalError(err) - } + InvalidNumeric(String), + UnrecognizedFormat, + UnrecognizedToken(String), + TimezoneUnsupported, + YearMonthDayError(&'static str), } type ParseResult = Result; -type ParseIResult = Result; -pub fn tokenize(parse_string: &str) -> Vec { +pub(crate) fn tokenize(parse_string: &str) -> Vec { let tokenizer = Tokenizer::new(parse_string); tokenizer.collect() } @@ -268,13 +249,13 @@ fn days_in_month(year: i32, month: i32) -> Result { 1 | 3 | 5 | 7 | 8 | 10 | 12 => Ok(31), 4 | 6 | 9 | 11 => Ok(30), _ => { - Err(ParseError::InvalidMonth) + Err(ParseError::ImpossibleTimestamp("Invalid month")) } } } #[derive(Debug, Hash, PartialEq, Eq)] -pub enum YMDLabel { +enum YMDLabel { Year, Month, Day, @@ -311,7 +292,7 @@ impl YMD { } } - fn append(&mut self, val: i32, token: &str, label: Option) -> ParseIResult<()> { + fn append(&mut self, val: i32, token: &str, label: Option) -> ParseResult<()> { let mut label = label; // Python auto-detects strings using the '__len__' function here. @@ -320,12 +301,11 @@ impl YMD { self.century_specified = true; match label { None | Some(YMDLabel::Year) => label = Some(YMDLabel::Year), - _ => { - return Err(ParseInternalError::ValueError(format!( - "Invalid label {:?} for token {:?}", - label, - token - ))) + Some(YMDLabel::Month) => { + return Err(ParseError::ImpossibleTimestamp("Invalid month")) + } + Some(YMDLabel::Day) => { + return Err(ParseError::ImpossibleTimestamp("Invalid day")) } } } @@ -335,12 +315,11 @@ impl YMD { match label { None => label = Some(YMDLabel::Year), Some(YMDLabel::Year) => (), - _ => { - return Err(ParseInternalError::ValueError(format!( - "Invalid label {:?} for token {:?}", - label, - token - ))) + Some(YMDLabel::Month) => { + return Err(ParseError::ImpossibleTimestamp("Invalid month")) + } + Some(YMDLabel::Day) => { + return Err(ParseError::ImpossibleTimestamp("Invalid day")) } } } @@ -350,9 +329,7 @@ impl YMD { match label { Some(YMDLabel::Month) => { if self.mstridx.is_some() { - Err(ParseInternalError::ValueError( - "Month already set.".to_owned(), - )) + Err(ParseError::YearMonthDayError("Month already set")) } else { self.mstridx = Some(self._ymd.len() - 1); Ok(()) @@ -360,9 +337,7 @@ impl YMD { } Some(YMDLabel::Day) => { if self.dstridx.is_some() { - Err(ParseInternalError::ValueError( - "Day already set.".to_owned(), - )) + Err(ParseError::YearMonthDayError("Day already set")) } else { self.dstridx = Some(self._ymd.len() - 1); Ok(()) @@ -370,9 +345,7 @@ impl YMD { } Some(YMDLabel::Year) => { if self.ystridx.is_some() { - Err(ParseInternalError::ValueError( - "Year already set.".to_owned(), - )) + Err(ParseError::YearMonthDayError("Year already set")) } else { self.ystridx = Some(self._ymd.len() - 1); Ok(()) @@ -385,7 +358,7 @@ impl YMD { fn resolve_from_stridxs( &mut self, strids: &mut HashMap, - ) -> ParseIResult<(Option, Option, Option)> { + ) -> ParseResult<(Option, Option, Option)> { if self._ymd.len() == 3 && strids.len() == 2 { let missing_key = if !strids.contains_key(&YMDLabel::Year) { YMDLabel::Year @@ -408,7 +381,7 @@ impl YMD { } if self._ymd.len() != strids.len() { - return Err(ParseInternalError::YMDEarlyResolve); + return Err(ParseError::YearMonthDayError("Tried to resolve year, month, and day without enough information")); } Ok(( @@ -428,7 +401,7 @@ impl YMD { &mut self, yearfirst: bool, dayfirst: bool, - ) -> ParseIResult<(Option, Option, Option)> { + ) -> ParseResult<(Option, Option, Option)> { let len_ymd = self._ymd.len(); let mut strids: HashMap = HashMap::new(); @@ -446,10 +419,9 @@ impl YMD { return self.resolve_from_stridxs(&mut strids); }; + // Received year, month, day, and ??? if len_ymd > 3 { - return Err(ParseInternalError::ValueError( - "More than three YMD values".to_owned(), - )); + return Err(ParseError::YearMonthDayError("Received extra tokens in resolving year, month, and day")); } match (len_ymd, self.mstridx) { @@ -515,7 +487,7 @@ impl YMD { } #[derive(Default, Debug, PartialEq)] -pub struct ParsingResult { +struct ParsingResult { year: Option, month: Option, day: Option, @@ -550,7 +522,7 @@ impl Parser { fuzzy_with_tokens: bool, default: Option<&NaiveDateTime>, ignoretz: bool, - tzinfos: HashMap, + tzinfos: &HashMap, ) -> ParseResult<(NaiveDateTime, Option, Option>)> { let default_date = default.unwrap_or(&Local::now().naive_local()).date(); @@ -725,7 +697,7 @@ impl Parser { res.day = day; if !self.info.validate(&mut res) { - Err(ParseError::InvalidParseResult(res)) + Err(ParseError::UnrecognizedFormat) } else if fuzzy_with_tokens { let skipped_tokens = self.recombine_skipped(skipped_idxs, l); Ok((res, Some(skipped_tokens))) @@ -823,7 +795,7 @@ impl Parser { &self, _dt: &NaiveDateTime, res: &ParsingResult, - tzinfos: HashMap, + tzinfos: &HashMap, ) -> ParseResult> { // TODO: Actual timezone support if let Some(offset) = res.tzoffset { @@ -854,7 +826,7 @@ impl Parser { ymd: &mut YMD, res: &mut ParsingResult, fuzzy: bool, - ) -> Result { + ) -> ParseResult { let mut idx = idx; let value_repr = &tokens[idx]; let mut value = Decimal::from_str(&value_repr).unwrap(); @@ -955,7 +927,7 @@ impl Parser { if let Ok(val) = tokens[idx + 4].parse::() { ymd.append(val, &tokens[idx + 4], None)?; } else { - return Err(ParseInternalError::ValueError("Unknown string format".to_owned())); + return Err(ParseError::UnrecognizedFormat); } } @@ -987,7 +959,7 @@ impl Parser { } else if ymd.could_be_day(value.to_i64().unwrap() as i32) { ymd.append(value.to_i64().unwrap() as i32, &value_repr, None)?; } else if !fuzzy { - return Err(ParseInternalError::ValueError("".to_owned())); + return Err(ParseError::UnrecognizedFormat); } Ok(idx) @@ -1003,7 +975,7 @@ impl Parser { } } - fn parsems(&self, seconds_str: &str) -> Result<(i32, i32), ParseInternalError> { + fn parsems(&self, seconds_str: &str) -> ParseResult<(i32, i32)> { if seconds_str.contains(".") { let split: Vec<&str> = seconds_str.split(".").collect(); let (i, f): (&str, &str) = (split[0], split[1]); @@ -1159,7 +1131,7 @@ pub fn parse(timestr: &str) -> ParseResult<(NaiveDateTime, Option)> false, None, false, - HashMap::new(), + &HashMap::new(), )?; Ok((res.0, res.1)) diff --git a/src/tests/fuzzing.rs b/src/tests/fuzzing.rs index e204d17..dc6e15a 100644 --- a/src/tests/fuzzing.rs +++ b/src/tests/fuzzing.rs @@ -3,21 +3,21 @@ use std::collections::HashMap; use parse; use ParseError; -use ParseInternalError; use Parser; #[test] fn test_fuzz() { - assert_eq!(parse("\x2D\x38\x31\x39\x34\x38\x34"), Err(ParseError::InvalidMonth)); + assert_eq!(parse("\x2D\x38\x31\x39\x34\x38\x34"), Err(ParseError::ImpossibleTimestamp("Invalid month"))); + // Garbage in the third delimited field assert_eq!(parse("2..\x00\x000d\x00+\x010d\x01\x00\x00\x00+"), - Err(ParseError::InternalError(ParseInternalError::ValueError("Unknown string format".to_owned())))); + Err(ParseError::UnrecognizedFormat)); // OverflowError: Python int too large to convert to C long // assert_eq!(parse("8888884444444888444444444881"), Err(ParseError::AmPmWithoutHour)); let default = NaiveDate::from_ymd(2016, 6, 29).and_hms(0, 0, 0); let mut p = Parser::default(); - let res = p.parse("\x0D\x31", None, None, false, false, Some(&default), false, HashMap::new()).unwrap(); + let res = p.parse("\x0D\x31", None, None, false, false, Some(&default), false, &HashMap::new()).unwrap(); assert_eq!(res.0, default); assert_eq!(parse("\x2D\x2D\x32\x31\x38\x6D"), Err(ParseError::ImpossibleTimestamp("Invalid minute"))); diff --git a/src/tests/pycompat_parser.rs b/src/tests/pycompat_parser.rs index 624ee7d..485bfa1 100644 --- a/src/tests/pycompat_parser.rs +++ b/src/tests/pycompat_parser.rs @@ -32,7 +32,7 @@ fn parse_and_assert( fuzzy_with_tokens: bool, default: Option<&NaiveDateTime>, ignoretz: bool, - tzinfos: HashMap, + tzinfos: &HashMap, ) { let mut parser = Parser::new(info); @@ -82,7 +82,7 @@ fn parse_fuzzy_and_assert( fuzzy_with_tokens: bool, default: Option<&NaiveDateTime>, ignoretz: bool, - tzinfos: HashMap, + tzinfos: &HashMap, ) { let mut parser = Parser::new(info); @@ -125,7 +125,7 @@ fn test_parse_default0() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Thu Sep 25 10:36:28", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -138,7 +138,7 @@ fn test_parse_default1() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Sep 10:36:28", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -151,7 +151,7 @@ fn test_parse_default2() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:36:28", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -164,7 +164,7 @@ fn test_parse_default3() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:36", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -177,7 +177,7 @@ fn test_parse_default4() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Sep 2003", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -190,7 +190,7 @@ fn test_parse_default5() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Sep", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -203,7 +203,7 @@ fn test_parse_default6() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "2003", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -216,7 +216,7 @@ fn test_parse_default7() { micros: 500000, tzo: None }; parse_and_assert(pdt, info, "10h36m28.5s", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -229,7 +229,7 @@ fn test_parse_default8() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10h36m28s", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -242,7 +242,7 @@ fn test_parse_default9() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10h36m", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -255,7 +255,7 @@ fn test_parse_default10() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10h", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -268,7 +268,7 @@ fn test_parse_default11() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10 h 36", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -281,7 +281,7 @@ fn test_parse_default12() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10 h 36.5", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -294,7 +294,7 @@ fn test_parse_default13() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "36 m 5", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -307,7 +307,7 @@ fn test_parse_default14() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "36 m 5 s", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -320,7 +320,7 @@ fn test_parse_default15() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "36 m 05", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -333,7 +333,7 @@ fn test_parse_default16() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "36 m 05 s", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -346,7 +346,7 @@ fn test_parse_default17() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10h am", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -359,7 +359,7 @@ fn test_parse_default18() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10h pm", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -372,7 +372,7 @@ fn test_parse_default19() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10am", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -385,7 +385,7 @@ fn test_parse_default20() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10pm", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -398,7 +398,7 @@ fn test_parse_default21() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00 am", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -411,7 +411,7 @@ fn test_parse_default22() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00 pm", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -424,7 +424,7 @@ fn test_parse_default23() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00am", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -437,7 +437,7 @@ fn test_parse_default24() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00pm", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -450,7 +450,7 @@ fn test_parse_default25() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00a.m", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -463,7 +463,7 @@ fn test_parse_default26() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00p.m", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -476,7 +476,7 @@ fn test_parse_default27() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00a.m.", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -489,7 +489,7 @@ fn test_parse_default28() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "10:00p.m.", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -502,7 +502,7 @@ fn test_parse_default29() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "October", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -515,7 +515,7 @@ fn test_parse_default30() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "31-Dec-00", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -528,7 +528,7 @@ fn test_parse_default31() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "0:01:02", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -541,7 +541,7 @@ fn test_parse_default32() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "12h 01m02s am", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -554,7 +554,7 @@ fn test_parse_default33() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "12:08 PM", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -567,7 +567,7 @@ fn test_parse_default34() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "01h02m03", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -580,7 +580,7 @@ fn test_parse_default35() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "01h02", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -593,7 +593,7 @@ fn test_parse_default36() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "01h02s", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -606,7 +606,7 @@ fn test_parse_default37() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "01m02", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -619,7 +619,7 @@ fn test_parse_default38() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "01m02h", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -632,7 +632,7 @@ fn test_parse_default39() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "2004 10 Apr 11h30m", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -645,7 +645,7 @@ fn test_parse_default40() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Sep 03", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -658,7 +658,7 @@ fn test_parse_default41() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Sep of 03", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -671,7 +671,7 @@ fn test_parse_default42() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "02:17NOV2017", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -684,7 +684,7 @@ fn test_parse_default43() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Thu Sep 10:36:28", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -697,7 +697,7 @@ fn test_parse_default44() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Thu 10:36:28", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -710,7 +710,7 @@ fn test_parse_default45() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Wed", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -723,7 +723,7 @@ fn test_parse_default46() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Wednesday", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -1355,7 +1355,7 @@ fn test_parse_tzinfo0() { micros: 0, tzo: Some(-10800), }; parse_and_assert(pdt, info, "Thu Sep 25 10:36:28 BRST 2003", None, None, false, false, - None, false, rs_tzinfo_map!()); + None, false, &rs_tzinfo_map!()); } #[test] @@ -1367,7 +1367,7 @@ fn test_parse_tzinfo1() { micros: 0, tzo: Some(-10800), }; parse_and_assert(pdt, info, "2003 10:36:28 BRST 25 Sep Thu", None, None, false, false, - None, false, rs_tzinfo_map!()); + None, false, &rs_tzinfo_map!()); } #[test] @@ -1379,7 +1379,7 @@ fn test_parse_offset0() { micros: 0, tzo: Some(-10800), }; parse_and_assert(pdt, info, "Thu, 25 Sep 2003 10:49:41 -0300", None, None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1391,7 +1391,7 @@ fn test_parse_offset1() { micros: 500000, tzo: Some(-10800), }; parse_and_assert(pdt, info, "2003-09-25T10:49:41.5-03:00", None, None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1403,7 +1403,7 @@ fn test_parse_offset2() { micros: 0, tzo: Some(-10800), }; parse_and_assert(pdt, info, "2003-09-25T10:49:41-03:00", None, None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1415,7 +1415,7 @@ fn test_parse_offset3() { micros: 500000, tzo: Some(-10800), }; parse_and_assert(pdt, info, "20030925T104941.5-0300", None, None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1427,7 +1427,7 @@ fn test_parse_offset4() { micros: 0, tzo: Some(-10800), }; parse_and_assert(pdt, info, "20030925T104941-0300", None, None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1439,7 +1439,7 @@ fn test_parse_dayfirst0() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10-09-2003", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1451,7 +1451,7 @@ fn test_parse_dayfirst1() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10.09.2003", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1463,7 +1463,7 @@ fn test_parse_dayfirst2() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10/09/2003", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1475,7 +1475,7 @@ fn test_parse_dayfirst3() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10 09 2003", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1487,7 +1487,7 @@ fn test_parse_dayfirst4() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "090107", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1499,7 +1499,7 @@ fn test_parse_dayfirst5() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "2015 09 25", Some(true), None, false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1511,7 +1511,7 @@ fn test_parse_yearfirst0() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10-09-03", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1523,7 +1523,7 @@ fn test_parse_yearfirst1() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10.09.03", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1535,7 +1535,7 @@ fn test_parse_yearfirst2() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10/09/03", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1547,7 +1547,7 @@ fn test_parse_yearfirst3() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "10 09 03", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1559,7 +1559,7 @@ fn test_parse_yearfirst4() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "090107", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1571,7 +1571,7 @@ fn test_parse_yearfirst5() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "2015 09 25", None, Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1583,7 +1583,7 @@ fn test_parse_dfyf0() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "090107", Some(true), Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1595,7 +1595,7 @@ fn test_parse_dfyf1() { micros: 0, tzo: None, }; parse_and_assert(pdt, info, "2015 09 25", Some(true), Some(true), false, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1608,7 +1608,7 @@ fn test_unspecified_fallback0() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "April 2009", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -1621,7 +1621,7 @@ fn test_unspecified_fallback1() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Feb 2007", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -1634,7 +1634,7 @@ fn test_unspecified_fallback2() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Feb 2008", None, None, false, false, - Some(default_rsdate), false, HashMap::new()); + Some(default_rsdate), false, &HashMap::new()); } #[test] @@ -1646,7 +1646,7 @@ fn test_parse_ignoretz0() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Thu Sep 25 10:36:28 BRST 2003", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1658,7 +1658,7 @@ fn test_parse_ignoretz1() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "1996.07.10 AD at 15:08:56 PDT", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1670,7 +1670,7 @@ fn test_parse_ignoretz2() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Tuesday, April 12, 1952 AD 3:30:42pm PST", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1682,7 +1682,7 @@ fn test_parse_ignoretz3() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "November 5, 1994, 8:15:30 am EST", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1694,7 +1694,7 @@ fn test_parse_ignoretz4() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "1994-11-05T08:15:30-05:00", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1706,7 +1706,7 @@ fn test_parse_ignoretz5() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "1994-11-05T08:15:30Z", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1718,7 +1718,7 @@ fn test_parse_ignoretz6() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "1976-07-04T00:01:02Z", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1730,7 +1730,7 @@ fn test_parse_ignoretz7() { micros: 0, tzo: None }; parse_and_assert(pdt, info, "Tue Apr 4 00:22:12 PDT 1995", None, None, false, false, - None, true, HashMap::new()); + None, true, &HashMap::new()); } #[test] @@ -1742,7 +1742,7 @@ fn test_fuzzy_tzinfo0() { micros: 0, tzo: Some(-10800) }; parse_fuzzy_and_assert(pdt, None, info, "Today is 25 of September of 2003, exactly at 10:49:41 with timezone -03:00.", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1755,7 +1755,7 @@ fn test_fuzzy_tokens_tzinfo0() { }; let tokens = vec!["Today is ".to_owned(), "of ".to_owned(), ", exactly at ".to_owned(), " with timezone ".to_owned(), ".".to_owned()]; parse_fuzzy_and_assert(pdt, Some(tokens), info, "Today is 25 of September of 2003, exactly at 10:49:41 with timezone -03:00.", None, None, true, true, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1767,7 +1767,7 @@ fn test_fuzzy_simple0() { micros: 0, tzo: None }; parse_fuzzy_and_assert(pdt, None, info, "I have a meeting on March 1, 1974", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1779,7 +1779,7 @@ fn test_fuzzy_simple1() { micros: 0, tzo: None }; parse_fuzzy_and_assert(pdt, None, info, "On June 8th, 2020, I am going to be the first man on Mars", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1791,7 +1791,7 @@ fn test_fuzzy_simple2() { micros: 0, tzo: None }; parse_fuzzy_and_assert(pdt, None, info, "Meet me at the AM/PM on Sunset at 3:00 AM on December 3rd, 2003", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1803,7 +1803,7 @@ fn test_fuzzy_simple3() { micros: 0, tzo: None }; parse_fuzzy_and_assert(pdt, None, info, "Meet me at 3:00 AM on December 3rd, 2003 at the AM/PM on Sunset", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1815,7 +1815,7 @@ fn test_fuzzy_simple4() { micros: 0, tzo: None }; parse_fuzzy_and_assert(pdt, None, info, "Jan 29, 1945 14:45 AM I going to see you there?", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } #[test] @@ -1827,5 +1827,5 @@ fn test_fuzzy_simple5() { micros: 0, tzo: None }; parse_fuzzy_and_assert(pdt, None, info, "2017-07-17 06:15:", None, None, true, false, - None, false, HashMap::new()); + None, false, &HashMap::new()); } diff --git a/src/weekday.rs b/src/weekday.rs index f874fcf..68d4773 100644 --- a/src/weekday.rs +++ b/src/weekday.rs @@ -64,7 +64,7 @@ pub fn day_of_week(year: u32, month: u32, day: u32) -> ParseResult { let c = (year - 1) / 100; (c, year - 1 - 100 * c) }, - _ => return Err(ParseError::InvalidMonth) + _ => return Err(ParseError::ImpossibleTimestamp("Invalid month")) }; let e = match month {