Skip to content

Commit c15d6ca

Browse files
committed
std: sys: pal: uefi: tests: Add systemtime tests
Add tests to ensure that extream system times are still representable. Signed-off-by: Ayush Singh <[email protected]>
1 parent d7d9815 commit c15d6ca

File tree

2 files changed

+96
-10
lines changed

2 files changed

+96
-10
lines changed

library/std/src/sys/pal/uefi/tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
use super::alloc::*;
2+
use super::time::system_time_internal::{from_uefi, to_uefi};
3+
use crate::time::Duration;
4+
5+
const SECS_IN_MINUTE: u64 = 60;
26

37
#[test]
48
fn align() {
@@ -19,3 +23,62 @@ fn align() {
1923
}
2024
}
2125
}
26+
27+
#[test]
28+
fn systemtime_start() {
29+
let t = r_efi::efi::Time {
30+
year: 1900,
31+
month: 1,
32+
day: 1,
33+
hour: 0,
34+
minute: 0,
35+
second: 0,
36+
pad1: 0,
37+
nanosecond: 0,
38+
timezone: -1440,
39+
daylight: 0,
40+
pad2: 0,
41+
};
42+
assert_eq!(from_uefi(&t), Duration::new(0, 0));
43+
assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap());
44+
assert!(to_uefi(&from_uefi(&t), 0, 0).is_none());
45+
}
46+
47+
#[test]
48+
fn systemtime_utc_start() {
49+
let t = r_efi::efi::Time {
50+
year: 1900,
51+
month: 1,
52+
day: 1,
53+
hour: 0,
54+
minute: 0,
55+
second: 0,
56+
pad1: 0,
57+
nanosecond: 0,
58+
timezone: 0,
59+
daylight: 0,
60+
pad2: 0,
61+
};
62+
assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0));
63+
assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap());
64+
assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some());
65+
}
66+
67+
#[test]
68+
fn systemtime_end() {
69+
let t = r_efi::efi::Time {
70+
year: 9999,
71+
month: 12,
72+
day: 31,
73+
hour: 23,
74+
minute: 59,
75+
second: 59,
76+
pad1: 0,
77+
nanosecond: 0,
78+
timezone: 1440,
79+
daylight: 0,
80+
pad2: 0,
81+
};
82+
assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some());
83+
assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none());
84+
}

library/std/src/sys/pal/uefi/time.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub struct Instant(Duration);
66
/// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then
77
/// the timezone is assumed to be in UTC.
88
///
9-
/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00
9+
/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 with timezone -1440 as anchor
1010
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
1111
pub struct SystemTime(Duration);
1212

@@ -24,6 +24,20 @@ pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
2424
pad2: 0,
2525
});
2626

27+
const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
28+
year: 9999,
29+
month: 12,
30+
day: 31,
31+
hour: 23,
32+
minute: 59,
33+
second: 59,
34+
nanosecond: 999_999_999,
35+
timezone: 1440,
36+
daylight: 0,
37+
pad1: 0,
38+
pad2: 0,
39+
});
40+
2741
impl Instant {
2842
pub fn now() -> Instant {
2943
// If we have a timestamp protocol, use it.
@@ -56,6 +70,7 @@ impl SystemTime {
5670
Self(system_time_internal::from_uefi(&t))
5771
}
5872

73+
#[expect(dead_code)]
5974
pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option<r_efi::efi::Time> {
6075
system_time_internal::to_uefi(&self.0, timezone, daylight)
6176
}
@@ -73,14 +88,11 @@ impl SystemTime {
7388
let temp = Self(self.0.checked_add(*other)?);
7489

7590
// Check if can be represented in UEFI
76-
if temp.to_uefi(0, 0).is_some() { Some(temp) } else { None }
91+
if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
7792
}
7893

7994
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
80-
let temp = Self(self.0.checked_sub(*other)?);
81-
82-
// Check if can be represented in UEFI
83-
if temp.to_uefi(0, 0).is_some() { Some(temp) } else { None }
95+
self.0.checked_sub(*other).map(Self)
8496
}
8597
}
8698

@@ -113,8 +125,18 @@ pub(crate) mod system_time_internal {
113125
}
114126

115127
pub(crate) const fn from_uefi(t: &Time) -> Duration {
116-
assert!(t.month <= 12);
117-
assert!(t.month != 0);
128+
assert!(t.month <= 12 && t.month != 0);
129+
assert!(t.year >= 1900 && t.year <= 9999);
130+
assert!(t.day <= 31 && t.day != 0);
131+
132+
assert!(t.second <= 59);
133+
assert!(t.hour < 24);
134+
assert!(t.nanosecond < 1_000_000_000);
135+
136+
assert!(
137+
(t.timezone <= 1440 && t.timezone >= -1440)
138+
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
139+
);
118140

119141
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
120142

@@ -148,8 +170,9 @@ pub(crate) mod system_time_internal {
148170

149171
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option<Time> {
150172
// Check timzone validity
151-
assert!(timezone <= 1440);
152-
assert!(timezone >= -1440);
173+
assert!(
174+
(timezone <= 1440 && timezone >= -1440) || timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
175+
);
153176

154177
let secs: u64 = if timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
155178
dur.as_secs()

0 commit comments

Comments
 (0)