Skip to content

Commit 6e55f0c

Browse files
committed
feat: Mock SystemTime::now() for the tests
Add a new crate `deltachat_time` with a fake `struct SystemTimeTools` for mocking `SystemTime::now()` 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::now()` instead of the mock 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 3b0e740 commit 6e55f0c

File tree

13 files changed

+76
-21
lines changed

13 files changed

+76
-21
lines changed

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ strip = true
3232

3333
[dependencies]
3434
deltachat_derive = { path = "./deltachat_derive" }
35+
deltachat-time = { path = "./deltachat-time" }
3536
format-flowed = { path = "./format-flowed" }
3637
ratelimit = { path = "./deltachat-ratelimit" }
3738

@@ -128,6 +129,7 @@ members = [
128129
"deltachat-rpc-server",
129130
"deltachat-ratelimit",
130131
"deltachat-repl",
132+
"deltachat-time",
131133
"format-flowed",
132134
]
133135

deltachat-time/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "deltachat-time"
3+
version = "1.0.0"
4+
description = "Time-related tools"
5+
edition = "2021"
6+
license = "MPL-2.0"
7+
8+
[dependencies]

deltachat-time/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![allow(missing_docs)]
2+
3+
use std::sync::RwLock;
4+
use std::time::{Duration, SystemTime};
5+
6+
static SYSTEM_TIME_SHIFT: RwLock<Duration> = RwLock::new(Duration::new(0, 0));
7+
8+
/// Fake struct for mocking `SystemTime::now()` for test purposes. You still need to use
9+
/// `SystemTime` as a struct representing a system time.
10+
pub struct SystemTimeTools();
11+
12+
impl SystemTimeTools {
13+
pub const UNIX_EPOCH: SystemTime = SystemTime::UNIX_EPOCH;
14+
15+
pub fn now() -> SystemTime {
16+
return SystemTime::now() + *SYSTEM_TIME_SHIFT.read().unwrap();
17+
}
18+
19+
/// Simulates a system clock forward adjustment by `duration`.
20+
pub fn shift(duration: Duration) {
21+
*SYSTEM_TIME_SHIFT.write().unwrap() += duration;
22+
}
23+
}
24+
25+
#[cfg(test)]
26+
mod tests {
27+
use super::*;
28+
29+
#[test]
30+
fn it_works() {
31+
SystemTimeTools::shift(Duration::from_secs(60));
32+
let t = SystemTimeTools::now();
33+
assert!(t > SystemTime::now());
34+
}
35+
}

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

@@ -3656,7 +3656,7 @@ pub enum MuteDuration {
36563656
Forever,
36573657

36583658
/// Chat is muted for a limited period of time.
3659-
Until(SystemTime),
3659+
Until(std::time::SystemTime),
36603660
}
36613661

36623662
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};
@@ -36,7 +36,7 @@ use crate::sql::{self, params_iter};
3636
use crate::sync::{self, Sync::*};
3737
use crate::tools::{
3838
duration_to_str, get_abs_path, improve_single_line_input, strip_rtlo_characters, time,
39-
EmailAddress,
39+
EmailAddress, SystemTime,
4040
};
4141
use crate::{chat, stock_str};
4242

src/context.rs

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

12181218
#[cfg(test)]
12191219
mod tests {
1220-
use std::time::{Duration, SystemTime};
1220+
use std::time::Duration;
12211221

12221222
use anyhow::Context as _;
12231223
use strum::IntoEnumIterator;
@@ -1234,7 +1234,7 @@ mod tests {
12341234
use crate::mimeparser::SystemMessage;
12351235
use crate::receive_imf::receive_imf;
12361236
use crate::test_utils::{get_chat_msg, TestContext};
1237-
use crate::tools::create_outgoing_rfc724_mid;
1237+
use crate::tools::{create_outgoing_rfc724_mid, SystemTime};
12381238

12391239
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
12401240
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`].
@@ -850,9 +850,9 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
850850
Ok(mut dir_handle) => {
851851
/* avoid deletion of files that are just created to build a message object */
852852
let diff = std::time::Duration::from_secs(60 * 60);
853-
let keep_files_newer_than = std::time::SystemTime::now()
853+
let keep_files_newer_than = SystemTime::now()
854854
.checked_sub(diff)
855-
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
855+
.unwrap_or(SystemTime::UNIX_EPOCH);
856856

857857
while let Ok(Some(entry)) = dir_handle.next_entry().await {
858858
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<()> {

0 commit comments

Comments
 (0)