Skip to content

Commit b9b0d20

Browse files
authored
test: Add golden tests infrastructure (#4395)
1 parent c68a2e3 commit b9b0d20

File tree

3 files changed

+96
-15
lines changed

3 files changed

+96
-15
lines changed

Cargo.lock

Lines changed: 44 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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ proptest = { version = "1", default-features = false, features = ["std"] }
104104
tempfile = "3"
105105
testdir = "0.7.3"
106106
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "macros"] }
107+
pretty_assertions = "1.3.0"
107108

108109
[workspace]
109110
members = [

src/test_utils.rs

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@
33
//! This private module is only compiled for test runs.
44
#![allow(clippy::indexing_slicing)]
55
use std::collections::BTreeMap;
6+
use std::fmt::Write;
67
use std::ops::{Deref, DerefMut};
78
use std::panic;
9+
use std::path::Path;
810
use std::sync::Arc;
911
use std::time::{Duration, Instant};
1012

1113
use ansi_term::Color;
1214
use async_channel::{self as channel, Receiver, Sender};
1315
use chat::ChatItem;
1416
use once_cell::sync::Lazy;
17+
use pretty_assertions::assert_eq;
1518
use rand::Rng;
1619
use tempfile::{tempdir, TempDir};
1720
use tokio::runtime::Handle;
1821
use tokio::sync::RwLock;
19-
use tokio::task;
22+
use tokio::{fs, task};
2023

2124
use crate::chat::{
2225
self, add_to_chat_contacts_table, create_group_chat, Chat, ChatId, MessageListOptions,
@@ -285,7 +288,7 @@ impl TestContext {
285288
println!("\n========== Chats of {}: ==========", self.name());
286289
if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await {
287290
for (chat, _) in chats.iter() {
288-
self.print_chat(*chat).await;
291+
print!("{}", self.display_chat(*chat).await);
289292
}
290293
}
291294
println!();
@@ -624,14 +627,38 @@ impl TestContext {
624627
res
625628
}
626629

630+
#[allow(unused)]
631+
pub async fn golden_test_chat(&self, chat_id: ChatId, filename: &str) {
632+
let filename = Path::new("test-data/golden/").join(filename);
633+
634+
let actual = self.display_chat(chat_id).await;
635+
636+
// We're using `unwrap_or_default()` here so that if the file doesn't exist,
637+
// it can be created using `write` below.
638+
let expected = fs::read(&filename).await.unwrap_or_default();
639+
let expected = String::from_utf8(expected).unwrap();
640+
if (std::env::var("UPDATE_GOLDEN_TESTS") == Ok("1".to_string())) && actual != expected {
641+
fs::write(&filename, &actual)
642+
.await
643+
.unwrap_or_else(|e| panic!("Error writing {filename:?}: {e}"));
644+
} else {
645+
assert_eq!(
646+
actual, expected,
647+
"To update the expected value, run `UPDATE_GOLDEN_TESTS=1 cargo test`"
648+
);
649+
}
650+
}
651+
627652
/// Prints out the entire chat to stdout.
628653
///
629654
/// You can use this to debug your test by printing the entire chat conversation.
630655
// This code is mainly the same as `log_msglist` in `cmdline.rs`, so one day, we could
631656
// merge them to a public function in the `deltachat` crate.
632657
#[allow(dead_code)]
633658
#[allow(clippy::indexing_slicing)]
634-
pub async fn print_chat(&self, chat_id: ChatId) {
659+
async fn display_chat(&self, chat_id: ChatId) -> String {
660+
let mut res = String::new();
661+
635662
let msglist = chat::get_chat_msgs_ex(
636663
self,
637664
chat_id,
@@ -662,7 +689,8 @@ impl TestContext {
662689
} else {
663690
format!("{} member(s)", members.len())
664691
};
665-
println!(
692+
writeln!(
693+
res,
666694
"{}#{}: {} [{}]{}{}{} {}",
667695
sel_chat.typ,
668696
sel_chat.get_id(),
@@ -686,32 +714,38 @@ impl TestContext {
686714
} else {
687715
""
688716
},
689-
);
717+
)
718+
.unwrap();
690719

691720
let mut lines_out = 0;
692721
for msg_id in msglist {
693722
if msg_id == MsgId::new(DC_MSG_ID_DAYMARKER) {
694-
println!(
723+
writeln!(res,
695724
"--------------------------------------------------------------------------------"
696-
);
725+
)
726+
.unwrap();
697727

698728
lines_out += 1
699729
} else if !msg_id.is_special() {
700730
if lines_out == 0 {
701-
println!(
731+
writeln!(res,
702732
"--------------------------------------------------------------------------------",
703-
);
733+
).unwrap();
704734
lines_out += 1
705735
}
706736
let msg = Message::load_from_db(self, msg_id).await.unwrap();
707-
log_msg(self, "", &msg).await;
737+
write_msg(self, "", &msg, &mut res).await;
708738
}
709739
}
710740
if lines_out > 0 {
711-
println!(
741+
writeln!(
742+
res,
712743
"--------------------------------------------------------------------------------"
713-
);
744+
)
745+
.unwrap();
714746
}
747+
748+
res
715749
}
716750

717751
pub async fn create_group_with_members(
@@ -1041,7 +1075,7 @@ fn print_event(event: &Event) {
10411075
/// Logs an individual message to stdout.
10421076
///
10431077
/// This includes a bunch of the message meta-data as well.
1044-
async fn log_msg(context: &Context, prefix: &str, msg: &Message) {
1078+
async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut String) {
10451079
let contact = match Contact::get_by_id(context, msg.get_from_id()).await {
10461080
Ok(contact) => contact,
10471081
Err(e) => {
@@ -1061,7 +1095,8 @@ async fn log_msg(context: &Context, prefix: &str, msg: &Message) {
10611095
_ => "",
10621096
};
10631097
let msgtext = msg.get_text();
1064-
println!(
1098+
writeln!(
1099+
buf,
10651100
"{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{}",
10661101
prefix,
10671102
msg.get_id(),
@@ -1095,7 +1130,8 @@ async fn log_msg(context: &Context, prefix: &str, msg: &Message) {
10951130
""
10961131
},
10971132
statestr,
1098-
);
1133+
)
1134+
.unwrap();
10991135
}
11001136

11011137
#[cfg(test)]

0 commit comments

Comments
 (0)