mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
test: Add golden tests infrastructure (#4395)
This commit is contained in:
44
Cargo.lock
generated
44
Cargo.lock
generated
@@ -977,6 +977,16 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.1.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curve25519-dalek"
|
name = "curve25519-dalek"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
@@ -1183,6 +1193,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pgp",
|
"pgp",
|
||||||
|
"pretty_assertions",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"proptest",
|
"proptest",
|
||||||
"qrcodegen",
|
"qrcodegen",
|
||||||
@@ -1400,6 +1411,12 @@ dependencies = [
|
|||||||
"cipher",
|
"cipher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -3201,6 +3218,15 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "output_vt100"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -3545,6 +3571,18 @@ version = "0.2.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
|
||||||
|
dependencies = [
|
||||||
|
"ctor",
|
||||||
|
"diff",
|
||||||
|
"output_vt100",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pretty_env_logger"
|
name = "pretty_env_logger"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -5744,6 +5782,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yasna"
|
name = "yasna"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ proptest = { version = "1", default-features = false, features = ["std"] }
|
|||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
testdir = "0.7.3"
|
testdir = "0.7.3"
|
||||||
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "macros"] }
|
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "macros"] }
|
||||||
|
pretty_assertions = "1.3.0"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
//! This private module is only compiled for test runs.
|
//! This private module is only compiled for test runs.
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::fmt::Write;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::panic;
|
use std::panic;
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
@@ -12,11 +14,12 @@ use ansi_term::Color;
|
|||||||
use async_channel::{self as channel, Receiver, Sender};
|
use async_channel::{self as channel, Receiver, Sender};
|
||||||
use chat::ChatItem;
|
use chat::ChatItem;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use tempfile::{tempdir, TempDir};
|
use tempfile::{tempdir, TempDir};
|
||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tokio::task;
|
use tokio::{fs, task};
|
||||||
|
|
||||||
use crate::chat::{
|
use crate::chat::{
|
||||||
self, add_to_chat_contacts_table, create_group_chat, Chat, ChatId, MessageListOptions,
|
self, add_to_chat_contacts_table, create_group_chat, Chat, ChatId, MessageListOptions,
|
||||||
@@ -285,7 +288,7 @@ impl TestContext {
|
|||||||
println!("\n========== Chats of {}: ==========", self.name());
|
println!("\n========== Chats of {}: ==========", self.name());
|
||||||
if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await {
|
if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await {
|
||||||
for (chat, _) in chats.iter() {
|
for (chat, _) in chats.iter() {
|
||||||
self.print_chat(*chat).await;
|
print!("{}", self.display_chat(*chat).await);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
@@ -624,6 +627,28 @@ impl TestContext {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub async fn golden_test_chat(&self, chat_id: ChatId, filename: &str) {
|
||||||
|
let filename = Path::new("test-data/golden/").join(filename);
|
||||||
|
|
||||||
|
let actual = self.display_chat(chat_id).await;
|
||||||
|
|
||||||
|
// We're using `unwrap_or_default()` here so that if the file doesn't exist,
|
||||||
|
// it can be created using `write` below.
|
||||||
|
let expected = fs::read(&filename).await.unwrap_or_default();
|
||||||
|
let expected = String::from_utf8(expected).unwrap();
|
||||||
|
if (std::env::var("UPDATE_GOLDEN_TESTS") == Ok("1".to_string())) && actual != expected {
|
||||||
|
fs::write(&filename, &actual)
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|e| panic!("Error writing {filename:?}: {e}"));
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
actual, expected,
|
||||||
|
"To update the expected value, run `UPDATE_GOLDEN_TESTS=1 cargo test`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Prints out the entire chat to stdout.
|
/// Prints out the entire chat to stdout.
|
||||||
///
|
///
|
||||||
/// You can use this to debug your test by printing the entire chat conversation.
|
/// You can use this to debug your test by printing the entire chat conversation.
|
||||||
@@ -631,7 +656,9 @@ impl TestContext {
|
|||||||
// merge them to a public function in the `deltachat` crate.
|
// merge them to a public function in the `deltachat` crate.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
pub async fn print_chat(&self, chat_id: ChatId) {
|
async fn display_chat(&self, chat_id: ChatId) -> String {
|
||||||
|
let mut res = String::new();
|
||||||
|
|
||||||
let msglist = chat::get_chat_msgs_ex(
|
let msglist = chat::get_chat_msgs_ex(
|
||||||
self,
|
self,
|
||||||
chat_id,
|
chat_id,
|
||||||
@@ -662,7 +689,8 @@ impl TestContext {
|
|||||||
} else {
|
} else {
|
||||||
format!("{} member(s)", members.len())
|
format!("{} member(s)", members.len())
|
||||||
};
|
};
|
||||||
println!(
|
writeln!(
|
||||||
|
res,
|
||||||
"{}#{}: {} [{}]{}{}{} {}",
|
"{}#{}: {} [{}]{}{}{} {}",
|
||||||
sel_chat.typ,
|
sel_chat.typ,
|
||||||
sel_chat.get_id(),
|
sel_chat.get_id(),
|
||||||
@@ -686,32 +714,38 @@ impl TestContext {
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut lines_out = 0;
|
let mut lines_out = 0;
|
||||||
for msg_id in msglist {
|
for msg_id in msglist {
|
||||||
if msg_id == MsgId::new(DC_MSG_ID_DAYMARKER) {
|
if msg_id == MsgId::new(DC_MSG_ID_DAYMARKER) {
|
||||||
println!(
|
writeln!(res,
|
||||||
"--------------------------------------------------------------------------------"
|
"--------------------------------------------------------------------------------"
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
lines_out += 1
|
lines_out += 1
|
||||||
} else if !msg_id.is_special() {
|
} else if !msg_id.is_special() {
|
||||||
if lines_out == 0 {
|
if lines_out == 0 {
|
||||||
println!(
|
writeln!(res,
|
||||||
"--------------------------------------------------------------------------------",
|
"--------------------------------------------------------------------------------",
|
||||||
);
|
).unwrap();
|
||||||
lines_out += 1
|
lines_out += 1
|
||||||
}
|
}
|
||||||
let msg = Message::load_from_db(self, msg_id).await.unwrap();
|
let msg = Message::load_from_db(self, msg_id).await.unwrap();
|
||||||
log_msg(self, "", &msg).await;
|
write_msg(self, "", &msg, &mut res).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lines_out > 0 {
|
if lines_out > 0 {
|
||||||
println!(
|
writeln!(
|
||||||
|
res,
|
||||||
"--------------------------------------------------------------------------------"
|
"--------------------------------------------------------------------------------"
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_group_with_members(
|
pub async fn create_group_with_members(
|
||||||
@@ -1041,7 +1075,7 @@ fn print_event(event: &Event) {
|
|||||||
/// Logs an individual message to stdout.
|
/// Logs an individual message to stdout.
|
||||||
///
|
///
|
||||||
/// This includes a bunch of the message meta-data as well.
|
/// This includes a bunch of the message meta-data as well.
|
||||||
async fn log_msg(context: &Context, prefix: &str, msg: &Message) {
|
async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut String) {
|
||||||
let contact = match Contact::get_by_id(context, msg.get_from_id()).await {
|
let contact = match Contact::get_by_id(context, msg.get_from_id()).await {
|
||||||
Ok(contact) => contact,
|
Ok(contact) => contact,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -1061,7 +1095,8 @@ async fn log_msg(context: &Context, prefix: &str, msg: &Message) {
|
|||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
let msgtext = msg.get_text();
|
let msgtext = msg.get_text();
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
"{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{}",
|
"{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{}",
|
||||||
prefix,
|
prefix,
|
||||||
msg.get_id(),
|
msg.get_id(),
|
||||||
@@ -1095,7 +1130,8 @@ async fn log_msg(context: &Context, prefix: &str, msg: &Message) {
|
|||||||
""
|
""
|
||||||
},
|
},
|
||||||
statestr,
|
statestr,
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user