chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,28 @@
use time::macros::date;
fn main() {
let _ = date!(+1_000_000-01-01);
let _ = date!(10_000-01-01);
let _ = date!(2021-W 60-1);
let _ = date!(2021-W60-1);
let _ = date!(2021-W 01-0);
let _ = date!(2021-W01-0);
let _ = date!(2021-W 01-8);
let _ = date!(2021-W01-8);
let _ = date!(2021-00-01);
let _ = date!(2021-13-01);
let _ = date!(2021-01-00);
let _ = date!(2021-01-32);
let _ = date!(2021-000);
let _ = date!(2021-366);
let _ = date!(0a);
let _ = date!(2021:);
let _ = date!(2021-W 0a);
let _ = date!(2021-W0a);
let _ = date!(2021-W 01:);
let _ = date!(2021-W01:);
let _ = date!(2021-W 01-0a);
let _ = date!(2021-W01-0a);
let _ = date!(2021-0a);
let _ = date!(2021-01-0a);
}

View File

@@ -0,0 +1,143 @@
error: invalid component: year was 1000000
--> tests/integration/compile-fail/invalid_date.rs:4:19
|
4 | let _ = date!(+1_000_000-01-01);
| ^^^^^^^^^^
error: years with more than four digits must have an explicit sign
--> tests/integration/compile-fail/invalid_date.rs:5:19
|
5 | let _ = date!(10_000-01-01);
| ^^^^^^
error: invalid component: week was 60
--> tests/integration/compile-fail/invalid_date.rs:6:24
|
6 | let _ = date!(2021-W 60-1);
| ^^^^
error: invalid component: week was 60
--> tests/integration/compile-fail/invalid_date.rs:7:24
|
7 | let _ = date!(2021-W60-1);
| ^^^
error: invalid component: day was 0
--> tests/integration/compile-fail/invalid_date.rs:8:29
|
8 | let _ = date!(2021-W 01-0);
| ^
error: invalid component: day was 0
--> tests/integration/compile-fail/invalid_date.rs:9:28
|
9 | let _ = date!(2021-W01-0);
| ^
error: invalid component: day was 8
--> tests/integration/compile-fail/invalid_date.rs:10:29
|
10 | let _ = date!(2021-W 01-8);
| ^
error: invalid component: day was 8
--> tests/integration/compile-fail/invalid_date.rs:11:28
|
11 | let _ = date!(2021-W01-8);
| ^
error: invalid component: month was 0
--> tests/integration/compile-fail/invalid_date.rs:12:24
|
12 | let _ = date!(2021-00-01);
| ^^
error: invalid component: month was 13
--> tests/integration/compile-fail/invalid_date.rs:13:24
|
13 | let _ = date!(2021-13-01);
| ^^
error: invalid component: day was 0
--> tests/integration/compile-fail/invalid_date.rs:14:27
|
14 | let _ = date!(2021-01-00);
| ^^
error: invalid component: day was 32
--> tests/integration/compile-fail/invalid_date.rs:15:27
|
15 | let _ = date!(2021-01-32);
| ^^
error: invalid component: ordinal was 0
--> tests/integration/compile-fail/invalid_date.rs:16:24
|
16 | let _ = date!(2021-000);
| ^^^
error: invalid component: ordinal was 366
--> tests/integration/compile-fail/invalid_date.rs:17:24
|
17 | let _ = date!(2021-366);
| ^^^
error: invalid component: year was 0a
--> tests/integration/compile-fail/invalid_date.rs:18:19
|
18 | let _ = date!(0a);
| ^^
error: unexpected token: :
--> tests/integration/compile-fail/invalid_date.rs:19:23
|
19 | let _ = date!(2021:);
| ^
error: invalid component: week was 0a
--> tests/integration/compile-fail/invalid_date.rs:20:26
|
20 | let _ = date!(2021-W 0a);
| ^^
error: invalid component: week was 0a
--> tests/integration/compile-fail/invalid_date.rs:21:24
|
21 | let _ = date!(2021-W0a);
| ^^^
error: unexpected token: :
--> tests/integration/compile-fail/invalid_date.rs:22:28
|
22 | let _ = date!(2021-W 01:);
| ^
error: unexpected token: :
--> tests/integration/compile-fail/invalid_date.rs:23:27
|
23 | let _ = date!(2021-W01:);
| ^
error: invalid component: day was 0a
--> tests/integration/compile-fail/invalid_date.rs:24:29
|
24 | let _ = date!(2021-W 01-0a);
| ^^
error: invalid component: day was 0a
--> tests/integration/compile-fail/invalid_date.rs:25:28
|
25 | let _ = date!(2021-W01-0a);
| ^^
error: invalid component: month or ordinal was 0a
--> tests/integration/compile-fail/invalid_date.rs:26:24
|
26 | let _ = date!(2021-0a);
| ^^
error: invalid component: day was 0a
--> tests/integration/compile-fail/invalid_date.rs:27:27
|
27 | let _ = date!(2021-01-0a);
| ^^

View File

@@ -0,0 +1,8 @@
use time::macros::datetime;
fn main() {
let _ = datetime!(2021-000 0:00);
let _ = datetime!(2021-001 24:00);
let _ = datetime!(2021-001 0:00 0);
let _ = datetime!(2021-001 0:00 UTC x);
}

View File

@@ -0,0 +1,23 @@
error: invalid component: ordinal was 0
--> tests/integration/compile-fail/invalid_datetime.rs:4:28
|
4 | let _ = datetime!(2021-000 0:00);
| ^^^
error: invalid component: hour was 24
--> tests/integration/compile-fail/invalid_datetime.rs:5:32
|
5 | let _ = datetime!(2021-001 24:00);
| ^^
error: unexpected token: 0
--> tests/integration/compile-fail/invalid_datetime.rs:6:37
|
6 | let _ = datetime!(2021-001 0:00 0);
| ^
error: unexpected token: x
--> tests/integration/compile-fail/invalid_datetime.rs:7:41
|
7 | let _ = datetime!(2021-001 0:00 UTC x);
| ^

View File

@@ -0,0 +1,46 @@
use time::macros::format_description;
fn main() {
let _ = format_description!();
let _ = format_description!("[]");
let _ = format_description!("[foo]");
let _ = format_description!("[");
let _ = format_description!("[hour foo]");
let _ = format_description!("" x);
let _ = format_description!(x);
let _ = format_description!(0);
let _ = format_description!({});
let _ = format_description!("[ invalid ]");
let _ = format_description!("[");
let _ = format_description!("[ ");
let _ = format_description!("[]");
let _ = format_description!("[day sign:mandatory]");
let _ = format_description!("[day sign:]");
let _ = format_description!("[day :mandatory]");
let _ = format_description!("[day sign:mandatory");
let _ = format_description!("[day padding:invalid]");
let _ = format_description!(version);
let _ = format_description!(version "");
let _ = format_description!(version =);
let _ = format_description!(version = 0);
let _ = format_description!(version = 1);
let _ = format_description!(version = 3);
let _ = format_description!(version = two);
let _ = format_description!(version = 2, r"\a");
let _ = format_description!(version = 2, r"\");
let _ = format_description!(version = 2, "[year [month]]");
let _ = format_description!(version = 2, "[optional[]]");
let _ = format_description!(version = 2, "[first[]]");
let _ = format_description!(version = 2, "[optional []");
let _ = format_description!(version = 2, "[first []");
let _ = format_description!(version = 2, "[optional [");
let _ = format_description!(version = 2, "[optional [[year");
let _ = format_description!(version = 2, "[optional ");
let _ = format_description!("[ignore]");
let _ = format_description!("[ignore count:0]");
}

View File

@@ -0,0 +1,229 @@
error: expected string literal
--> tests/integration/compile-fail/invalid_format_description.rs:4:13
|
4 | let _ = format_description!();
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected component name
--> tests/integration/compile-fail/invalid_format_description.rs:5:33
|
5 | let _ = format_description!("[]");
| ^^^^
error: invalid component
--> tests/integration/compile-fail/invalid_format_description.rs:6:33
|
6 | let _ = format_description!("[foo]");
| ^^^^^^^
error: expected component name
--> tests/integration/compile-fail/invalid_format_description.rs:7:33
|
7 | let _ = format_description!("[");
| ^^^
error: modifier must be of the form `key:value`
--> tests/integration/compile-fail/invalid_format_description.rs:8:33
|
8 | let _ = format_description!("[hour foo]");
| ^^^^^^^^^^^^
error: unexpected token: x
--> tests/integration/compile-fail/invalid_format_description.rs:9:36
|
9 | let _ = format_description!("" x);
| ^
error: expected string literal
--> tests/integration/compile-fail/invalid_format_description.rs:10:33
|
10 | let _ = format_description!(x);
| ^
error: expected string literal
--> tests/integration/compile-fail/invalid_format_description.rs:11:33
|
11 | let _ = format_description!(0);
| ^
error: expected string literal
--> tests/integration/compile-fail/invalid_format_description.rs:12:33
|
12 | let _ = format_description!({});
| ^^
error: invalid component
--> tests/integration/compile-fail/invalid_format_description.rs:14:33
|
14 | let _ = format_description!("[ invalid ]");
| ^^^^^^^^^^^^^
error: expected component name
--> tests/integration/compile-fail/invalid_format_description.rs:15:33
|
15 | let _ = format_description!("[");
| ^^^
error: expected component name
--> tests/integration/compile-fail/invalid_format_description.rs:16:33
|
16 | let _ = format_description!("[ ");
| ^^^^
error: expected component name
--> tests/integration/compile-fail/invalid_format_description.rs:17:33
|
17 | let _ = format_description!("[]");
| ^^^^
error: invalid modifier key
--> tests/integration/compile-fail/invalid_format_description.rs:18:33
|
18 | let _ = format_description!("[day sign:mandatory]");
| ^^^^^^^^^^^^^^^^^^^^^^
error: expected modifier value
--> tests/integration/compile-fail/invalid_format_description.rs:19:33
|
19 | let _ = format_description!("[day sign:]");
| ^^^^^^^^^^^^^
error: expected modifier key
--> tests/integration/compile-fail/invalid_format_description.rs:20:33
|
20 | let _ = format_description!("[day :mandatory]");
| ^^^^^^^^^^^^^^^^^^
error: unclosed bracket
--> tests/integration/compile-fail/invalid_format_description.rs:21:33
|
21 | let _ = format_description!("[day sign:mandatory");
| ^^^^^^^^^^^^^^^^^^^^^
error: invalid modifier value
--> tests/integration/compile-fail/invalid_format_description.rs:22:33
|
22 | let _ = format_description!("[day padding:invalid]");
| ^^^^^^^^^^^^^^^^^^^^^^^
error: expected `=`
--> tests/integration/compile-fail/invalid_format_description.rs:24:13
|
24 | let _ = format_description!(version);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected `=`
--> tests/integration/compile-fail/invalid_format_description.rs:25:41
|
25 | let _ = format_description!(version "");
| ^^
error: expected 1 or 2
--> tests/integration/compile-fail/invalid_format_description.rs:26:13
|
26 | let _ = format_description!(version =);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid format description version
--> tests/integration/compile-fail/invalid_format_description.rs:27:43
|
27 | let _ = format_description!(version = 0);
| ^
error: unexpected end of input
--> tests/integration/compile-fail/invalid_format_description.rs:28:13
|
28 | let _ = format_description!(version = 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid format description version
--> tests/integration/compile-fail/invalid_format_description.rs:29:43
|
29 | let _ = format_description!(version = 3);
| ^
error: expected 1 or 2
--> tests/integration/compile-fail/invalid_format_description.rs:30:43
|
30 | let _ = format_description!(version = two);
| ^^^
error: invalid escape sequence
--> tests/integration/compile-fail/invalid_format_description.rs:32:46
|
32 | let _ = format_description!(version = 2, r"\a");
| ^^^^^
error: unexpected end of input
--> tests/integration/compile-fail/invalid_format_description.rs:33:46
|
33 | let _ = format_description!(version = 2, r"\");
| ^^^^
error: modifier must be of the form `key:value`
--> tests/integration/compile-fail/invalid_format_description.rs:35:46
|
35 | let _ = format_description!(version = 2, "[year [month]]");
| ^^^^^^^^^^^^^^^^
error: expected whitespace after `optional`
--> tests/integration/compile-fail/invalid_format_description.rs:36:46
|
36 | let _ = format_description!(version = 2, "[optional[]]");
| ^^^^^^^^^^^^^^
error: expected whitespace after `first`
--> tests/integration/compile-fail/invalid_format_description.rs:37:46
|
37 | let _ = format_description!(version = 2, "[first[]]");
| ^^^^^^^^^^^
error: unclosed bracket
--> tests/integration/compile-fail/invalid_format_description.rs:38:46
|
38 | let _ = format_description!(version = 2, "[optional []");
| ^^^^^^^^^^^^^^
error: unclosed bracket
--> tests/integration/compile-fail/invalid_format_description.rs:39:46
|
39 | let _ = format_description!(version = 2, "[first []");
| ^^^^^^^^^^^
error: unclosed bracket
--> tests/integration/compile-fail/invalid_format_description.rs:40:46
|
40 | let _ = format_description!(version = 2, "[optional [");
| ^^^^^^^^^^^^^
error: unclosed bracket
--> tests/integration/compile-fail/invalid_format_description.rs:41:46
|
41 | let _ = format_description!(version = 2, "[optional [[year");
| ^^^^^^^^^^^^^^^^^^
error: expected opening bracket
--> tests/integration/compile-fail/invalid_format_description.rs:42:46
|
42 | let _ = format_description!(version = 2, "[optional ");
| ^^^^^^^^^^^^
error: missing required modifier
--> tests/integration/compile-fail/invalid_format_description.rs:44:33
|
44 | let _ = format_description!("[ignore]");
| ^^^^^^^^^^
error: invalid modifier value
--> tests/integration/compile-fail/invalid_format_description.rs:45:33
|
45 | let _ = format_description!("[ignore count:0]");
| ^^^^^^^^^^^^^^^^^^

View File

@@ -0,0 +1,12 @@
use time::macros::offset;
fn main() {
let _ = offset!(+26);
let _ = offset!(+0:60);
let _ = offset!(+0:00:60);
let _ = offset!(0);
let _ = offset!();
let _ = offset!(+0a);
let _ = offset!(+0:0a);
let _ = offset!(+0:00:0a);
}

View File

@@ -0,0 +1,49 @@
error: invalid component: hour was 26
--> tests/integration/compile-fail/invalid_offset.rs:4:22
|
4 | let _ = offset!(+26);
| ^^
error: invalid component: minute was 60
--> tests/integration/compile-fail/invalid_offset.rs:5:24
|
5 | let _ = offset!(+0:60);
| ^^
error: invalid component: second was 60
--> tests/integration/compile-fail/invalid_offset.rs:6:27
|
6 | let _ = offset!(+0:00:60);
| ^^
error: unexpected token: 0
--> tests/integration/compile-fail/invalid_offset.rs:7:21
|
7 | let _ = offset!(0);
| ^
error: missing component: sign
--> tests/integration/compile-fail/invalid_offset.rs:8:13
|
8 | let _ = offset!();
| ^^^^^^^^^
|
= note: this error originates in the macro `offset` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid component: hour was 0a
--> tests/integration/compile-fail/invalid_offset.rs:9:22
|
9 | let _ = offset!(+0a);
| ^^
error: invalid component: minute was 0a
--> tests/integration/compile-fail/invalid_offset.rs:10:24
|
10 | let _ = offset!(+0:0a);
| ^^
error: invalid component: second was 0a
--> tests/integration/compile-fail/invalid_offset.rs:11:27
|
11 | let _ = offset!(+0:00:0a);
| ^^

View File

@@ -0,0 +1,16 @@
use time::serde;
serde::format_description!(); // unexpected end of input
serde::format_description!("bad string", OffsetDateTime, "[year] [month]"); // module name is not ident
serde::format_description!(my_format: OffsetDateTime, "[year] [month]"); // not a comma
serde::format_description!(my_format,); // missing formattable and string
serde::format_description!(my_format, "[year] [month]"); // missing formattable
serde::format_description!(OffsetDateTime, "[year] [month]"); // missing ident
serde::format_description!(my_format, OffsetDateTime); // missing string format
serde::format_description!(my_format, OffsetDateTime,); // missing string format
serde::format_description!(my_format, OffsetDateTime "[year] [month]"); // missing comma
serde::format_description!(my_format, OffsetDateTime : "[year] [month]"); // not a comma
serde::format_description!(my_format, OffsetDateTime, "[bad]"); // bad component name
serde::format_description!(my_format, OffsetDateTime, not_string); // not in scope
fn main() {}

View File

@@ -0,0 +1,79 @@
error: unexpected end of input
--> tests/integration/compile-fail/invalid_serializer.rs:3:1
|
3 | serde::format_description!(); // unexpected end of input
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected token: "bad string"
--> tests/integration/compile-fail/invalid_serializer.rs:4:28
|
4 | serde::format_description!("bad string", OffsetDateTime, "[year] [month]"); // module name is not ident
| ^^^^^^^^^^^^
error: unexpected token: :
--> tests/integration/compile-fail/invalid_serializer.rs:5:37
|
5 | serde::format_description!(my_format: OffsetDateTime, "[year] [month]"); // not a comma
| ^
error: unexpected end of input
--> tests/integration/compile-fail/invalid_serializer.rs:6:1
|
6 | serde::format_description!(my_format,); // missing formattable and string
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected token: "[year] [month]"
--> tests/integration/compile-fail/invalid_serializer.rs:7:39
|
7 | serde::format_description!(my_format, "[year] [month]"); // missing formattable
| ^^^^^^^^^^^^^^^^
error: unexpected token: "[year] [month]"
--> tests/integration/compile-fail/invalid_serializer.rs:8:44
|
8 | serde::format_description!(OffsetDateTime, "[year] [month]"); // missing ident
| ^^^^^^^^^^^^^^^^
error: unexpected end of input
--> tests/integration/compile-fail/invalid_serializer.rs:9:1
|
9 | serde::format_description!(my_format, OffsetDateTime); // missing string format
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected end of input
--> tests/integration/compile-fail/invalid_serializer.rs:10:1
|
10 | serde::format_description!(my_format, OffsetDateTime,); // missing string format
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected token: "[year] [month]"
--> tests/integration/compile-fail/invalid_serializer.rs:11:54
|
11 | serde::format_description!(my_format, OffsetDateTime "[year] [month]"); // missing comma
| ^^^^^^^^^^^^^^^^
error: unexpected token: :
--> tests/integration/compile-fail/invalid_serializer.rs:12:54
|
12 | serde::format_description!(my_format, OffsetDateTime : "[year] [month]"); // not a comma
| ^
error: invalid component
--> tests/integration/compile-fail/invalid_serializer.rs:13:55
|
13 | serde::format_description!(my_format, OffsetDateTime, "[bad]"); // bad component name
| ^^^^^^^
error[E0425]: cannot find value `not_string` in this scope
--> tests/integration/compile-fail/invalid_serializer.rs:14:55
|
14 | serde::format_description!(my_format, OffsetDateTime, not_string); // not in scope
| ^^^^^^^^^^ not found in this scope

View File

@@ -0,0 +1,17 @@
use time::macros::time;
fn main() {
let _ = time!(24:00);
let _ = time!(0:60);
let _ = time!(0:00:60);
let _ = time!(x);
let _ = time!(0:00:00 x);
let _ = time!("");
let _ = time!(0:);
let _ = time!(0,);
let _ = time!(0:00:0a);
let _ = time!(0:00 pm);
let _ = time!(0);
let _ = time!(0 pm);
let _ = time!(1 am :);
}

View File

@@ -0,0 +1,81 @@
error: invalid component: hour was 24
--> tests/integration/compile-fail/invalid_time.rs:4:19
|
4 | let _ = time!(24:00);
| ^^
error: invalid component: minute was 60
--> tests/integration/compile-fail/invalid_time.rs:5:21
|
5 | let _ = time!(0:60);
| ^^
error: invalid component: second was 60
--> tests/integration/compile-fail/invalid_time.rs:6:24
|
6 | let _ = time!(0:00:60);
| ^^
error: unexpected token: x
--> tests/integration/compile-fail/invalid_time.rs:7:19
|
7 | let _ = time!(x);
| ^
error: unexpected token: x
--> tests/integration/compile-fail/invalid_time.rs:8:27
|
8 | let _ = time!(0:00:00 x);
| ^
error: invalid component: hour was ""
--> tests/integration/compile-fail/invalid_time.rs:9:19
|
9 | let _ = time!("");
| ^^
error: unexpected end of input
--> tests/integration/compile-fail/invalid_time.rs:10:13
|
10 | let _ = time!(0:);
| ^^^^^^^^^
|
= note: this error originates in the macro `time` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected token: ,
--> tests/integration/compile-fail/invalid_time.rs:11:20
|
11 | let _ = time!(0,);
| ^
error: invalid component: second was 0a
--> tests/integration/compile-fail/invalid_time.rs:12:24
|
12 | let _ = time!(0:00:0a);
| ^^
error: invalid component: hour was 0
--> tests/integration/compile-fail/invalid_time.rs:13:19
|
13 | let _ = time!(0:00 pm);
| ^^^^^^^
error: unexpected end of input
--> tests/integration/compile-fail/invalid_time.rs:14:13
|
14 | let _ = time!(0);
| ^^^^^^^^
|
= note: this error originates in the macro `time` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid component: hour was 0
--> tests/integration/compile-fail/invalid_time.rs:15:19
|
15 | let _ = time!(0 pm);
| ^^^^
error: unexpected token: :
--> tests/integration/compile-fail/invalid_time.rs:16:24
|
16 | let _ = time!(1 am :);
| ^

View File

@@ -0,0 +1,9 @@
use time::macros::utc_datetime;
fn main() {
let _ = utc_datetime!(2021-000 0:00);
let _ = utc_datetime!(2021-001 24:00);
let _ = utc_datetime!(2021-001 0:00 0);
let _ = utc_datetime!(2021-001 0:00 UTC);
let _ = utc_datetime!(2021-001 0:00 UTC x);
}

View File

@@ -0,0 +1,29 @@
error: invalid component: ordinal was 0
--> tests/integration/compile-fail/invalid_utc_datetime.rs:4:32
|
4 | let _ = utc_datetime!(2021-000 0:00);
| ^^^
error: invalid component: hour was 24
--> tests/integration/compile-fail/invalid_utc_datetime.rs:5:36
|
5 | let _ = utc_datetime!(2021-001 24:00);
| ^^
error: unexpected token: 0
--> tests/integration/compile-fail/invalid_utc_datetime.rs:6:41
|
6 | let _ = utc_datetime!(2021-001 0:00 0);
| ^
error: unexpected token: UTC
--> tests/integration/compile-fail/invalid_utc_datetime.rs:7:41
|
7 | let _ = utc_datetime!(2021-001 0:00 UTC);
| ^^^
error: unexpected token: UTC
--> tests/integration/compile-fail/invalid_utc_datetime.rs:8:41
|
8 | let _ = utc_datetime!(2021-001 0:00 UTC x);
| ^^^

View File

@@ -0,0 +1,7 @@
use rstest::rstest;
use time::convert::*;
#[rstest]
fn issue_749() {
assert_eq!(Nanosecond::per(Second), 1_000_000_000u32);
}

1113
vendor/time/tests/integration/date.rs vendored Normal file

File diff suppressed because it is too large Load Diff

201
vendor/time/tests/integration/derives.rs vendored Normal file
View File

@@ -0,0 +1,201 @@
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
use time::error::{self, ConversionRange, IndeterminateOffset, TryFromParsed};
use time::ext::NumericalDuration;
use time::format_description::{self, modifier, well_known, Component, BorrowedFormatItem, OwnedFormatItem};
use time::macros::{date, offset, time, utc_datetime, datetime};
use time::parsing::Parsed;
use time::{Duration, Error, Month, Time, Weekday};
#[expect(deprecated)]
use time::Instant;
macro_rules! assert_cloned_eq {
($x:expr) => {
assert_eq!($x.clone(), $x)
};
}
fn component_range_error() -> error::ComponentRange {
Time::from_hms(24, 0, 0).expect_err("24 is not a valid hour")
}
fn invalid_format_description() -> error::InvalidFormatDescription {
format_description::parse("[").expect_err("format description is invalid")
}
#[expect(clippy::cognitive_complexity, reason = "all test the same thing")]
#[test]
fn clone() {
#[expect(deprecated)]
let instant = Instant::now();
assert_cloned_eq!(date!(2021-001));
assert_cloned_eq!(time!(0:00));
assert_cloned_eq!(offset!(UTC));
assert_cloned_eq!(datetime!(2021-001 0:00));
assert_cloned_eq!(datetime!(2021-001 0:00 UTC));
assert_cloned_eq!(utc_datetime!(2021-001 0:00));
assert_cloned_eq!(Weekday::Monday);
assert_cloned_eq!(Month::January);
assert_cloned_eq!(Duration::ZERO);
assert_cloned_eq!(instant);
assert_cloned_eq!(IndeterminateOffset);
assert_cloned_eq!(ConversionRange);
assert_cloned_eq!(invalid_format_description());
assert_cloned_eq!(TryFromParsed::InsufficientInformation);
#[expect(clippy::clone_on_copy)] // needed for coverage
let _ = Parsed::new().clone();
assert_cloned_eq!(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("foo")
));
assert_cloned_eq!(error::DifferentVariant);
assert_cloned_eq!(error::InvalidVariant);
assert_cloned_eq!(error::ParseFromDescription::InvalidComponent("foo"));
assert_cloned_eq!(Component::OffsetSecond(modifier::OffsetSecond::default()));
assert_cloned_eq!(well_known::Rfc2822);
assert_cloned_eq!(well_known::Rfc3339);
assert_cloned_eq!(well_known::Iso8601::DEFAULT);
assert_cloned_eq!(well_known::iso8601::FormattedComponents::None);
assert_cloned_eq!(well_known::iso8601::DateKind::Calendar);
assert_cloned_eq!(well_known::iso8601::TimePrecision::Hour {
decimal_digits: None
});
assert_cloned_eq!(well_known::iso8601::OffsetPrecision::Hour);
assert_cloned_eq!(well_known::iso8601::FormattedComponents::None);
assert_cloned_eq!(component_range_error());
assert_cloned_eq!(BorrowedFormatItem::Literal(b""));
assert_cloned_eq!(modifier::Day::default());
assert_cloned_eq!(modifier::MonthRepr::default());
assert_cloned_eq!(modifier::Month::default());
assert_cloned_eq!(modifier::Ordinal::default());
assert_cloned_eq!(modifier::WeekdayRepr::default());
assert_cloned_eq!(modifier::Weekday::default());
assert_cloned_eq!(modifier::WeekNumberRepr::default());
assert_cloned_eq!(modifier::WeekNumber::default());
assert_cloned_eq!(modifier::YearRepr::default());
assert_cloned_eq!(modifier::Year::default());
assert_cloned_eq!(modifier::Hour::default());
assert_cloned_eq!(modifier::Minute::default());
assert_cloned_eq!(modifier::Period::default());
assert_cloned_eq!(modifier::Second::default());
assert_cloned_eq!(modifier::SubsecondDigits::default());
assert_cloned_eq!(modifier::Subsecond::default());
assert_cloned_eq!(modifier::OffsetHour::default());
assert_cloned_eq!(modifier::OffsetMinute::default());
assert_cloned_eq!(modifier::OffsetSecond::default());
assert_cloned_eq!(modifier::Padding::default());
}
#[test]
fn hash() {
let mut hasher = DefaultHasher::new();
date!(2021-001).hash(&mut hasher);
time!(0:00).hash(&mut hasher);
offset!(UTC).hash(&mut hasher);
datetime!(2021-001 0:00).hash(&mut hasher);
datetime!(2021-001 0:00 UTC).hash(&mut hasher);
utc_datetime!(2021-001 0:00).hash(&mut hasher);
Weekday::Monday.hash(&mut hasher);
Month::January.hash(&mut hasher);
#[expect(deprecated)]
Instant::now().hash(&mut hasher);
Duration::ZERO.hash(&mut hasher);
component_range_error().hash(&mut hasher);
}
#[test]
fn partial_ord() {
#[expect(deprecated)]
let instant = Instant::now();
assert_eq!(offset!(UTC).partial_cmp(&offset!(+1)), Some(Ordering::Less));
assert_eq!(
offset!(+1).partial_cmp(&offset!(UTC)),
Some(Ordering::Greater)
);
assert_eq!(
(instant - 1.seconds()).partial_cmp(&instant),
Some(Ordering::Less)
);
assert_eq!(
(instant + 1.seconds()).partial_cmp(&instant),
Some(Ordering::Greater)
);
}
#[test]
fn ord() {
assert_eq!(offset!(UTC).cmp(&offset!(+1)), Ordering::Less);
assert_eq!(offset!(+1).cmp(&offset!(UTC)), Ordering::Greater);
assert_eq!(offset!(UTC).cmp(&offset!(UTC)), Ordering::Equal);
}
#[test]
fn debug() {
macro_rules! debug_all {
() => {};
(#[$meta:meta] $x:expr; $($rest:tt)*) => {
#[$meta]
let _unused = format!("{:?}", $x);
debug_all!($($rest)*);
};
($x:expr; $($rest:tt)*) => {
let _unused = format!("{:?}", $x);
debug_all!($($rest)*);
};
}
debug_all! {
utc_datetime!(2021-001 0:00);
Duration::ZERO;
IndeterminateOffset;
ConversionRange;
TryFromParsed::InsufficientInformation;
Parsed::new();
#[expect(deprecated)]
Instant::now();
error::ParseFromDescription::InvalidComponent("foo");
error::Format::InvalidComponent("foo");
well_known::Rfc2822;
well_known::Rfc3339;
well_known::Iso8601::DEFAULT;
well_known::iso8601::FormattedComponents::None;
well_known::iso8601::DateKind::Calendar;
well_known::iso8601::TimePrecision::Hour { decimal_digits: None };
well_known::iso8601::OffsetPrecision::Hour;
well_known::iso8601::Config::DEFAULT;
component_range_error();
Error::ConversionRange(ConversionRange);
modifier::Day::default();
modifier::MonthRepr::default();
modifier::Month::default();
modifier::Ordinal::default();
modifier::WeekdayRepr::default();
modifier::Weekday::default();
modifier::WeekNumberRepr::default();
modifier::WeekNumber::default();
modifier::YearRepr::default();
modifier::Year::default();
modifier::Hour::default();
modifier::Minute::default();
modifier::Period::default();
modifier::Second::default();
modifier::SubsecondDigits::default();
modifier::Subsecond::default();
modifier::OffsetHour::default();
modifier::OffsetMinute::default();
modifier::OffsetSecond::default();
modifier::Padding::default();
BorrowedFormatItem::Literal(b"abcdef");
BorrowedFormatItem::Compound(&[BorrowedFormatItem::Component(Component::Day(modifier::Day::default()))]);
BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[]));
BorrowedFormatItem::First(&[]);
OwnedFormatItem::from(BorrowedFormatItem::Literal(b"abcdef"));
OwnedFormatItem::from(BorrowedFormatItem::Compound(&[BorrowedFormatItem::Component(Component::Day(modifier::Day::default()))]));
OwnedFormatItem::from(BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[])));
OwnedFormatItem::from(BorrowedFormatItem::First(&[]));
}
}

1048
vendor/time/tests/integration/duration.rs vendored Normal file

File diff suppressed because it is too large Load Diff

194
vendor/time/tests/integration/error.rs vendored Normal file
View File

@@ -0,0 +1,194 @@
use std::error::Error as _;
use std::io;
use time::error::{
ComponentRange, ConversionRange, DifferentVariant, Error, Format, IndeterminateOffset,
InvalidFormatDescription, InvalidVariant, Parse, ParseFromDescription, TryFromParsed,
};
use time::macros::format_description;
use time::parsing::Parsed;
use time::{Date, Time, format_description};
macro_rules! assert_display_eq {
($a:expr, $b:expr $(,)?) => {
assert_eq!($a.to_string(), $b.to_string())
};
}
macro_rules! assert_dbg_reflexive {
($a:expr) => {
assert_eq!(format!("{:?}", $a), format!("{:?}", $a))
};
}
macro_rules! assert_source {
($err:expr,None $(,)?) => {
assert!($err.source().is_none())
};
($err:expr, $source:ty $(,)?) => {
assert!($err.source().unwrap().is::<$source>())
};
}
fn component_range() -> ComponentRange {
Date::from_ordinal_date(0, 367).expect_err("367 is not a valid day")
}
fn insufficient_type_information() -> Format {
Time::MIDNIGHT
.format(format_description!("[year]"))
.expect_err("missing date and UTC offset")
}
fn unexpected_trailing_characters() -> Parse {
Time::parse("a", format_description!("")).expect_err("should fail to parse")
}
fn invalid_format_description() -> InvalidFormatDescription {
format_description::parse("[").expect_err("format description is invalid")
}
fn io_error() -> io::Error {
io::Error::last_os_error()
}
fn invalid_literal() -> ParseFromDescription {
Parsed::parse_literal(b"a", b"b").expect_err("should fail to parse")
}
#[test]
fn debug() {
assert_dbg_reflexive!(Parse::from(ParseFromDescription::InvalidComponent("a")));
assert_dbg_reflexive!(invalid_format_description());
assert_dbg_reflexive!(DifferentVariant);
assert_dbg_reflexive!(InvalidVariant);
}
#[test]
fn display() {
assert_display_eq!(ConversionRange, Error::from(ConversionRange));
assert_display_eq!(component_range(), Error::from(component_range()));
assert_display_eq!(component_range(), TryFromParsed::from(component_range()));
assert_display_eq!(IndeterminateOffset, Error::from(IndeterminateOffset));
assert_display_eq!(
TryFromParsed::InsufficientInformation,
Error::from(TryFromParsed::InsufficientInformation)
);
assert_display_eq!(
insufficient_type_information(),
Error::from(insufficient_type_information())
);
assert_display_eq!(
Format::InvalidComponent("a"),
Error::from(Format::InvalidComponent("a"))
);
assert_display_eq!(
ParseFromDescription::InvalidComponent("a"),
Error::from(Parse::from(ParseFromDescription::InvalidComponent("a")))
);
assert_display_eq!(invalid_literal(), Parse::from(invalid_literal()));
assert_display_eq!(
component_range(),
Error::from(Parse::from(TryFromParsed::from(component_range())))
);
assert_display_eq!(
ParseFromDescription::InvalidComponent("a"),
Parse::from(ParseFromDescription::InvalidComponent("a"))
);
assert_display_eq!(
component_range(),
Parse::from(TryFromParsed::from(component_range()))
);
assert_display_eq!(
unexpected_trailing_characters(),
Error::from(unexpected_trailing_characters()),
);
assert_display_eq!(
invalid_format_description(),
Error::from(invalid_format_description())
);
assert_display_eq!(io_error(), Format::from(io_error()));
assert_display_eq!(DifferentVariant, Error::from(DifferentVariant));
assert_display_eq!(InvalidVariant, Error::from(InvalidVariant));
}
#[test]
fn source() {
assert_source!(Error::from(ConversionRange), ConversionRange);
assert_source!(Error::from(component_range()), ComponentRange);
assert_source!(TryFromParsed::from(component_range()), ComponentRange);
assert_source!(TryFromParsed::InsufficientInformation, None);
assert_source!(insufficient_type_information(), None);
assert_source!(Format::InvalidComponent("a"), None);
assert_source!(Error::from(insufficient_type_information()), Format);
assert_source!(Error::from(IndeterminateOffset), IndeterminateOffset);
assert_source!(
Parse::from(TryFromParsed::InsufficientInformation),
TryFromParsed
);
assert_source!(
Error::from(TryFromParsed::InsufficientInformation),
TryFromParsed
);
assert_source!(
Parse::from(ParseFromDescription::InvalidComponent("a")),
ParseFromDescription
);
assert_source!(
Error::from(ParseFromDescription::InvalidComponent("a")),
ParseFromDescription
);
assert_source!(unexpected_trailing_characters(), ParseFromDescription);
assert_source!(
Error::from(unexpected_trailing_characters()),
ParseFromDescription
);
assert_source!(
Error::from(invalid_format_description()),
InvalidFormatDescription
);
assert_source!(Format::from(io_error()), io::Error);
assert_source!(Error::from(DifferentVariant), DifferentVariant);
assert_source!(Error::from(InvalidVariant), InvalidVariant);
}
#[test]
fn component_name() {
assert_eq!(component_range().name(), "ordinal");
}
#[expect(clippy::cognitive_complexity, reason = "all test the same thing")]
#[test]
fn conversion() {
assert!(ComponentRange::try_from(Error::from(component_range())).is_ok());
assert!(ConversionRange::try_from(Error::from(ConversionRange)).is_ok());
assert!(Format::try_from(Error::from(insufficient_type_information())).is_ok());
assert!(IndeterminateOffset::try_from(Error::from(IndeterminateOffset)).is_ok());
assert!(InvalidFormatDescription::try_from(Error::from(invalid_format_description())).is_ok());
assert!(ParseFromDescription::try_from(Error::from(invalid_literal())).is_ok());
assert!(ParseFromDescription::try_from(Parse::from(invalid_literal())).is_ok());
assert!(ParseFromDescription::try_from(unexpected_trailing_characters()).is_ok());
assert!(Parse::try_from(Error::from(unexpected_trailing_characters())).is_ok());
assert!(Parse::try_from(Error::from(invalid_literal())).is_ok());
assert!(Parse::try_from(Error::from(TryFromParsed::InsufficientInformation)).is_ok());
assert!(DifferentVariant::try_from(Error::from(DifferentVariant)).is_ok());
assert!(InvalidVariant::try_from(Error::from(InvalidVariant)).is_ok());
assert!(ComponentRange::try_from(TryFromParsed::ComponentRange(component_range())).is_ok());
assert!(TryFromParsed::try_from(Error::from(TryFromParsed::InsufficientInformation)).is_ok());
assert!(TryFromParsed::try_from(Parse::from(TryFromParsed::InsufficientInformation)).is_ok());
assert!(io::Error::try_from(Format::from(io_error())).is_ok());
assert!(ComponentRange::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(ConversionRange::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(Format::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(IndeterminateOffset::try_from(Error::from(ConversionRange)).is_err());
assert!(InvalidFormatDescription::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(ParseFromDescription::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(Parse::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(DifferentVariant::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(InvalidVariant::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(ComponentRange::try_from(TryFromParsed::InsufficientInformation).is_err());
assert!(TryFromParsed::try_from(Error::from(IndeterminateOffset)).is_err());
assert!(TryFromParsed::try_from(unexpected_trailing_characters()).is_err());
assert!(io::Error::try_from(insufficient_type_information()).is_err());
}

112
vendor/time/tests/integration/ext.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
mod numerical_duration {
use time::ext::NumericalDuration;
use time::Duration;
#[test]
fn unsigned() {
assert_eq!(5.nanoseconds(), Duration::nanoseconds(5));
assert_eq!(5.microseconds(), Duration::microseconds(5));
assert_eq!(5.milliseconds(), Duration::milliseconds(5));
assert_eq!(5.seconds(), Duration::seconds(5));
assert_eq!(5.minutes(), Duration::minutes(5));
assert_eq!(5.hours(), Duration::hours(5));
assert_eq!(5.days(), Duration::days(5));
assert_eq!(5.weeks(), Duration::weeks(5));
}
#[test]
fn signed() {
assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5));
assert_eq!((-5).microseconds(), Duration::microseconds(-5));
assert_eq!((-5).milliseconds(), Duration::milliseconds(-5));
assert_eq!((-5).seconds(), Duration::seconds(-5));
assert_eq!((-5).minutes(), Duration::minutes(-5));
assert_eq!((-5).hours(), Duration::hours(-5));
assert_eq!((-5).days(), Duration::days(-5));
assert_eq!((-5).weeks(), Duration::weeks(-5));
}
#[test]
fn float() {
// Ensure values truncate rather than round.
assert_eq!(1.9.nanoseconds(), Duration::nanoseconds(1));
assert_eq!(1.0.nanoseconds(), Duration::nanoseconds(1));
assert_eq!(1.0.microseconds(), Duration::microseconds(1));
assert_eq!(1.0.milliseconds(), Duration::milliseconds(1));
assert_eq!(1.0.seconds(), Duration::seconds(1));
assert_eq!(1.0.minutes(), Duration::minutes(1));
assert_eq!(1.0.hours(), Duration::hours(1));
assert_eq!(1.0.days(), Duration::days(1));
assert_eq!(1.0.weeks(), Duration::weeks(1));
assert_eq!(1.5.nanoseconds(), Duration::nanoseconds(1));
assert_eq!(1.5.microseconds(), Duration::nanoseconds(1_500));
assert_eq!(1.5.milliseconds(), Duration::microseconds(1_500));
assert_eq!(1.5.seconds(), Duration::milliseconds(1_500));
assert_eq!(1.5.minutes(), Duration::seconds(90));
assert_eq!(1.5.hours(), Duration::minutes(90));
assert_eq!(1.5.days(), Duration::hours(36));
assert_eq!(1.5.weeks(), Duration::hours(252));
}
#[test]
fn arithmetic() {
assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds());
assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds());
}
}
mod numerical_std_duration {
use std::time::Duration as StdDuration;
use time::ext::NumericalStdDuration;
#[test]
fn unsigned() {
assert_eq!(5.std_nanoseconds(), StdDuration::from_nanos(5));
assert_eq!(5.std_microseconds(), StdDuration::from_micros(5));
assert_eq!(5.std_milliseconds(), StdDuration::from_millis(5));
assert_eq!(5.std_seconds(), StdDuration::from_secs(5));
assert_eq!(5.std_minutes(), StdDuration::from_secs(5 * 60));
assert_eq!(5.std_hours(), StdDuration::from_secs(5 * 3_600));
assert_eq!(5.std_days(), StdDuration::from_secs(5 * 86_400));
assert_eq!(5.std_weeks(), StdDuration::from_secs(5 * 604_800));
}
#[test]
fn float() {
// Ensure values truncate rather than round.
assert_eq!(1.9.std_nanoseconds(), StdDuration::from_nanos(1));
assert_eq!(1.0.std_nanoseconds(), StdDuration::from_nanos(1));
assert_eq!(1.0.std_microseconds(), StdDuration::from_micros(1));
assert_eq!(1.0.std_milliseconds(), StdDuration::from_millis(1));
assert_eq!(1.0.std_seconds(), StdDuration::from_secs(1));
assert_eq!(1.0.std_minutes(), StdDuration::from_secs(60));
assert_eq!(1.0.std_hours(), StdDuration::from_secs(3_600));
assert_eq!(1.0.std_days(), StdDuration::from_secs(86_400));
assert_eq!(1.0.std_weeks(), StdDuration::from_secs(604_800));
assert_eq!(1.5.std_nanoseconds(), StdDuration::from_nanos(1));
assert_eq!(1.5.std_microseconds(), StdDuration::from_nanos(1_500));
assert_eq!(1.5.std_milliseconds(), StdDuration::from_micros(1_500));
assert_eq!(1.5.std_seconds(), StdDuration::from_millis(1_500));
assert_eq!(1.5.std_minutes(), StdDuration::from_secs(90));
assert_eq!(1.5.std_hours(), StdDuration::from_secs(90 * 60));
assert_eq!(1.5.std_days(), StdDuration::from_secs(36 * 3_600));
assert_eq!(1.5.std_weeks(), StdDuration::from_secs(252 * 3_600));
}
#[test]
fn arithmetic() {
assert_eq!(
2.std_seconds() + 500.std_milliseconds(),
2_500.std_milliseconds()
);
assert_eq!(
2.std_seconds() - 500.std_milliseconds(),
1_500.std_milliseconds()
);
}
}

View File

@@ -0,0 +1,68 @@
use time::format_description::{modifier, BorrowedFormatItem, Component, OwnedFormatItem};
#[test]
fn borrowed_format_item_component_conversions() {
let component = Component::Year(modifier::Year::default());
let item = BorrowedFormatItem::from(component);
assert!(matches!(item, BorrowedFormatItem::Component(inner) if inner == component));
assert_eq!(Component::try_from(item), Ok(component));
assert!(Component::try_from(BorrowedFormatItem::Literal(b"")).is_err());
assert!(<&[BorrowedFormatItem<'_>]>::try_from(BorrowedFormatItem::Literal(b"")).is_err());
}
#[test]
fn borrowed_format_item_compound_conversions() {
let compound = [BorrowedFormatItem::Literal(b"")].as_slice();
let item = BorrowedFormatItem::from(compound);
assert!(matches!(item, BorrowedFormatItem::Compound(inner) if inner == compound));
assert_eq!(<&[BorrowedFormatItem<'_>]>::try_from(item), Ok(compound));
}
#[test]
fn borrowed_format_item_equality() {
let component = Component::Year(modifier::Year::default());
let compound = [BorrowedFormatItem::Literal(b"")].as_slice();
let component_item = BorrowedFormatItem::from(component);
let compound_item = BorrowedFormatItem::from(compound);
assert_eq!(component, component_item);
assert_eq!(component_item, component);
assert_eq!(compound, compound_item);
assert_eq!(compound_item, compound);
}
#[test]
fn owned_format_item_component_conversions() {
let component = Component::Year(modifier::Year::default());
let item = OwnedFormatItem::from(component);
assert!(matches!(item, OwnedFormatItem::Component(inner) if inner == component));
assert_eq!(Component::try_from(item), Ok(component));
assert!(Component::try_from(OwnedFormatItem::Literal(Box::new([]))).is_err());
assert!(Vec::<OwnedFormatItem>::try_from(OwnedFormatItem::Literal(Box::new([]))).is_err());
}
#[test]
fn owned_format_item_compound_conversions() {
let compound = vec![OwnedFormatItem::Literal(Box::new([]))];
let item = OwnedFormatItem::from(compound.clone());
assert!(matches!(item.clone(), OwnedFormatItem::Compound(inner) if inner.to_vec() == compound));
assert_eq!(Vec::<OwnedFormatItem>::try_from(item), Ok(compound));
}
#[test]
fn owned_format_item_equality() {
let component = Component::Year(modifier::Year::default());
let compound = OwnedFormatItem::from([BorrowedFormatItem::Literal(b"")].as_slice());
let component_item = OwnedFormatItem::from(component);
assert_eq!(component, component_item);
assert_eq!(component_item, component);
assert_eq!(
compound,
[OwnedFormatItem::Literal(Box::new([]))].as_slice()
);
assert_eq!(
[OwnedFormatItem::Literal(Box::new([]))].as_slice(),
compound
);
}

View File

@@ -0,0 +1,851 @@
use std::io;
use std::num::NonZero;
use time::format_description::well_known::iso8601::{DateKind, OffsetPrecision, TimePrecision};
use time::format_description::well_known::{Iso8601, Rfc2822, Rfc3339, iso8601};
use time::format_description::{self, BorrowedFormatItem, OwnedFormatItem};
use time::macros::{date, datetime, format_description as fd, offset, time, utc_datetime};
use time::{OffsetDateTime, Time};
#[test]
fn rfc_2822() -> time::Result<()> {
assert_eq!(
datetime!(2021-01-02 03:04:05 UTC).format(&Rfc2822)?,
"Sat, 02 Jan 2021 03:04:05 +0000"
);
assert_eq!(
utc_datetime!(2021-01-02 03:04:05).format(&Rfc2822)?,
"Sat, 02 Jan 2021 03:04:05 +0000"
);
assert_eq!(
datetime!(2021-01-02 03:04:05 +06:07).format(&Rfc2822)?,
"Sat, 02 Jan 2021 03:04:05 +0607"
);
assert_eq!(
datetime!(2021-01-02 03:04:05 -06:07).format(&Rfc2822)?,
"Sat, 02 Jan 2021 03:04:05 -0607"
);
assert!(matches!(
datetime!(1885-01-01 01:01:01 UTC).format(&Rfc2822),
Err(time::error::Format::InvalidComponent("year"))
));
assert!(matches!(
utc_datetime!(1885-01-01 01:01:01).format(&Rfc2822),
Err(time::error::Format::InvalidComponent("year"))
));
assert!(matches!(
datetime!(2000-01-01 00:00:00 +00:00:01).format(&Rfc2822),
Err(time::error::Format::InvalidComponent("offset_second"))
));
Ok(())
}
#[test]
fn rfc_3339() -> time::Result<()> {
assert_eq!(
datetime!(2021-01-02 03:04:05 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.1 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.1Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.12 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.12Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.123Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_4 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.1234Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_45 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.12345Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_456 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.123456Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_456_7 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.1234567Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_456_78 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.12345678Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_456_789 UTC).format(&Rfc3339)?,
"2021-01-02T03:04:05.123456789Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_456_789 -01:02).format(&Rfc3339)?,
"2021-01-02T03:04:05.123456789-01:02"
);
assert_eq!(
datetime!(2021-01-02 03:04:05.123_456_789 +01:02).format(&Rfc3339)?,
"2021-01-02T03:04:05.123456789+01:02"
);
assert!(matches!(
datetime!(-0001-01-01 0:00 UTC).format(&Rfc3339),
Err(time::error::Format::InvalidComponent("year"))
));
assert!(matches!(
datetime!(0000-01-01 0:00 +00:00:01).format(&Rfc3339),
Err(time::error::Format::InvalidComponent("offset_second"))
));
Ok(())
}
#[test]
fn iso_8601() -> time::Result<()> {
macro_rules! assert_format_config {
($formatted:literal $(, $($config:tt)+)?) => {
assert_eq!(
datetime!(2021-01-02 03:04:05 UTC).format(
&Iso8601::<{ iso8601::Config::DEFAULT$($($config)+)?.encode() }>
)?,
$formatted
);
};
}
assert_eq!(
datetime!(-123_456-01-02 03:04:05 UTC).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_year_is_six_digits(true)
.encode()
},
>
)?,
"-123456-01-02T03:04:05.000000000Z"
);
assert_eq!(
datetime!(-123_456-01-02 03:04:05 UTC).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_date_kind(DateKind::Ordinal)
.set_year_is_six_digits(true)
.encode()
},
>
)?,
"-123456-002T03:04:05.000000000Z"
);
assert_eq!(
datetime!(-123_456-01-02 03:04:05 UTC).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_date_kind(DateKind::Week)
.set_year_is_six_digits(true)
.encode()
},
>
)?,
"-123456-W01-4T03:04:05.000000000Z"
);
assert_eq!(
datetime!(2021-01-02 03:04:05+1:00).format(&Iso8601::DEFAULT)?,
"2021-01-02T03:04:05.000000000+01:00"
);
assert_eq!(
datetime!(2021-01-02 03:04:05+1:00).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_offset_precision(OffsetPrecision::Hour)
.encode()
},
>
)?,
"2021-01-02T03:04:05.000000000+01"
);
assert_format_config!("2021-01-02T03:04:05.000000000Z");
assert_format_config!("20210102T030405.000000000Z", .set_use_separators(false));
assert_format_config!("+002021-01-02T03:04:05.000000000Z", .set_year_is_six_digits(true));
assert_format_config!("2021-01-02T03Z", .set_time_precision(TimePrecision::Hour { decimal_digits: None }));
assert_format_config!("2021-01-02T03:04Z", .set_time_precision(TimePrecision::Minute { decimal_digits: None }));
assert_format_config!("2021-01-02T03:04:05Z", .set_time_precision(TimePrecision::Second { decimal_digits: None }));
assert_format_config!("2021-002T03:04:05.000000000Z", .set_date_kind(DateKind::Ordinal));
assert_format_config!("2020-W53-6T03:04:05.000000000Z", .set_date_kind(DateKind::Week));
assert!(matches!(
datetime!(+10_000-01-01 0:00 UTC).format(&Iso8601::DEFAULT),
Err(time::error::Format::InvalidComponent("year"))
));
assert!(matches!(
datetime!(+10_000-W01-1 0:00 UTC).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_date_kind(DateKind::Week)
.encode()
},
>
),
Err(time::error::Format::InvalidComponent("year"))
));
assert!(matches!(
datetime!(+10_000-001 0:00 UTC).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_date_kind(DateKind::Ordinal)
.encode()
},
>
),
Err(time::error::Format::InvalidComponent("year"))
));
assert!(matches!(
datetime!(2021-01-02 03:04:05 +0:00:01).format(&Iso8601::DEFAULT),
Err(time::error::Format::InvalidComponent("offset_second"))
));
assert!(matches!(
datetime!(2021-01-02 03:04:05 +0:01).format(
&Iso8601::<
{
iso8601::Config::DEFAULT
.set_offset_precision(OffsetPrecision::Hour)
.encode()
},
>
),
Err(time::error::Format::InvalidComponent("offset_minute"))
));
Ok(())
}
#[test]
fn iso_8601_issue_678() -> time::Result<()> {
macro_rules! assert_format_config {
($formatted:literal $(, $($config:tt)+)?) => {
assert_eq!(
datetime!(2021-01-02 03:04:05.999_999_999 UTC).format(
&Iso8601::<{ iso8601::Config::DEFAULT$($($config)+)?.encode() }>
)?,
$formatted
);
};
}
assert_format_config!("2021-01-02T03:04:05.999999999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZero::new(9) }));
assert_format_config!("2021-01-02T03:04:05.999999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZero::new(6) }));
assert_format_config!("2021-01-02T03:04:05.999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZero::new(3) }));
Ok(())
}
#[test]
fn format_time() -> time::Result<()> {
let format_output = [
(fd!("[hour]"), "13"),
(fd!("[hour repr:12]"), "01"),
(fd!("[hour repr:12 padding:none]"), "1"),
(fd!("[hour repr:12 padding:space]"), " 1"),
(fd!("[hour repr:24]"), "13"),
(fd!("[hour repr:24]"), "13"),
(fd!("[hour repr:24 padding:none]"), "13"),
(fd!("[hour repr:24 padding:space]"), "13"),
(fd!("[minute]"), "02"),
(fd!("[minute padding:none]"), "2"),
(fd!("[minute padding:space]"), " 2"),
(fd!("[minute padding:zero]"), "02"),
(fd!("[period]"), "PM"),
(fd!("[period case:upper]"), "PM"),
(fd!("[period case:lower]"), "pm"),
(fd!("[second]"), "03"),
(fd!("[second padding:none]"), "3"),
(fd!("[second padding:space]"), " 3"),
(fd!("[second padding:zero]"), "03"),
(fd!("[subsecond]"), "456789012"),
(fd!("[subsecond digits:1]"), "4"),
(fd!("[subsecond digits:2]"), "45"),
(fd!("[subsecond digits:3]"), "456"),
(fd!("[subsecond digits:4]"), "4567"),
(fd!("[subsecond digits:5]"), "45678"),
(fd!("[subsecond digits:6]"), "456789"),
(fd!("[subsecond digits:7]"), "4567890"),
(fd!("[subsecond digits:8]"), "45678901"),
(fd!("[subsecond digits:9]"), "456789012"),
(fd!("[subsecond digits:1+]"), "456789012"),
];
for &(format_description, output) in &format_output {
assert_eq!(
time!(13:02:03.456_789_012).format(format_description)?,
output
);
assert!(
time!(13:02:03.456_789_012)
.format_into(&mut io::sink(), format_description)
.is_ok()
);
assert_eq!(
time!(13:02:03.456_789_012).format(&OwnedFormatItem::from(format_description))?,
output
);
assert!(
time!(13:02:03.456_789_012)
.format_into(&mut io::sink(), &OwnedFormatItem::from(format_description))
.is_ok()
);
}
assert_eq!(
time!(1:02:03).format(fd!("[hour repr:12][period]"))?,
"01AM"
);
assert_eq!(
Time::MIDNIGHT.format(fd!("[hour repr:12][period case:lower]"))?,
"12am"
);
assert_eq!(Time::MIDNIGHT.format(fd!("[subsecond digits:1+]"))?, "0");
assert_eq!(
time!(0:00:00.01).format(fd!("[subsecond digits:1+]"))?,
"01"
);
assert_eq!(
time!(0:00:00.001).format(fd!("[subsecond digits:1+]"))?,
"001"
);
assert_eq!(
time!(0:00:00.0001).format(fd!("[subsecond digits:1+]"))?,
"0001"
);
assert_eq!(
time!(0:00:00.00001).format(fd!("[subsecond digits:1+]"))?,
"00001"
);
assert_eq!(
time!(0:00:00.000001).format(fd!("[subsecond digits:1+]"))?,
"000001"
);
assert_eq!(
time!(0:00:00.0000001).format(fd!("[subsecond digits:1+]"))?,
"0000001"
);
assert_eq!(
time!(0:00:00.00000001).format(fd!("[subsecond digits:1+]"))?,
"00000001"
);
assert_eq!(
time!(0:00:00.000000001).format(fd!("[subsecond digits:1+]"))?,
"000000001"
);
Ok(())
}
#[test]
fn display_time() {
assert_eq!(time!(0:00).to_string(), "0:00:00.0");
assert_eq!(time!(23:59).to_string(), "23:59:00.0");
assert_eq!(time!(23:59:59).to_string(), "23:59:59.0");
assert_eq!(time!(0:00:01).to_string(), "0:00:01.0");
assert_eq!(time!(0:00:00.1).to_string(), "0:00:00.1");
assert_eq!(time!(0:00:00.01).to_string(), "0:00:00.01");
assert_eq!(time!(0:00:00.001).to_string(), "0:00:00.001");
assert_eq!(time!(0:00:00.000_1).to_string(), "0:00:00.0001");
assert_eq!(time!(0:00:00.000_01).to_string(), "0:00:00.00001");
assert_eq!(time!(0:00:00.000_001).to_string(), "0:00:00.000001");
assert_eq!(time!(0:00:00.000_000_1).to_string(), "0:00:00.0000001");
assert_eq!(time!(0:00:00.000_000_01).to_string(), "0:00:00.00000001");
assert_eq!(time!(0:00:00.000_000_001).to_string(), "0:00:00.000000001");
assert_eq!(format!("{:>12}", time!(0:00)), " 0:00:00.0");
assert_eq!(format!("{:x^14}", time!(0:00)), "xx0:00:00.0xxx");
}
#[test]
fn format_date() -> time::Result<()> {
let format_output = [
(fd!("[day]"), "31"),
(fd!("[month]"), "12"),
(fd!("[month repr:short]"), "Dec"),
(fd!("[month repr:long]"), "December"),
(fd!("[ordinal]"), "365"),
(fd!("[weekday]"), "Tuesday"),
(fd!("[weekday repr:short]"), "Tue"),
(fd!("[weekday repr:sunday]"), "3"),
(fd!("[weekday repr:sunday one_indexed:false]"), "2"),
(fd!("[weekday repr:monday]"), "2"),
(fd!("[weekday repr:monday one_indexed:false]"), "1"),
(fd!("[week_number]"), "01"),
(fd!("[week_number padding:none]"), "1"),
(fd!("[week_number padding:space]"), " 1"),
(fd!("[week_number repr:sunday]"), "52"),
(fd!("[week_number repr:monday]"), "52"),
(fd!("[year]"), "2019"),
(fd!("[year base:iso_week]"), "2020"),
(fd!("[year sign:mandatory]"), "+2019"),
(fd!("[year base:iso_week sign:mandatory]"), "+2020"),
(fd!("[year repr:century]"), "20"),
(fd!("[year repr:last_two]"), "19"),
(fd!("[year base:iso_week repr:last_two]"), "20"),
(fd!("[year range:standard]"), "2019"),
(fd!("[year range:standard repr:century]"), "20"),
(fd!("[year range:standard repr:last_two]"), "19"),
];
for &(format_description, output) in &format_output {
assert_eq!(date!(2019-12-31).format(format_description)?, output);
assert!(
date!(2019-12-31)
.format_into(&mut io::sink(), format_description)
.is_ok()
);
assert_eq!(
date!(2019-12-31).format(&OwnedFormatItem::from(format_description))?,
output
);
assert!(
date!(2019-12-31)
.format_into(&mut io::sink(), &OwnedFormatItem::from(format_description))
.is_ok()
);
}
Ok(())
}
#[test]
fn format_date_err() {
assert!(matches!(
date!(+10_000-01-01).format(fd!("[year range:standard]")),
Err(time::error::Format::ComponentRange(cr)) if cr.name() == "year"
));
assert!(matches!(
date!(+10_000-01-01).format(fd!("[year repr:century range:standard]")),
Err(time::error::Format::ComponentRange(cr)) if cr.name() == "year"
));
}
#[test]
fn display_date() {
assert_eq!(date!(2019-01-01).to_string(), "2019-01-01");
assert_eq!(date!(2019-12-31).to_string(), "2019-12-31");
assert_eq!(date!(-4713-11-24).to_string(), "-4713-11-24");
assert_eq!(date!(-0001-01-01).to_string(), "-0001-01-01");
assert_eq!(date!(+10_000-01-01).to_string(), "+10000-01-01");
assert_eq!(date!(+100_000-01-01).to_string(), "+100000-01-01");
assert_eq!(date!(-10_000-01-01).to_string(), "-10000-01-01");
assert_eq!(date!(-100_000-01-01).to_string(), "-100000-01-01");
}
#[test]
fn format_offset() -> time::Result<()> {
let value_format_output = [
(
offset!(+01:02:03),
fd!("[offset_hour sign:automatic]"),
"01",
),
(
offset!(+01:02:03),
fd!("[offset_hour sign:mandatory]"),
"+01",
),
(
offset!(-01:02:03),
fd!("[offset_hour sign:automatic]"),
"-01",
),
(
offset!(-01:02:03),
fd!("[offset_hour sign:mandatory]"),
"-01",
),
(offset!(+01:02:03), fd!("[offset_minute]"), "02"),
(offset!(+01:02:03), fd!("[offset_second]"), "03"),
];
for &(value, format_description, output) in &value_format_output {
assert_eq!(value.format(format_description)?, output);
assert!(
value
.format_into(&mut io::sink(), format_description)
.is_ok()
);
assert_eq!(
value.format(&OwnedFormatItem::from(format_description))?,
output
);
assert!(
value
.format_into(&mut io::sink(), &OwnedFormatItem::from(format_description))
.is_ok()
);
}
Ok(())
}
#[test]
fn display_offset() {
assert_eq!(offset!(UTC).to_string(), "+00:00:00");
assert_eq!(offset!(+0:00:01).to_string(), "+00:00:01");
assert_eq!(offset!(-0:00:01).to_string(), "-00:00:01");
assert_eq!(offset!(+1).to_string(), "+01:00:00");
assert_eq!(offset!(-1).to_string(), "-01:00:00");
assert_eq!(offset!(+23:59).to_string(), "+23:59:00");
assert_eq!(offset!(-23:59).to_string(), "-23:59:00");
assert_eq!(offset!(+23:59:59).to_string(), "+23:59:59");
assert_eq!(offset!(-23:59:59).to_string(), "-23:59:59");
assert_eq!(format!("{:>10}", offset!(UTC)), " +00:00:00");
assert_eq!(format!("{:x^14}", offset!(UTC)), "xx+00:00:00xxx");
}
#[test]
fn format_pdt() -> time::Result<()> {
let format_description = fd!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]");
assert_eq!(
datetime!(1970-01-01 0:00).format(format_description)?,
"1970-01-01 00:00:00.0"
);
assert!(
datetime!(1970-01-01 0:00)
.format_into(&mut io::sink(), format_description)
.is_ok()
);
assert_eq!(
datetime!(1970-01-01 0:00).format(&OwnedFormatItem::from(format_description))?,
"1970-01-01 00:00:00.0"
);
assert!(
datetime!(1970-01-01 0:00)
.format_into(&mut io::sink(), &OwnedFormatItem::from(format_description))
.is_ok()
);
Ok(())
}
#[test]
fn display_pdt() {
assert_eq!(
datetime!(1970-01-01 0:00).to_string(),
String::from("1970-01-01 0:00:00.0")
);
assert_eq!(
datetime!(1970-01-01 0:00:01).to_string(),
String::from("1970-01-01 0:00:01.0")
);
}
#[test]
fn format_odt() -> time::Result<()> {
let format_description = format_description::parse(
"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:1+] [offset_hour \
sign:mandatory]:[offset_minute]:[offset_second]",
)?;
assert_eq!(
datetime!(1970-01-01 0:00 UTC).format(&format_description)?,
"1970-01-01 00:00:00.0 +00:00:00"
);
assert!(
datetime!(1970-01-01 0:00 UTC)
.format_into(&mut io::sink(), &format_description)
.is_ok()
);
assert_eq!(
datetime!(1970-01-01 0:00 UTC).format(&OwnedFormatItem::from(&format_description))?,
"1970-01-01 00:00:00.0 +00:00:00"
);
assert!(
datetime!(1970-01-01 0:00 UTC)
.format_into(&mut io::sink(), &OwnedFormatItem::from(format_description))
.is_ok()
);
Ok(())
}
#[test]
fn display_odt() {
assert_eq!(
datetime!(1970-01-01 0:00 UTC).to_string(),
"1970-01-01 0:00:00.0 +00:00:00"
);
}
#[test]
fn format_udt() -> time::Result<()> {
let format_description = fd!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]");
assert_eq!(
utc_datetime!(1970-01-01 0:00).format(format_description)?,
"1970-01-01 00:00:00.0"
);
assert!(
utc_datetime!(1970-01-01 0:00)
.format_into(&mut io::sink(), format_description)
.is_ok()
);
assert_eq!(
utc_datetime!(1970-01-01 0:00).format(&OwnedFormatItem::from(format_description))?,
"1970-01-01 00:00:00.0"
);
assert!(
utc_datetime!(1970-01-01 0:00)
.format_into(&mut io::sink(), &OwnedFormatItem::from(format_description))
.is_ok()
);
Ok(())
}
#[test]
fn display_udt() {
assert_eq!(
utc_datetime!(1970-01-01 0:00).to_string(),
"1970-01-01 0:00:00.0 +00"
);
}
#[test]
fn insufficient_type_information() {
let assert_insufficient_type_information = |res| {
assert!(matches!(
res,
Err(time::error::Format::InsufficientTypeInformation { .. })
));
};
assert_insufficient_type_information(Time::MIDNIGHT.format(fd!("[year]")));
assert_insufficient_type_information(Time::MIDNIGHT.format(&BorrowedFormatItem::First(&[
BorrowedFormatItem::Compound(fd!("[year]")),
])));
}
#[expect(clippy::cognitive_complexity, reason = "all test the same thing")]
#[test]
fn failed_write() -> time::Result<()> {
macro_rules! assert_err {
($val:expr, $format:expr) => {{
let val = $val;
let format = $format;
let success_len = val.format(&format)?.len();
for len in 0..success_len {
let mut buf = &mut vec![0; len][..];
let res = val.format_into(&mut buf, &format);
assert!(matches!(
res,
Err(time::error::Format::StdIo(e)) if e.kind() == io::ErrorKind::WriteZero)
);
}
}};
}
assert_err!(Time::MIDNIGHT, fd!("foo"));
assert_err!(Time::MIDNIGHT, OwnedFormatItem::from(fd!("foo")));
assert_err!(Time::MIDNIGHT, BorrowedFormatItem::Compound(fd!("foo")));
assert_err!(
Time::MIDNIGHT,
BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(fd!("foo")))
);
assert_err!(
Time::MIDNIGHT,
OwnedFormatItem::from(BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(
fd!("foo")
)))
);
assert_err!(OffsetDateTime::UNIX_EPOCH, Rfc3339);
assert_err!(datetime!(2021-001 0:00:00.1 UTC), Rfc3339);
assert_err!(datetime!(2021-001 0:00 +0:01), Rfc3339);
assert_err!(OffsetDateTime::UNIX_EPOCH, Rfc2822);
assert_err!(OffsetDateTime::UNIX_EPOCH, Iso8601::DEFAULT);
assert_err!(datetime!(2021-001 0:00 +0:01), Iso8601::DEFAULT);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_year_is_six_digits(true)
.encode()
},
>
);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_date_kind(DateKind::Ordinal)
.encode()
},
>
);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_year_is_six_digits(true)
.set_date_kind(DateKind::Ordinal)
.encode()
},
>
);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_year_is_six_digits(true)
.set_date_kind(DateKind::Week)
.encode()
},
>
);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_date_kind(DateKind::Week)
.encode()
},
>
);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_time_precision(TimePrecision::Minute {
decimal_digits: None,
})
.encode()
},
>
);
assert_err!(
OffsetDateTime::UNIX_EPOCH,
Iso8601::<
{
iso8601::Config::DEFAULT
.set_time_precision(TimePrecision::Hour {
decimal_digits: None,
})
.encode()
},
>
);
assert_err!(Time::MIDNIGHT, fd!("[hour padding:space]"));
assert_err!(offset!(+1), fd!("[offset_hour sign:mandatory]"));
assert_err!(offset!(-1), fd!("[offset_hour]"));
assert_err!(date!(-1-001), fd!("[year]"));
assert_err!(date!(2021-001), fd!("[year sign:mandatory]"));
assert_err!(date!(+999_999-001), fd!("[year]"));
assert_err!(date!(+99_999-001), fd!("[year]"));
let component_names = [
"day",
"month",
"ordinal",
"weekday",
"week_number",
"year",
"hour",
"minute",
"period",
"second",
"subsecond",
"offset_hour",
"offset_minute",
"offset_second",
];
for component in &component_names {
let component = format!("[{component}]");
assert_err!(
OffsetDateTime::UNIX_EPOCH,
format_description::parse(&component)?
);
}
Ok(())
}
#[test]
fn first() -> time::Result<()> {
assert_eq!(Time::MIDNIGHT.format(&BorrowedFormatItem::First(&[]))?, "");
assert_eq!(
Time::MIDNIGHT.format(&BorrowedFormatItem::First(&[BorrowedFormatItem::Compound(
fd!("[hour]")
)]))?,
"00"
);
assert_eq!(
Time::MIDNIGHT.format(&OwnedFormatItem::First(Box::new([])))?,
""
);
assert_eq!(
Time::MIDNIGHT.format(&OwnedFormatItem::from(BorrowedFormatItem::First(&[
BorrowedFormatItem::Compound(fd!("[hour]"))
])))?,
"00"
);
Ok(())
}
#[test]
fn ignore() -> time::Result<()> {
assert_eq!(Time::MIDNIGHT.format(fd!("[ignore count:2]"))?, "");
Ok(())
}
#[test]
fn end() -> time::Result<()> {
assert_eq!(Time::MIDNIGHT.format(fd!("[end]"))?, "");
Ok(())
}
#[test]
fn unix_timestamp() -> time::Result<()> {
let dt = datetime!(2009-02-13 23:31:30.123456789 UTC);
assert_eq!(dt.format(&fd!("[unix_timestamp]"))?, "1234567890");
assert_eq!(
dt.format(&fd!("[unix_timestamp sign:mandatory]"))?,
"+1234567890"
);
assert_eq!(
dt.format(&fd!("[unix_timestamp precision:millisecond]"))?,
"1234567890123"
);
assert_eq!(
dt.format(&fd!("[unix_timestamp precision:microsecond]"))?,
"1234567890123456"
);
assert_eq!(
dt.format(&fd!("[unix_timestamp precision:nanosecond]"))?,
"1234567890123456789"
);
assert_eq!(
datetime!(1969-12-31 23:59:59 UTC).format(&fd!("[unix_timestamp]"))?,
"-1"
);
Ok(())
}

237
vendor/time/tests/integration/instant.rs vendored Normal file
View File

@@ -0,0 +1,237 @@
#![expect(deprecated)]
use std::cmp::Ordering;
use std::thread;
use std::time::Instant as StdInstant;
use time::ext::{NumericalDuration, NumericalStdDuration};
use time::{Duration, Instant};
#[test]
fn elapsed() {
let instant = Instant::now();
thread::sleep(1.std_milliseconds());
assert!(instant.elapsed() >= 1.milliseconds());
}
#[test]
fn checked_add() {
let now = Instant::now();
assert_eq!(now.checked_add(0.seconds()), Some(now));
assert_eq!(now.checked_add(5.seconds()), Some(now + 5.seconds()));
assert_eq!(now.checked_add((-5).seconds()), Some(now + (-5).seconds()));
}
#[test]
fn checked_sub() {
let now = Instant::now();
assert_eq!(now.checked_sub(0.seconds()), Some(now));
assert_eq!(now.checked_sub(5.seconds()), Some(now - 5.seconds()));
assert_eq!(now.checked_sub((-5).seconds()), Some(now - (-5).seconds()));
}
#[test]
fn into_inner() {
let now = Instant::now();
assert_eq!(now.into_inner(), now.0);
}
#[test]
fn std_from() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time);
assert_eq!(now_time, now_std);
}
#[test]
fn from_std() {
let now_std = StdInstant::now();
let now_time = Instant::from(now_std);
assert_eq!(now_time, now_std);
}
#[test]
fn sub() {
let start = Instant::now();
thread::sleep(1.std_milliseconds());
assert!(Instant::now() - start >= 1.milliseconds());
assert_eq!(start - start, Duration::ZERO);
}
#[test]
fn sub_std() {
let start = StdInstant::now();
thread::sleep(1.std_milliseconds());
assert!(Instant::now() - start >= 1.milliseconds());
}
#[test]
fn std_sub() {
let start = Instant::now();
thread::sleep(1.std_milliseconds());
assert!(StdInstant::now() - start >= 1.milliseconds());
}
#[test]
fn add_duration() {
let start = Instant::now();
assert!(start + 0.seconds() <= Instant::now());
thread::sleep(1.std_milliseconds());
assert!(start + 1.milliseconds() <= Instant::now());
}
#[test]
fn std_add_duration() {
let start = StdInstant::now();
thread::sleep(1.std_milliseconds());
assert!(start + 1.milliseconds() <= StdInstant::now());
}
#[test]
fn add_std_duration() {
let start = Instant::now();
thread::sleep(1.std_milliseconds());
assert!(start + 1.std_milliseconds() <= Instant::now());
}
#[test]
fn add_assign_duration() {
let mut start = Instant::now();
thread::sleep(1.std_milliseconds());
start += 1.milliseconds();
assert!(start <= Instant::now());
}
#[test]
fn std_add_assign_duration() {
let mut start = StdInstant::now();
thread::sleep(1.std_milliseconds());
start += 1.milliseconds();
assert!(start <= StdInstant::now());
}
#[test]
fn add_assign_std_duration() {
let mut start = Instant::now();
thread::sleep(1.std_milliseconds());
start += 1.std_milliseconds();
assert!(start <= Instant::now());
}
#[test]
fn sub_duration() {
let instant = Instant::now();
assert!(instant - 100.milliseconds() <= Instant::now());
assert_eq!(instant - Duration::ZERO, instant);
}
#[test]
fn std_sub_duration() {
let instant = StdInstant::now();
assert!(instant - 100.milliseconds() <= StdInstant::now());
}
#[test]
fn sub_std_duration() {
let instant = Instant::now();
assert!(instant - 100.std_milliseconds() <= Instant::now());
}
#[test]
fn sub_assign_duration() {
let mut instant = Instant::now();
instant -= 100.milliseconds();
assert!(instant <= Instant::now());
}
#[test]
fn std_sub_assign_duration() {
let mut instant = StdInstant::now();
instant -= 100.milliseconds();
assert!(instant <= StdInstant::now());
}
#[test]
fn sub_assign_std_duration() {
let mut instant = Instant::now();
instant -= 100.std_milliseconds();
assert!(instant <= Instant::now());
}
#[test]
fn eq_std() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time);
assert_eq!(now_time, now_std);
}
#[test]
fn std_eq() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time);
assert_eq!(now_std, now_time);
}
#[test]
fn ord() {
let now_time = Instant::now();
let now_std = now_time + 1.seconds();
assert_eq!(now_time.cmp(&now_std), Ordering::Less);
let now_time = Instant::now();
let now_std = now_time - 1.seconds();
assert_eq!(now_time.cmp(&now_std), Ordering::Greater);
}
#[test]
fn partial_ord_std() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) + 1.seconds();
assert!(now_time < now_std);
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) - 1.seconds();
assert!(now_time > now_std);
}
#[test]
fn std_partial_ord() {
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) + 1.seconds();
assert!(now_std > now_time);
let now_time = Instant::now();
let now_std = StdInstant::from(now_time) - 1.seconds();
assert!(now_std < now_time);
}
#[test]
fn sub_regression() {
let now = Instant::now();
let future = now + Duration::seconds(5);
let past = now - Duration::seconds(5);
assert_eq!(future - now, Duration::seconds(5));
assert_eq!(now - past, Duration::seconds(5));
assert_eq!(future - past, Duration::seconds(10));
assert_eq!(now - future, Duration::seconds(-5));
assert_eq!(past - now, Duration::seconds(-5));
assert_eq!(past - future, Duration::seconds(-10));
}
#[test]
fn as_ref() {
let now = Instant::now();
assert_eq!(now.as_ref(), now.as_ref());
}
#[test]
fn borrow() {
use std::borrow::Borrow;
let now = Instant::now();
assert_eq!(
<Instant as Borrow<StdInstant>>::borrow(&now),
<Instant as Borrow<StdInstant>>::borrow(&now)
);
}

393
vendor/time/tests/integration/macros.rs vendored Normal file
View File

@@ -0,0 +1,393 @@
use core::num::NonZero;
use rstest::rstest;
use time::format_description::modifier::{
Day, End, Ignore, Month, MonthRepr, OffsetMinute, OffsetSecond, Ordinal, Padding, Period,
TrailingInput, UnixTimestamp, UnixTimestampPrecision, WeekNumber, WeekNumberRepr, Weekday,
WeekdayRepr, Year, YearRepr,
};
use time::format_description::{BorrowedFormatItem, Component};
use time::macros::{date, format_description, time};
use time::{Date, Time};
#[rstest]
fn nontrivial_string() {
assert!(format_description!(r"").is_empty());
assert!(format_description!(r###""###).is_empty());
assert!(format_description!(b"").is_empty());
assert!(format_description!(br"").is_empty());
assert!(format_description!(br###""###).is_empty());
#[rustfmt::skip]
assert_eq!(
format_description!("foo\
bar\n\r\t\\\"\'\0\x20\x4E\x4e\u{20}\u{4E}\u{4_e}"),
&[BorrowedFormatItem::Literal(b"foobar\n\r\t\\\"'\0 NN NN")]
);
#[rustfmt::skip]
assert_eq!(
format_description!(b"foo\
bar\n\r\t\\\"\'\0\x20\x4E\x4e"),
&[BorrowedFormatItem::Literal(b"foobar\n\r\t\\\"'\0 NN")]
);
}
#[rstest]
fn format_description_version() {
assert_eq!(
format_description!(version = 1, "[["),
&[BorrowedFormatItem::Literal(b"[")]
);
assert_eq!(
format_description!(version = 1, r"\\"),
&[BorrowedFormatItem::Literal(br"\\")]
);
assert_eq!(
format_description!(version = 2, r"\\"),
&[BorrowedFormatItem::Literal(br"\")]
);
}
#[rstest]
fn nested_v1() {
assert_eq!(
format_description!(version = 1, "[optional [[[]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Literal(
b"["
))]
);
assert_eq!(
format_description!(version = 1, "[optional [ [[ ]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(
&[
BorrowedFormatItem::Literal(b" "),
BorrowedFormatItem::Literal(b"["),
BorrowedFormatItem::Literal(b" "),
]
))]
);
assert_eq!(
format_description!(version = 1, "[first [a][[[]]"),
&[BorrowedFormatItem::First(&[
BorrowedFormatItem::Literal(b"a"),
BorrowedFormatItem::Literal(b"[")
])]
);
}
#[rstest]
fn optional() {
assert_eq!(
format_description!(version = 2, "[optional [:[year]]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(
&[
BorrowedFormatItem::Literal(b":"),
BorrowedFormatItem::Component(Component::Year(Default::default()))
]
))]
);
assert_eq!(
format_description!(version = 2, "[optional [[year]]]"),
&[BorrowedFormatItem::Optional(
&BorrowedFormatItem::Component(Component::Year(Default::default()))
)]
);
assert_eq!(
format_description!(version = 2, r"[optional [\[]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Literal(
b"["
))]
);
assert_eq!(
format_description!(version = 2, r"[optional [ \[ ]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(
&[
BorrowedFormatItem::Literal(b" "),
BorrowedFormatItem::Literal(b"["),
BorrowedFormatItem::Literal(b" "),
]
))]
);
}
#[rstest]
fn first() {
assert_eq!(
format_description!(version = 2, "[first [a]]"),
&[BorrowedFormatItem::First(&[BorrowedFormatItem::Literal(
b"a"
)])]
);
assert_eq!(
format_description!(version = 2, "[first [a] [b]]"),
&[BorrowedFormatItem::First(&[
BorrowedFormatItem::Literal(b"a"),
BorrowedFormatItem::Literal(b"b"),
])]
);
assert_eq!(
format_description!(version = 2, "[first [a][b]]"),
&[BorrowedFormatItem::First(&[
BorrowedFormatItem::Literal(b"a"),
BorrowedFormatItem::Literal(b"b"),
])]
);
assert_eq!(
format_description!(version = 2, r"[first [a][\[]]"),
&[BorrowedFormatItem::First(&[
BorrowedFormatItem::Literal(b"a"),
BorrowedFormatItem::Literal(b"["),
])]
);
assert_eq!(
format_description!(version = 2, r"[first [a][\[\[]]"),
&[BorrowedFormatItem::First(&[
BorrowedFormatItem::Literal(b"a"),
BorrowedFormatItem::Compound(&[
BorrowedFormatItem::Literal(b"["),
BorrowedFormatItem::Literal(b"["),
])
])]
);
assert_eq!(
format_description!(
version = 2,
"[first [[period case:upper]] [[period case:lower]] ]"
),
&[BorrowedFormatItem::First(&[
BorrowedFormatItem::Component(Component::Period(
Period::default()
.with_is_uppercase(true)
.with_case_sensitive(true)
)),
BorrowedFormatItem::Component(Component::Period(
Period::default()
.with_is_uppercase(false)
.with_case_sensitive(true)
)),
])]
);
}
#[rstest]
fn backslash_escape() {
assert_eq!(
format_description!(version = 2, r"[optional [\]]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Literal(
b"]"
))]
);
assert_eq!(
format_description!(version = 2, r"[optional [\[]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Literal(
b"["
))]
);
assert_eq!(
format_description!(version = 2, r"[optional [\\]]"),
&[BorrowedFormatItem::Optional(&BorrowedFormatItem::Literal(
br"\"
))]
);
assert_eq!(
format_description!(version = 2, r"\\"),
&[BorrowedFormatItem::Literal(br"\")]
);
assert_eq!(
format_description!(version = 2, r"\["),
&[BorrowedFormatItem::Literal(br"[")]
);
assert_eq!(
format_description!(version = 2, r"\]"),
&[BorrowedFormatItem::Literal(br"]")]
);
assert_eq!(
format_description!(version = 2, r"foo\\"),
&[
BorrowedFormatItem::Literal(b"foo"),
BorrowedFormatItem::Literal(br"\"),
]
);
assert_eq!(
format_description!(version = 2, r"\\"),
&[BorrowedFormatItem::Literal(br"\")]
);
assert_eq!(
format_description!(version = 2, r"\["),
&[BorrowedFormatItem::Literal(br"[")]
);
assert_eq!(
format_description!(version = 2, r"\]"),
&[BorrowedFormatItem::Literal(br"]")]
);
assert_eq!(
format_description!(version = 2, r"foo\\"),
&[
BorrowedFormatItem::Literal(b"foo"),
BorrowedFormatItem::Literal(br"\"),
]
);
}
#[rstest]
fn format_description_coverage() {
assert_eq!(
format_description!("[day padding:space][day padding:zero][day padding:none]"),
&[
BorrowedFormatItem::Component(Component::Day(
Day::default().with_padding(Padding::Space)
)),
BorrowedFormatItem::Component(Component::Day(
Day::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Component(Component::Day(
Day::default().with_padding(Padding::None)
))
]
);
assert_eq!(
format_description!(
"[offset_minute padding:space][offset_minute padding:zero][offset_minute padding:none]"
),
&[
BorrowedFormatItem::Component(Component::OffsetMinute(
OffsetMinute::default().with_padding(Padding::Space)
)),
BorrowedFormatItem::Component(Component::OffsetMinute(
OffsetMinute::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Component(Component::OffsetMinute(
OffsetMinute::default().with_padding(Padding::None)
))
]
);
assert_eq!(
format_description!(
"[offset_second padding:space][offset_second padding:zero][offset_second padding:none]"
),
&[
BorrowedFormatItem::Component(Component::OffsetSecond(
OffsetSecond::default().with_padding(Padding::Space)
)),
BorrowedFormatItem::Component(Component::OffsetSecond(
OffsetSecond::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Component(Component::OffsetSecond(
OffsetSecond::default().with_padding(Padding::None)
)),
]
);
assert_eq!(
format_description!("[ordinal padding:space][ordinal padding:zero][ordinal padding:none]"),
&[
BorrowedFormatItem::Component(Component::Ordinal(
Ordinal::default().with_padding(Padding::Space)
)),
BorrowedFormatItem::Component(Component::Ordinal(
Ordinal::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Component(Component::Ordinal(
Ordinal::default().with_padding(Padding::None)
)),
]
);
assert_eq!(
format_description!("[month repr:numerical]"),
&[BorrowedFormatItem::Component(Component::Month(
Month::default()
.with_repr(MonthRepr::Numerical)
.with_padding(Padding::Zero)
))]
);
assert_eq!(
format_description!("[week_number repr:iso ]"),
&[BorrowedFormatItem::Component(Component::WeekNumber(
WeekNumber::default()
.with_padding(Padding::Zero)
.with_repr(WeekNumberRepr::Iso)
))]
);
assert_eq!(
format_description!("[weekday repr:long one_indexed:true]"),
&[BorrowedFormatItem::Component(Component::Weekday(
Weekday::default()
.with_repr(WeekdayRepr::Long)
.with_one_indexed(true)
))]
);
assert_eq!(
format_description!("[year repr:full base:calendar]"),
&[BorrowedFormatItem::Component(Component::Year(
Year::default()
.with_repr(YearRepr::Full)
.with_iso_week_based(false)
.with_padding(Padding::Zero)
.with_sign_is_mandatory(false)
))]
);
assert_eq!(
format_description!("[[ "),
&[
BorrowedFormatItem::Literal(b"["),
BorrowedFormatItem::Literal(b" ")
]
);
assert_eq!(
format_description!("[ignore count:2]"),
&[BorrowedFormatItem::Component(Component::Ignore(
Ignore::count(const { NonZero::new(2).unwrap() })
))]
);
assert_eq!(
format_description!("[unix_timestamp precision:nanosecond sign:mandatory]"),
&[BorrowedFormatItem::Component(Component::UnixTimestamp(
UnixTimestamp::default()
.with_precision(UnixTimestampPrecision::Nanosecond)
.with_sign_is_mandatory(true)
))]
);
assert_eq!(
format_description!("[end]"),
&[BorrowedFormatItem::Component(
Component::End(End::default())
)]
);
assert_eq!(
format_description!("[end trailing_input:prohibit]"),
&[BorrowedFormatItem::Component(Component::End(
End::default().with_trailing_input(TrailingInput::Prohibit)
))]
);
assert_eq!(
format_description!("[end trailing_input:discard]"),
&[BorrowedFormatItem::Component(Component::End(
End::default().with_trailing_input(TrailingInput::Discard)
))]
);
}
#[rstest]
fn date_coverage() {
assert_eq!(Ok(date!(2000-001)), Date::from_ordinal_date(2000, 1));
assert_eq!(Ok(date!(2019-W01-1)), Date::from_ordinal_date(2018, 365));
assert_eq!(Ok(date!(2021-W52-6)), Date::from_ordinal_date(2022, 1));
assert_eq!(Ok(date!(2021-W34-5)), Date::from_ordinal_date(2021, 239));
}
#[rstest]
fn time_coverage() {
assert_eq!(time!(12 AM), Time::MIDNIGHT);
assert_eq!(Ok(time!(12 PM)), Time::from_hms(12, 0, 0));
}
mod demo {
#[expect(dead_code)]
type Result<T> = core::result::Result<T, ()>;
#[expect(dead_code)]
type Option = core::option::Option<()>;
time::serde::format_description!(
seconds,
OffsetDateTime,
"[year]-[month]-[day]T[hour]:[minute]:[second]Z"
);
}

134
vendor/time/tests/integration/main.rs vendored Normal file
View File

@@ -0,0 +1,134 @@
#![allow(missing_docs, reason = "may be removed in the future")]
#![allow(
clippy::missing_const_for_fn,
clippy::std_instead_of_core,
clippy::std_instead_of_alloc,
clippy::alloc_instead_of_core,
reason = "irrelevant for tests"
)]
#[cfg(not(all(
feature = "default",
feature = "alloc",
feature = "formatting",
feature = "large-dates",
feature = "local-offset",
feature = "macros",
feature = "parsing",
feature = "quickcheck",
feature = "serde-human-readable",
feature = "serde-well-known",
feature = "std",
feature = "rand",
feature = "serde",
)))]
#[test]
fn run_with_all_features() -> Result<(), Box<dyn std::error::Error>> {
#[derive(Debug)]
struct Error(std::process::ExitStatus);
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for Error {}
let status = std::process::Command::new("cargo")
.args(["test", "--all-features"])
.status()?;
return if status.success() {
Ok(())
} else {
Err(Box::new(Error(status)))
};
// Intentionally unreachable. This is to show the user a warning when they don't provide
// `--all-features`.
"Tests must be run with `--all-features`. Because the flag was not provided, `cargo test \
--all-features` is run.";
}
macro_rules! require_all_features {
($($x:item)*) => {$(
#[cfg(all(
feature = "default",
feature = "alloc",
feature = "formatting",
feature = "large-dates",
feature = "local-offset",
feature = "macros",
feature = "parsing",
feature = "quickcheck",
feature = "serde-human-readable",
feature = "serde-well-known",
feature = "std",
feature = "rand",
feature = "serde",
))]
$x
)*};
}
require_all_features! {
/// Assert that the given expression panics.
macro_rules! assert_panic {
($($x:tt)*) => {
assert!(std::panic::catch_unwind(|| {
$($x)*
})
.is_err())
}
}
/// `assert_eq!` or `assert_ne!` depending on the value of `$is_eq`.
///
/// This provides better diagnostics than `assert_eq!($left == $right, $is_eq)`.
macro_rules! assert_eq_ne {
($left:expr, $right:expr, $is_eq:expr $(, $($rest:tt)*)?) => {{
if $is_eq {
assert_eq!($left, $right $(, $($rest)*)?);
} else {
assert_ne!($left, $right $(, $($rest)*)?);
}
}}
}
mod convert;
mod date;
mod derives;
mod duration;
mod error;
mod ext;
mod format_description;
mod formatting;
mod instant;
mod macros;
mod meta;
mod month;
mod offset_date_time;
mod parse_format_description;
mod parsed;
mod parsing;
mod primitive_date_time;
#[path = "quickcheck.rs"]
mod quickcheck_mod;
mod rand;
mod serde;
mod serde_helpers;
mod time;
mod utc_date_time;
mod utc_offset;
mod util;
mod weekday;
#[cfg(__ui_tests)]
#[test]
fn compile_fail() {
let tests = trybuild::TestCases::new();
// Path is relative from `time/Cargo.toml`.
tests.compile_fail("./tests/integration/compile-fail/*.rs");
}
}

1139
vendor/time/tests/integration/meta.rs vendored Normal file

File diff suppressed because it is too large Load Diff

178
vendor/time/tests/integration/month.rs vendored Normal file
View File

@@ -0,0 +1,178 @@
use rstest::rstest;
use time::Month::{self, *};
#[rstest]
#[case(January, December)]
#[case(February, January)]
#[case(March, February)]
#[case(April, March)]
#[case(May, April)]
#[case(June, May)]
#[case(July, June)]
#[case(August, July)]
#[case(September, August)]
#[case(October, September)]
#[case(November, October)]
#[case(December, November)]
fn previous(#[case] month: Month, #[case] expected: Month) {
assert_eq!(month.previous(), expected);
}
#[rstest]
#[case(January, February)]
#[case(February, March)]
#[case(March, April)]
#[case(April, May)]
#[case(May, June)]
#[case(June, July)]
#[case(July, August)]
#[case(August, September)]
#[case(September, October)]
#[case(October, November)]
#[case(November, December)]
#[case(December, January)]
fn next(#[case] month: Month, #[case] expected: Month) {
assert_eq!(month.next(), expected);
}
#[rstest]
#[case(January, 0, January)]
#[case(January, 1, February)]
#[case(January, 2, March)]
#[case(January, 3, April)]
#[case(January, 4, May)]
#[case(January, 5, June)]
#[case(January, 6, July)]
#[case(January, 7, August)]
#[case(January, 8, September)]
#[case(January, 9, October)]
#[case(January, 10, November)]
#[case(January, 11, December)]
#[case(December, 0, December)]
#[case(December, 1, January)]
#[case(December, 2, February)]
#[case(December, 3, March)]
#[case(December, 4, April)]
#[case(December, 5, May)]
#[case(December, 6, June)]
#[case(December, 7, July)]
#[case(December, 8, August)]
#[case(December, 9, September)]
#[case(December, 10, October)]
#[case(December, 11, November)]
#[case(January, 12, January)]
#[case(January, u8::MAX, April)]
#[case(December, 12, December)]
#[case(December, u8::MAX, March)]
fn nth_next(#[case] month: Month, #[case] n: u8, #[case] expected: Month) {
assert_eq!(month.nth_next(n), expected);
}
#[rstest]
#[case(January, 0, January)]
#[case(January, 1, December)]
#[case(January, 2, November)]
#[case(January, 3, October)]
#[case(January, 4, September)]
#[case(January, 5, August)]
#[case(January, 6, July)]
#[case(January, 7, June)]
#[case(January, 8, May)]
#[case(January, 9, April)]
#[case(January, 10, March)]
#[case(January, 11, February)]
#[case(December, 0, December)]
#[case(December, 1, November)]
#[case(December, 2, October)]
#[case(December, 3, September)]
#[case(December, 4, August)]
#[case(December, 5, July)]
#[case(December, 6, June)]
#[case(December, 7, May)]
#[case(December, 8, April)]
#[case(December, 9, March)]
#[case(December, 10, February)]
#[case(December, 11, January)]
#[case(January, 12, January)]
#[case(January, u8::MAX, October)]
#[case(December, 12, December)]
#[case(December, u8::MAX, September)]
fn nth_prev(#[case] month: Month, #[case] n: u8, #[case] expected: Month) {
assert_eq!(month.nth_prev(n), expected);
}
#[rstest]
#[case(January, "January")]
#[case(February, "February")]
#[case(March, "March")]
#[case(April, "April")]
#[case(May, "May")]
#[case(June, "June")]
#[case(July, "July")]
#[case(August, "August")]
#[case(September, "September")]
#[case(October, "October")]
#[case(November, "November")]
#[case(December, "December")]
fn display(#[case] month: Month, #[case] expected: &str) {
assert_eq!(month.to_string(), expected);
}
#[rstest]
#[case("January", Ok(January))]
#[case("February", Ok(February))]
#[case("March", Ok(March))]
#[case("April", Ok(April))]
#[case("May", Ok(May))]
#[case("June", Ok(June))]
#[case("July", Ok(July))]
#[case("August", Ok(August))]
#[case("September", Ok(September))]
#[case("October", Ok(October))]
#[case("November", Ok(November))]
#[case("December", Ok(December))]
#[case("foo", Err(time::error::InvalidVariant))]
fn from_str(#[case] s: &str, #[case] expected: Result<Month, time::error::InvalidVariant>) {
assert_eq!(s.parse::<Month>(), expected);
}
#[rstest]
#[case(January, 1)]
#[case(February, 2)]
#[case(March, 3)]
#[case(April, 4)]
#[case(May, 5)]
#[case(June, 6)]
#[case(July, 7)]
#[case(August, 8)]
#[case(September, 9)]
#[case(October, 10)]
#[case(November, 11)]
#[case(December, 12)]
fn to_u8(#[case] month: Month, #[case] expected: u8) {
assert_eq!(u8::from(month), expected);
}
#[rstest]
#[case(1, January)]
#[case(2, February)]
#[case(3, March)]
#[case(4, April)]
#[case(5, May)]
#[case(6, June)]
#[case(7, July)]
#[case(8, August)]
#[case(9, September)]
#[case(10, October)]
#[case(11, November)]
#[case(12, December)]
fn try_from_u8_success(#[case] input: u8, #[case] expected: Month) {
assert_eq!(Month::try_from(input), Ok(expected));
}
#[rstest]
#[case(0)]
#[case(13)]
fn try_from_u8_error(#[case] input: u8) {
assert!(matches!(Month::try_from(input), Err(err) if err.name() == "month"));
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,878 @@
use core::num::NonZero;
use rstest::rstest;
use rstest_reuse::{apply, template};
use time::error::InvalidFormatDescription;
use time::format_description::modifier::*;
use time::format_description::{
self, BorrowedFormatItem, Component, OwnedFormatItem, StaticFormatDescription,
};
use time::macros::format_description;
/// A modifier with its value and string representation.
///
/// This alias is used to avoid repeating the tuple in countless locations.
type M<T> = (T, &'static str);
#[rustfmt::skip] // does not format well
#[template]
#[rstest]
fn modifiers(
#[values(
(Padding::Space, "padding:space"),
(Padding::Zero, "padding:zero"),
(Padding::None, "padding:none"),
)]
padding: _,
#[values(
(false, "repr:24"),
(true, "repr:12"),
)]
hour_is_12_hour_clock: _,
#[values(
(true, "case:upper"),
(false, "case:lower"),
)]
period_is_uppercase: _,
#[values(
(MonthRepr::Numerical, "repr:numerical"),
(MonthRepr::Long, "repr:long"),
(MonthRepr::Short, "repr:short"),
)]
month_repr: _,
#[values(
(SubsecondDigits::One, "digits:1"),
(SubsecondDigits::Two, "digits:2"),
(SubsecondDigits::Three, "digits:3"),
(SubsecondDigits::Four, "digits:4"),
(SubsecondDigits::Five, "digits:5"),
(SubsecondDigits::Six, "digits:6"),
(SubsecondDigits::Seven, "digits:7"),
(SubsecondDigits::Eight, "digits:8"),
(SubsecondDigits::Nine, "digits:9"),
(SubsecondDigits::OneOrMore, "digits:1+"),
)]
subsecond_digits: _,
#[values(
(WeekdayRepr::Short, "repr:short"),
(WeekdayRepr::Long, "repr:long"),
(WeekdayRepr::Sunday, "repr:sunday"),
(WeekdayRepr::Monday, "repr:monday"),
)]
weekday_repr: _,
#[values(
(WeekNumberRepr::Iso, "repr:iso"),
(WeekNumberRepr::Sunday, "repr:sunday"),
(WeekNumberRepr::Monday, "repr:monday"),
)]
week_number_repr: _,
#[values(
(YearRepr::Full, "repr:full"),
(YearRepr::Century, "repr:century"),
(YearRepr::LastTwo, "repr:last_two"),
)]
year_repr: _,
#[values(
(YearRange::Standard, "range:standard"),
(YearRange::Extended, "range:extended"),
)]
year_range: _,
#[values(
(false, "base:calendar"),
(true, "base:iso_week"),
)]
year_is_iso_week_based: _,
#[values(
(false, "sign:automatic"),
(true, "sign:mandatory"),
)]
sign_is_mandatory: _,
#[values(
(true, "one_indexed:true"),
(false, "one_indexed:false"),
)]
weekday_is_one_indexed: _,
#[values(
(true, "case_sensitive:true"),
(false, "case_sensitive:false"),
)]
case_sensitive: _,
#[values(
(NonZero::new(1).unwrap(), "count:1"),
(NonZero::new(2).unwrap(), "count:2"),
(NonZero::new(3).unwrap(), "count:3"),
(NonZero::new(10).unwrap(), "count:10"),
(NonZero::new(100).unwrap(), "count:100"),
(NonZero::new(1_000).unwrap(), "count:1000"),
)]
ignore_count: _,
#[values(
(UnixTimestampPrecision::Second, "precision:second"),
(UnixTimestampPrecision::Millisecond, "precision:millisecond"),
(UnixTimestampPrecision::Microsecond, "precision:microsecond"),
(UnixTimestampPrecision::Nanosecond, "precision:nanosecond"),
)]
unix_timestamp_precision: _,
#[values(
(TrailingInput::Prohibit, "trailing_input:prohibit"),
(TrailingInput::Discard, "trailing_input:discard"),
)]
trailing_input: _,
) {}
#[rstest]
fn empty() {
assert_eq!(format_description::parse_borrowed::<2>(""), Ok(vec![]));
assert_eq!(
format_description::parse_owned::<2>(""),
Ok(OwnedFormatItem::Compound(Box::new([])))
);
}
#[rstest]
#[case("foo bar", [b"foo bar".as_slice()])]
#[case(" leading spaces", [b" leading spaces".as_slice()])]
#[case("trailing spaces ", [b"trailing spaces ".as_slice()])]
#[case(" ", [b" ".as_slice()])]
#[case("[[", [b"[".as_slice()])]
#[case("foo[[bar", [b"foo".as_slice(), b"[".as_slice(), b"bar".as_slice()])]
fn only_literal<const N: usize>(#[case] format_description: &str, #[case] expected: [&[u8]; N]) {
assert_eq!(
format_description::parse(format_description),
Ok(expected
.into_iter()
.map(BorrowedFormatItem::Literal)
.collect())
);
}
#[rstest]
#[case("[day]", Component::Day(Day::default()))]
#[case("[end]", Component::End(End::default()))]
#[case("[hour]", Component::Hour(Hour::default()))]
#[case("[minute]", Component::Minute(Minute::default()))]
#[case("[month]", Component::Month(Month::default()))]
#[case("[offset_hour]", Component::OffsetHour(OffsetHour::default()))]
#[case("[offset_minute]", Component::OffsetMinute(OffsetMinute::default()))]
#[case("[offset_second]", Component::OffsetSecond(OffsetSecond::default()))]
#[case("[ordinal]", Component::Ordinal(Ordinal::default()))]
#[case("[period]", Component::Period(Period::default()))]
#[case("[second]", Component::Second(Second::default()))]
#[case("[subsecond]", Component::Subsecond(Subsecond::default()))]
#[case("[unix_timestamp]", Component::UnixTimestamp(UnixTimestamp::default()))]
#[case("[weekday]", Component::Weekday(Weekday::default()))]
#[case("[week_number]", Component::WeekNumber(WeekNumber::default()))]
#[case("[year]", Component::Year(Year::default()))]
fn simple_component(#[case] format_description: &str, #[case] component: Component) {
assert_eq!(
format_description::parse(format_description),
Ok(vec![BorrowedFormatItem::Component(component)])
);
}
#[rstest]
fn errors() {
use InvalidFormatDescription::*;
macro_rules! assert_errs {
($($format_description:literal, $error:pat $(if $condition:expr)?,)*) => {$(
assert!(matches!(
format_description::parse($format_description),
Err($error) $(if $condition)?
));
assert!(matches!(
format_description::parse_owned::<2>($format_description),
Err($error) $(if $condition)?
));
)*};
}
assert_errs! {
"[ invalid ]", InvalidComponentName { name, index: 2, .. } if name == "invalid",
"[", MissingComponentName { index: 0, .. },
"[ ", MissingComponentName { index: 1, .. },
"[]", MissingComponentName { index: 0, .. },
"[day sign:mandatory]", InvalidModifier { value, index: 5, .. } if value == "sign",
"[day sign:]", InvalidModifier { value, index: 9,.. } if value.is_empty(),
"[day :mandatory]", InvalidModifier { value, index: 5,.. } if value.is_empty(),
"[day sign:mandatory", UnclosedOpeningBracket { index: 0, .. },
"[day padding:invalid]", InvalidModifier { value, index: 13, .. } if value == "invalid",
"[ignore]", MissingRequiredModifier { name: "count", index: 1, .. },
"[ignore count:70000]", InvalidModifier { value, index: 14, .. } if value == "70000",
}
}
macro_rules! placeholder {
($($x:tt)*) => {
" {}"
};
}
macro_rules! parse_with_modifiers {
($modifier_name:literal, $($modifier:ident),+) => {
format_description::parse(
&format!(
concat!(
"[",
$modifier_name,
$(placeholder!($modifier),)+
"]",
),
$($modifier.1),+
)
)
};
}
#[apply(modifiers)]
fn day_component(padding: M<Padding>) {
assert_eq!(
parse_with_modifiers!("day", padding),
Ok(vec![BorrowedFormatItem::Component(Component::Day(
Day::default().with_padding(padding.0)
))])
);
}
#[apply(modifiers)]
fn end_component(trailing_input: M<TrailingInput>) {
assert_eq!(
parse_with_modifiers!("end", trailing_input),
Ok(vec![BorrowedFormatItem::Component(Component::End(
End::default().with_trailing_input(trailing_input.0)
))])
);
}
#[apply(modifiers)]
fn minute_component(padding: M<Padding>) {
assert_eq!(
parse_with_modifiers!("minute", padding),
Ok(vec![BorrowedFormatItem::Component(Component::Minute(
Minute::default().with_padding(padding.0)
))])
);
}
#[apply(modifiers)]
fn offset_minute_component(padding: M<Padding>) {
assert_eq!(
parse_with_modifiers!("offset_minute", padding),
Ok(vec![BorrowedFormatItem::Component(
Component::OffsetMinute(OffsetMinute::default().with_padding(padding.0))
)])
);
}
#[apply(modifiers)]
fn offset_second_component(padding: M<Padding>) {
assert_eq!(
parse_with_modifiers!("offset_second", padding),
Ok(vec![BorrowedFormatItem::Component(
Component::OffsetSecond(OffsetSecond::default().with_padding(padding.0))
)])
);
}
#[apply(modifiers)]
fn ordinal_component(padding: M<Padding>) {
assert_eq!(
parse_with_modifiers!("ordinal", padding),
Ok(vec![BorrowedFormatItem::Component(Component::Ordinal(
Ordinal::default().with_padding(padding.0)
))])
);
}
#[apply(modifiers)]
fn second_component(padding: M<Padding>) {
assert_eq!(
parse_with_modifiers!("second", padding),
Ok(vec![BorrowedFormatItem::Component(Component::Second(
Second::default().with_padding(padding.0)
))])
);
}
#[apply(modifiers)]
fn hour_component(padding: M<Padding>, hour_is_12_hour_clock: M<bool>) {
assert_eq!(
parse_with_modifiers!("hour", padding, hour_is_12_hour_clock),
Ok(vec![BorrowedFormatItem::Component(Component::Hour(
Hour::default()
.with_padding(padding.0)
.with_is_12_hour_clock(hour_is_12_hour_clock.0)
))])
);
}
#[apply(modifiers)]
fn month_component(padding: M<Padding>, case_sensitive: M<bool>, month_repr: M<MonthRepr>) {
assert_eq!(
parse_with_modifiers!("month", padding, case_sensitive, month_repr),
Ok(vec![BorrowedFormatItem::Component(Component::Month(
Month::default()
.with_padding(padding.0)
.with_repr(month_repr.0)
.with_case_sensitive(case_sensitive.0)
))])
);
}
#[apply(modifiers)]
fn period_component(case_sensitive: M<bool>, period_is_uppercase: M<bool>) {
assert_eq!(
parse_with_modifiers!("period", period_is_uppercase, case_sensitive),
Ok(vec![BorrowedFormatItem::Component(Component::Period(
Period::default()
.with_is_uppercase(period_is_uppercase.0)
.with_case_sensitive(case_sensitive.0)
))])
);
}
#[apply(modifiers)]
fn weekday_component(
case_sensitive: M<bool>,
weekday_is_one_indexed: M<bool>,
weekday_repr: M<WeekdayRepr>,
) {
assert_eq!(
parse_with_modifiers!(
"weekday",
case_sensitive,
weekday_is_one_indexed,
weekday_repr
),
Ok(vec![BorrowedFormatItem::Component(Component::Weekday(
Weekday::default()
.with_repr(weekday_repr.0)
.with_one_indexed(weekday_is_one_indexed.0)
.with_case_sensitive(case_sensitive.0)
))])
);
}
#[apply(modifiers)]
fn week_number_component(padding: M<Padding>, week_number_repr: M<WeekNumberRepr>) {
assert_eq!(
parse_with_modifiers!("week_number", padding, week_number_repr),
Ok(vec![BorrowedFormatItem::Component(Component::WeekNumber(
WeekNumber::default()
.with_padding(padding.0)
.with_repr(week_number_repr.0)
))])
);
}
#[apply(modifiers)]
fn offset_hour_component(padding: M<Padding>, sign_is_mandatory: M<bool>) {
assert_eq!(
parse_with_modifiers!("offset_hour", padding, sign_is_mandatory),
Ok(vec![BorrowedFormatItem::Component(Component::OffsetHour(
OffsetHour::default()
.with_padding(padding.0)
.with_sign_is_mandatory(sign_is_mandatory.0)
))])
);
}
#[apply(modifiers)]
fn year_component(
padding: M<Padding>,
year_repr: M<YearRepr>,
year_range: M<YearRange>,
year_is_iso_week_based: M<bool>,
sign_is_mandatory: M<bool>,
) {
assert_eq!(
parse_with_modifiers!(
"year",
padding,
year_repr,
year_range,
year_is_iso_week_based,
sign_is_mandatory
),
Ok(vec![BorrowedFormatItem::Component(Component::Year(
Year::default()
.with_padding(padding.0)
.with_repr(year_repr.0)
.with_range(year_range.0)
.with_iso_week_based(year_is_iso_week_based.0)
.with_sign_is_mandatory(sign_is_mandatory.0)
))])
);
}
#[apply(modifiers)]
fn unix_timestamp_component(
sign_is_mandatory: M<bool>,
unix_timestamp_precision: M<UnixTimestampPrecision>,
) {
assert_eq!(
parse_with_modifiers!(
"unix_timestamp",
sign_is_mandatory,
unix_timestamp_precision
),
Ok(vec![BorrowedFormatItem::Component(
Component::UnixTimestamp(
UnixTimestamp::default()
.with_sign_is_mandatory(sign_is_mandatory.0)
.with_precision(unix_timestamp_precision.0)
)
)])
);
}
#[apply(modifiers)]
fn subsecond_component(subsecond_digits: M<SubsecondDigits>) {
assert_eq!(
parse_with_modifiers!("subsecond", subsecond_digits),
Ok(vec![BorrowedFormatItem::Component(Component::Subsecond(
Subsecond::default().with_digits(subsecond_digits.0)
))]),
);
}
#[apply(modifiers)]
fn ignore_component(ignore_count: M<NonZero<u16>>) {
assert_eq!(
parse_with_modifiers!("ignore", ignore_count),
Ok(vec![BorrowedFormatItem::Component(Component::Ignore(
Ignore::count(ignore_count.0)
))])
);
}
#[rstest]
fn optional() {
assert_eq!(
format_description::parse_owned::<2>("[optional [:[year]]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Compound(Box::new([
OwnedFormatItem::Literal(Box::new(*b":")),
OwnedFormatItem::Component(Component::Year(Default::default()))
]))
)))
);
assert_eq!(
format_description::parse_owned::<2>("[optional [[year]]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Component(Component::Year(Default::default()))
)))
);
assert_eq!(
format_description::parse_owned::<2>(r"[optional [\[]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Literal(Box::new(*b"["))
)))
);
assert_eq!(
format_description::parse_owned::<2>(r"[optional [ \[ ]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Compound(Box::new([
OwnedFormatItem::Literal(Box::new(*b" ")),
OwnedFormatItem::Literal(Box::new(*b"[")),
OwnedFormatItem::Literal(Box::new(*b" ")),
]))
)))
);
}
#[rstest]
fn first() {
assert_eq!(
format_description::parse_owned::<2>("[first [a]]"),
Ok(OwnedFormatItem::First(Box::new([
OwnedFormatItem::Literal(Box::new(*b"a"))
])))
);
assert_eq!(
format_description::parse_owned::<2>("[first [a] [b]]"),
Ok(OwnedFormatItem::First(Box::new([
OwnedFormatItem::Literal(Box::new(*b"a")),
OwnedFormatItem::Literal(Box::new(*b"b")),
])))
);
assert_eq!(
format_description::parse_owned::<2>("[first [a][b]]"),
Ok(OwnedFormatItem::First(Box::new([
OwnedFormatItem::Literal(Box::new(*b"a")),
OwnedFormatItem::Literal(Box::new(*b"b")),
])))
);
assert_eq!(
format_description::parse_owned::<2>(r"[first [a][\[]]"),
Ok(OwnedFormatItem::First(Box::new([
OwnedFormatItem::Literal(Box::new(*b"a")),
OwnedFormatItem::Literal(Box::new(*b"[")),
])))
);
assert_eq!(
format_description::parse_owned::<2>(r"[first [a][\[\[]]"),
Ok(OwnedFormatItem::First(Box::new([
OwnedFormatItem::Literal(Box::new(*b"a")),
OwnedFormatItem::Compound(Box::new([
OwnedFormatItem::Literal(Box::new(*b"[")),
OwnedFormatItem::Literal(Box::new(*b"[")),
]))
])))
);
assert_eq!(
format_description::parse_owned::<2>(
"[first [[period case:upper]] [[period case:lower]] ]"
),
Ok(OwnedFormatItem::First(Box::new([
OwnedFormatItem::Component(Component::Period(
Period::default()
.with_is_uppercase(true)
.with_case_sensitive(true)
)),
OwnedFormatItem::Component(Component::Period(
Period::default()
.with_is_uppercase(false)
.with_case_sensitive(true)
)),
])))
);
}
#[rstest]
fn backslash_escape() {
assert_eq!(
format_description::parse_owned::<2>(r"[optional [\]]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Literal(Box::new(*b"]"))
)))
);
assert_eq!(
format_description::parse_owned::<2>(r"[optional [\[]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Literal(Box::new(*b"["))
)))
);
assert_eq!(
format_description::parse_owned::<2>(r"[optional [\\]]"),
Ok(OwnedFormatItem::Optional(Box::new(
OwnedFormatItem::Literal(Box::new(*br"\"))
)))
);
assert_eq!(
format_description::parse_owned::<2>(r"\\"),
Ok(OwnedFormatItem::Literal(Box::new(*br"\")))
);
assert_eq!(
format_description::parse_owned::<2>(r"\["),
Ok(OwnedFormatItem::Literal(Box::new(*br"[")))
);
assert_eq!(
format_description::parse_owned::<2>(r"\]"),
Ok(OwnedFormatItem::Literal(Box::new(*br"]")))
);
assert_eq!(
format_description::parse_owned::<2>(r"foo\\"),
Ok(OwnedFormatItem::Compound(Box::new([
OwnedFormatItem::Literal(Box::new(*b"foo")),
OwnedFormatItem::Literal(Box::new(*br"\")),
])))
);
assert_eq!(
format_description::parse_borrowed::<2>(r"\\"),
Ok(vec![BorrowedFormatItem::Literal(br"\")])
);
assert_eq!(
format_description::parse_borrowed::<2>(r"\["),
Ok(vec![BorrowedFormatItem::Literal(br"[")])
);
assert_eq!(
format_description::parse_borrowed::<2>(r"\]"),
Ok(vec![BorrowedFormatItem::Literal(br"]")])
);
assert_eq!(
format_description::parse_borrowed::<2>(r"foo\\"),
Ok(vec![
BorrowedFormatItem::Literal(b"foo"),
BorrowedFormatItem::Literal(br"\"),
])
);
}
#[rstest]
#[case(r"\a", 1)]
#[case(r"\", 0)]
fn backslash_escape_error(#[case] format_description: &str, #[case] expected_index: usize) {
assert!(matches!(
format_description::parse_owned::<2>(format_description),
Err(InvalidFormatDescription::Expected {
what: "valid escape sequence",
index,
..
}) if index == expected_index
));
assert!(matches!(
format_description::parse_borrowed::<2>(format_description),
Err(InvalidFormatDescription::Expected {
what: "valid escape sequence",
index,
..
}) if index == expected_index
));
}
#[rstest]
fn nested_v1_error() {
assert!(matches!(
format_description::parse_owned::<2>("[optional [[[]]"),
Err(InvalidFormatDescription::MissingComponentName { index: 11, .. })
));
assert!(matches!(
format_description::parse_owned::<2>("[optional [ [[ ]]"),
Err(InvalidFormatDescription::MissingComponentName { index: 12, .. })
));
assert!(matches!(
format_description::parse_owned::<2>("[first [a][[[]]"),
Err(InvalidFormatDescription::UnclosedOpeningBracket { index: 0, .. })
));
}
#[rstest]
fn nested_error() {
use InvalidFormatDescription::*;
assert!(matches!(
format_description::parse("[optional []]"),
Err(NotSupported {
what: "optional item",
context: "runtime-parsed format descriptions",
index: 0,
..
})
));
assert!(matches!(
format_description::parse("[first []]"),
Err(NotSupported {
what: "'first' item",
context: "runtime-parsed format descriptions",
index: 0,
..
})
));
assert!(matches!(
format_description::parse_owned::<2>("[year [month]]"),
Err(InvalidModifier { value, index: 6, .. }) if value == "["
));
assert!(matches!(
format_description::parse_owned::<2>("[optional[]]"),
Err(Expected {
what: "whitespace after `optional`",
index: 8,
..
})
));
assert!(matches!(
format_description::parse_owned::<2>("[first[]]"),
Err(Expected {
what: "whitespace after `first`",
index: 5,
..
})
));
assert!(matches!(
format_description::parse_owned::<2>("[optional []"),
Err(UnclosedOpeningBracket { index: 0, .. })
));
assert!(matches!(
format_description::parse_owned::<2>("[first []"),
Err(UnclosedOpeningBracket { index: 0, .. })
));
assert!(matches!(
format_description::parse_owned::<2>("[optional ["),
Err(UnclosedOpeningBracket { index: 10, .. })
));
assert!(matches!(
format_description::parse_owned::<2>("[optional [[year"),
Err(UnclosedOpeningBracket { index: 11, .. })
));
assert!(matches!(
format_description::parse_owned::<2>("[optional "),
Err(Expected {
what: "opening bracket",
index: 9,
..
})
));
}
#[rstest]
#[case("[", "missing component name at byte index 0")]
#[case("[foo", "unclosed opening bracket at byte index 0")]
#[case("[foo]", "invalid component name `foo` at byte index 1")]
#[case("[day bar]", "invalid modifier `bar` at byte index 5")]
#[case("[]", "missing component name at byte index 0")]
#[case(
"[optional []]",
"optional item is not supported in runtime-parsed format descriptions at byte index 0"
)]
#[case(
"[ignore]",
"missing required modifier `count` for component at byte index 1"
)]
fn error_display(#[case] format_description: &str, #[case] error: &str) {
// la10736/rstest#217
#[expect(clippy::unwrap_used, reason = "purpose of the test")]
let test = || {
assert_eq!(
format_description::parse(format_description)
.unwrap_err()
.to_string(),
error
);
};
test();
}
#[rstest]
#[case("[optional ", "expected opening bracket at byte index 9")]
fn error_display_owned(#[case] format_description: &str, #[case] error: &str) {
// la10736/rstest#217
#[expect(clippy::unwrap_used, reason = "purpose of the test")]
let test = || {
assert_eq!(
format_description::parse_owned::<2>(format_description)
.unwrap_err()
.to_string(),
error
)
};
test();
}
#[rstest]
fn rfc_3339() {
assert_eq!(
format_description::parse(
"[year]-[month repr:numerical]-[day]T[hour]:[minute]:[second].[subsecond][offset_hour \
sign:mandatory]:[offset_minute]"
),
Ok(vec![
BorrowedFormatItem::Component(Component::Year(
Year::default()
.with_padding(Padding::Zero)
.with_repr(YearRepr::Full)
.with_iso_week_based(false)
.with_sign_is_mandatory(false)
)),
BorrowedFormatItem::Literal(b"-"),
BorrowedFormatItem::Component(Component::Month(
Month::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Literal(b"-"),
BorrowedFormatItem::Component(Component::Day(
Day::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Literal(b"T"),
BorrowedFormatItem::Component(Component::Hour(
Hour::default()
.with_padding(Padding::Zero)
.with_is_12_hour_clock(false)
)),
BorrowedFormatItem::Literal(b":"),
BorrowedFormatItem::Component(Component::Minute(
Minute::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Literal(b":"),
BorrowedFormatItem::Component(Component::Second(
Second::default().with_padding(Padding::Zero)
)),
BorrowedFormatItem::Literal(b"."),
BorrowedFormatItem::Component(Component::Subsecond(
Subsecond::default().with_digits(SubsecondDigits::OneOrMore)
)),
BorrowedFormatItem::Component(Component::OffsetHour(
OffsetHour::default()
.with_padding(Padding::Zero)
.with_sign_is_mandatory(true)
)),
BorrowedFormatItem::Literal(b":"),
BorrowedFormatItem::Component(Component::OffsetMinute(
OffsetMinute::default().with_padding(Padding::Zero)
))
])
);
}
#[rstest]
#[case("foo", format_description!("foo"))]
#[case("%a", format_description!("[weekday repr:short]"))]
#[case("%A", format_description!("[weekday]"))]
#[case("%b", format_description!("[month repr:short]"))]
#[case("%B", format_description!("[month repr:long]"))]
#[case("%C", format_description!("[year repr:century]"))]
#[case("%d", format_description!("[day]"))]
#[case("%e", format_description!("[day padding:space]"))]
#[case("%g", format_description!("[year repr:last_two base:iso_week]"))]
#[case("%G", format_description!("[year base:iso_week]"))]
#[case("%h", format_description!("[month repr:short]"))]
#[case("%H", format_description!("[hour]"))]
#[case("%I", format_description!("[hour repr:12]"))]
#[case("%j", format_description!("[ordinal]"))]
#[case("%k", format_description!("[hour padding:space]"))]
#[case("%l", format_description!("[hour repr:12 padding:space]"))]
#[case("%m", format_description!("[month]"))]
#[case("%M", format_description!("[minute]"))]
#[case("%n", format_description!("\n"))]
#[case("%p", format_description!("[period]"))]
#[case("%P", format_description!("[period case:lower]"))]
#[case("%s", format_description!("[unix_timestamp]"))]
#[case("%S", format_description!("[second]"))]
#[case("%t", format_description!("\t"))]
#[case("%u", format_description!("[weekday repr:monday]"))]
#[case("%U", format_description!("[week_number repr:sunday]"))]
#[case("%V", format_description!("[week_number]"))]
#[case("%w", format_description!("[weekday repr:sunday]"))]
#[case("%W", format_description!("[week_number repr:monday]"))]
#[case("%y", format_description!("[year repr:last_two]"))]
#[case("%Y", format_description!("[year]"))]
#[case("%%", format_description!("%"))]
fn strftime_equivalence(
#[case] strftime: &str,
#[case] custom: StaticFormatDescription,
) -> time::Result<()> {
let borrowed = format_description::parse_strftime_borrowed(strftime)?;
let owned = format_description::parse_strftime_owned(strftime)?;
assert_eq!(borrowed, custom);
assert_eq!(owned, OwnedFormatItem::from(custom));
Ok(())
}
#[rstest]
#[case(
"%c",
"[weekday repr:short] [month repr:short] [day padding:space] [hour]:[minute]:[second] [year]"
)]
#[case("%D", "[month]/[day]/[year repr:last_two]")]
#[case("%F", "[year]-[month repr:numerical]-[day]")]
#[case("%r", "[hour repr:12]:[minute]:[second] [period]")]
#[case("%R", "[hour]:[minute]")]
#[case("%T", "[hour]:[minute]:[second]")]
#[case("%x", "[month]/[day]/[year repr:last_two]")]
#[case("%X", "[hour]:[minute]:[second]")]
#[case("%z", "[offset_hour sign:mandatory][offset_minute]")]
fn strftime_compound_equivalence(#[case] strftime: &str, #[case] custom: &str) -> time::Result<()> {
let borrowed = format_description::parse_strftime_borrowed(strftime)?;
let owned = format_description::parse_strftime_owned(strftime)?;
let custom = format_description::parse(custom)?;
// Until equality is implemented better, we need to convert to a compound.
let custom = vec![BorrowedFormatItem::Compound(&custom)];
assert_eq!(borrowed, custom);
assert_eq!(owned, OwnedFormatItem::from(custom));
Ok(())
}

182
vendor/time/tests/integration/parsed.rs vendored Normal file
View File

@@ -0,0 +1,182 @@
use std::num::NonZero;
use time::format_description::modifier::{Hour, WeekNumber, WeekNumberRepr};
use time::format_description::{BorrowedFormatItem, Component};
use time::parsing::Parsed;
use time::{Month, Time, Weekday, error};
#[test]
fn getters_setters() {
macro_rules! getters_setters {
($( $(#[$attr:meta])* $setter:ident $getter:ident $value:expr;)*) => {$(
$(#[$attr])*
{
let mut parsed = Parsed::new();
parsed.$setter($value);
assert_eq!(parsed.$getter(), Some($value));
}
)*};
}
getters_setters! {
set_year year 5;
set_year_last_two year_last_two 5;
set_iso_year iso_year 5;
set_iso_year_last_two iso_year_last_two 5;
set_month month Month::May;
set_sunday_week_number sunday_week_number 5;
set_monday_week_number monday_week_number 5;
set_iso_week_number iso_week_number NonZero::new(5).expect("valid value");
set_weekday weekday Weekday::Monday;
set_ordinal ordinal NonZero::new(5).expect("valid value");
set_day day NonZero::new(5).expect("valid value");
set_hour_24 hour_24 5;
set_hour_12 hour_12 NonZero::new(5).expect("valid value");
set_hour_12_is_pm hour_12_is_pm true;
set_minute minute 5;
set_second second 5;
set_subsecond subsecond 5;
set_offset_hour offset_hour 5;
#[expect(deprecated)] set_offset_minute offset_minute 5;
set_offset_minute_signed offset_minute_signed -5;
#[expect(deprecated)] set_offset_second offset_second 5;
set_offset_second_signed offset_second_signed -5;
}
#[expect(deprecated)]
{
let mut parsed = Parsed::new();
parsed.set_offset_minute(200);
assert_eq!(parsed.offset_minute(), None);
parsed.set_offset_second(200);
assert_eq!(parsed.offset_second(), None);
}
}
#[test]
fn builder_methods() {
#[expect(deprecated)]
let parsed = Parsed::new()
.with_year(5)
.and_then(|parsed| parsed.with_year_last_two(5))
.and_then(|parsed| parsed.with_iso_year(5))
.and_then(|parsed| parsed.with_iso_year_last_two(5))
.and_then(|parsed| parsed.with_month(Month::May))
.and_then(|parsed| parsed.with_sunday_week_number(5))
.and_then(|parsed| parsed.with_monday_week_number(5))
.and_then(|parsed| parsed.with_iso_week_number(NonZero::new(5).expect("valid value")))
.and_then(|parsed| parsed.with_weekday(Weekday::Monday))
.and_then(|parsed| parsed.with_ordinal(NonZero::new(5).expect("valid value")))
.and_then(|parsed| parsed.with_day(NonZero::new(5).expect("valid value")))
.and_then(|parsed| parsed.with_hour_24(5))
.and_then(|parsed| parsed.with_hour_12(NonZero::new(5).expect("valid value")))
.and_then(|parsed| parsed.with_hour_12_is_pm(true))
.and_then(|parsed| parsed.with_minute(5))
.and_then(|parsed| parsed.with_second(5))
.and_then(|parsed| parsed.with_subsecond(5))
.and_then(|parsed| parsed.with_offset_hour(5))
.and_then(|parsed| parsed.with_offset_minute(5))
.and_then(|parsed| parsed.with_offset_second(5))
.expect("all values are valid");
assert_eq!(parsed.year(), Some(5));
assert_eq!(parsed.year_last_two(), Some(5));
assert_eq!(parsed.iso_year(), Some(5));
assert_eq!(parsed.iso_year_last_two(), Some(5));
assert_eq!(parsed.month(), Some(Month::May));
assert_eq!(parsed.sunday_week_number(), Some(5));
assert_eq!(parsed.monday_week_number(), Some(5));
assert_eq!(
parsed.iso_week_number(),
Some(NonZero::new(5).expect("valid value"))
);
assert_eq!(parsed.weekday(), Some(Weekday::Monday));
assert_eq!(
parsed.ordinal(),
Some(NonZero::new(5).expect("valid value"))
);
assert_eq!(parsed.day(), Some(NonZero::new(5).expect("valid value")));
assert_eq!(parsed.hour_24(), Some(5));
assert_eq!(
parsed.hour_12(),
Some(NonZero::new(5).expect("valid value"))
);
assert_eq!(parsed.hour_12_is_pm(), Some(true));
assert_eq!(parsed.minute(), Some(5));
assert_eq!(parsed.second(), Some(5));
assert_eq!(parsed.subsecond(), Some(5));
assert_eq!(parsed.offset_hour(), Some(5));
#[expect(deprecated)]
{
assert_eq!(parsed.offset_minute(), Some(5));
assert_eq!(parsed.offset_second(), Some(5));
}
let parsed = Parsed::new()
.with_offset_minute_signed(-5)
.and_then(|parsed| parsed.with_offset_second_signed(-5))
.expect("all values are valid");
assert_eq!(parsed.offset_minute_signed(), Some(-5));
assert_eq!(parsed.offset_second_signed(), Some(-5));
#[expect(deprecated)]
{
assert!(Parsed::new().with_offset_minute(200).is_none());
assert!(Parsed::new().with_offset_second(200).is_none());
}
}
#[test]
fn single_item_parse() {
assert!(Time::parse("a", &BorrowedFormatItem::Literal(b"a")).is_err());
assert!(Time::parse("b", &BorrowedFormatItem::Literal(b"a")).is_err());
}
#[test]
fn component_err() {
macro_rules! input_or_empty {
() => {
b""
};
($input:expr) => {
$input
};
}
macro_rules! assert_invalid_component {
($component_name:expr, $component:expr $(, $input:expr)?) => {{
let mut parsed = Parsed::new();
assert_eq!(
parsed.parse_component(input_or_empty!($($input)?), $component),
Err(error::ParseFromDescription::InvalidComponent(
$component_name
))
);
}};
}
assert_invalid_component!("day", Component::Day(<_>::default()));
assert_invalid_component!("month", Component::Month(<_>::default()));
assert_invalid_component!("ordinal", Component::Ordinal(<_>::default()));
assert_invalid_component!("weekday", Component::Weekday(<_>::default()));
assert_invalid_component!("week number", Component::WeekNumber(<_>::default()));
assert_invalid_component!("year", Component::Year(<_>::default()));
assert_invalid_component!("minute", Component::Minute(<_>::default()));
assert_invalid_component!("period", Component::Period(<_>::default()));
assert_invalid_component!("second", Component::Second(<_>::default()));
assert_invalid_component!("subsecond", Component::Subsecond(<_>::default()));
assert_invalid_component!("offset hour", Component::OffsetHour(<_>::default()));
assert_invalid_component!("offset minute", Component::OffsetMinute(<_>::default()));
assert_invalid_component!("offset second", Component::OffsetSecond(<_>::default()));
assert_invalid_component!(
"week number",
Component::WeekNumber(WeekNumber::default().with_repr(WeekNumberRepr::Iso)),
b"00"
);
assert_invalid_component!(
"hour",
Component::Hour(Hour::default().with_is_12_hour_clock(true)),
b"00"
);
}

2002
vendor/time/tests/integration/parsing.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,891 @@
use std::cmp::Ordering;
use time::ext::{NumericalDuration, NumericalStdDuration};
use time::macros::{date, datetime, offset, time};
use time::{Duration, Month, PrimitiveDateTime, Weekday};
#[test]
fn new() {
assert_eq!(
PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)),
datetime!(2019-01-01 0:00),
);
}
#[test]
fn date() {
assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
}
#[test]
fn time() {
assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
}
#[test]
fn year() {
assert_eq!(datetime!(2019-01-01 0:00).year(), 2019);
assert_eq!(datetime!(2019-12-31 0:00).year(), 2019);
assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
}
#[test]
fn month() {
assert_eq!(datetime!(2019-01-01 0:00).month(), Month::January);
assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
}
#[test]
fn day() {
assert_eq!(datetime!(2019-01-01 0:00).day(), 1);
assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
}
#[test]
fn ordinal() {
assert_eq!(datetime!(2019-01-01 0:00).ordinal(), 1);
assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
}
#[test]
fn iso_week() {
assert_eq!(datetime!(2019-01-01 0:00).iso_week(), 1);
assert_eq!(datetime!(2019-10-04 0:00).iso_week(), 40);
assert_eq!(datetime!(2020-01-01 0:00).iso_week(), 1);
assert_eq!(datetime!(2020-12-31 0:00).iso_week(), 53);
assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
}
#[test]
fn sunday_based_week() {
assert_eq!(datetime!(2019-01-01 0:00).sunday_based_week(), 0);
assert_eq!(datetime!(2020-01-01 0:00).sunday_based_week(), 0);
assert_eq!(datetime!(2020-12-31 0:00).sunday_based_week(), 52);
assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
}
#[test]
fn monday_based_week() {
assert_eq!(datetime!(2019-01-01 0:00).monday_based_week(), 0);
assert_eq!(datetime!(2020-01-01 0:00).monday_based_week(), 0);
assert_eq!(datetime!(2020-12-31 0:00).monday_based_week(), 52);
assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
}
#[test]
fn to_calendar_date() {
assert_eq!(
datetime!(2019-01-02 0:00).to_calendar_date(),
(2019, Month::January, 2)
);
}
#[test]
fn to_ordinal_date() {
assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
}
#[test]
fn to_iso_week_date() {
use Weekday::*;
assert_eq!(
datetime!(2019-01-01 0:00).to_iso_week_date(),
(2019, 1, Tuesday)
);
assert_eq!(
datetime!(2019-10-04 0:00).to_iso_week_date(),
(2019, 40, Friday)
);
assert_eq!(
datetime!(2020-01-01 0:00).to_iso_week_date(),
(2020, 1, Wednesday)
);
assert_eq!(
datetime!(2020-12-31 0:00).to_iso_week_date(),
(2020, 53, Thursday)
);
assert_eq!(
datetime!(2021-01-01 0:00).to_iso_week_date(),
(2020, 53, Friday)
);
}
#[test]
fn weekday() {
use Weekday::*;
assert_eq!(datetime!(2019-01-01 0:00).weekday(), Tuesday);
assert_eq!(datetime!(2019-02-01 0:00).weekday(), Friday);
assert_eq!(datetime!(2019-03-01 0:00).weekday(), Friday);
assert_eq!(datetime!(2019-04-01 0:00).weekday(), Monday);
assert_eq!(datetime!(2019-05-01 0:00).weekday(), Wednesday);
assert_eq!(datetime!(2019-06-01 0:00).weekday(), Saturday);
assert_eq!(datetime!(2019-07-01 0:00).weekday(), Monday);
assert_eq!(datetime!(2019-08-01 0:00).weekday(), Thursday);
assert_eq!(datetime!(2019-09-01 0:00).weekday(), Sunday);
assert_eq!(datetime!(2019-10-01 0:00).weekday(), Tuesday);
assert_eq!(datetime!(2019-11-01 0:00).weekday(), Friday);
assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
}
#[test]
fn to_julian_day() {
assert_eq!(datetime!(-999_999-01-01 0:00).to_julian_day(), -363_521_074);
assert_eq!(datetime!(-4713-11-24 0:00).to_julian_day(), 0);
assert_eq!(datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
assert_eq!(datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
assert_eq!(datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
}
#[test]
fn as_hms() {
assert_eq!(datetime!(2020-01-01 1:02:03).as_hms(), (1, 2, 3));
}
#[test]
fn as_hms_milli() {
assert_eq!(
datetime!(2020-01-01 1:02:03.004).as_hms_milli(),
(1, 2, 3, 4)
);
}
#[test]
fn as_hms_micro() {
assert_eq!(
datetime!(2020-01-01 1:02:03.004_005).as_hms_micro(),
(1, 2, 3, 4_005)
);
}
#[test]
fn as_hms_nano() {
assert_eq!(
datetime!(2020-01-01 1:02:03.004_005_006).as_hms_nano(),
(1, 2, 3, 4_005_006)
);
}
#[test]
fn hour() {
assert_eq!(datetime!(2019-01-01 0:00).hour(), 0);
assert_eq!(datetime!(2019-01-01 23:59:59).hour(), 23);
}
#[test]
fn minute() {
assert_eq!(datetime!(2019-01-01 0:00).minute(), 0);
assert_eq!(datetime!(2019-01-01 23:59:59).minute(), 59);
}
#[test]
fn second() {
assert_eq!(datetime!(2019-01-01 0:00).second(), 0);
assert_eq!(datetime!(2019-01-01 23:59:59).second(), 59);
}
#[test]
fn millisecond() {
assert_eq!(datetime!(2019-01-01 0:00).millisecond(), 0);
assert_eq!(datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
}
#[test]
fn microsecond() {
assert_eq!(datetime!(2019-01-01 0:00).microsecond(), 0);
assert_eq!(
datetime!(2019-01-01 23:59:59.999_999).microsecond(),
999_999
);
}
#[test]
fn nanosecond() {
assert_eq!(datetime!(2019-01-01 0:00).nanosecond(), 0);
assert_eq!(
datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
999_999_999
);
}
#[test]
fn assume_offset() {
assert_eq!(
datetime!(2019-01-01 0:00)
.assume_offset(offset!(UTC))
.unix_timestamp(),
1_546_300_800,
);
assert_eq!(
datetime!(2019-01-01 0:00)
.assume_offset(offset!(-1))
.unix_timestamp(),
1_546_304_400,
);
}
#[test]
fn assume_utc() {
assert_eq!(
datetime!(2019-01-01 0:00).assume_utc().unix_timestamp(),
1_546_300_800,
);
}
#[test]
fn replace_time() {
assert_eq!(
datetime!(2020-01-01 12:00).replace_time(time!(5:00)),
datetime!(2020-01-01 5:00)
);
}
#[test]
fn replace_date() {
assert_eq!(
datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
datetime!(2020-01-30 12:00)
);
}
#[test]
fn replace_year() {
assert_eq!(
datetime!(2022-02-18 12:00).replace_year(2019),
Ok(datetime!(2019-02-18 12:00))
);
assert!(
datetime!(2022-02-18 12:00)
.replace_year(-1_000_000_000)
.is_err()
); // -1_000_000_000 isn't a valid year
assert!(
datetime!(2022-02-18 12:00)
.replace_year(1_000_000_000)
.is_err()
); // 1_000_000_000 isn't a valid year
}
#[test]
fn replace_month() {
assert_eq!(
datetime!(2022-02-18 12:00).replace_month(Month::January),
Ok(datetime!(2022-01-18 12:00))
);
assert!(
datetime!(2022-01-30 12:00)
.replace_month(Month::February)
.is_err()
); // 30 isn't a valid day in February
}
#[test]
fn replace_day() {
assert_eq!(
datetime!(2022-02-18 12:00).replace_day(1),
Ok(datetime!(2022-02-01 12:00))
);
// 00 isn't a valid day
assert!(datetime!(2022-02-18 12:00).replace_day(0).is_err());
// 30 isn't a valid day in February
assert!(datetime!(2022-02-18 12:00).replace_day(30).is_err());
}
#[test]
fn replace_ordinal() {
assert_eq!(
datetime!(2022-02-18 12:00).replace_ordinal(1),
Ok(datetime!(2022-001 12:00))
);
assert_eq!(
datetime!(2024-02-29 12:00).replace_ordinal(366),
Ok(datetime!(2024-366 12:00))
);
assert!(datetime!(2022-049 12:00).replace_ordinal(0).is_err()); // 0 isn't a valid day
assert!(datetime!(2022-049 12:00).replace_ordinal(366).is_err()); // 2022 isn't a leap year
assert!(datetime!(2022-049 12:00).replace_ordinal(367).is_err()); // 367 isn't a valid day
}
#[test]
fn replace_hour() {
assert_eq!(
datetime!(2022-02-18 01:02:03.004_005_006).replace_hour(7),
Ok(datetime!(2022-02-18 07:02:03.004_005_006))
);
assert!(
datetime!(2022-02-18 01:02:03.004_005_006)
.replace_hour(24)
.is_err()
); // 24 isn't a valid hour
}
#[test]
fn replace_minute() {
assert_eq!(
datetime!(2022-02-18 01:02:03.004_005_006).replace_minute(7),
Ok(datetime!(2022-02-18 01:07:03.004_005_006))
);
assert!(
datetime!(2022-02-18 01:02:03.004_005_006)
.replace_minute(60)
.is_err()
); // 60 isn't a valid minute
}
#[test]
fn replace_second() {
assert_eq!(
datetime!(2022-02-18 01:02:03.004_005_006).replace_second(7),
Ok(datetime!(2022-02-18 01:02:07.004_005_006))
);
assert!(
datetime!(2022-02-18 01:02:03.004_005_006)
.replace_second(60)
.is_err()
); // 60 isn't a valid second
}
#[test]
fn replace_millisecond() {
assert_eq!(
datetime!(2022-02-18 01:02:03.004_005_006).replace_millisecond(7),
Ok(datetime!(2022-02-18 01:02:03.007))
);
assert!(
datetime!(2022-02-18 01:02:03.004_005_006)
.replace_millisecond(1_000)
.is_err()
); // 1_000 isn't a valid millisecond
}
#[test]
fn replace_microsecond() {
assert_eq!(
datetime!(2022-02-18 01:02:03.004_005_006).replace_microsecond(7_008),
Ok(datetime!(2022-02-18 01:02:03.007_008))
);
assert!(
datetime!(2022-02-18 01:02:03.004_005_006)
.replace_microsecond(1_000_000)
.is_err()
); // 1_000_000 isn't a valid microsecond
}
#[test]
fn replace_nanosecond() {
assert_eq!(
datetime!(2022-02-18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
Ok(datetime!(2022-02-18 01:02:03.007_008_009))
);
assert!(
datetime!(2022-02-18 01:02:03.004_005_006)
.replace_nanosecond(1_000_000_000)
.is_err()
); // 1_000_000_000 isn't a valid nanosecond
}
#[test]
fn truncate_to_day() {
assert_eq!(
datetime!(2021-11-12 17:47:53.123_456_789).truncate_to_day(),
datetime!(2021-11-12 0:00)
);
assert_eq!(
datetime!(2021-11-12 0:00).truncate_to_day(),
datetime!(2021-11-12 0:00)
);
}
#[test]
fn truncate_to_hour() {
assert_eq!(
datetime!(2021-11-12 17:47:53.123_456_789).truncate_to_hour(),
datetime!(2021-11-12 17:00)
);
assert_eq!(
datetime!(2021-11-12 0:00).truncate_to_hour(),
datetime!(2021-11-12 0:00)
);
}
#[test]
fn truncate_to_minute() {
assert_eq!(
datetime!(2021-11-12 17:47:53.123_456_789).truncate_to_minute(),
datetime!(2021-11-12 17:47)
);
assert_eq!(
datetime!(2021-11-12 0:00).truncate_to_minute(),
datetime!(2021-11-12 0:00)
);
}
#[test]
fn truncate_to_second() {
assert_eq!(
datetime!(2021-11-12 17:47:53.123_456_789).truncate_to_second(),
datetime!(2021-11-12 17:47:53)
);
assert_eq!(
datetime!(2021-11-12 0:00).truncate_to_second(),
datetime!(2021-11-12 0:00)
);
}
#[test]
fn truncate_to_millisecond() {
assert_eq!(
datetime!(2021-11-12 17:47:53.123_456_789).truncate_to_millisecond(),
datetime!(2021-11-12 17:47:53.123)
);
assert_eq!(
datetime!(2021-11-12 0:00).truncate_to_millisecond(),
datetime!(2021-11-12 0:00)
);
}
#[test]
fn truncate_to_microsecond() {
assert_eq!(
datetime!(2021-11-12 17:47:53.123_456_789).truncate_to_microsecond(),
datetime!(2021-11-12 17:47:53.123_456)
);
assert_eq!(
datetime!(2021-11-12 0:00).truncate_to_microsecond(),
datetime!(2021-11-12 0:00)
);
}
#[test]
fn add_duration() {
assert_eq!(
datetime!(2019-01-01 0:00) + 5.days(),
datetime!(2019-01-06 0:00),
);
assert_eq!(
datetime!(2019-12-31 0:00) + 1.days(),
datetime!(2020-01-01 0:00),
);
assert_eq!(
datetime!(2019-12-31 23:59:59) + 2.seconds(),
datetime!(2020-01-01 0:00:01),
);
assert_eq!(
datetime!(2020-01-01 0:00:01) + (-2).seconds(),
datetime!(2019-12-31 23:59:59),
);
assert_eq!(
datetime!(1999-12-31 23:00) + 1.hours(),
datetime!(2000-01-01 0:00),
);
}
#[test]
fn add_std_duration() {
assert_eq!(
datetime!(2019-01-01 0:00) + 5.std_days(),
datetime!(2019-01-06 0:00),
);
assert_eq!(
datetime!(2019-12-31 0:00) + 1.std_days(),
datetime!(2020-01-01 0:00),
);
assert_eq!(
datetime!(2019-12-31 23:59:59) + 2.std_seconds(),
datetime!(2020-01-01 0:00:01),
);
}
#[test]
fn add_assign_duration() {
let mut new_years_day_2019 = datetime!(2019-01-01 0:00);
new_years_day_2019 += 5.days();
assert_eq!(new_years_day_2019, datetime!(2019-01-06 0:00));
let mut new_years_eve_2020_days = datetime!(2019-12-31 0:00);
new_years_eve_2020_days += 1.days();
assert_eq!(new_years_eve_2020_days, datetime!(2020-01-01 0:00));
let mut new_years_eve_2020_seconds = datetime!(2019-12-31 23:59:59);
new_years_eve_2020_seconds += 2.seconds();
assert_eq!(new_years_eve_2020_seconds, datetime!(2020-01-01 0:00:01));
let mut new_years_day_2020_days = datetime!(2020-01-01 0:00:01);
new_years_day_2020_days += (-2).seconds();
assert_eq!(new_years_day_2020_days, datetime!(2019-12-31 23:59:59));
}
#[test]
fn add_assign_std_duration() {
let mut ny19 = datetime!(2019-01-01 0:00);
ny19 += 5.std_days();
assert_eq!(ny19, datetime!(2019-01-06 0:00));
let mut nye20 = datetime!(2019-12-31 0:00);
nye20 += 1.std_days();
assert_eq!(nye20, datetime!(2020-01-01 0:00));
let mut nye20t = datetime!(2019-12-31 23:59:59);
nye20t += 2.std_seconds();
assert_eq!(nye20t, datetime!(2020-01-01 0:00:01));
}
#[test]
fn sub_duration() {
assert_eq!(
datetime!(2019-01-06 0:00) - 5.days(),
datetime!(2019-01-01 0:00),
);
assert_eq!(
datetime!(2020-01-01 0:00) - 1.days(),
datetime!(2019-12-31 0:00),
);
assert_eq!(
datetime!(2020-01-01 0:00:01) - 2.seconds(),
datetime!(2019-12-31 23:59:59),
);
assert_eq!(
datetime!(2019-12-31 23:59:59) - (-2).seconds(),
datetime!(2020-01-01 0:00:01),
);
assert_eq!(
datetime!(1999-12-31 23:00) - (-1).hours(),
datetime!(2000-01-01 0:00),
);
}
#[test]
fn sub_std_duration() {
assert_eq!(
datetime!(2019-01-06 0:00) - 5.std_days(),
datetime!(2019-01-01 0:00),
);
assert_eq!(
datetime!(2020-01-01 0:00) - 1.std_days(),
datetime!(2019-12-31 0:00),
);
assert_eq!(
datetime!(2020-01-01 0:00:01) - 2.std_seconds(),
datetime!(2019-12-31 23:59:59),
);
}
#[test]
fn sub_assign_duration() {
let mut new_years_day_2019 = datetime!(2019-01-06 0:00);
new_years_day_2019 -= 5.days();
assert_eq!(new_years_day_2019, datetime!(2019-01-01 0:00));
let mut new_years_day_2020_days = datetime!(2020-01-01 0:00);
new_years_day_2020_days -= 1.days();
assert_eq!(new_years_day_2020_days, datetime!(2019-12-31 0:00));
let mut new_years_day_2020_seconds = datetime!(2020-01-01 0:00:01);
new_years_day_2020_seconds -= 2.seconds();
assert_eq!(new_years_day_2020_seconds, datetime!(2019-12-31 23:59:59));
let mut new_years_eve_2020_seconds = datetime!(2019-12-31 23:59:59);
new_years_eve_2020_seconds -= (-2).seconds();
assert_eq!(new_years_eve_2020_seconds, datetime!(2020-01-01 0:00:01));
}
#[test]
fn sub_assign_std_duration() {
let mut ny19 = datetime!(2019-01-06 0:00);
ny19 -= 5.std_days();
assert_eq!(ny19, datetime!(2019-01-01 0:00));
let mut ny20 = datetime!(2020-01-01 0:00);
ny20 -= 1.std_days();
assert_eq!(ny20, datetime!(2019-12-31 0:00));
let mut ny20t = datetime!(2020-01-01 0:00:01);
ny20t -= 2.std_seconds();
assert_eq!(ny20t, datetime!(2019-12-31 23:59:59));
}
#[test]
fn sub_datetime() {
assert_eq!(
datetime!(2019-01-02 0:00) - datetime!(2019-01-01 0:00),
1.days()
);
assert_eq!(
datetime!(2019-01-01 0:00) - datetime!(2019-01-02 0:00),
(-1).days()
);
assert_eq!(
datetime!(2020-01-01 0:00) - datetime!(2019-12-31 0:00),
1.days()
);
assert_eq!(
datetime!(2019-12-31 0:00) - datetime!(2020-01-01 0:00),
(-1).days()
);
}
#[test]
fn ord() {
use Ordering::*;
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Equal)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2020-01-01 0:00)),
Some(Less)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-02-01 0:00)),
Some(Less)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-01-02 0:00)),
Some(Less)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-01-01 1:00)),
Some(Less)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-01-01 0:01)),
Some(Less)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-01-01 0:00:01)),
Some(Less)
);
assert_eq!(
datetime!(2019-01-01 0:00).partial_cmp(&datetime!(2019-01-01 0:00:00.000_000_001)),
Some(Less)
);
assert_eq!(
datetime!(2020-01-01 0:00).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(2019-02-01 0:00).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(2019-01-02 0:00).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(2019-01-01 1:00).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(2019-01-01 0:01).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(2019-01-01 0:00:01).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(2019-01-01 0:00:00.000_000_001).partial_cmp(&datetime!(2019-01-01 0:00)),
Some(Greater)
);
assert_eq!(
datetime!(-0001-01-01 0:00).partial_cmp(&datetime!(0001-01-01 0:00)),
Some(Less)
);
}
#[test]
fn checked_add_duration() {
// Successful addition
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add(5.nanoseconds()),
Some(datetime!(2021-10-25 14:01:53.450_000_005))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add(4.seconds()),
Some(datetime!(2021-10-25 14:01:57.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add(2.days()),
Some(datetime!(2021-10-27 14:01:53.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add(1.weeks()),
Some(datetime!(2021-11-01 14:01:53.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add((-5).nanoseconds()),
Some(datetime!(2021-10-25 14:01:53.449_999_995))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add((-4).seconds()),
Some(datetime!(2021-10-25 14:01:49.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add((-2).days()),
Some(datetime!(2021-10-23 14:01:53.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_add((-1).weeks()),
Some(datetime!(2021-10-18 14:01:53.45))
);
// Addition with underflow
assert_eq!(
datetime!(-999_999-01-01 0:00).checked_add((-1).nanoseconds()),
None
);
assert_eq!(
datetime!(-999_999-01-01 0:00).checked_add(Duration::MIN),
None
);
assert_eq!(
datetime!(-999_990-01-01 0:00).checked_add((-530).weeks()),
None
);
// Addition with overflow
assert_eq!(
datetime!(+999_999-12-31 23:59:59.999_999_999).checked_add(1.nanoseconds()),
None
);
assert_eq!(
datetime!(+999_999-12-31 23:59:59.999_999_999).checked_add(Duration::MAX),
None
);
assert_eq!(
datetime!(+999_990-12-31 23:59:59.999_999_999).checked_add(530.weeks()),
None
);
}
#[test]
fn checked_sub_duration() {
// Successful subtraction
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub((-5).nanoseconds()),
Some(datetime!(2021-10-25 14:01:53.450_000_005))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub((-4).seconds()),
Some(datetime!(2021-10-25 14:01:57.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub((-2).days()),
Some(datetime!(2021-10-27 14:01:53.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub((-1).weeks()),
Some(datetime!(2021-11-01 14:01:53.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub(5.nanoseconds()),
Some(datetime!(2021-10-25 14:01:53.449_999_995))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub(4.seconds()),
Some(datetime!(2021-10-25 14:01:49.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub(2.days()),
Some(datetime!(2021-10-23 14:01:53.45))
);
assert_eq!(
datetime!(2021-10-25 14:01:53.45).checked_sub(1.weeks()),
Some(datetime!(2021-10-18 14:01:53.45))
);
// Subtraction with underflow
assert_eq!(
datetime!(-999_999-01-01 0:00).checked_sub(1.nanoseconds()),
None
);
assert_eq!(
datetime!(-999_999-01-01 0:00).checked_sub(Duration::MAX),
None
);
assert_eq!(
datetime!(-999_990-01-01 0:00).checked_sub(530.weeks()),
None
);
// Subtraction with overflow
assert_eq!(
datetime!(+999_999-12-31 23:59:59.999_999_999).checked_sub((-1).nanoseconds()),
None
);
assert_eq!(
datetime!(+999_999-12-31 23:59:59.999_999_999).checked_sub(Duration::MIN),
None
);
assert_eq!(
datetime!(+999_990-12-31 23:59:59.999_999_999).checked_sub((-530).weeks()),
None
);
}
#[test]
fn saturating_add_duration() {
assert_eq!(
datetime!(2021-11-12 17:47).saturating_add(2.days()),
datetime!(2021-11-14 17:47)
);
assert_eq!(
datetime!(2021-11-12 17:47).saturating_add((-2).days()),
datetime!(2021-11-10 17:47)
);
// Adding with underflow
assert_eq!(
PrimitiveDateTime::MIN.saturating_add((-10).days()),
PrimitiveDateTime::MIN
);
// Adding with overflow
assert_eq!(
PrimitiveDateTime::MAX.saturating_add(10.days()),
PrimitiveDateTime::MAX
);
// Adding zero duration at boundaries
assert_eq!(
PrimitiveDateTime::MIN.saturating_add(Duration::ZERO),
PrimitiveDateTime::MIN
);
assert_eq!(
PrimitiveDateTime::MAX.saturating_add(Duration::ZERO),
PrimitiveDateTime::MAX
);
}
#[test]
fn saturating_sub_duration() {
assert_eq!(
datetime!(2021-11-12 17:47).saturating_sub(2.days()),
datetime!(2021-11-10 17:47)
);
assert_eq!(
datetime!(2021-11-12 17:47).saturating_sub((-2).days()),
datetime!(2021-11-14 17:47)
);
// Subtracting with underflow
assert_eq!(
PrimitiveDateTime::MIN.saturating_sub(10.days()),
PrimitiveDateTime::MIN
);
// Subtracting with overflow
assert_eq!(
PrimitiveDateTime::MAX.saturating_sub((-10).days()),
PrimitiveDateTime::MAX
);
// Subtracting zero duration at boundaries
assert_eq!(
PrimitiveDateTime::MIN.saturating_sub(Duration::ZERO),
PrimitiveDateTime::MIN
);
assert_eq!(
PrimitiveDateTime::MAX.saturating_sub(Duration::ZERO),
PrimitiveDateTime::MAX
);
}

View File

@@ -0,0 +1,429 @@
use num_conv::prelude::*;
use quickcheck::{Arbitrary, TestResult};
use quickcheck_macros::quickcheck;
use time::macros::{format_description, time};
use time::Weekday::*;
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
macro_rules! test_shrink {
($type:ty,
$fn_name:ident,
$($method:ident()).+
$(, min=$min_value:literal)?
) => {
#[quickcheck]
fn $fn_name(v: $type) -> TestResult {
let method_value = v.$($method()).+;
if method_value == test_shrink!(@min_or_zero $($min_value)?) {
TestResult::discard()
} else {
TestResult::from_bool(v.shrink().any(|shrunk|
if method_value > 0 {
shrunk.$($method()).+ < v.$($method()).+
} else {
shrunk.$($method()).+ > v.$($method()).+
}
))
}
}
};
(@min_or_zero) => { 0 };
(@min_or_zero $min:literal) => { $min };
}
macro_rules! no_panic {
($($x:tt)*) => {
std::panic::catch_unwind(|| {
$($x)*
})
.is_ok()
}
}
#[quickcheck]
fn date_yo_roundtrip(d: Date) -> bool {
Date::from_ordinal_date(d.year(), d.ordinal()) == Ok(d)
}
#[quickcheck]
fn date_ymd_roundtrip(d: Date) -> bool {
Date::from_calendar_date(d.year(), d.month(), d.day()) == Ok(d)
}
#[quickcheck]
fn date_ywd_roundtrip(d: Date) -> bool {
let (year, week, weekday) = d.to_iso_week_date();
Date::from_iso_week_date(year, week, weekday) == Ok(d)
}
#[quickcheck]
fn date_format_century_last_two_equivalent(d: Date) -> bool {
let split_format = format_description!("[year repr:century][year repr:last_two]-[month]-[day]");
let split = d.format(&split_format).expect("formatting failed");
let combined_format = format_description!("[year]-[month]-[day]");
let combined = d.format(&combined_format).expect("formatting failed");
split == combined
}
#[quickcheck]
fn date_parse_century_last_two_equivalent_extended(d: Date) -> TestResult {
// With the extended range, there is an ambiguity when parsing a year with fewer than six
// digits, as the first four are consumed by the century, leaving at most one for the last
// two digits.
if !matches!(d.year().unsigned_abs().to_string().len(), 6) {
return TestResult::discard();
}
let split_format = format_description!("[year repr:century][year repr:last_two]-[month]-[day]");
let combined_format = format_description!("[year]-[month]-[day]");
let combined = d.format(&combined_format).expect("formatting failed");
TestResult::from_bool(Date::parse(&combined, &split_format).expect("parsing failed") == d)
}
#[quickcheck]
fn date_parse_century_last_two_equivalent_standard(d: Date) -> TestResult {
// With the standard range, the year must be at most four digits.
if !matches!(d.year(), -9999..=9999) {
return TestResult::discard();
}
let split_format = format_description!(
"[year repr:century range:standard][year repr:last_two range:standard]-[month]-[day]"
);
let combined_format = format_description!("[year range:standard]-[month]-[day]");
let combined = d.format(&combined_format).expect("formatting failed");
TestResult::from_bool(Date::parse(&combined, &split_format).expect("parsing failed") == d)
}
#[quickcheck]
fn julian_day_roundtrip(d: Date) -> bool {
Date::from_julian_day(d.to_julian_day()) == Ok(d)
}
#[quickcheck]
fn duration_roundtrip(d: Duration) -> bool {
Duration::new(d.whole_seconds(), d.subsec_nanoseconds()) == d
}
#[quickcheck]
fn time_roundtrip(t: Time) -> bool {
Time::from_hms_nano(t.hour(), t.minute(), t.second(), t.nanosecond()) == Ok(t)
}
#[quickcheck]
fn primitive_date_time_roundtrip(a: PrimitiveDateTime) -> bool {
PrimitiveDateTime::new(a.date(), a.time()) == a
}
#[quickcheck]
fn utc_offset_roundtrip(o: UtcOffset) -> bool {
let (hours, minutes, seconds) = o.as_hms();
UtcOffset::from_hms(hours, minutes, seconds) == Ok(o)
}
#[quickcheck]
fn offset_date_time_roundtrip(a: OffsetDateTime) -> TestResult {
// Values near the edge of what is allowed may panic if the conversion brings the underlying
// value outside the valid range of values.
if a.date() == Date::MIN || a.date() == Date::MAX {
return TestResult::discard();
}
TestResult::from_bool(PrimitiveDateTime::new(a.date(), a.time()).assume_offset(a.offset()) == a)
}
#[quickcheck]
fn unix_timestamp_roundtrip(odt: OffsetDateTime) -> TestResult {
match odt.date() {
Date::MIN | Date::MAX => TestResult::discard(),
_ => TestResult::from_bool({
// nanoseconds are not stored in the basic Unix timestamp
let odt = odt - Duration::nanoseconds(odt.nanosecond().into());
OffsetDateTime::from_unix_timestamp(odt.unix_timestamp()) == Ok(odt)
}),
}
}
#[quickcheck]
fn unix_timestamp_nanos_roundtrip(odt: OffsetDateTime) -> TestResult {
match odt.date() {
Date::MIN | Date::MAX => TestResult::discard(),
_ => TestResult::from_bool(
OffsetDateTime::from_unix_timestamp_nanos(odt.unix_timestamp_nanos()) == Ok(odt),
),
}
}
#[quickcheck]
fn number_from_monday_roundtrip(w: Weekday) -> bool {
Monday.nth_next(w.number_from_monday() + 7 - 1) == w
}
#[quickcheck]
fn number_from_sunday_roundtrip(w: Weekday) -> bool {
Sunday.nth_next(w.number_from_sunday() + 7 - 1) == w
}
#[quickcheck]
fn number_days_from_monday_roundtrip(w: Weekday) -> bool {
Monday.nth_next(w.number_days_from_monday()) == w
}
#[quickcheck]
fn number_days_from_sunday_roundtrip(w: Weekday) -> bool {
Sunday.nth_next(w.number_days_from_sunday()) == w
}
#[quickcheck]
fn weekday_supports_arbitrary(w: Weekday) -> bool {
(1..=7).contains(&w.number_from_monday())
}
#[quickcheck]
fn weekday_can_shrink(w: Weekday) -> bool {
match w {
Monday => w.shrink().next().is_none(),
_ => w.shrink().next() == Some(w.previous()),
}
}
#[quickcheck]
fn month_supports_arbitrary(m: Month) -> bool {
(1..=12).contains(&u8::from(m))
}
#[quickcheck]
fn month_can_shrink(m: Month) -> bool {
match m {
Month::January => m.shrink().next().is_none(),
_ => m.shrink().next() == Some(m.previous()),
}
}
#[quickcheck]
fn date_replace_year(date: Date, year: i32) -> bool {
date.replace_year(year) == Date::from_calendar_date(year, date.month(), date.day())
}
#[quickcheck]
fn date_replace_month(date: Date, month: Month) -> bool {
date.replace_month(month) == Date::from_calendar_date(date.year(), month, date.day())
}
#[quickcheck]
fn date_replace_day(date: Date, day: u8) -> bool {
date.replace_day(day) == Date::from_calendar_date(date.year(), date.month(), day)
}
#[quickcheck]
fn time_replace_hour(time: Time, hour: u8) -> bool {
time.replace_hour(hour)
== Time::from_hms_nano(hour, time.minute(), time.second(), time.nanosecond())
}
#[quickcheck]
fn pdt_replace_year(pdt: PrimitiveDateTime, year: i32) -> bool {
pdt.replace_year(year)
== Date::from_calendar_date(year, pdt.month(), pdt.day())
.map(|date| date.with_time(pdt.time()))
}
#[quickcheck]
fn pdt_replace_month(pdt: PrimitiveDateTime, month: Month) -> bool {
pdt.replace_month(month)
== Date::from_calendar_date(pdt.year(), month, pdt.day())
.map(|date| date.with_time(pdt.time()))
}
#[quickcheck]
fn pdt_replace_day(pdt: PrimitiveDateTime, day: u8) -> bool {
pdt.replace_day(day)
== Date::from_calendar_date(pdt.year(), pdt.month(), day)
.map(|date| date.with_time(pdt.time()))
}
// Regression test for #481
#[quickcheck]
fn time_sub_time_no_panic(time_a: Time, time_b: Time) -> bool {
no_panic! {
let _ = time_a - time_b;
let _ = time_b - time_a;
}
}
#[quickcheck]
fn time_duration_until_since_range(time_a: Time, time_b: Time) -> bool {
let a_until_b = time_a.duration_until(time_b);
let b_until_a = time_b.duration_until(time_a);
let a_since_b = time_a.duration_since(time_b);
let b_since_a = time_b.duration_since(time_a);
(Duration::ZERO..Duration::DAY).contains(&a_until_b)
&& (Duration::ZERO..Duration::DAY).contains(&b_until_a)
&& (Duration::ZERO..Duration::DAY).contains(&a_since_b)
&& (Duration::ZERO..Duration::DAY).contains(&b_since_a)
}
#[quickcheck]
fn time_duration_until_since_arithmetic(time_a: Time, time_b: Time) -> bool {
let a_until_b = time_a.duration_until(time_b);
let b_until_a = time_b.duration_until(time_a);
let a_since_b = time_a.duration_since(time_b);
let b_since_a = time_b.duration_since(time_a);
time_a + a_until_b == time_b
&& time_b + b_until_a == time_a
&& time_b + a_since_b == time_a
&& time_a + b_since_a == time_b
}
#[quickcheck]
fn from_julian_day_no_panic(julian_day: i32) -> TestResult {
if !(Date::MIN.to_julian_day()..=Date::MAX.to_julian_day()).contains(&julian_day) {
return TestResult::discard();
}
TestResult::from_bool(
std::panic::catch_unwind(|| {
let _ = Date::from_julian_day(julian_day);
})
.is_ok(),
)
}
#[quickcheck]
fn odt_eq_no_panic(left: OffsetDateTime, right: OffsetDateTime) -> bool {
no_panic! {
let _ = left == right;
}
}
#[quickcheck]
fn odt_ord_no_panic(left: OffsetDateTime, right: OffsetDateTime) -> bool {
no_panic! {
let _ = left < right;
let _ = left > right;
}
}
#[quickcheck]
fn odt_sub_no_panic(left: OffsetDateTime, right: OffsetDateTime) -> bool {
no_panic! {
let _ = left - right;
}
}
#[quickcheck]
fn odt_to_offset_no_panic(odt: OffsetDateTime, offset: UtcOffset) -> TestResult {
let offset_difference = offset.whole_seconds() - odt.offset().whole_seconds();
if Date::MIN
.midnight()
.assume_utc()
.checked_add(Duration::seconds(offset_difference.extend()))
.is_none()
|| Date::MAX
.with_time(time!(23:59:59.999_999_999))
.assume_utc()
.checked_add(Duration::seconds(offset_difference.extend()))
.is_none()
{
return TestResult::discard();
}
TestResult::from_bool(no_panic! {
let _ = odt.to_offset(offset);
})
}
#[quickcheck]
fn odt_replace_offset_no_panic(odt: OffsetDateTime, offset: UtcOffset) -> TestResult {
if Date::MIN
.midnight()
.assume_offset(odt.offset())
.checked_add(Duration::seconds(offset.whole_seconds().extend()))
.is_none()
|| Date::MAX
.with_time(time!(23:59:59.999_999_999))
.assume_offset(odt.offset())
.checked_add(Duration::seconds(offset.whole_seconds().extend()))
.is_none()
{
return TestResult::discard();
}
TestResult::from_bool(no_panic! {
let _ = odt.replace_offset(offset);
})
}
test_shrink!(Date, date_can_shrink_year, year());
test_shrink!(Date, date_can_shrink_ordinal, ordinal(), min = 1);
test_shrink!(Duration, duration_can_shrink_seconds, whole_seconds());
test_shrink!(Duration, duration_can_shrink_ns, subsec_nanoseconds());
test_shrink!(Time, time_can_shrink_hour, hour());
test_shrink!(Time, time_can_shrink_minute, minute());
test_shrink!(Time, time_can_shrink_second, second());
test_shrink!(Time, time_can_shrink_nanosecond, nanosecond());
test_shrink!(
PrimitiveDateTime,
primitive_date_time_can_shrink_year,
year()
);
test_shrink!(
PrimitiveDateTime,
primitive_date_time_can_shrink_ordinal,
ordinal(),
min = 1
);
test_shrink!(
PrimitiveDateTime,
primitive_date_time_can_shrink_hour,
hour()
);
test_shrink!(
PrimitiveDateTime,
primitive_date_time_can_shrink_minute,
minute()
);
test_shrink!(
PrimitiveDateTime,
primitive_date_time_can_shrink_second,
second()
);
test_shrink!(
PrimitiveDateTime,
primitive_date_time_can_shrink_nanosecond,
nanosecond()
);
test_shrink!(UtcOffset, utc_offset_can_shrink, whole_seconds());
test_shrink!(
OffsetDateTime,
offset_date_time_can_shrink_offset,
offset().whole_seconds()
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_year, year());
test_shrink!(
OffsetDateTime,
offset_date_time_can_shrink_ordinal,
ordinal(),
min = 1
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_hour, hour());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_minute, minute());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_second, second());
test_shrink!(
OffsetDateTime,
offset_date_time_can_shrink_nanosecond,
nanosecond()
);

73
vendor/time/tests/integration/rand.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
use rand08::Rng as _;
use rand09::Rng as _;
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
#[test]
fn support08() {
// Work around rust-random/rand#1020.
let mut rng = rand08::rngs::mock::StepRng::new(0, 656_175_560);
for _ in 0..7 {
let _ = rng.r#gen::<Weekday>();
}
for _ in 0..12 {
let _ = rng.r#gen::<Month>();
}
let _ = rng.r#gen::<Time>();
let _ = rng.r#gen::<Date>();
let _ = rng.r#gen::<UtcOffset>();
let _ = rng.r#gen::<PrimitiveDateTime>();
let _ = rng.r#gen::<OffsetDateTime>();
let _ = rng.r#gen::<Duration>();
}
#[test]
fn support09() {
// Work around rust-random/rand#1020.
let mut rng = StepRng::new(0, 656_175_560);
for _ in 0..7 {
let _ = rng.random::<Weekday>();
}
for _ in 0..12 {
let _ = rng.random::<Month>();
}
let _ = rng.random::<Time>();
let _ = rng.random::<Date>();
let _ = rng.random::<UtcOffset>();
let _ = rng.random::<PrimitiveDateTime>();
let _ = rng.random::<OffsetDateTime>();
let _ = rng.random::<Duration>();
}
// copy of `StepRng` from rand 0.8 to avoid deprecation warnings
#[derive(Debug, Clone)]
struct StepRng {
v: u64,
a: u64,
}
impl StepRng {
fn new(initial: u64, increment: u64) -> Self {
Self {
v: initial,
a: increment,
}
}
}
impl rand09::RngCore for StepRng {
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64 {
let res = self.v;
self.v = self.v.wrapping_add(self.a);
res
}
fn fill_bytes(&mut self, dst: &mut [u8]) {
rand09::rand_core::impls::fill_bytes_via_next(self, dst)
}
}

View File

@@ -0,0 +1,46 @@
use serde::{Deserialize, Serialize, Serializer};
use serde_test::{assert_ser_tokens_error, Token};
use time::macros::{datetime, format_description};
use time::{error, OffsetDateTime};
/// Trigger `time::error::Format::StdIo` errors.
///
/// `StdIo` won't be reached during normal serde operation: it's instantiated
/// only during calls to `format_into()`, but most `Serializable`
/// implementations will only call `format()` because serde `Serializer`
/// interface doesn't expose the underlying `io::Write`.
///
/// Therefore, we need a contrived serializer to trigger coverage.
fn serialize<S: Serializer>(datetime: &OffsetDateTime, _serializer: S) -> Result<S::Ok, S::Error> {
Err(datetime
.format_into(
&mut [0u8; 0].as_mut_slice(),
format_description!("nonempty format description"),
)
.map_err(error::Format::into_invalid_serde_value::<S>)
.expect_err("Writing to a zero-length buffer should always error."))
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct TestBadIo {
#[serde(serialize_with = "serialize")]
dt: OffsetDateTime,
}
#[test]
fn custom_serialize_io_error() {
let value = TestBadIo {
dt: datetime!(2000-01-01 00:00 -4:00),
};
assert_ser_tokens_error::<TestBadIo>(
&value,
&[
Token::Struct {
name: "TestBadIo",
len: 1,
},
Token::Str("dt"),
],
"failed to write whole buffer",
);
}

View File

@@ -0,0 +1,128 @@
use serde::{Deserialize, Serialize};
use serde_test::{
assert_de_tokens_error, assert_ser_tokens_error, assert_tokens, Configure, Token,
};
use time::macros::datetime;
use time::serde::iso8601;
use time::OffsetDateTime;
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct Test {
#[serde(with = "iso8601")]
dt: OffsetDateTime,
#[serde(with = "iso8601::option")]
option_dt: Option<OffsetDateTime>,
}
#[test]
fn serialize() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: Some(datetime!(2000-01-01 00:00:00 UTC)),
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("+002000-01-01T00:00:00.000000000Z"),
Token::Str("option_dt"),
Token::Some,
Token::BorrowedStr("+002000-01-01T00:00:00.000000000Z"),
Token::StructEnd,
],
);
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: None,
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("+002000-01-01T00:00:00.000000000Z"),
Token::Str("option_dt"),
Token::None,
Token::StructEnd,
],
);
}
#[test]
fn serialize_error() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 +00:00:01),
option_dt: None,
};
assert_ser_tokens_error::<Test>(
&value,
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
],
"The offset_second component cannot be formatted into the requested format.",
);
}
#[test]
fn deserialize_error() {
assert_de_tokens_error::<Test>(
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("bad"),
Token::StructEnd,
],
"the 'year' component could not be parsed",
);
}
#[test]
fn issue_674_leap_second_support() {
serde_test::assert_de_tokens::<Test>(
&Test {
dt: datetime!(2016-12-31 23:59:59.999999999 UTC),
option_dt: Some(datetime!(2016-12-31 23:59:59.999999999 UTC)),
},
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("2016-12-31T23:59:60.000Z"),
Token::Str("option_dt"),
Token::Some,
Token::BorrowedStr("2016-12-31T23:59:60.000Z"),
Token::StructEnd,
],
);
}
#[test]
fn issue_724_truncation() {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Demo(#[serde(with = "time::serde::iso8601")] OffsetDateTime);
let value = datetime!(2025-01-10 23:01:16.000081999 UTC);
let info = Demo(value);
let serialized = serde_json::to_string(&info).expect("serialization failed");
assert_eq!(serialized, r#""+002025-01-10T23:01:16.000081999Z""#);
let deserialized: Demo = serde_json::from_str(&serialized).expect("deserialization failed");
assert_eq!(info, deserialized);
}

View File

@@ -0,0 +1,148 @@
use std::error::Error;
use serde::{Deserialize, Serialize};
use serde_test::Configure;
use time::macros::{date, datetime, time};
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, Weekday};
enum Format {
Compact,
Readable,
}
use Format::*;
fn serialize<T: Serialize>(val: T) -> Result<String, Box<dyn Error>> {
let mut buf: Vec<u8> = Vec::new();
let mut ser = serde_json::Serializer::new(&mut buf);
val.serialize(&mut ser)?;
let str = String::from_utf8(buf)?;
Ok(str)
}
fn deserialize<'a, T: Deserialize<'a>>(from: &'a str, fmt: Format) -> serde_json::Result<T> {
let mut de = serde_json::Deserializer::from_str(from);
match fmt {
Compact => T::deserialize((&mut de).compact()),
Readable => T::deserialize((&mut de).readable()),
}
}
#[test]
fn weekday_json() -> Result<(), Box<dyn Error>> {
use Weekday::*;
assert_eq!(serialize(Monday.compact())?, "1");
assert_eq!(deserialize::<Weekday>("1", Compact)?, Monday);
assert_eq!(serialize(Monday.readable())?, "\"Monday\"");
assert_eq!(deserialize::<Weekday>("\"Monday\"", Readable)?, Monday);
assert_eq!(deserialize::<Weekday>("1", Readable)?, Monday);
Ok(())
}
#[test]
fn month_json() -> Result<(), Box<dyn Error>> {
use Month::*;
assert_eq!(serialize(March.compact())?, "3");
assert_eq!(deserialize::<Month>("3", Compact)?, March);
assert_eq!(serialize(March.readable())?, "\"March\"");
assert_eq!(deserialize::<Month>("\"March\"", Readable)?, March);
assert_eq!(deserialize::<Month>("3", Readable)?, March);
Ok(())
}
#[test]
fn time_json() -> Result<(), Box<dyn Error>> {
let time = time!(12:40:20);
assert_eq!(serialize(time.compact())?, "[12,40,20,0]");
assert_eq!(deserialize::<Time>("[12,40,20,0]", Compact)?, time);
assert_eq!(serialize(time.readable())?, "\"12:40:20.0\"");
assert_eq!(deserialize::<Time>("\"12:40:20.0\"", Readable)?, time);
assert_eq!(deserialize::<Time>("[12,40,20,0]", Readable)?, time);
Ok(())
}
#[test]
fn primitive_datetime_json() -> Result<(), Box<dyn Error>> {
let dt = datetime!(2022-05-20 12:40:20);
assert_eq!(serialize(dt.compact())?, "[2022,140,12,40,20,0]");
assert_eq!(
deserialize::<PrimitiveDateTime>("[2022,140,12,40,20,0]", Compact)?,
dt
);
assert_eq!(serialize(dt.readable())?, "\"2022-05-20 12:40:20.0\"");
assert_eq!(
deserialize::<PrimitiveDateTime>("\"2022-05-20 12:40:20.0\"", Readable)?,
dt
);
assert_eq!(
deserialize::<PrimitiveDateTime>("[2022,140,12,40,20,0]", Readable)?,
dt
);
Ok(())
}
#[test]
fn offset_datetime_json() -> Result<(), Box<dyn Error>> {
let dt = datetime!(2022-05-20 12:40:20).assume_utc();
assert_eq!(serialize(dt.compact())?, "[2022,140,12,40,20,0,0,0,0]");
assert_eq!(
deserialize::<OffsetDateTime>("[2022,140,12,40,20,0,0,0,0]", Compact)?,
dt
);
assert_eq!(
serialize(dt.readable())?,
"\"2022-05-20 12:40:20.0 +00:00:00\""
);
assert_eq!(
deserialize::<OffsetDateTime>("\"2022-05-20 12:40:20.0 +00:00:00\"", Readable)?,
dt
);
assert_eq!(
deserialize::<OffsetDateTime>("[2022,140,12,40,20,0,0,0,0]", Readable)?,
dt
);
Ok(())
}
#[test]
fn duration_json() -> Result<(), Box<dyn Error>> {
let dur = Duration::new(50, 0);
assert_eq!(serialize(dur.compact())?, "[50,0]");
assert_eq!(deserialize::<Duration>("[50,0]", Compact)?, dur);
assert_eq!(serialize(dur.readable())?, "\"50.000000000\"");
assert_eq!(deserialize::<Duration>("\"50.000000000\"", Readable)?, dur);
assert_eq!(deserialize::<Duration>("[50,0]", Readable)?, dur);
Ok(())
}
#[test]
fn date_json() -> Result<(), Box<dyn Error>> {
let date = date!(2022-04-05);
assert_eq!(serialize(date.compact())?, "[2022,95]");
assert_eq!(deserialize::<Date>("[2022,95]", Compact)?, date);
assert_eq!(serialize(date.readable())?, "\"2022-04-05\"");
assert_eq!(deserialize::<Date>("\"2022-04-05\"", Readable)?, date);
assert_eq!(deserialize::<Date>("[2022,95]", Readable)?, date);
Ok(())
}

View File

@@ -0,0 +1,305 @@
#[rustfmt::skip] // Tries to remove the leading `::`, which breaks compilation.
use ::serde::{Deserialize, Serialize};
use serde_test::{
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens_error, assert_tokens, Configure,
Token,
};
use time::format_description::well_known::{iso8601, Iso8601};
use time::format_description::BorrowedFormatItem;
use time::macros::{date, datetime, offset, time};
use time::{serde, Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};
// Not used in the tests, but ensures that the macro compiles.
#[expect(dead_code)]
const ISO_FORMAT: Iso8601<{ iso8601::Config::DEFAULT.encode() }> =
Iso8601::<{ iso8601::Config::DEFAULT.encode() }>;
time::serde::format_description!(my_format, OffsetDateTime, ISO_FORMAT);
time::serde::format_description!(
my_format2,
OffsetDateTime,
Iso8601::<{ iso8601::Config::DEFAULT.encode() }>
);
mod nested {
time::serde::format_description!(
pub(super) offset_dt_format,
OffsetDateTime,
"custom format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
sign:mandatory]:[offset_minute]"
);
time::serde::format_description!(
pub primitive_dt_format,
PrimitiveDateTime,
"custom format: [year]-[month]-[day] [hour]:[minute]:[second]"
);
time::serde::format_description!(
pub(in crate::serde::macros) time_format,
Time,
"custom format: [minute]:[second]"
);
}
serde::format_description!(date_format, Date, "custom format: [year]-[month]-[day]");
serde::format_description!(
offset_format,
UtcOffset,
"custom format: [offset_hour sign:mandatory]:[offset_minute]"
);
const TIME_FORMAT_ALT: &[BorrowedFormatItem<'_>] =
time::macros::format_description!("[hour]:[minute]");
serde::format_description!(time_format_alt, Time, TIME_FORMAT_ALT);
serde::format_description!(
time_format_alt2,
Time,
time::macros::format_description!("[hour]:[minute]")
);
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct TestCustomFormat {
#[serde(with = "nested::offset_dt_format")]
offset_dt: OffsetDateTime,
#[serde(with = "nested::primitive_dt_format::option")]
primitive_dt: Option<PrimitiveDateTime>,
#[serde(with = "date_format")]
date: Date,
#[serde(with = "nested::time_format::option")]
time: Option<Time>,
#[serde(with = "offset_format")]
offset: UtcOffset,
#[serde(with = "time_format_alt")]
time_alt: Time,
}
#[test]
fn custom_serialize() {
let value = TestCustomFormat {
offset_dt: datetime!(2000-01-01 00:00 -4:00),
primitive_dt: Some(datetime!(2000-01-01 00:00)),
date: date!(2000-01-01),
time: None,
offset: offset!(-4),
time_alt: time!(12:34),
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "TestCustomFormat",
len: 6,
},
Token::Str("offset_dt"),
Token::BorrowedStr("custom format: 2000-01-01 00:00:00 -04:00"),
Token::Str("primitive_dt"),
Token::Some,
Token::BorrowedStr("custom format: 2000-01-01 00:00:00"),
Token::Str("date"),
Token::BorrowedStr("custom format: 2000-01-01"),
Token::Str("time"),
Token::None,
Token::Str("offset"),
Token::BorrowedStr("custom format: -04:00"),
Token::Str("time_alt"),
Token::BorrowedStr("12:34"),
Token::StructEnd,
],
);
}
#[test]
fn custom_serialize_error() {
// Deserialization error due to parse problem.
assert_de_tokens_error::<TestCustomFormat>(
&[
Token::Struct {
name: "TestCustomFormat",
len: 5,
},
Token::Str("offset_dt"),
Token::BorrowedStr("custom format: 2000-01-01 0:00:00 -04:00"),
],
"the 'hour' component could not be parsed",
);
// Parse problem in optional field.
assert_de_tokens_error::<TestCustomFormat>(
&[
Token::Struct {
name: "TestCustomFormat",
len: 5,
},
Token::Str("offset_dt"),
Token::BorrowedStr("custom format: 2000-01-01 00:00:00 -04:00"),
Token::Str("primitive_dt"),
Token::Some,
Token::BorrowedStr("custom format: 2000-01-01 0:00:00 -04:00"),
],
"the 'hour' component could not be parsed",
);
// Type error
assert_de_tokens_error::<TestCustomFormat>(
&[
Token::Struct {
name: "TestCustomFormat",
len: 5,
},
Token::Str("offset_dt"),
Token::Bool(false),
],
"invalid type: boolean `false`, expected a(n) `OffsetDateTime` in the format \"custom \
format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \
sign:mandatory]:[offset_minute]\"",
);
assert_de_tokens_error::<TestCustomFormat>(
&[
Token::Struct {
name: "TestCustomFormat",
len: 5,
},
Token::Str("offset_dt"),
Token::BorrowedStr("custom format: 2000-01-01 00:00:00 -04:00"),
Token::Str("primitive_dt"),
Token::Bool(false),
],
"invalid type: boolean `false`, expected an `Option<PrimitiveDateTime>` in the format \
\"custom format: [year]-[month]-[day] [hour]:[minute]:[second]\"",
);
}
// This format string has offset_hour and offset_minute, but is for formatting PrimitiveDateTime.
serde::format_description!(
primitive_date_time_format_bad,
PrimitiveDateTime,
"[offset_hour]:[offset_minute]"
);
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct TestCustomFormatPrimitiveDateTimeBad {
#[serde(with = "primitive_date_time_format_bad")]
dt: PrimitiveDateTime,
}
#[test]
fn custom_serialize_bad_type_error() {
let value = TestCustomFormatPrimitiveDateTimeBad {
dt: datetime!(2000-01-01 00:00),
};
assert_ser_tokens_error::<TestCustomFormatPrimitiveDateTimeBad>(
&value,
&[
Token::Struct {
name: "TestCustomFormatPrimitiveDateTimeBad",
len: 1,
},
Token::Str("dt"),
],
"The type being formatted does not contain sufficient information to format a component.",
);
}
// Test the behavior of versioning.
serde::format_description!(version = 1, version_test_1, Time, "[[ [hour]:[minute]");
serde::format_description!(version = 1, version_test_2, Time, r"\\ [hour]:[minute]");
serde::format_description!(version = 2, version_test_3, Time, r"\\ [hour]:[minute]");
serde::format_description!(version, Time, "[hour]:[minute]");
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct TestVersioning {
#[serde(with = "version_test_1")]
time_1: Time,
#[serde(with = "version_test_2")]
time_2: Time,
#[serde(with = "version_test_3")]
time_3: Time,
#[serde(with = "version")]
time_4: Time,
}
#[test]
fn versioning() {
let value = TestVersioning {
time_1: Time::MIDNIGHT,
time_2: Time::MIDNIGHT,
time_3: Time::MIDNIGHT,
time_4: Time::MIDNIGHT,
};
assert_tokens(
&value,
&[
Token::Struct {
name: "TestVersioning",
len: 4,
},
Token::Str("time_1"),
Token::Str("[ 00:00"),
Token::Str("time_2"),
Token::Str(r"\\ 00:00"),
Token::Str("time_3"),
Token::Str(r"\ 00:00"),
Token::Str("time_4"),
Token::Str("00:00"),
Token::StructEnd,
],
);
}
serde::format_description!(
version = 1,
nested_v1,
Time,
"[hour]:[minute][optional [:[second]]]"
);
serde::format_description!(
version = 2,
nested_v2,
Time,
"[hour]:[minute][optional [:[second]]]"
);
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct TestNested {
#[serde(with = "nested_v1")]
time_1: Time,
#[serde(with = "nested_v2")]
time_2: Time,
}
#[test]
fn nested() {
let value = TestNested {
time_1: time!(12:34:56),
time_2: time!(12:34:56),
};
assert_tokens(
&value,
&[
Token::Struct {
name: "TestNested",
len: 2,
},
Token::Str("time_1"),
Token::Str("12:34:56"),
Token::Str("time_2"),
Token::Str("12:34:56"),
Token::StructEnd,
],
);
let expected = TestNested {
time_1: time!(12:34),
time_2: time!(12:34),
};
assert_de_tokens(
&expected,
&[
Token::Struct {
name: "TestNested",
len: 2,
},
Token::Str("time_1"),
Token::Str("12:34"),
Token::Str("time_2"),
Token::Str("12:34"),
Token::StructEnd,
],
);
}

View File

@@ -0,0 +1,996 @@
use serde_test::{
Compact, Configure, Readable, Token, assert_de_tokens, assert_de_tokens_error, assert_tokens,
};
use time::macros::{date, datetime, offset, time};
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
mod error_conditions;
mod iso8601;
mod json;
mod macros;
mod rfc2822;
mod rfc3339;
mod timestamps;
#[test]
fn time() {
assert_tokens(
&Time::MIDNIGHT.compact(),
&[
Token::Tuple { len: 4 },
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::TupleEnd,
],
);
assert_tokens(
&time!(23:58:59.123_456_789).compact(),
&[
Token::Tuple { len: 4 },
Token::U8(23),
Token::U8(58),
Token::U8(59),
Token::U32(123_456_789),
Token::TupleEnd,
],
);
assert_tokens(
&Time::MIDNIGHT.readable(),
&[Token::BorrowedStr("00:00:00.0")],
);
assert_tokens(
&time!(23:58:59.123_456_789).readable(),
&[Token::BorrowedStr("23:58:59.123456789")],
);
}
#[test]
fn time_error() {
assert_de_tokens_error::<Compact<Time>>(
&[
Token::Tuple { len: 4 },
Token::U8(24),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::TupleEnd,
],
"invalid hour, expected an in-range value",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::BorrowedStr("24:00:00.0")],
"the 'hour' component could not be parsed",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::BorrowedStr("23-00:00.0")],
"a character literal was not valid",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::BorrowedStr("0:00:00.0")],
"the 'hour' component could not be parsed",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::BorrowedStr("00:00:00.0x")],
"unexpected trailing characters; the end of input was expected",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Time`",
);
assert_de_tokens_error::<Compact<Time>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Time`",
);
}
#[test]
fn time_partial() {
assert_de_tokens_error::<Compact<Time>>(
&[Token::Tuple { len: 4 }, Token::TupleEnd],
"expected hour",
);
assert_de_tokens_error::<Compact<Time>>(
&[Token::Tuple { len: 4 }, Token::U8(0), Token::TupleEnd],
"expected minute",
);
assert_de_tokens_error::<Compact<Time>>(
&[
Token::Tuple { len: 4 },
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected second",
);
assert_de_tokens_error::<Compact<Time>>(
&[
Token::Tuple { len: 4 },
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected nanosecond",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::Tuple { len: 4 }, Token::TupleEnd],
"expected hour",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::Tuple { len: 4 }, Token::U8(0), Token::TupleEnd],
"expected minute",
);
assert_de_tokens_error::<Readable<Time>>(
&[
Token::Tuple { len: 4 },
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected second",
);
assert_de_tokens_error::<Readable<Time>>(
&[
Token::Tuple { len: 4 },
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected nanosecond",
);
}
#[test]
fn date() {
assert_tokens(
&date!(-9999-001).compact(),
&[
Token::Tuple { len: 2 },
Token::I32(-9999),
Token::U16(1),
Token::TupleEnd,
],
);
assert_tokens(
&date!(+9999-365).compact(),
&[
Token::Tuple { len: 2 },
Token::I32(9999),
Token::U16(365),
Token::TupleEnd,
],
);
assert_tokens(
&date!(-9999-001).readable(),
&[Token::BorrowedStr("-9999-01-01")],
);
assert_tokens(
&date!(+9999-365).readable(),
&[Token::BorrowedStr("9999-12-31")],
);
}
#[test]
fn date_error() {
assert_de_tokens_error::<Readable<Date>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Date`",
);
assert_de_tokens_error::<Compact<Date>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Date`",
);
}
#[test]
fn date_partial() {
assert_de_tokens_error::<Compact<Date>>(
&[Token::Tuple { len: 2 }, Token::TupleEnd],
"expected year",
);
assert_de_tokens_error::<Compact<Date>>(
&[Token::Tuple { len: 2 }, Token::I32(9999), Token::TupleEnd],
"expected day of year",
);
assert_de_tokens_error::<Readable<Date>>(
&[Token::Tuple { len: 2 }, Token::TupleEnd],
"expected year",
);
assert_de_tokens_error::<Readable<Date>>(
&[Token::Tuple { len: 2 }, Token::I32(9999), Token::TupleEnd],
"expected day of year",
);
}
#[test]
fn primitive_date_time() {
assert_tokens(
&datetime!(-9999-001 0:00).compact(),
&[
Token::Tuple { len: 6 },
Token::I32(-9999),
Token::U16(1),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::TupleEnd,
],
);
assert_tokens(
&datetime!(+9999-365 23:58:59.123_456_789).compact(),
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::U8(58),
Token::U8(59),
Token::U32(123_456_789),
Token::TupleEnd,
],
);
assert_tokens(
&datetime!(-9999-001 0:00).readable(),
&[Token::BorrowedStr("-9999-01-01 00:00:00.0")],
);
assert_tokens(
&datetime!(+9999-365 23:58:59.123_456_789).readable(),
&[Token::BorrowedStr("9999-12-31 23:58:59.123456789")],
);
}
#[test]
fn primitive_date_time_error() {
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `PrimitiveDateTime`",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `PrimitiveDateTime`",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(2021),
Token::U16(366),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::TupleEnd,
],
"invalid ordinal, expected an in-range value",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(2021),
Token::U16(1),
Token::U8(24),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::TupleEnd,
],
"invalid hour, expected an in-range value",
);
}
#[test]
fn primitive_date_time_partial() {
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[Token::Tuple { len: 6 }, Token::TupleEnd],
"expected year",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[Token::Tuple { len: 6 }, Token::I32(9999), Token::TupleEnd],
"expected day of year",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::TupleEnd,
],
"expected hour",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::TupleEnd,
],
"expected minute",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::U8(58),
Token::TupleEnd,
],
"expected second",
);
assert_de_tokens_error::<Compact<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::U8(58),
Token::U8(59),
Token::TupleEnd,
],
"expected nanosecond",
);
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[Token::Tuple { len: 6 }, Token::TupleEnd],
"expected year",
);
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[Token::Tuple { len: 6 }, Token::I32(9999), Token::TupleEnd],
"expected day of year",
);
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::TupleEnd,
],
"expected hour",
);
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::TupleEnd,
],
"expected minute",
);
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::U8(58),
Token::TupleEnd,
],
"expected second",
);
assert_de_tokens_error::<Readable<PrimitiveDateTime>>(
&[
Token::Tuple { len: 6 },
Token::I32(9999),
Token::U16(365),
Token::U8(23),
Token::U8(58),
Token::U8(59),
Token::TupleEnd,
],
"expected nanosecond",
);
}
#[test]
fn offset_date_time() {
assert_tokens(
&datetime!(-9999-001 0:00 UTC)
.to_offset(offset!(+23:58:59))
.compact(),
&[
Token::Tuple { len: 9 },
Token::I32(-9999),
Token::U16(1),
Token::U8(23),
Token::U8(58),
Token::U8(59),
Token::U32(0),
Token::I8(23),
Token::I8(58),
Token::I8(59),
Token::TupleEnd,
],
);
assert_tokens(
&datetime!(+9999-365 23:58:59.123_456_789 UTC)
.to_offset(offset!(-23:58:59))
.compact(),
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::I8(-23),
Token::I8(-58),
Token::I8(-59),
Token::TupleEnd,
],
);
assert_tokens(
&datetime!(-9999-001 0:00 UTC)
.to_offset(offset!(+23:58:59))
.readable(),
&[Token::BorrowedStr("-9999-01-01 23:58:59.0 +23:58:59")],
);
assert_tokens(
&datetime!(+9999-365 23:58:59.123_456_789 UTC)
.to_offset(offset!(-23:58:59))
.readable(),
&[Token::BorrowedStr(
"9999-12-31 00:00:00.123456789 -23:58:59",
)],
);
}
#[test]
fn offset_date_time_error() {
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected an `OffsetDateTime`",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected an `OffsetDateTime`",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(2021),
Token::U16(366),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::I8(0),
Token::I8(0),
Token::I8(0),
Token::TupleEnd,
],
"invalid ordinal, expected an in-range value",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(2021),
Token::U16(1),
Token::U8(24),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::I8(0),
Token::I8(0),
Token::I8(0),
Token::TupleEnd,
],
"invalid hour, expected an in-range value",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(2021),
Token::U16(1),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(0),
Token::I8(26),
Token::I8(0),
Token::I8(0),
Token::TupleEnd,
],
"invalid offset hour, expected an in-range value",
);
// the Deserialize impl does not recognize leap second times as valid
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(2021),
Token::U16(365),
Token::U8(23),
Token::U8(59),
Token::U8(60),
Token::U32(0),
Token::I8(0),
Token::I8(0),
Token::I8(0),
Token::TupleEnd,
],
"invalid second, expected an in-range value",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[Token::BorrowedStr("2021-12-31 23:59:60.0 +00:00:00")],
"second was not in range",
);
}
#[test]
fn offset_date_time_partial() {
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[Token::Tuple { len: 9 }, Token::TupleEnd],
"expected year",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[Token::Tuple { len: 9 }, Token::I32(9999), Token::TupleEnd],
"expected day of year",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::TupleEnd,
],
"expected hour",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::TupleEnd,
],
"expected minute",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected second",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected nanosecond",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::TupleEnd,
],
"expected offset hours",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::I8(-23),
Token::TupleEnd,
],
"expected offset minutes",
);
assert_de_tokens_error::<Compact<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::I8(-23),
Token::I8(-58),
Token::TupleEnd,
],
"expected offset seconds",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[Token::Tuple { len: 9 }, Token::TupleEnd],
"expected year",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[Token::Tuple { len: 9 }, Token::I32(9999), Token::TupleEnd],
"expected day of year",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::TupleEnd,
],
"expected hour",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::TupleEnd,
],
"expected minute",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected second",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::TupleEnd,
],
"expected nanosecond",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::TupleEnd,
],
"expected offset hours",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::I8(-23),
Token::TupleEnd,
],
"expected offset minutes",
);
assert_de_tokens_error::<Readable<OffsetDateTime>>(
&[
Token::Tuple { len: 9 },
Token::I32(9999),
Token::U16(365),
Token::U8(0),
Token::U8(0),
Token::U8(0),
Token::U32(123_456_789),
Token::I8(-23),
Token::I8(-58),
Token::TupleEnd,
],
"expected offset seconds",
);
}
#[test]
fn utc_offset() {
assert_tokens(
&offset!(-23:58:59).compact(),
&[
Token::Tuple { len: 3 },
Token::I8(-23),
Token::I8(-58),
Token::I8(-59),
Token::TupleEnd,
],
);
assert_tokens(
&offset!(+23:58:59).compact(),
&[
Token::Tuple { len: 3 },
Token::I8(23),
Token::I8(58),
Token::I8(59),
Token::TupleEnd,
],
);
assert_tokens(
&offset!(-23:58:59).readable(),
&[Token::BorrowedStr("-23:58:59")],
);
assert_tokens(
&offset!(+23:58:59).readable(),
&[Token::BorrowedStr("+23:58:59")],
);
}
#[test]
fn utc_offset_error() {
assert_de_tokens_error::<Readable<UtcOffset>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `UtcOffset`",
);
assert_de_tokens_error::<Compact<UtcOffset>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `UtcOffset`",
);
assert_de_tokens_error::<Compact<UtcOffset>>(
&[
Token::Tuple { len: 3 },
Token::I8(26),
Token::I8(0),
Token::I8(0),
Token::TupleEnd,
],
"invalid offset hour, expected an in-range value",
);
}
#[test]
fn utc_offset_partial() {
assert_de_tokens_error::<Compact<UtcOffset>>(
&[Token::Tuple { len: 0 }, Token::TupleEnd],
"expected offset hours",
);
assert_de_tokens_error::<Readable<UtcOffset>>(
&[Token::Tuple { len: 0 }, Token::TupleEnd],
"expected offset hours",
);
let value = offset!(+23);
assert_de_tokens::<Compact<UtcOffset>>(
&value.compact(),
&[Token::Tuple { len: 1 }, Token::I8(23), Token::TupleEnd],
);
let value = offset!(+23);
assert_de_tokens::<Readable<UtcOffset>>(
&value.readable(),
&[Token::Tuple { len: 1 }, Token::I8(23), Token::TupleEnd],
);
let value = offset!(+23:58);
assert_de_tokens::<Compact<UtcOffset>>(
&value.compact(),
&[
Token::Tuple { len: 2 },
Token::I8(23),
Token::I8(58),
Token::TupleEnd,
],
);
let value = offset!(+23:58);
assert_de_tokens::<Readable<UtcOffset>>(
&value.readable(),
&[
Token::Tuple { len: 2 },
Token::I8(23),
Token::I8(58),
Token::TupleEnd,
],
);
}
#[test]
fn duration() {
assert_tokens(
&Duration::MIN.compact(),
&[
Token::Tuple { len: 2 },
Token::I64(i64::MIN),
Token::I32(-999_999_999),
Token::TupleEnd,
],
);
assert_tokens(
&Duration::MAX.compact(),
&[
Token::Tuple { len: 2 },
Token::I64(i64::MAX),
Token::I32(999_999_999),
Token::TupleEnd,
],
);
assert_tokens(
&Duration::MIN.readable(),
&[Token::BorrowedStr("-9223372036854775808.999999999")],
);
assert_tokens(
&Duration::MAX.readable(),
&[Token::BorrowedStr("9223372036854775807.999999999")],
);
assert_tokens(
&Duration::ZERO.readable(),
&[Token::BorrowedStr("0.000000000")],
);
assert_tokens(
&Duration::nanoseconds(123).readable(),
&[Token::BorrowedStr("0.000000123")],
);
assert_tokens(
&Duration::nanoseconds(-123).readable(),
&[Token::BorrowedStr("-0.000000123")],
);
}
#[test]
fn duration_error() {
assert_de_tokens_error::<Readable<Duration>>(
&[Token::BorrowedStr("x")],
r#"invalid value: string "x", expected a decimal point"#,
);
assert_de_tokens_error::<Readable<Duration>>(
&[Token::BorrowedStr("x.0")],
r#"invalid value: string "x", expected seconds"#,
);
assert_de_tokens_error::<Readable<Duration>>(
&[Token::BorrowedStr("0.x")],
r#"invalid value: string "x", expected nanoseconds"#,
);
assert_de_tokens_error::<Readable<Duration>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Duration`",
);
assert_de_tokens_error::<Compact<Duration>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Duration`",
);
}
#[test]
fn duration_partial() {
assert_de_tokens_error::<Compact<Duration>>(
&[Token::Tuple { len: 2 }, Token::TupleEnd],
"expected seconds",
);
assert_de_tokens_error::<Compact<Duration>>(
&[
Token::Tuple { len: 2 },
Token::I64(i64::MAX),
Token::TupleEnd,
],
"expected nanoseconds",
);
assert_de_tokens_error::<Readable<Duration>>(
&[Token::Tuple { len: 2 }, Token::TupleEnd],
"expected seconds",
);
assert_de_tokens_error::<Readable<Duration>>(
&[
Token::Tuple { len: 2 },
Token::I64(i64::MAX),
Token::TupleEnd,
],
"expected nanoseconds",
);
}
#[test]
fn weekday() {
use Weekday::*;
assert_tokens(&Monday.compact(), &[Token::U8(1)]);
assert_tokens(&Tuesday.compact(), &[Token::U8(2)]);
assert_tokens(&Wednesday.compact(), &[Token::U8(3)]);
assert_tokens(&Thursday.compact(), &[Token::U8(4)]);
assert_tokens(&Friday.compact(), &[Token::U8(5)]);
assert_tokens(&Saturday.compact(), &[Token::U8(6)]);
assert_tokens(&Sunday.compact(), &[Token::U8(7)]);
assert_tokens(&Monday.readable(), &[Token::BorrowedStr("Monday")]);
assert_tokens(&Tuesday.readable(), &[Token::BorrowedStr("Tuesday")]);
assert_tokens(&Wednesday.readable(), &[Token::BorrowedStr("Wednesday")]);
assert_tokens(&Thursday.readable(), &[Token::BorrowedStr("Thursday")]);
assert_tokens(&Friday.readable(), &[Token::BorrowedStr("Friday")]);
assert_tokens(&Saturday.readable(), &[Token::BorrowedStr("Saturday")]);
assert_tokens(&Sunday.readable(), &[Token::BorrowedStr("Sunday")]);
}
#[test]
fn weekday_error() {
assert_de_tokens_error::<Compact<Weekday>>(
&[Token::U8(0)],
"invalid value: integer `0`, expected a value in the range 1..=7",
);
assert_de_tokens_error::<Readable<Weekday>>(
&[Token::BorrowedStr("NotADay")],
r#"invalid value: string "NotADay", expected a `Weekday`"#,
);
assert_de_tokens_error::<Readable<Weekday>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Weekday`",
);
assert_de_tokens_error::<Compact<Weekday>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Weekday`",
);
}
#[test]
fn month() {
use Month::*;
assert_tokens(&January.compact(), &[Token::U8(1)]);
assert_tokens(&February.compact(), &[Token::U8(2)]);
assert_tokens(&March.compact(), &[Token::U8(3)]);
assert_tokens(&April.compact(), &[Token::U8(4)]);
assert_tokens(&May.compact(), &[Token::U8(5)]);
assert_tokens(&June.compact(), &[Token::U8(6)]);
assert_tokens(&July.compact(), &[Token::U8(7)]);
assert_tokens(&August.compact(), &[Token::U8(8)]);
assert_tokens(&September.compact(), &[Token::U8(9)]);
assert_tokens(&October.compact(), &[Token::U8(10)]);
assert_tokens(&November.compact(), &[Token::U8(11)]);
assert_tokens(&December.compact(), &[Token::U8(12)]);
assert_tokens(&January.readable(), &[Token::BorrowedStr("January")]);
assert_tokens(&February.readable(), &[Token::BorrowedStr("February")]);
assert_tokens(&March.readable(), &[Token::BorrowedStr("March")]);
assert_tokens(&April.readable(), &[Token::BorrowedStr("April")]);
assert_tokens(&May.readable(), &[Token::BorrowedStr("May")]);
assert_tokens(&June.readable(), &[Token::BorrowedStr("June")]);
assert_tokens(&July.readable(), &[Token::BorrowedStr("July")]);
assert_tokens(&August.readable(), &[Token::BorrowedStr("August")]);
assert_tokens(&September.readable(), &[Token::BorrowedStr("September")]);
assert_tokens(&October.readable(), &[Token::BorrowedStr("October")]);
assert_tokens(&November.readable(), &[Token::BorrowedStr("November")]);
assert_tokens(&December.readable(), &[Token::BorrowedStr("December")]);
}
#[test]
fn month_error() {
assert_de_tokens_error::<Compact<Month>>(
&[Token::U8(0)],
"invalid value: integer `0`, expected a value in the range 1..=12",
);
assert_de_tokens_error::<Readable<Month>>(
&[Token::BorrowedStr("NotAMonth")],
r#"invalid value: string "NotAMonth", expected a `Month`"#,
);
assert_de_tokens_error::<Readable<Month>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Month`",
);
assert_de_tokens_error::<Compact<Month>>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected a `Month`",
);
}

View File

@@ -0,0 +1,56 @@
use serde::{Deserialize, Serialize};
use serde_test::{assert_tokens, Configure, Token};
use time::serde::rfc2822;
use time::OffsetDateTime;
use time_macros::datetime;
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct Test {
#[serde(with = "rfc2822")]
dt: OffsetDateTime,
#[serde(with = "rfc2822::option")]
option_dt: Option<OffsetDateTime>,
}
#[test]
fn serialize_deserialize() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: Some(datetime!(2000-01-01 00:00:00 UTC)),
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("Sat, 01 Jan 2000 00:00:00 +0000"),
Token::Str("option_dt"),
Token::Some,
Token::BorrowedStr("Sat, 01 Jan 2000 00:00:00 +0000"),
Token::StructEnd,
],
);
}
#[test]
fn parse_json() -> serde_json::Result<()> {
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
enum Wrapper {
A(Test),
}
assert_eq!(
serde_json::from_str::<Wrapper>(
r#"{"dt": "Sat, 01 Jan 2000 00:00:00 +0000", "option_dt": null}"#
)?,
Wrapper::A(Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: None,
})
);
Ok(())
}

View File

@@ -0,0 +1,141 @@
use serde::{Deserialize, Serialize};
use serde_test::{
assert_de_tokens_error, assert_ser_tokens_error, assert_tokens, Configure, Token,
};
use time::macros::datetime;
use time::serde::rfc3339;
use time::OffsetDateTime;
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct Test {
#[serde(with = "rfc3339")]
dt: OffsetDateTime,
#[serde(with = "rfc3339::option")]
option_dt: Option<OffsetDateTime>,
}
#[test]
fn serialize_deserialize() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: Some(datetime!(2000-01-01 00:00:00 UTC)),
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("2000-01-01T00:00:00Z"),
Token::Str("option_dt"),
Token::Some,
Token::BorrowedStr("2000-01-01T00:00:00Z"),
Token::StructEnd,
],
);
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: None,
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("2000-01-01T00:00:00Z"),
Token::Str("option_dt"),
Token::None,
Token::StructEnd,
],
);
assert_de_tokens_error::<Test>(
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("bad"),
Token::StructEnd,
],
"the 'year' component could not be parsed",
);
let value = Test {
dt: datetime!(2000-01-01 00:00:00 +00:00:01),
option_dt: None,
};
assert_ser_tokens_error::<Test>(
&value,
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
],
"The offset_second component cannot be formatted into the requested format.",
);
}
#[test]
fn parse_json() -> serde_json::Result<()> {
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
enum Wrapper {
A(Test),
}
assert_eq!(
serde_json::from_str::<Wrapper>("{\"dt\": \"2000-01-01T00:00:00Z\", \"option_dt\": null}")?,
Wrapper::A(Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: None,
})
);
Ok(())
}
#[test]
fn issue_479() -> serde_json::Result<()> {
const A: &str = r#"{
"date": "2022-05-01T10:20:42.123Z"
}"#;
const B: &str = r#"{
"date": "2022-05-01T10:20:42.123Z",
"maybe_date": "2022-05-01T10:20:42.123Z"
}"#;
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct S {
#[serde(with = "time::serde::rfc3339")]
date: OffsetDateTime,
#[serde(with = "time::serde::rfc3339::option", default)]
maybe_date: Option<OffsetDateTime>,
}
let a = serde_json::from_str::<S>(A)?;
let b = serde_json::from_str::<S>(B)?;
assert_eq!(
a,
S {
date: datetime!(2022-05-01 10:20:42.123 UTC),
maybe_date: None
}
);
assert_eq!(
b,
S {
date: datetime!(2022-05-01 10:20:42.123 UTC),
maybe_date: Some(datetime!(2022-05-01 10:20:42.123 UTC))
}
);
Ok(())
}

View File

@@ -0,0 +1,138 @@
use serde::{Deserialize, Serialize};
use serde_test::{assert_de_tokens_error, assert_tokens, Configure, Token};
use time::macros::datetime;
use time::serde::timestamp;
use time::OffsetDateTime;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Test {
#[serde(with = "timestamp")]
dt: OffsetDateTime,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct TestMilliseconds {
#[serde(with = "timestamp::milliseconds")]
dt: OffsetDateTime,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct TestMicroseconds {
#[serde(with = "timestamp::microseconds")]
dt: OffsetDateTime,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct TestNanoseconds {
#[serde(with = "timestamp::nanoseconds")]
dt: OffsetDateTime,
}
#[test]
fn serialize_timestamp() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 1,
},
Token::Str("dt"),
Token::I64(946684800),
Token::StructEnd,
],
);
assert_de_tokens_error::<Test>(
&[
Token::Struct {
name: "Test",
len: 1,
},
Token::Str("dt"),
Token::Str("bad"),
Token::StructEnd,
],
"invalid type: string \"bad\", expected i64",
);
}
#[test]
fn serialize_timestamp_milliseconds() -> serde_json::Result<()> {
let value_milliseconds = TestMilliseconds {
dt: datetime!(2000-01-01 00:00:00.999 UTC),
};
assert_de_tokens_error::<TestMilliseconds>(
&[
Token::Struct {
name: "TestMilliseconds",
len: 1,
},
Token::Str("dt"),
Token::Str("bad"),
Token::StructEnd,
],
"invalid type: string \"bad\", expected i128",
);
// serde_test does not support I128, see: https://github.com/serde-rs/test/issues/18
let milliseconds_str = r#"{"dt":946684800999}"#;
let deserialized_milliseconds: TestMilliseconds = serde_json::from_str(milliseconds_str)?;
let serialized_milliseconds = serde_json::to_string(&value_milliseconds)?;
assert_eq!(value_milliseconds.dt, deserialized_milliseconds.dt);
assert_eq!(serialized_milliseconds, milliseconds_str);
Ok(())
}
#[test]
fn serialize_timestamp_microseconds() -> serde_json::Result<()> {
let value_microseconds = TestMicroseconds {
dt: datetime!(2000-01-01 00:00:00.999_999 UTC),
};
assert_de_tokens_error::<TestMicroseconds>(
&[
Token::Struct {
name: "TestMicroseconds",
len: 1,
},
Token::Str("dt"),
Token::Str("bad"),
Token::StructEnd,
],
"invalid type: string \"bad\", expected i128",
);
// serde_test does not support I128, see: https://github.com/serde-rs/test/issues/18
let microseconds_str = r#"{"dt":946684800999999}"#;
let deserialized_microseconds: TestMicroseconds = serde_json::from_str(microseconds_str)?;
let serialized_microseconds = serde_json::to_string(&value_microseconds)?;
assert_eq!(value_microseconds.dt, deserialized_microseconds.dt);
assert_eq!(serialized_microseconds, microseconds_str);
Ok(())
}
#[test]
fn serialize_timestamp_nanoseconds() -> serde_json::Result<()> {
let value_nanoseconds = TestNanoseconds {
dt: datetime!(2000-01-01 00:00:00.999_999_999 UTC),
};
assert_de_tokens_error::<TestNanoseconds>(
&[
Token::Struct {
name: "TestNanoseconds",
len: 1,
},
Token::Str("dt"),
Token::Str("bad"),
Token::StructEnd,
],
"invalid type: string \"bad\", expected i128",
);
// serde_test does not support I128, see: https://github.com/serde-rs/test/issues/18
let nanoseconds_str = r#"{"dt":946684800999999999}"#;
let deserialized_nanoseconds: TestNanoseconds = serde_json::from_str(nanoseconds_str)?;
let serialized_nanoseconds = serde_json::to_string(&value_nanoseconds)?;
assert_eq!(value_nanoseconds.dt, deserialized_nanoseconds.dt);
assert_eq!(serialized_nanoseconds, nanoseconds_str);
Ok(())
}

View File

@@ -0,0 +1,223 @@
use serde::{Deserialize, Serialize};
use serde_test::{Token, assert_de_tokens_error, assert_ser_tokens_error, assert_tokens};
use time::OffsetDateTime;
use time::macros::datetime;
#[test]
fn success() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Full(
#[serde(with = "time::serde::rfc2822")] OffsetDateTime,
#[serde(with = "time::serde::rfc2822::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc2822::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc3339")] OffsetDateTime,
#[serde(with = "time::serde::rfc3339::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc3339::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::timestamp")] OffsetDateTime,
#[serde(with = "time::serde::timestamp::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::timestamp::option")] Option<OffsetDateTime>,
);
assert_tokens(
&Full(
datetime!(2021-01-02 03:04:05 UTC),
Some(datetime!(2021-01-02 03:04:05 UTC)),
None,
datetime!(2021-01-02 03:04:05 UTC),
Some(datetime!(2021-01-02 03:04:05 UTC)),
None,
datetime!(2021-01-02 03:04:05 UTC),
Some(datetime!(2021-01-02 03:04:05 UTC)),
None,
),
&[
Token::TupleStruct {
name: "Full",
len: 9,
},
Token::Str("Sat, 02 Jan 2021 03:04:05 +0000"),
Token::Some,
Token::Str("Sat, 02 Jan 2021 03:04:05 +0000"),
Token::None,
Token::Str("2021-01-02T03:04:05Z"),
Token::Some,
Token::Str("2021-01-02T03:04:05Z"),
Token::None,
Token::I64(1_609_556_645),
Token::Some,
Token::I64(1_609_556_645),
Token::None,
Token::TupleStructEnd,
],
);
}
#[test]
fn rfc2822_error() {
#[derive(Serialize, Deserialize)]
struct Rfc2822(
#[serde(with = "time::serde::rfc2822")] OffsetDateTime,
#[serde(with = "time::serde::rfc2822::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc2822::option")] Option<OffsetDateTime>,
);
assert_ser_tokens_error(
&Rfc2822(
datetime!(2021-01-02 03:04:05 +0:00:01),
Some(datetime!(2021-01-02 03:04:05 UTC)),
None,
),
&[Token::TupleStruct {
name: "Rfc2822",
len: 3,
}],
"The offset_second component cannot be formatted into the requested format.",
);
assert_ser_tokens_error(
&Rfc2822(
datetime!(2021-01-02 03:04:05 UTC),
Some(datetime!(2021-01-02 03:04:05 +0:00:01)),
None,
),
&[
Token::TupleStruct {
name: "Rfc2822",
len: 3,
},
Token::Str("Sat, 02 Jan 2021 03:04:05 +0000"),
],
"The offset_second component cannot be formatted into the requested format.",
);
assert_de_tokens_error::<Rfc2822>(
&[
Token::TupleStruct {
name: "Rfc2822",
len: 3,
},
Token::Bool(false),
],
"invalid type: boolean `false`, expected an RFC2822-formatted `OffsetDateTime`",
);
assert_de_tokens_error::<Rfc2822>(
&[
Token::TupleStruct {
name: "Rfc2822",
len: 3,
},
Token::Str("Sat, 02 Jan 2021 03:04:05 +0000"),
Token::Bool(false),
],
"invalid type: boolean `false`, expected an RFC2822-formatted `Option<OffsetDateTime>`",
);
assert_de_tokens_error::<Rfc2822>(
&[
Token::TupleStruct {
name: "Rfc2822",
len: 3,
},
Token::Str("Sat, 02 Jan 2021 03:04:05 +0000"),
Token::Some,
Token::Bool(false),
],
"invalid type: boolean `false`, expected an RFC2822-formatted `OffsetDateTime`",
);
}
#[test]
fn rfc3339_error() {
#[derive(Serialize, Deserialize)]
struct Rfc3339(
#[serde(with = "time::serde::rfc3339")] OffsetDateTime,
#[serde(with = "time::serde::rfc3339::option")] Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc3339::option")] Option<OffsetDateTime>,
);
assert_ser_tokens_error(
&Rfc3339(
datetime!(2021-01-02 03:04:05 +0:00:01),
Some(datetime!(2021-01-02 03:04:05 UTC)),
None,
),
&[Token::TupleStruct {
name: "Rfc3339",
len: 3,
}],
"The offset_second component cannot be formatted into the requested format.",
);
assert_ser_tokens_error(
&Rfc3339(
datetime!(2021-01-02 03:04:05 UTC),
Some(datetime!(2021-01-02 03:04:05 +0:00:01)),
None,
),
&[
Token::TupleStruct {
name: "Rfc3339",
len: 3,
},
Token::Str("2021-01-02T03:04:05Z"),
],
"The offset_second component cannot be formatted into the requested format.",
);
assert_de_tokens_error::<Rfc3339>(
&[
Token::TupleStruct {
name: "Rfc3339",
len: 3,
},
Token::Bool(false),
],
"invalid type: boolean `false`, expected an RFC3339-formatted `OffsetDateTime`",
);
assert_de_tokens_error::<Rfc3339>(
&[
Token::TupleStruct {
name: "Rfc3339",
len: 3,
},
Token::Str("2021-01-02T03:04:05Z"),
Token::Bool(false),
],
"invalid type: boolean `false`, expected an RFC3339-formatted `Option<OffsetDateTime>`",
);
assert_de_tokens_error::<Rfc3339>(
&[
Token::TupleStruct {
name: "Rfc3339",
len: 3,
},
Token::Str("2021-01-02T03:04:05Z"),
Token::Some,
Token::Bool(false),
],
"invalid type: boolean `false`, expected an RFC3339-formatted `OffsetDateTime`",
);
}
#[test]
fn timestamp_error() {
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct Timestamp(#[serde(with = "time::serde::timestamp")] OffsetDateTime);
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct OptTimestamp(#[serde(with = "time::serde::timestamp::option")] Option<OffsetDateTime>);
assert_de_tokens_error::<Timestamp>(
&[Token::Bool(false)],
"invalid type: boolean `false`, expected i64",
);
assert_de_tokens_error::<OptTimestamp>(
&[Token::Some, Token::Bool(false)],
"invalid type: boolean `false`, expected i64",
);
assert_de_tokens_error::<Timestamp>(
&[Token::I64(100_000_000_000_000)],
"invalid timestamp, expected an in-range value",
);
assert_de_tokens_error::<OptTimestamp>(
&[Token::Some, Token::I64(-100_000_000_000_000)],
"invalid timestamp, expected an in-range value",
);
}

423
vendor/time/tests/integration/time.rs vendored Normal file
View File

@@ -0,0 +1,423 @@
use time::ext::{NumericalDuration, NumericalStdDuration};
use time::macros::time;
use time::{Result, Time};
#[test]
fn from_hms() -> Result<()> {
let time = Time::from_hms(1, 2, 3)?;
assert_eq!(time.hour(), 1);
assert_eq!(time.minute(), 2);
assert_eq!(time.second(), 3);
assert_eq!(time.nanosecond(), 0);
assert!(Time::from_hms(24, 0, 0).is_err());
assert!(Time::from_hms(0, 60, 0).is_err());
assert!(Time::from_hms(0, 0, 60).is_err());
Ok(())
}
#[test]
fn from_hms_milli() -> Result<()> {
let time = Time::from_hms_milli(1, 2, 3, 4)?;
assert_eq!(time.hour(), 1);
assert_eq!(time.minute(), 2);
assert_eq!(time.second(), 3);
assert_eq!(time.millisecond(), 4);
assert_eq!(time.nanosecond(), 4_000_000);
assert!(Time::from_hms_milli(24, 0, 0, 0).is_err());
assert!(Time::from_hms_milli(0, 60, 0, 0).is_err());
assert!(Time::from_hms_milli(0, 0, 60, 0).is_err());
assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err());
Ok(())
}
#[test]
fn from_hms_micro() -> Result<()> {
let time = Time::from_hms_micro(1, 2, 3, 4)?;
assert_eq!(time.hour(), 1);
assert_eq!(time.minute(), 2);
assert_eq!(time.second(), 3);
assert_eq!(time.microsecond(), 4);
assert_eq!(time.nanosecond(), 4_000);
assert!(Time::from_hms_micro(24, 0, 0, 0).is_err());
assert!(Time::from_hms_micro(0, 60, 0, 0).is_err());
assert!(Time::from_hms_micro(0, 0, 60, 0).is_err());
assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err());
Ok(())
}
#[test]
fn from_hms_nano() -> Result<()> {
let time = Time::from_hms_nano(1, 2, 3, 4)?;
assert_eq!(time.hour(), 1);
assert_eq!(time.minute(), 2);
assert_eq!(time.second(), 3);
assert_eq!(time.nanosecond(), 4);
assert!(Time::from_hms_nano(24, 0, 0, 0).is_err());
assert!(Time::from_hms_nano(0, 60, 0, 0).is_err());
assert!(Time::from_hms_nano(0, 0, 60, 0).is_err());
assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err());
Ok(())
}
#[test]
fn as_hms() {
assert_eq!(time!(1:02:03).as_hms(), (1, 2, 3));
}
#[test]
fn as_hms_milli() {
assert_eq!(time!(1:02:03.004).as_hms_milli(), (1, 2, 3, 4));
}
#[test]
fn as_hms_micro() {
assert_eq!(time!(1:02:03.004_005).as_hms_micro(), (1, 2, 3, 4_005));
}
#[test]
fn as_hms_nano() {
assert_eq!(
time!(1:02:03.004_005_006).as_hms_nano(),
(1, 2, 3, 4_005_006)
);
}
#[test]
fn hour() -> Result<()> {
for hour in 0..24 {
assert_eq!(Time::from_hms(hour, 0, 0)?.hour(), hour);
assert_eq!(Time::from_hms(hour, 59, 59)?.hour(), hour);
}
Ok(())
}
#[test]
fn minute() -> Result<()> {
for minute in 0..60 {
assert_eq!(Time::from_hms(0, minute, 0)?.minute(), minute);
assert_eq!(Time::from_hms(23, minute, 59)?.minute(), minute);
}
Ok(())
}
#[test]
fn second() -> Result<()> {
for second in 0..60 {
assert_eq!(Time::from_hms(0, 0, second)?.second(), second);
assert_eq!(Time::from_hms(23, 59, second)?.second(), second);
}
Ok(())
}
#[test]
fn millisecond() -> Result<()> {
for milli in 0..1_000 {
assert_eq!(Time::from_hms_milli(0, 0, 0, milli)?.millisecond(), milli);
assert_eq!(
Time::from_hms_milli(23, 59, 59, milli)?.millisecond(),
milli
);
}
Ok(())
}
#[test]
fn microsecond() -> Result<()> {
for micro in (0..1_000_000).step_by(1_000) {
assert_eq!(Time::from_hms_micro(0, 0, 0, micro)?.microsecond(), micro);
assert_eq!(
Time::from_hms_micro(23, 59, 59, micro)?.microsecond(),
micro
);
}
Ok(())
}
#[test]
fn nanosecond() -> Result<()> {
for nano in (0..1_000_000_000).step_by(1_000_000) {
assert_eq!(Time::from_hms_nano(0, 0, 0, nano)?.nanosecond(), nano);
assert_eq!(Time::from_hms_nano(23, 59, 59, nano)?.nanosecond(), nano);
}
Ok(())
}
#[test]
fn duration_until() -> Result<()> {
assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
assert_eq!(time!(12:30).duration_until(time!(14:00)), 90.minutes());
Ok(())
}
#[test]
fn duration_since() -> Result<()> {
assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
assert_eq!(time!(14:00).duration_since(time!(12:30)), 90.minutes());
Ok(())
}
#[test]
fn replace_hour() {
assert_eq!(
time!(1:02:03.004_005_006).replace_hour(7),
Ok(time!(7:02:03.004_005_006))
);
assert!(time!(1:02:03.004_005_006).replace_hour(24).is_err());
}
#[test]
fn replace_minute() {
assert_eq!(
time!(1:02:03.004_005_006).replace_minute(7),
Ok(time!(1:07:03.004_005_006))
);
assert!(time!(1:02:03.004_005_006).replace_minute(60).is_err());
}
#[test]
fn replace_second() {
assert_eq!(
time!(1:02:03.004_005_006).replace_second(7),
Ok(time!(1:02:07.004_005_006))
);
assert!(time!(1:02:03.004_005_006).replace_second(60).is_err());
}
#[test]
fn replace_millisecond() {
assert_eq!(
time!(1:02:03.004_005_006).replace_millisecond(7),
Ok(time!(1:02:03.007))
);
assert!(
time!(1:02:03.004_005_006)
.replace_millisecond(1_000)
.is_err()
);
}
#[test]
fn replace_millisecond_regression() {
assert!(Time::MIDNIGHT.replace_millisecond(9999).is_err());
assert!(Time::MIDNIGHT.replace_millisecond(4294).is_err());
assert!(Time::MIDNIGHT.replace_millisecond(4295).is_err());
}
#[test]
fn replace_microsecond() {
assert_eq!(
time!(1:02:03.004_005_006).replace_microsecond(7_008),
Ok(time!(1:02:03.007_008))
);
assert!(
time!(1:02:03.004_005_006)
.replace_microsecond(1_000_000)
.is_err()
);
}
#[test]
fn replace_nanosecond() {
assert_eq!(
time!(1:02:03.004_005_006).replace_nanosecond(7_008_009),
Ok(time!(1:02:03.007_008_009))
);
assert!(
time!(1:02:03.004_005_006)
.replace_nanosecond(1_000_000_000)
.is_err()
);
}
#[test]
fn truncate_to_hour() {
assert_eq!(time!(1:02:03.004_005_006).truncate_to_hour(), time!(1:00));
assert_eq!(Time::MIDNIGHT.truncate_to_hour(), Time::MIDNIGHT);
}
#[test]
fn truncate_to_minute() {
assert_eq!(time!(1:02:03.004_005_006).truncate_to_minute(), time!(1:02));
assert_eq!(Time::MIDNIGHT.truncate_to_minute(), Time::MIDNIGHT);
}
#[test]
fn truncate_to_second() {
assert_eq!(
time!(1:02:03.004_005_006).truncate_to_second(),
time!(1:02:03)
);
assert_eq!(Time::MIDNIGHT.truncate_to_second(), Time::MIDNIGHT);
}
#[test]
fn truncate_to_millisecond() {
assert_eq!(
time!(1:02:03.004_005_006).truncate_to_millisecond(),
time!(1:02:03.004)
);
assert_eq!(Time::MIDNIGHT.truncate_to_millisecond(), Time::MIDNIGHT);
}
#[test]
fn truncate_to_microsecond() {
assert_eq!(
time!(1:02:03.004_005_006).truncate_to_microsecond(),
time!(1:02:03.004_005)
);
assert_eq!(Time::MIDNIGHT.truncate_to_microsecond(), Time::MIDNIGHT);
}
#[test]
fn add_duration() {
assert_eq!(time!(0:00) + 1.seconds(), time!(0:00:01));
assert_eq!(time!(0:00) + 1.minutes(), time!(0:01));
assert_eq!(time!(0:00) + 1.hours(), time!(1:00));
assert_eq!(time!(0:00) + 1.days(), time!(0:00));
}
#[test]
fn add_assign_duration() {
let mut time = time!(0:00);
time += 1.seconds();
assert_eq!(time, time!(0:00:01));
time += 1.minutes();
assert_eq!(time, time!(0:01:01));
time += 1.hours();
assert_eq!(time, time!(1:01:01));
time += 1.days();
assert_eq!(time, time!(1:01:01));
}
#[test]
fn sub_duration() {
assert_eq!(time!(12:00) - 1.hours(), time!(11:00));
// Underflow
assert_eq!(time!(0:00) - 1.seconds(), time!(23:59:59));
assert_eq!(time!(0:00) - 1.minutes(), time!(23:59));
assert_eq!(time!(0:00) - 1.hours(), time!(23:00));
assert_eq!(time!(0:00) - 1.days(), time!(0:00));
}
#[test]
fn sub_assign_duration() {
let mut time = time!(0:00);
time -= 1.seconds();
assert_eq!(time, time!(23:59:59));
time -= 1.minutes();
assert_eq!(time, time!(23:58:59));
time -= 1.hours();
assert_eq!(time, time!(22:58:59));
time -= 1.days();
assert_eq!(time, time!(22:58:59));
}
#[test]
fn add_std_duration() {
assert_eq!(time!(0:00) + 1.std_milliseconds(), time!(0:00:00.001));
assert_eq!(time!(0:00) + 1.std_seconds(), time!(0:00:01));
assert_eq!(time!(0:00) + 1.std_minutes(), time!(0:01));
assert_eq!(time!(0:00) + 1.std_hours(), time!(1:00));
assert_eq!(time!(0:00) + 1.std_days(), time!(0:00));
}
#[test]
fn add_assign_std_duration() {
let mut time = time!(0:00);
time += 1.std_seconds();
assert_eq!(time, time!(0:00:01));
time += 1.std_minutes();
assert_eq!(time, time!(0:01:01));
time += 1.std_hours();
assert_eq!(time, time!(1:01:01));
time += 1.std_days();
assert_eq!(time, time!(1:01:01));
}
#[test]
fn sub_std_duration() {
assert_eq!(time!(12:00) - 1.std_hours(), time!(11:00));
// Underflow
assert_eq!(time!(0:00) - 1.std_milliseconds(), time!(23:59:59.999));
assert_eq!(time!(0:00) - 1.std_seconds(), time!(23:59:59));
assert_eq!(time!(0:00) - 1.std_minutes(), time!(23:59));
assert_eq!(time!(0:00) - 1.std_hours(), time!(23:00));
assert_eq!(time!(0:00) - 1.std_days(), time!(0:00));
}
#[test]
fn sub_assign_std_duration() {
let mut time = time!(0:00);
time -= 1.std_seconds();
assert_eq!(time, time!(23:59:59));
time -= 1.std_minutes();
assert_eq!(time, time!(23:58:59));
time -= 1.std_hours();
assert_eq!(time, time!(22:58:59));
time -= 1.std_days();
assert_eq!(time, time!(22:58:59));
}
#[test]
fn sub_time() {
assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
assert_eq!(time!(1:00) - time!(0:00), 1.hours());
assert_eq!(time!(1:00) - time!(0:00:01), 59.minutes() + 59.seconds());
}
#[test]
fn ordering() {
assert!(time!(0:00) < time!(0:00:00.000_000_001));
assert!(time!(0:00) < time!(0:00:01));
assert!(time!(12:00) > time!(11:00));
assert_eq!(time!(0:00), time!(0:00));
}
#[test]
fn ordering_lexico_endianness() {
// Endianness of nanoseconds
assert!(time!(00:00:00.4) > time!(00:00:00.1));
// Endianness of one field wrt the others
// Hourt wrt others
assert!(time!(01:00:00) > time!(00:01:00.0));
assert!(time!(01:00:00) > time!(00:00:01.0));
assert!(time!(01:00:00) > time!(00:00:00.1));
// Minutes wrt to others
assert!(time!(00:01:00) > time!(00:00:01.0));
assert!(time!(00:01:00) > time!(00:00:00.1));
// Second wrt to others
assert!(time!(00:00:01) > time!(00:00:00.1));
}
#[test]
fn issue_481() {
assert_eq!(time!(0:00) - time!(01:00:00.1), (-3600.1).seconds());
assert_eq!(
time!(0:00) - time!(23:59:59.999_999_999),
(-86_399.999_999_999).seconds()
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
use std::cmp::Ordering;
use rstest::rstest;
use time::macros::offset;
use time::{OffsetDateTime, UtcOffset};
#[test]
fn utc_is_zero() {
assert_eq!(offset!(UTC), offset!(+0));
}
#[rstest]
#[case(0, 0, 0, offset!(UTC))]
#[case(0, 0, 1, offset!(+0:00:01))]
#[case(0, 0, -1, offset!(-0:00:01))]
#[case(1, 0, 0, offset!(+1))]
#[case(-1, 0, 0, offset!(-1))]
#[case(23, 59, 0, offset!(+23:59))]
#[case(-23, -59, 0, offset!(-23:59))]
#[case(23, 59, 59, offset!(+23:59:59))]
#[case(-23, -59, -59, offset!(-23:59:59))]
#[case(1, 2, 3, offset!(+1:02:03))]
#[case(1, -2, -3, offset!(+1:02:03))]
#[case(0, 2, -3, offset!(+0:02:03))]
fn from_hms(
#[case] hours: i8,
#[case] minutes: i8,
#[case] seconds: i8,
#[case] expected: UtcOffset,
) {
assert_eq!(UtcOffset::from_hms(hours, minutes, seconds), Ok(expected));
}
#[rstest]
#[case(0, offset!(UTC))]
#[case(1, offset!(+0:00:01))]
#[case(-1, offset!(-0:00:01))]
#[case(3_600, offset!(+1))]
#[case(-3_600, offset!(-1))]
#[case(86_340, offset!(+23:59))]
#[case(-86_340, offset!(-23:59))]
#[case(86_399, offset!(+23:59:59))]
#[case(-86_399, offset!(-23:59:59))]
fn from_whole_seconds(#[case] seconds: i32, #[case] expected: UtcOffset) {
assert_eq!(UtcOffset::from_whole_seconds(seconds), Ok(expected));
}
#[rstest]
#[case(offset!(UTC), (0, 0, 0))]
#[case(offset!(+0:00:01), (0, 0, 1))]
#[case(offset!(-0:00:01), (0, 0, -1))]
#[case(offset!(+1), (1, 0, 0))]
#[case(offset!(-1), (-1, 0, 0))]
#[case(offset!(+23:59), (23, 59, 0))]
#[case(offset!(-23:59), (-23, -59, 0))]
#[case(offset!(+23:59:59), (23, 59, 59))]
#[case(offset!(-23:59:59), (-23, -59, -59))]
fn as_hms(#[case] offset: UtcOffset, #[case] expected: (i8, i8, i8)) {
assert_eq!(offset.as_hms(), expected);
}
#[rstest]
#[case(offset!(+1:02:03), 1)]
#[case(offset!(-1:02:03), -1)]
fn whole_hours(#[case] offset: UtcOffset, #[case] expected: i8) {
assert_eq!(offset.whole_hours(), expected);
}
#[rstest]
#[case(offset!(+1:02:03), 62)]
#[case(offset!(-1:02:03), -62)]
fn whole_minutes(#[case] offset: UtcOffset, #[case] expected: i16) {
assert_eq!(offset.whole_minutes(), expected);
}
#[rstest]
#[case(offset!(+1:02:03), 2)]
#[case(offset!(-1:02:03), -2)]
fn minutes_past_hour(#[case] offset: UtcOffset, #[case] expected: i8) {
assert_eq!(offset.minutes_past_hour(), expected);
}
#[rstest]
#[case(offset!(UTC), 0)]
#[case(offset!(+0:00:01), 1)]
#[case(offset!(-0:00:01), -1)]
#[case(offset!(+1), 3_600)]
#[case(offset!(-1), -3_600)]
#[case(offset!(+23:59), 86_340)]
#[case(offset!(-23:59), -86_340)]
#[case(offset!(+23:59:59), 86_399)]
#[case(offset!(-23:59:59), -86_399)]
fn whole_seconds(#[case] offset: UtcOffset, #[case] expected: i32) {
assert_eq!(offset.whole_seconds(), expected);
}
#[rstest]
#[case(offset!(+1:02:03), 3)]
#[case(offset!(-1:02:03), -3)]
fn seconds_past_minute(#[case] offset: UtcOffset, #[case] expected: i8) {
assert_eq!(offset.seconds_past_minute(), expected);
}
#[rstest]
#[case(offset!(UTC), true)]
#[case(offset!(+0:00:01), false)]
#[case(offset!(-0:00:01), false)]
#[case(offset!(+1), false)]
#[case(offset!(-1), false)]
#[case(offset!(+23:59), false)]
#[case(offset!(-23:59), false)]
#[case(offset!(+23:59:59), false)]
#[case(offset!(-23:59:59), false)]
fn is_utc(#[case] offset: UtcOffset, #[case] expected: bool) {
assert_eq!(offset.is_utc(), expected);
}
#[rstest]
#[case(offset!(UTC), false)]
#[case(offset!(+0:00:01), true)]
#[case(offset!(-0:00:01), false)]
#[case(offset!(+1), true)]
#[case(offset!(-1), false)]
#[case(offset!(+23:59), true)]
#[case(offset!(-23:59), false)]
#[case(offset!(+23:59:59), true)]
#[case(offset!(-23:59:59), false)]
fn is_positive(#[case] offset: UtcOffset, #[case] expected: bool) {
assert_eq!(offset.is_positive(), expected);
}
#[rstest]
#[case(offset!(UTC), false)]
#[case(offset!(+0:00:01), false)]
#[case(offset!(-0:00:01), true)]
#[case(offset!(+1), false)]
#[case(offset!(-1), true)]
#[case(offset!(+23:59), false)]
#[case(offset!(-23:59), true)]
#[case(offset!(+23:59:59), false)]
#[case(offset!(-23:59:59), true)]
fn is_negative(#[case] offset: UtcOffset, #[case] expected: bool) {
assert_eq!(offset.is_negative(), expected);
}
#[rstest]
#[case(offset!(UTC), offset!(UTC), Ordering::Equal)]
#[case(offset!(+1), offset!(+1), Ordering::Equal)]
#[case(offset!(-1), offset!(-1), Ordering::Equal)]
#[case(offset!(+1), offset!(UTC), Ordering::Greater)]
#[case(offset!(UTC), offset!(-1), Ordering::Greater)]
#[case(offset!(-1), offset!(+1), Ordering::Less)]
#[case(offset!(+23:59), offset!(+23:58), Ordering::Greater)]
#[case(offset!(-23:59), offset!(-23:58), Ordering::Less)]
#[case(offset!(+23:59:59), offset!(+23:59:58), Ordering::Greater)]
#[case(offset!(-23:59:59), offset!(-23:59:58), Ordering::Less)]
fn ordering(#[case] a: UtcOffset, #[case] b: UtcOffset, #[case] expected: Ordering) {
assert_eq!(a.cmp(&b), expected);
}
#[rstest]
#[case(offset!(UTC), offset!(UTC))]
#[case(offset!(+0:00:01), offset!(-0:00:01))]
#[case(offset!(-0:00:01), offset!(+0:00:01))]
#[case(offset!(+1), offset!(-1))]
#[case(offset!(-1), offset!(+1))]
#[case(offset!(+23:59), offset!(-23:59))]
#[case(offset!(-23:59), offset!(+23:59))]
#[case(offset!(+23:59:59), offset!(-23:59:59))]
#[case(offset!(-23:59:59), offset!(+23:59:59))]
fn neg(#[case] offset: UtcOffset, #[case] expected: UtcOffset) {
assert_eq!(-offset, expected);
}
#[test]
fn local_offset_at() {
assert!(UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH).is_ok());
}
#[test]
fn current_local_offset() {
assert!(UtcOffset::current_local_offset().is_ok());
}
#[test]
fn local_offset_success_when_multithreaded() {
std::thread::spawn(|| {
assert!(UtcOffset::current_local_offset().is_ok());
})
.join()
.expect("failed to join thread");
}

493
vendor/time/tests/integration/util.rs vendored Normal file
View File

@@ -0,0 +1,493 @@
use rstest::rstest;
use time::Month::*;
use time::{util, Month};
#[rstest]
#[case(2019, January, 31)]
#[case(2019, February, 28)]
#[case(2019, March, 31)]
#[case(2019, April, 30)]
#[case(2019, May, 31)]
#[case(2019, June, 30)]
#[case(2019, July, 31)]
#[case(2019, August, 31)]
#[case(2019, September, 30)]
#[case(2019, October, 31)]
#[case(2019, November, 30)]
#[case(2019, December, 31)]
#[case(2020, January, 31)]
#[case(2020, February, 29)]
#[case(2020, March, 31)]
#[case(2020, April, 30)]
#[case(2020, May, 31)]
#[case(2020, June, 30)]
#[case(2020, July, 31)]
#[case(2020, August, 31)]
#[case(2020, September, 30)]
#[case(2020, October, 31)]
#[case(2020, November, 30)]
#[case(2020, December, 31)]
fn days_in_year_month(#[case] year: i32, #[case] month: Month, #[case] expected: u8) {
#[expect(deprecated)]
{
assert_eq!(util::days_in_year_month(year, month), expected);
}
}
#[rstest]
#[case(0, true)]
#[case(1, false)]
#[case(2, false)]
#[case(3, false)]
#[case(4, true)]
#[case(5, false)]
#[case(6, false)]
#[case(7, false)]
#[case(8, true)]
#[case(9, false)]
#[case(10, false)]
#[case(11, false)]
#[case(12, true)]
#[case(13, false)]
#[case(14, false)]
#[case(15, false)]
#[case(16, true)]
#[case(17, false)]
#[case(18, false)]
#[case(19, false)]
#[case(20, true)]
#[case(21, false)]
#[case(22, false)]
#[case(23, false)]
#[case(24, true)]
#[case(25, false)]
#[case(26, false)]
#[case(27, false)]
#[case(28, true)]
#[case(29, false)]
#[case(30, false)]
#[case(31, false)]
#[case(32, true)]
#[case(33, false)]
#[case(34, false)]
#[case(35, false)]
#[case(36, true)]
#[case(37, false)]
#[case(38, false)]
#[case(39, false)]
#[case(40, true)]
#[case(41, false)]
#[case(42, false)]
#[case(43, false)]
#[case(44, true)]
#[case(45, false)]
#[case(46, false)]
#[case(47, false)]
#[case(48, true)]
#[case(49, false)]
#[case(50, false)]
#[case(51, false)]
#[case(52, true)]
#[case(53, false)]
#[case(54, false)]
#[case(55, false)]
#[case(56, true)]
#[case(57, false)]
#[case(58, false)]
#[case(59, false)]
#[case(60, true)]
#[case(61, false)]
#[case(62, false)]
#[case(63, false)]
#[case(64, true)]
#[case(65, false)]
#[case(66, false)]
#[case(67, false)]
#[case(68, true)]
#[case(69, false)]
#[case(70, false)]
#[case(71, false)]
#[case(72, true)]
#[case(73, false)]
#[case(74, false)]
#[case(75, false)]
#[case(76, true)]
#[case(77, false)]
#[case(78, false)]
#[case(79, false)]
#[case(80, true)]
#[case(81, false)]
#[case(82, false)]
#[case(83, false)]
#[case(84, true)]
#[case(85, false)]
#[case(86, false)]
#[case(87, false)]
#[case(88, true)]
#[case(89, false)]
#[case(90, false)]
#[case(91, false)]
#[case(92, true)]
#[case(93, false)]
#[case(94, false)]
#[case(95, false)]
#[case(96, true)]
#[case(97, false)]
#[case(98, false)]
#[case(99, false)]
#[case(100, false)]
#[case(101, false)]
#[case(102, false)]
#[case(103, false)]
#[case(104, true)]
#[case(105, false)]
#[case(106, false)]
#[case(107, false)]
#[case(108, true)]
#[case(109, false)]
#[case(110, false)]
#[case(111, false)]
#[case(112, true)]
#[case(113, false)]
#[case(114, false)]
#[case(115, false)]
#[case(116, true)]
#[case(117, false)]
#[case(118, false)]
#[case(119, false)]
#[case(120, true)]
#[case(121, false)]
#[case(122, false)]
#[case(123, false)]
#[case(124, true)]
#[case(125, false)]
#[case(126, false)]
#[case(127, false)]
#[case(128, true)]
#[case(129, false)]
#[case(130, false)]
#[case(131, false)]
#[case(132, true)]
#[case(133, false)]
#[case(134, false)]
#[case(135, false)]
#[case(136, true)]
#[case(137, false)]
#[case(138, false)]
#[case(139, false)]
#[case(140, true)]
#[case(141, false)]
#[case(142, false)]
#[case(143, false)]
#[case(144, true)]
#[case(145, false)]
#[case(146, false)]
#[case(147, false)]
#[case(148, true)]
#[case(149, false)]
#[case(150, false)]
#[case(151, false)]
#[case(152, true)]
#[case(153, false)]
#[case(154, false)]
#[case(155, false)]
#[case(156, true)]
#[case(157, false)]
#[case(158, false)]
#[case(159, false)]
#[case(160, true)]
#[case(161, false)]
#[case(162, false)]
#[case(163, false)]
#[case(164, true)]
#[case(165, false)]
#[case(166, false)]
#[case(167, false)]
#[case(168, true)]
#[case(169, false)]
#[case(170, false)]
#[case(171, false)]
#[case(172, true)]
#[case(173, false)]
#[case(174, false)]
#[case(175, false)]
#[case(176, true)]
#[case(177, false)]
#[case(178, false)]
#[case(179, false)]
#[case(180, true)]
#[case(181, false)]
#[case(182, false)]
#[case(183, false)]
#[case(184, true)]
#[case(185, false)]
#[case(186, false)]
#[case(187, false)]
#[case(188, true)]
#[case(189, false)]
#[case(190, false)]
#[case(191, false)]
#[case(192, true)]
#[case(193, false)]
#[case(194, false)]
#[case(195, false)]
#[case(196, true)]
#[case(197, false)]
#[case(198, false)]
#[case(199, false)]
#[case(200, false)]
#[case(201, false)]
#[case(202, false)]
#[case(203, false)]
#[case(204, true)]
#[case(205, false)]
#[case(206, false)]
#[case(207, false)]
#[case(208, true)]
#[case(209, false)]
#[case(210, false)]
#[case(211, false)]
#[case(212, true)]
#[case(213, false)]
#[case(214, false)]
#[case(215, false)]
#[case(216, true)]
#[case(217, false)]
#[case(218, false)]
#[case(219, false)]
#[case(220, true)]
#[case(221, false)]
#[case(222, false)]
#[case(223, false)]
#[case(224, true)]
#[case(225, false)]
#[case(226, false)]
#[case(227, false)]
#[case(228, true)]
#[case(229, false)]
#[case(230, false)]
#[case(231, false)]
#[case(232, true)]
#[case(233, false)]
#[case(234, false)]
#[case(235, false)]
#[case(236, true)]
#[case(237, false)]
#[case(238, false)]
#[case(239, false)]
#[case(240, true)]
#[case(241, false)]
#[case(242, false)]
#[case(243, false)]
#[case(244, true)]
#[case(245, false)]
#[case(246, false)]
#[case(247, false)]
#[case(248, true)]
#[case(249, false)]
#[case(250, false)]
#[case(251, false)]
#[case(252, true)]
#[case(253, false)]
#[case(254, false)]
#[case(255, false)]
#[case(256, true)]
#[case(257, false)]
#[case(258, false)]
#[case(259, false)]
#[case(260, true)]
#[case(261, false)]
#[case(262, false)]
#[case(263, false)]
#[case(264, true)]
#[case(265, false)]
#[case(266, false)]
#[case(267, false)]
#[case(268, true)]
#[case(269, false)]
#[case(270, false)]
#[case(271, false)]
#[case(272, true)]
#[case(273, false)]
#[case(274, false)]
#[case(275, false)]
#[case(276, true)]
#[case(277, false)]
#[case(278, false)]
#[case(279, false)]
#[case(280, true)]
#[case(281, false)]
#[case(282, false)]
#[case(283, false)]
#[case(284, true)]
#[case(285, false)]
#[case(286, false)]
#[case(287, false)]
#[case(288, true)]
#[case(289, false)]
#[case(290, false)]
#[case(291, false)]
#[case(292, true)]
#[case(293, false)]
#[case(294, false)]
#[case(295, false)]
#[case(296, true)]
#[case(297, false)]
#[case(298, false)]
#[case(299, false)]
#[case(300, false)]
#[case(301, false)]
#[case(302, false)]
#[case(303, false)]
#[case(304, true)]
#[case(305, false)]
#[case(306, false)]
#[case(307, false)]
#[case(308, true)]
#[case(309, false)]
#[case(310, false)]
#[case(311, false)]
#[case(312, true)]
#[case(313, false)]
#[case(314, false)]
#[case(315, false)]
#[case(316, true)]
#[case(317, false)]
#[case(318, false)]
#[case(319, false)]
#[case(320, true)]
#[case(321, false)]
#[case(322, false)]
#[case(323, false)]
#[case(324, true)]
#[case(325, false)]
#[case(326, false)]
#[case(327, false)]
#[case(328, true)]
#[case(329, false)]
#[case(330, false)]
#[case(331, false)]
#[case(332, true)]
#[case(333, false)]
#[case(334, false)]
#[case(335, false)]
#[case(336, true)]
#[case(337, false)]
#[case(338, false)]
#[case(339, false)]
#[case(340, true)]
#[case(341, false)]
#[case(342, false)]
#[case(343, false)]
#[case(344, true)]
#[case(345, false)]
#[case(346, false)]
#[case(347, false)]
#[case(348, true)]
#[case(349, false)]
#[case(350, false)]
#[case(351, false)]
#[case(352, true)]
#[case(353, false)]
#[case(354, false)]
#[case(355, false)]
#[case(356, true)]
#[case(357, false)]
#[case(358, false)]
#[case(359, false)]
#[case(360, true)]
#[case(361, false)]
#[case(362, false)]
#[case(363, false)]
#[case(364, true)]
#[case(365, false)]
#[case(366, false)]
#[case(367, false)]
#[case(368, true)]
#[case(369, false)]
#[case(370, false)]
#[case(371, false)]
#[case(372, true)]
#[case(373, false)]
#[case(374, false)]
#[case(375, false)]
#[case(376, true)]
#[case(377, false)]
#[case(378, false)]
#[case(379, false)]
#[case(380, true)]
#[case(381, false)]
#[case(382, false)]
#[case(383, false)]
#[case(384, true)]
#[case(385, false)]
#[case(386, false)]
#[case(387, false)]
#[case(388, true)]
#[case(389, false)]
#[case(390, false)]
#[case(391, false)]
#[case(392, true)]
#[case(393, false)]
#[case(394, false)]
#[case(395, false)]
#[case(396, true)]
#[case(397, false)]
#[case(398, false)]
#[case(399, false)]
fn is_leap_year(#[case] year: i32, #[case] expected: bool) {
assert_eq!(util::is_leap_year(year), expected, "year {year} failed");
}
#[rstest]
#[case(1900, 365)]
#[case(2000, 366)]
#[case(2004, 366)]
#[case(2005, 365)]
#[case(2100, 365)]
fn days_in_year(#[case] year: i32, #[case] expected: u16) {
assert_eq!(util::days_in_year(year), expected);
}
#[rstest]
fn weeks_in_year() {
let num_weeks_for_years = [
52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52,
52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52,
52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52,
52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52,
52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52,
52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52,
52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52,
53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52,
53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52,
53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53,
52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53,
52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52,
52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52,
52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52,
52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52,
52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52,
52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52,
52, 53, 52, 52, 52, 52, 52, 53, 52,
];
for (year, &num_weeks) in (0..400).zip(&num_weeks_for_years) {
assert_eq!(util::weeks_in_year(year), num_weeks);
}
}
#[rstest]
#[expect(deprecated)]
fn local_offset_soundness() {
use time::util::local_offset::*;
// These functions no longer do anything so they always return `Sound`.
assert_eq!(get_soundness(), Soundness::Sound);
// Safety: This no longer has any safety requirements.
unsafe { set_soundness(Soundness::Unsound) };
assert_eq!(get_soundness(), Soundness::Sound);
// Safety: See above.
unsafe { set_soundness(Soundness::Sound) };
assert_eq!(get_soundness(), Soundness::Sound);
}

145
vendor/time/tests/integration/weekday.rs vendored Normal file
View File

@@ -0,0 +1,145 @@
use rstest::rstest;
use time::Weekday::{self, *};
#[rstest]
#[case(Sunday, Saturday)]
#[case(Monday, Sunday)]
#[case(Tuesday, Monday)]
#[case(Wednesday, Tuesday)]
#[case(Thursday, Wednesday)]
#[case(Friday, Thursday)]
#[case(Saturday, Friday)]
fn previous(#[case] current: Weekday, #[case] expected: Weekday) {
assert_eq!(current.previous(), expected);
}
#[rstest]
#[case(Sunday, Monday)]
#[case(Monday, Tuesday)]
#[case(Tuesday, Wednesday)]
#[case(Wednesday, Thursday)]
#[case(Thursday, Friday)]
#[case(Friday, Saturday)]
#[case(Saturday, Sunday)]
fn next(#[case] current: Weekday, #[case] expected: Weekday) {
assert_eq!(current.next(), expected);
}
#[rstest]
#[case(Sunday, 0, Sunday)]
#[case(Sunday, 1, Monday)]
#[case(Sunday, 2, Tuesday)]
#[case(Sunday, 3, Wednesday)]
#[case(Sunday, 4, Thursday)]
#[case(Sunday, 5, Friday)]
#[case(Sunday, 6, Saturday)]
#[case(Monday, 0, Monday)]
#[case(Monday, 1, Tuesday)]
#[case(Monday, 2, Wednesday)]
#[case(Monday, 3, Thursday)]
#[case(Monday, 4, Friday)]
#[case(Monday, 5, Saturday)]
#[case(Monday, 6, Sunday)]
#[case(Sunday, 7, Sunday)]
#[case(Sunday, u8::MAX, Wednesday)]
#[case(Monday, 7, Monday)]
#[case(Monday, u8::MAX, Thursday)]
fn nth_next(#[case] current: Weekday, #[case] n: u8, #[case] expected: Weekday) {
assert_eq!(current.nth_next(n), expected);
}
#[rstest]
#[case(Sunday, 0, Sunday)]
#[case(Sunday, 1, Saturday)]
#[case(Sunday, 2, Friday)]
#[case(Sunday, 3, Thursday)]
#[case(Sunday, 4, Wednesday)]
#[case(Sunday, 5, Tuesday)]
#[case(Sunday, 6, Monday)]
#[case(Monday, 0, Monday)]
#[case(Monday, 1, Sunday)]
#[case(Monday, 2, Saturday)]
#[case(Monday, 3, Friday)]
#[case(Monday, 4, Thursday)]
#[case(Monday, 5, Wednesday)]
#[case(Monday, 6, Tuesday)]
#[case(Sunday, 7, Sunday)]
#[case(Sunday, u8::MAX, Thursday)]
#[case(Monday, 7, Monday)]
#[case(Monday, u8::MAX, Friday)]
fn nth_prev(#[case] current: Weekday, #[case] n: u8, #[case] expected: Weekday) {
assert_eq!(current.nth_prev(n), expected);
}
#[rstest]
#[case(Monday, 1)]
#[case(Tuesday, 2)]
#[case(Wednesday, 3)]
#[case(Thursday, 4)]
#[case(Friday, 5)]
#[case(Saturday, 6)]
#[case(Sunday, 7)]
fn number_from_monday(#[case] weekday: Weekday, #[case] expected: u8) {
assert_eq!(weekday.number_from_monday(), expected);
}
#[rstest]
#[case(Sunday, 1)]
#[case(Monday, 2)]
#[case(Tuesday, 3)]
#[case(Wednesday, 4)]
#[case(Thursday, 5)]
#[case(Friday, 6)]
#[case(Saturday, 7)]
fn number_from_sunday(#[case] weekday: Weekday, #[case] expected: u8) {
assert_eq!(weekday.number_from_sunday(), expected);
}
#[rstest]
#[case(Monday, 0)]
#[case(Tuesday, 1)]
#[case(Wednesday, 2)]
#[case(Thursday, 3)]
#[case(Friday, 4)]
#[case(Saturday, 5)]
#[case(Sunday, 6)]
fn number_days_from_monday(#[case] weekday: Weekday, #[case] expected: u8) {
assert_eq!(weekday.number_days_from_monday(), expected);
}
#[rstest]
#[case(Sunday, 0)]
#[case(Monday, 1)]
#[case(Tuesday, 2)]
#[case(Wednesday, 3)]
#[case(Thursday, 4)]
#[case(Friday, 5)]
#[case(Saturday, 6)]
fn number_days_from_sunday(#[case] weekday: Weekday, #[case] expected: u8) {
assert_eq!(weekday.number_days_from_sunday(), expected);
}
#[rstest]
#[case(Monday, "Monday")]
#[case(Tuesday, "Tuesday")]
#[case(Wednesday, "Wednesday")]
#[case(Thursday, "Thursday")]
#[case(Friday, "Friday")]
#[case(Saturday, "Saturday")]
#[case(Sunday, "Sunday")]
fn display(#[case] weekday: Weekday, #[case] expected: &str) {
assert_eq!(weekday.to_string(), expected);
}
#[rstest]
#[case("Monday", Ok(Monday))]
#[case("Tuesday", Ok(Tuesday))]
#[case("Wednesday", Ok(Wednesday))]
#[case("Thursday", Ok(Thursday))]
#[case("Friday", Ok(Friday))]
#[case("Saturday", Ok(Saturday))]
#[case("Sunday", Ok(Sunday))]
#[case("foo", Err(time::error::InvalidVariant))]
fn from_str(#[case] input: &str, #[case] expected: Result<Weekday, time::error::InvalidVariant>) {
assert_eq!(input.parse::<Weekday>(), expected);
}