Skip to content

Commit 0029cfc

Browse files
committed
feat: Mock SystemTime::now() for the tests
Add a fake `struct SystemTime` for mocking `SystemTime::now()` etc. for test purposes. One still needs to use `std::time::SystemTime` as a struct representing a system time. I think such a minimalistic approach is ok -- even if somebody uses the original `SystemTime::elapsed()` or `now()` instead of mocks by mistake, that could break only tests but not the program itself. The worst thing that can happen is that tests using `SystemTime::shift()` and checking messages timestamps f.e. wouldn't catch the corresponding bugs, but now we don't have such tests at all which is much worse.
1 parent d7f8d17 commit 0029cfc

File tree

8 files changed

+49
-17
lines changed

8 files changed

+49
-17
lines changed

src/chat.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::convert::{TryFrom, TryInto};
66
use std::fmt;
77
use std::path::{Path, PathBuf};
88
use std::str::FromStr;
9-
use std::time::{Duration, SystemTime};
9+
use std::time::Duration;
1010

1111
use anyhow::{anyhow, bail, ensure, Context as _, Result};
1212
use deltachat_derive::{FromSql, ToSql};
@@ -44,7 +44,7 @@ use crate::sync::{self, Sync::*, SyncData};
4444
use crate::tools::{
4545
buf_compress, create_id, create_outgoing_rfc724_mid, create_smeared_timestamp,
4646
create_smeared_timestamps, get_abs_path, gm2local_offset, improve_single_line_input,
47-
smeared_time, strip_rtlo_characters, time, IsNoneOrEmpty,
47+
smeared_time, strip_rtlo_characters, time, IsNoneOrEmpty, SystemTime,
4848
};
4949
use crate::webxdc::WEBXDC_SUFFIX;
5050

@@ -3637,7 +3637,7 @@ pub enum MuteDuration {
36373637
Forever,
36383638

36393639
/// Chat is muted for a limited period of time.
3640-
Until(SystemTime),
3640+
Until(std::time::SystemTime),
36413641
}
36423642

36433643
impl rusqlite::types::ToSql for MuteDuration {

src/contact.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::convert::{TryFrom, TryInto};
66
use std::fmt;
77
use std::ops::Deref;
88
use std::path::{Path, PathBuf};
9-
use std::time::{SystemTime, UNIX_EPOCH};
9+
use std::time::UNIX_EPOCH;
1010

1111
use anyhow::{bail, ensure, Context as _, Result};
1212
use async_channel::{self as channel, Receiver, Sender};
@@ -35,7 +35,7 @@ use crate::sql::{self, params_iter};
3535
use crate::sync::{self, Sync::*, SyncData};
3636
use crate::tools::{
3737
duration_to_str, get_abs_path, improve_single_line_input, strip_rtlo_characters, time,
38-
EmailAddress,
38+
EmailAddress, SystemTime,
3939
};
4040
use crate::{chat, stock_str};
4141

src/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ pub fn get_version_str() -> &'static str {
10511051

10521052
#[cfg(test)]
10531053
mod tests {
1054-
use std::time::{Duration, SystemTime};
1054+
use std::time::Duration;
10551055

10561056
use anyhow::Context as _;
10571057
use strum::IntoEnumIterator;
@@ -1067,7 +1067,7 @@ mod tests {
10671067
use crate::message::{Message, Viewtype};
10681068
use crate::receive_imf::receive_imf;
10691069
use crate::test_utils::TestContext;
1070-
use crate::tools::create_outgoing_rfc724_mid;
1070+
use crate::tools::{create_outgoing_rfc724_mid, SystemTime};
10711071

10721072
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
10731073
async fn test_wrong_db() -> Result<()> {

src/ephemeral.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use std::collections::BTreeSet;
6767
use std::convert::{TryFrom, TryInto};
6868
use std::num::ParseIntError;
6969
use std::str::FromStr;
70-
use std::time::{Duration, SystemTime, UNIX_EPOCH};
70+
use std::time::{Duration, UNIX_EPOCH};
7171

7272
use anyhow::{ensure, Result};
7373
use async_channel::Receiver;
@@ -85,7 +85,7 @@ use crate::message::{Message, MessageState, MsgId, Viewtype};
8585
use crate::mimeparser::SystemMessage;
8686
use crate::sql::{self, params_iter};
8787
use crate::stock_str;
88-
use crate::tools::{duration_to_str, time};
88+
use crate::tools::{duration_to_str, time, SystemTime};
8989

9090
/// Ephemeral timer value.
9191
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]

src/sql.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::message::{Message, MsgId, Viewtype};
2121
use crate::param::{Param, Params};
2222
use crate::peerstate::{deduplicate_peerstates, Peerstate};
2323
use crate::stock_str;
24-
use crate::tools::{delete_file, time};
24+
use crate::tools::{delete_file, time, SystemTime};
2525

2626
/// Extension to [`rusqlite::ToSql`] trait
2727
/// which also includes [`Send`] and [`Sync`].
@@ -857,9 +857,9 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
857857
Ok(mut dir_handle) => {
858858
/* avoid deletion of files that are just created to build a message object */
859859
let diff = std::time::Duration::from_secs(60 * 60);
860-
let keep_files_newer_than = std::time::SystemTime::now()
860+
let keep_files_newer_than = SystemTime::now()
861861
.checked_sub(diff)
862-
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
862+
.unwrap_or(SystemTime::UNIX_EPOCH);
863863

864864
while let Ok(Some(entry)) = dir_handle.next_entry().await {
865865
let name_f = entry.file_name();

src/sync.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ impl Context {
319319

320320
#[cfg(test)]
321321
mod tests {
322-
use std::time::{Duration, SystemTime};
322+
use std::time::Duration;
323323

324324
use anyhow::bail;
325325

@@ -329,6 +329,7 @@ mod tests {
329329
use crate::contact::{Contact, Origin};
330330
use crate::test_utils::TestContext;
331331
use crate::token::Namespace;
332+
use crate::tools::SystemTime;
332333

333334
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
334335
async fn test_config_sync_msgs() -> Result<()> {

src/timesmearing.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ impl SmearedTimestamp {
7979

8080
#[cfg(test)]
8181
mod tests {
82-
use std::time::SystemTime;
83-
8482
use super::*;
8583
use crate::test_utils::TestContext;
86-
use crate::tools::{create_smeared_timestamp, create_smeared_timestamps, smeared_time, time};
84+
use crate::tools::{
85+
create_smeared_timestamp, create_smeared_timestamps, smeared_time, time, SystemTime,
86+
};
8787

8888
#[test]
8989
fn test_smeared_timestamp() {

src/tools.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ use std::io::{Cursor, Write};
99
use std::mem;
1010
use std::path::{Path, PathBuf};
1111
use std::str::from_utf8;
12+
#[cfg(test)]
13+
use std::sync::RwLock;
1214
// `std::time::Instant` may use `libc::clock_gettime(CLOCK_MONOTONIC)`, e.g. on Android, and does
1315
// not advance while being in deep sleep mode, so use `SystemTime` for now. When the issue on
1416
// Android will be solved, we can switch to the true `Instant` easily.
1517
pub use std::time::SystemTime as Instant;
16-
use std::time::{Duration, SystemTime};
18+
use std::time::{Duration, SystemTimeError};
1719

1820
use anyhow::{bail, Context as _, Result};
1921
use base64::Engine as _;
@@ -479,6 +481,35 @@ pub async fn read_dir(path: &Path) -> Result<Vec<fs::DirEntry>> {
479481
Ok(res)
480482
}
481483

484+
#[cfg(test)]
485+
static SYSTEM_TIME_SHIFT: RwLock<Duration> = RwLock::new(Duration::new(0, 0));
486+
487+
/// Fake struct for mocking `SystemTime::now()` etc. for test purposes. You still need to use
488+
/// `std::time::SystemTime` as a struct representing a system time.
489+
pub(crate) struct SystemTime();
490+
491+
impl SystemTime {
492+
pub const UNIX_EPOCH: std::time::SystemTime = std::time::SystemTime::UNIX_EPOCH;
493+
494+
#[allow(unused)]
495+
pub fn elapsed(t: &std::time::SystemTime) -> Result<Duration, SystemTimeError> {
496+
Self::now().duration_since(*t)
497+
}
498+
499+
pub fn now() -> std::time::SystemTime {
500+
#[cfg(not(test))]
501+
return std::time::SystemTime::now();
502+
#[cfg(test)]
503+
return std::time::SystemTime::now() + *SYSTEM_TIME_SHIFT.read().unwrap();
504+
}
505+
506+
/// Simulates a system clock forward adjustment by `duration`.
507+
#[cfg(test)]
508+
pub fn shift(duration: Duration) {
509+
*SYSTEM_TIME_SHIFT.write().unwrap() += duration;
510+
}
511+
}
512+
482513
pub(crate) fn time() -> i64 {
483514
SystemTime::now()
484515
.duration_since(SystemTime::UNIX_EPOCH)

0 commit comments

Comments
 (0)