Skip to content

Commit c239ed0

Browse files
authored
Merge pull request #238 from stillbeingnick/bugfix/issue/coreutils-date-invalid
Changing ErrMode::Cut to ErrMode::Backtrack to allow alt parser flow (Fix for uutils/coreutils issue 8754)
2 parents 29e3686 + 3074fe3 commit c239ed0

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

src/items/date.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,10 @@ pub(super) fn iso1(input: &mut &str) -> ModalResult<Date> {
138138
let (year, _, month, _, day) =
139139
(year_str, s('-'), s(dec_uint), s('-'), s(dec_uint)).parse_next(input)?;
140140

141+
// Map err to Backtrack instead of Cut to avoid early termination of parsing
141142
(year, month, day)
142143
.try_into()
143-
.map_err(|e| ErrMode::Cut(ctx_err(e)))
144+
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
144145
}
145146

146147
/// Parse `[year][month][day]`
@@ -156,7 +157,7 @@ pub(super) fn iso2(input: &mut &str) -> ModalResult<Date> {
156157

157158
(year, month, day)
158159
.try_into()
159-
.map_err(|e| ErrMode::Cut(ctx_err(e)))
160+
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
160161
}
161162

162163
/// Parse `[year]/[month]/[day]` or `[month]/[day]/[year]` or `[month]/[day]`.
@@ -178,19 +179,21 @@ fn us(input: &mut &str) -> ModalResult<Date> {
178179
let day = day_from_str(s2)?;
179180
(s1, n, day)
180181
.try_into()
181-
.map_err(|e| ErrMode::Cut(ctx_err(e)))
182+
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
182183
}
183184
Some(s2) => {
184185
// [month]/[day]/[year]
185186
let month = month_from_str(s1)?;
186187
(s2, month, n)
187188
.try_into()
188-
.map_err(|e| ErrMode::Cut(ctx_err(e)))
189+
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
189190
}
190191
None => {
191192
// [month]/[day]
192193
let month = month_from_str(s1)?;
193-
(month, n).try_into().map_err(|e| ErrMode::Cut(ctx_err(e)))
194+
(month, n)
195+
.try_into()
196+
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
194197
}
195198
}
196199
}
@@ -213,10 +216,10 @@ fn literal1(input: &mut &str) -> ModalResult<Date> {
213216
match year {
214217
Some(year) => (year, month, day)
215218
.try_into()
216-
.map_err(|e| ErrMode::Cut(ctx_err(e))),
219+
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
217220
None => (month, day)
218221
.try_into()
219-
.map_err(|e| ErrMode::Cut(ctx_err(e))),
222+
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
220223
}
221224
}
222225

@@ -242,10 +245,10 @@ fn literal2(input: &mut &str) -> ModalResult<Date> {
242245
match year {
243246
Some(year) => (year, month, day)
244247
.try_into()
245-
.map_err(|e| ErrMode::Cut(ctx_err(e))),
248+
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
246249
None => (month, day)
247250
.try_into()
248-
.map_err(|e| ErrMode::Cut(ctx_err(e))),
251+
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
249252
}
250253
}
251254

@@ -274,12 +277,12 @@ fn literal_month(input: &mut &str) -> ModalResult<u8> {
274277

275278
fn month_from_str(s: &str) -> ModalResult<u8> {
276279
s.parse::<u8>()
277-
.map_err(|_| ErrMode::Cut(ctx_err("month must be a valid u8 number")))
280+
.map_err(|_| ErrMode::Backtrack(ctx_err("month must be a valid u8 number")))
278281
}
279282

280283
fn day_from_str(s: &str) -> ModalResult<u8> {
281284
s.parse::<u8>()
282-
.map_err(|_| ErrMode::Cut(ctx_err("day must be a valid u8 number")))
285+
.map_err(|_| ErrMode::Backtrack(ctx_err("day must be a valid u8 number")))
283286
}
284287

285288
#[cfg(test)]

tests/time.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,37 @@ fn test_time_invalid(#[case] input: &str) {
128128
"Input string '{input}' did not produce an error when parsing"
129129
);
130130
}
131+
132+
#[rstest]
133+
#[case::decimal_1_whole("1.123456789 seconds ago")]
134+
#[case::decimal_2_whole("12.123456789 seconds ago")]
135+
#[case::decimal_3_whole("123.123456789 seconds ago")]
136+
#[case::decimal_4_whole("1234.123456789 seconds ago")]
137+
#[case::decimal_5_whole("12345.123456789 seconds ago")]
138+
#[case::decimal_6_whole("123456.123456789 seconds ago")]
139+
#[case::decimal_7_whole("1234567.123456789 seconds ago")]
140+
#[case::decimal_8_whole("12345678.123456789 seconds ago")]
141+
#[case::decimal_9_whole("123456789.123456789 seconds ago")]
142+
#[case::decimal_10_whole("1234567891.123456789 seconds ago")]
143+
#[case::decimal_11_whole("12345678912.123456789 seconds ago")]
144+
#[case::decimal_12_whole("123456789123.123456789 seconds ago")]
145+
fn test_time_seconds_ago(#[case] input: &str) {
146+
let result = parse_datetime::parse_datetime(input);
147+
assert!(
148+
result.is_ok(),
149+
"Input string '{input}', produced {result:?}, instead of Ok(Zoned)"
150+
);
151+
}
152+
153+
#[rstest]
154+
#[case::decimal_13_whole("1234567891234.123456789 seconds ago")]
155+
#[case::decimal_14_whole("12345678912345.123456789 seconds ago")]
156+
#[case::decimal_15_whole("123456789123456.123456789 seconds ago")]
157+
fn test_time_seconds_ago_invalid(#[case] input: &str) {
158+
let result = parse_datetime::parse_datetime(input);
159+
assert_eq!(
160+
result,
161+
Err(parse_datetime::ParseDateTimeError::InvalidInput),
162+
"Input string '{input}' did not produce an error when parsing"
163+
);
164+
}

0 commit comments

Comments
 (0)