@@ -252,7 +252,7 @@ pub(crate) mod function {
252252 ///
253253 /// The goal is to only accept inputs that _unambiguously_ look like
254254 /// git's raw date format.
255- pub fn parse_raw ( input : & str ) -> Option < Time > {
255+ fn parse_raw ( input : & str ) -> Option < Time > {
256256 let mut split = input. split_whitespace ( ) ;
257257 let seconds = split. next ( ) ?. parse :: < SecondsSinceUnixEpoch > ( ) . ok ( ) ?;
258258 let offset_str = split. next ( ) ?;
@@ -279,7 +279,7 @@ pub(crate) mod function {
279279 return None ;
280280 }
281281 let offset: i32 = sign * ( ( hours as i32 ) * 3600 + ( minutes as i32 ) * 60 ) ;
282- Some ( Time { seconds, offset } )
282+ Time { seconds, offset } . into ( )
283283 }
284284
285285 /// This is just like `Zoned::strptime`, but it allows parsing datetimes
@@ -298,6 +298,75 @@ pub(crate) mod function {
298298 static P : rfc2822:: DateTimeParser = rfc2822:: DateTimeParser :: new ( ) . relaxed_weekday ( true ) ;
299299 P . parse_zoned ( input)
300300 }
301+
302+ #[ cfg( test) ]
303+ mod tests {
304+ use super :: * ;
305+
306+ #[ test]
307+ fn parse_raw_valid ( ) {
308+ // These examples show how it's more loose than it has to be,
309+ // merely as a side effect of the implementation.
310+ for ( valid, expected_seconds, expected_offset) in [
311+ ( "12345 +0000" , 12345 , 0 ) ,
312+ ( "-1234567 +0000" , -1234567 , 0 ) ,
313+ ( "+1234567 -000000" , 1234567 , 0 ) ,
314+ ( " +0 -000000 " , 0 , 0 ) ,
315+ ( "\t -0\t -0000\t " , 0 , 0 ) ,
316+ ( "\n -0\r \n -0000\n " , 0 , 0 ) ,
317+ ] {
318+ assert_eq ! (
319+ parse_raw( valid) ,
320+ Some ( Time {
321+ seconds: expected_seconds,
322+ offset: expected_offset
323+ } ) ,
324+ "should succeed: '{valid}'"
325+ ) ;
326+ }
327+ }
328+
329+ #[ test]
330+ fn parse_raw_invalid ( ) {
331+ for ( bad_date_str, message) in [
332+ ( "123456 !0600" , "invalid sign - must be + or -" ) ,
333+ ( "123456 0600" , "missing offset sign" ) ,
334+ ( "123456 +060" , "positive offset too short" ) ,
335+ ( "123456 -060" , "negative offset too short" ) ,
336+ ( "123456 +06000" , "not enough offset seconds" ) ,
337+ ( "123456 --060" , "duplicate offset sign with correct offset length" ) ,
338+ ( "123456 -+060" , "multiple offset signs with correct offset length" ) ,
339+ ( "123456 --0600" , "multiple offset signs, but incorrect offset length" ) ,
340+ ( "123456 +-06000" , "multiple offset signs with correct offset length" ) ,
341+ ( "123456 +-0600" , "multiple offset signs with incorrect offset length" ) ,
342+ ( "123456 +-060" , "multiple offset signs with correct offset length" ) ,
343+ ( "123456 +10030" , "invalid offset length with one 'second' field" ) ,
344+ ( "123456 06000" , "invalid offset length, missing sign" ) ,
345+ ( "123456 +0600 extra" , "extra field past offset" ) ,
346+ ( "123456 +0600 2005" , "extra field past offset that looks like year" ) ,
347+ ( "123456+0600" , "missing space between unix timestamp and offset" ) ,
348+ (
349+ "123456 + 600" ,
350+ "extra spaces between sign and offset (which also is too short)" ,
351+ ) ,
352+ ( "123456 -1500" , "negative offset hours out of bounds" ) ,
353+ ( "123456 +1500" , "positive offset hours out of bounds" ) ,
354+ ( "123456 +6600" , "positive offset hours out of bounds" ) ,
355+ ( "123456 +0660" , "invalid offset minutes" ) ,
356+ ( "123456 +060010" , "positive offset seconds is allowed but only if zero" ) ,
357+ ( "123456 -060010" , "negative offset seconds is allowed but only if zero" ) ,
358+ ( "123456 +0075" , "positive offset minutes invalid" ) ,
359+ ( "++123456 +0000" , "duplicate timestamp sign" ) ,
360+ ( "--123456 +0000" , "duplicate timestamp sign" ) ,
361+ ( "1234567 -+1+1+0" , "unsigned offset parsing rejects '+'" ) ,
362+ ] {
363+ assert ! (
364+ parse_raw( bad_date_str) . is_none( ) ,
365+ "should fail: '{bad_date_str}': {message}"
366+ ) ;
367+ }
368+ }
369+ }
301370}
302371
303372mod relative {
0 commit comments