aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDirk Van Haerenborgh <vhdirk@gmail.com>2019-11-14 19:22:38 +0100
committerDirk Van Haerenborgh <vhdirk@gmail.com>2019-11-14 19:22:38 +0100
commitcc6896cca0839f5d97c5daee8ffba824c3c0d229 (patch)
tree991e348c590f3da671a1acc9ebd4f57cd497f974
parent1e060f14736922bfbd065a2ac611c64b9e2f5104 (diff)
downloadmail-cc6896cca0839f5d97c5daee8ffba824c3c0d229.tar.gz
add more tests
-rw-r--r--.travis.yml11
-rw-r--r--Cargo.toml1
-rw-r--r--src/ffi.rs18
-rw-r--r--src/message.rs65
-rw-r--r--src/thread.rs4
-rw-r--r--tests/fixtures.rs18
-rw-r--r--tests/lib.rs2
-rw-r--r--tests/test_database.rs44
-rw-r--r--tests/test_message.rs316
-rw-r--r--tests/test_thread.rs108
10 files changed, 551 insertions, 36 deletions
diff --git a/.travis.yml b/.travis.yml
index 5099a5d..26d147c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,14 @@
dist: bionic
language: rust
-sudo: false
+sudo: required
rust:
- stable
- beta
- nightly
+# Cache cargo symbols for faster build
+cache: cargo
+
addons:
apt:
packages:
@@ -13,6 +16,12 @@ addons:
- notmuch
- git
+before_script:
+ - export PATH=$HOME/.cargo/bin:$PATH
+ - cargo install cargo-update || echo "cargo-update already installed"
+ - cargo install cargo-travis || echo "cargo-travis already installed"
+ - cargo install-update -a # update outdated cached binaries
+
script:
- cargo build --no-default-features --verbose --all
# clone notmuch to have mail corpora
diff --git a/Cargo.toml b/Cargo.toml
index c88b049..f51bda2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ description = "Rust interface and bindings for notmuch"
license = "GPL-3.0+"
readme = "README.md"
keywords = ["email", "notmuch"]
+autotests = false
[badges]
travis-ci = { repository = "vhdirk/notmuch-rs" }
diff --git a/src/ffi.rs b/src/ffi.rs
index 1e29783..5dc93aa 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -1484,6 +1484,24 @@ extern "C" {
exact: notmuch_bool_t,
) -> *mut notmuch_message_properties_t;
+
+ /// Return the number of properties named "key" belonging to the specific message.
+ ///
+ /// @param[in] message The message to examine
+ /// @param[in] key key to count
+ /// @param[out] count The number of matching properties associated with this message.
+ ///
+ /// @returns
+ ///
+ /// NOTMUCH_STATUS_SUCCESS: successful count, possibly some other error.
+ ///
+ /// @since libnotmuch 5.2 (notmuch 0.27)
+ pub fn notmuch_message_count_properties(
+ message: *mut notmuch_message_t,
+ key: *const c_char,
+ count: *mut c_uint,
+ ) -> notmuch_status_t;
+
/// Is the given *properties* iterator pointing at a valid `(key,value)` pair.
///
/// When this function returns TRUE, `notmuch_message_properties_{key,value}`
diff --git a/src/message.rs b/src/message.rs
index feafcb3..03623a1 100644
--- a/src/message.rs
+++ b/src/message.rs
@@ -1,6 +1,7 @@
-use std::ffi::CString;
+use std::ffi::{CString, CStr};
use std::path::PathBuf;
use std::cell::RefCell;
+use std::ptr;
use supercow::{Supercow};
use error::{Error, Result};
@@ -29,6 +30,16 @@ impl<'o, O> MessageOwner for Message<'o, O> where O: MessageOwner + 'o {}
impl<'o, O> FilenamesOwner for Message<'o, O> where O: MessageOwner + 'o {}
impl<'o, O> TagsOwner for Message<'o, O> where O: MessageOwner + 'o {}
+
+// impl<'o, O> PartialEq for Message<'o, O>
+// where
+// O: MessageOwner + 'o
+// {
+// fn eq(self: &Self, other: &Message<'o, O>) -> bool{
+// self.id() == other.id()
+// }
+// }
+
impl<'o, O> Message<'o, O>
where
O: MessageOwner + 'o,
@@ -137,6 +148,58 @@ where
{
<Self as MessageExt<'o, O>>::properties(self, key, exact)
}
+
+ pub fn remove_all_properties(&self, key: &str) -> Result<()>
+ {
+ let key_str = CString::new(key).unwrap();
+ unsafe {
+ ffi::notmuch_message_remove_all_properties(self.ptr, key_str.as_ptr())
+ }.as_result()
+ }
+
+ pub fn count_properties(&self, key: &str) -> Result<u32>
+ {
+ let key_str = CString::new(key).unwrap();
+ let mut cnt = 0;
+ unsafe {
+ ffi::notmuch_message_count_properties(self.ptr, key_str.as_ptr(), &mut cnt)
+ }.as_result()?;
+
+ Ok(cnt)
+ }
+
+ pub fn property(&self, key: &str, exact: bool) -> Result<String>
+ {
+ let key_str = CString::new(key).unwrap();
+ let mut prop = ptr::null();
+ unsafe {
+ ffi::notmuch_message_get_property(self.ptr, key_str.as_ptr(), &mut prop)
+ }.as_result()?;
+
+ // TODO: the unwrap here is not good
+ Ok(unsafe{
+ CStr::from_ptr(prop)
+ }.to_str().unwrap().to_string())
+ }
+
+ pub fn add_property(&self, key: &str, value: &str) -> Result<()>
+ {
+ let key_str = CString::new(key).unwrap();
+ let value_str = CString::new(value).unwrap();
+ unsafe {
+ ffi::notmuch_message_add_property(self.ptr, key_str.as_ptr(), value_str.as_ptr())
+ }.as_result()
+ }
+
+ pub fn remove_property(&self, key: &str, value: &str) -> Result<()>
+ {
+ let key_str = CString::new(key).unwrap();
+ let value_str = CString::new(value).unwrap();
+ unsafe {
+ ffi::notmuch_message_remove_property(self.ptr, key_str.as_ptr(), value_str.as_ptr())
+ }.as_result()
+ }
+
}
pub trait MessageExt<'o, O>
diff --git a/src/thread.rs b/src/thread.rs
index 34cebd3..1ebcc24 100644
--- a/src/thread.rs
+++ b/src/thread.rs
@@ -61,6 +61,10 @@ where
<Self as ThreadExt<'d, 'q>>::toplevel_messages(self)
}
+ pub fn matched_messages(self: &Self) -> i32 {
+ unsafe { ffi::notmuch_thread_get_matched_messages(self.ptr) }
+ }
+
/// Get a `Messages` iterator for all messages in 'thread' in
/// oldest-first order.
pub fn messages(self: &Self) -> Messages<'_, Self> {
diff --git a/tests/fixtures.rs b/tests/fixtures.rs
index 8887da8..c9e04c8 100644
--- a/tests/fixtures.rs
+++ b/tests/fixtures.rs
@@ -114,22 +114,16 @@ impl MailBox {
-> Result<(String, PathBuf)>
{
- let mut builder = EmailBuilder::new();
+ let mut builder = EmailBuilder::new()
+ .subject(subject.unwrap_or_else(|| "Test mail".to_string()));
+
- if let Some(val) = subject {
- builder = builder.subject(val);
- }
if let Some(val) = body {
builder = builder.text(val);
}
- builder = match to {
- Some(val) => builder.to(val),
- None => builder.to(format!("to@{}.localhost", self.hostname()))
- };
- builder = match from {
- Some(val) => builder.from(val),
- None => builder.from(format!("from@{}.localhost", self.hostname()))
- };
+
+ builder = builder.to(to.unwrap_or_else(|| "to@example.com".to_string()))
+ .from(from.unwrap_or_else(|| "src@example.com".to_string()));
for h in headers.into_iter(){
let hdr: Header = h.into();
diff --git a/tests/lib.rs b/tests/lib.rs
index c5095f4..bd3138d 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -8,4 +8,6 @@ extern crate lettre_email;
mod fixtures;
mod test_database;
+mod test_thread;
+mod test_message;
diff --git a/tests/test_database.rs b/tests/test_database.rs
index 09dcd3c..557e0c3 100644
--- a/tests/test_database.rs
+++ b/tests/test_database.rs
@@ -71,7 +71,7 @@ mod database {
fn test_path(){
let mailbox = MailBox::new();
let db = notmuch::Database::create(&mailbox.path()).unwrap();
- assert!(db.path() == mailbox.path());
+ assert_eq!(db.path(), mailbox.path());
}
#[test]
@@ -122,8 +122,8 @@ mod revision {
let db1 = notmuch::Database::create(&mailbox1.path()).unwrap();
let rev1 = db1.revision();
- assert!(rev0 != rev1);
- assert!(rev0.uuid != rev1.uuid);
+ assert_ne!(rev0, rev1);
+ assert_ne!(rev0.uuid, rev1.uuid);
}
#[test]
@@ -165,8 +165,8 @@ mod messages {
let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap();
let msg = db.index_file(&filename, None).unwrap();
- assert!(msg.filename() == filename);
- assert!(msg.id() == msgid);
+ assert_eq!(msg.filename(), filename);
+ assert_eq!(msg.id(), msgid);
}
@@ -192,11 +192,11 @@ mod messages {
let msg0 = db.index_file(&filename, None).unwrap();
let msg1 = db.find_message(&msgid).unwrap().unwrap();
- assert!(msg0.id() == msgid);
- assert!(msg0.id() == msg1.id());
+ assert_eq!(msg0.id(), msgid);
+ assert_eq!(msg0.id(), msg1.id());
- assert!(msg0.filename() == filename);
- assert!(msg0.filename() == msg1.filename());
+ assert_eq!(msg0.filename(), filename);
+ assert_eq!(msg0.filename(), msg1.filename());
}
#[test]
@@ -219,7 +219,7 @@ mod tags {
let tags = db.all_tags().unwrap();
- assert!(tags.count() == 0);
+ assert_eq!(tags.count(), 0);
}
#[test]
@@ -232,7 +232,7 @@ mod tags {
msg.add_tag(&"hello").unwrap();
let tags: Vec<String> = db.all_tags().unwrap().collect();
- assert!(tags.len() == 1);
+ assert_eq!(tags.len(), 1);
assert!(tags.iter().any(|x| x == "hello"));
}
@@ -243,12 +243,12 @@ mod tags {
let t1: Vec<String> = db.all_tags().unwrap().collect();
let t2: Vec<String> = db.all_tags().unwrap().collect();
- assert!(t1 == t2);
+ assert_eq!(t1, t2);
}
}
-struct PopulatedDatabase {
+struct DatabaseFixture {
// Return a read-write Database.
// The database will have 3 messages, 2 threads.
@@ -256,7 +256,7 @@ struct PopulatedDatabase {
pub database: notmuch::Database,
}
-impl PopulatedDatabase {
+impl DatabaseFixture {
pub fn new() -> Self{
let mailbox = MailBox::new();
@@ -281,15 +281,15 @@ mod query {
#[test]
fn test_count_messages() {
- let db = PopulatedDatabase::new();
+ let db = DatabaseFixture::new();
let query = db.database.create_query("*").unwrap();
- assert!(query.count_messages().unwrap() == 3);
+ assert_eq!(query.count_messages().unwrap(), 3);
}
#[test]
fn test_message_no_results() {
- let db = PopulatedDatabase::new();
+ let db = DatabaseFixture::new();
let query = db.database.create_query("not_a_matching_query").unwrap();
let mut messages = query.search_messages().unwrap();
@@ -299,7 +299,7 @@ mod query {
#[test]
fn test_message_match() {
- let db = PopulatedDatabase::new();
+ let db = DatabaseFixture::new();
let query = db.database.create_query("*").unwrap();
let mut messages = query.search_messages().unwrap();
@@ -309,15 +309,15 @@ mod query {
#[test]
fn test_count_threads() {
- let db = PopulatedDatabase::new();
+ let db = DatabaseFixture::new();
let query = db.database.create_query("*").unwrap();
- assert!(query.count_threads().unwrap() == 2);
+ assert_eq!(query.count_threads().unwrap(), 2);
}
#[test]
fn test_threads_no_results() {
- let db = PopulatedDatabase::new();
+ let db = DatabaseFixture::new();
let query = db.database.create_query("not_a_matching_query").unwrap();
let mut threads = query.search_threads().unwrap();
@@ -327,7 +327,7 @@ mod query {
#[test]
fn test_threads_match() {
- let db = PopulatedDatabase::new();
+ let db = DatabaseFixture::new();
let query = db.database.create_query("*").unwrap();
let mut threads = query.search_threads().unwrap();
diff --git a/tests/test_message.rs b/tests/test_message.rs
new file mode 100644
index 0000000..ce86df0
--- /dev/null
+++ b/tests/test_message.rs
@@ -0,0 +1,316 @@
+use std::sync::Arc;
+use std::path::PathBuf;
+use fixtures::MailBox;
+
+struct MessageFixture {
+ // Return a single thread with 2 messages
+ pub mailbox: MailBox,
+ pub database: Arc<notmuch::Database>,
+ pub maildir_msg: (String, PathBuf),
+ pub message: notmuch::Message<'static, notmuch::Database>,
+}
+
+impl MessageFixture {
+ pub fn new() -> Self{
+ let mailbox = MailBox::new();
+
+ let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap();
+
+ let database = Arc::new(notmuch::Database::create(&mailbox.path()).unwrap());
+ let message = <notmuch::Database as notmuch::DatabaseExt>::index_file(database.clone(), &filename, None).unwrap();
+
+ Self {
+ mailbox,
+ database,
+ maildir_msg: (msgid, filename),
+ message
+ }
+ }
+}
+
+mod message {
+
+ use super::*;
+
+ #[test]
+ fn test_messageid() {
+ let msg = MessageFixture::new();
+ let copy = <notmuch::Database as notmuch::DatabaseExt>::find_message_by_filename(msg.database.clone(), &msg.message.filename()).unwrap().unwrap();
+ assert_eq!(msg.message.id(), copy.id())
+ }
+
+ #[test]
+ fn test_messageid_find() {
+ let msg = MessageFixture::new();
+ let copy = <notmuch::Database as notmuch::DatabaseExt>::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap();
+ assert_eq!(msg.message.id(), copy.id())
+ }
+
+ #[test]
+ fn test_path() {
+ let msg = MessageFixture::new();
+ assert_eq!(msg.message.filename(), msg.maildir_msg.1)
+ }
+
+
+ #[test]
+ fn test_filenames() {
+ let msg = MessageFixture::new();
+ let mut filenames = msg.message.filenames();
+ let filename = filenames.next().unwrap();
+
+ assert_eq!(filename, msg.message.filename());
+
+ assert!(filenames.next().is_none());
+ let names: Vec<PathBuf> = msg.message.filenames().collect();
+
+ assert_eq!(names, vec![msg.maildir_msg.1]);
+ }
+
+ #[test]
+ fn test_header() {
+ let msg = MessageFixture::new();
+ assert_eq!(msg.message.header(&"from").unwrap(), Some("<src@example.com>"));
+ }
+
+ #[test]
+ fn test_header_not_present() {
+ let msg = MessageFixture::new();
+ assert_eq!(msg.message.header(&"foo").unwrap(), None);
+ }
+
+ #[test]
+ fn test_freeze() {
+ let msg = MessageFixture::new();
+
+ msg.message.freeze().unwrap();
+ msg.message.add_tag(&"foo").unwrap();
+ msg.message.add_tag(&"bar").unwrap();
+ msg.message.remove_tag(&"foo").unwrap();
+ msg.message.thaw().unwrap();
+
+ assert!(msg.message.tags().all(|x| x != "foo"));
+ assert!(msg.message.tags().any(|x| x == "bar"));
+ }
+
+ #[test]
+ fn test_freeze_context() {
+ let msg = MessageFixture::new();
+
+ {
+ let _frozen = notmuch::FrozenMessage::new(&msg.message).unwrap();
+ msg.message.add_tag(&"foo").unwrap();
+ msg.message.add_tag(&"bar").unwrap();
+ msg.message.remove_tag(&"foo").unwrap();
+
+ }
+ assert!(msg.message.tags().all(|x| x != "foo"));
+ assert!(msg.message.tags().any(|x| x == "bar"));
+ }
+
+
+ #[test]
+ fn test_freeze_err() {
+ // not sure if this test is ok?
+ let msg = MessageFixture::new();
+
+ msg.message.add_tag(&"foo").unwrap();
+
+ msg.message.freeze().unwrap();
+ assert!(msg.message.remove_all_tags().is_ok());
+
+ let copy = <notmuch::Database as notmuch::DatabaseExt>::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap();
+ assert!(copy.tags().any(|x| x == "foo"));
+
+ msg.message.thaw().unwrap();
+
+ assert!(!msg.message.tags().any(|x| x == "foo"));
+
+ let copy2 = <notmuch::Database as notmuch::DatabaseExt>::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap();
+ assert!(!copy2.tags().any(|x| x == "foo"));
+ }
+
+ #[test]
+ fn test_freeze_context_err() {
+ // not sure if this test is ok?
+ let msg = MessageFixture::new();
+ msg.message.add_tag(&"foo").unwrap();
+
+ {
+ let _frozen = notmuch::FrozenMessage::new(&msg.message).unwrap();
+ assert!(msg.message.remove_all_tags().is_ok());
+ assert!(!msg.message.tags().any(|x| x == "foo"));
+
+ let copy = <notmuch::Database as notmuch::DatabaseExt>::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap();
+ assert!(copy.tags().any(|x| x == "foo"));
+ }
+
+ let copy2 = <notmuch::Database as notmuch::DatabaseExt>::find_message(msg.database.clone(), &msg.message.id()).unwrap().unwrap();
+ assert!(!copy2.tags().any(|x| x == "foo"));
+ assert!(!msg.message.tags().any(|x| x == "foo"));
+ }
+
+ #[test]
+ fn test_replies() {
+ let msg = MessageFixture::new();
+ assert_eq!(msg.message.replies().count(), 0);
+ }
+
+}
+
+
+// def test_date(self, msg):
+// # XXX Someone seems to treat things as local time instead of
+// # UTC or the other way around.
+// now = int(time.time())
+// assert abs(now - msg.date) < 3600*24
+
+
+// struct MessagePropertiesFixture {
+// // Return a single thread with 2 messages
+// pub mailbox: MailBox,
+// pub database: Arc<notmuch::Database>,
+// pub maildir_msg: (String, PathBuf),
+// pub message: notmuch::Message<'static, notmuch::Database>,
+// }
+
+// impl MessagePropertiesFixture {
+// pub fn new() -> Self{
+// let mailbox = MailBox::new();
+
+// let (msgid, filename) = mailbox.deliver(None, None, None, None, vec![], true, None, false, false, false).unwrap();
+
+// let database = Arc::new(notmuch::Database::create(&mailbox.path()).unwrap());
+// let message = <notmuch::Database as notmuch::DatabaseExt>::index_file(database.clone(), &filename, None).unwrap();
+// let properties = <notmuch::Message as notmuch::MessageExt>::properties(&message, false);
+
+// Self {
+// mailbox,
+// database,
+// maildir_msg: (msgid, filename),
+// message
+// }
+// }
+// }
+
+
+mod properties {
+ use super::*;
+
+ #[test]
+ fn test_add_single() {
+ let msg = MessageFixture::new();
+ msg.message.add_property(&"foo", &"bar").unwrap();
+ assert_eq!(msg.message.property(&"foo", true).unwrap(), "bar");
+
+ msg.message.add_property(&"bar", &"baz").unwrap();
+ assert_eq!(msg.message.property(&"bar", true).unwrap(), "baz");
+ }
+
+ #[test]
+ fn test_add_dup() {
+ let msg = MessageFixture::new();
+ msg.message.add_property(&"foo", &"bar").unwrap();
+ msg.message.add_property(&"foo", &"baz").unwrap();
+
+ assert_eq!(msg.message.property(&"foo", true).unwrap(), "bar");
+
+ let props = msg.message.properties(&"foo", true);
+ let expect = vec![("foo", "bar"), ("foo", "baz")];
+ for (&(ek, ev), (pk, pv)) in expect.iter().zip(props) {
+ assert_eq!(ek, pk);
+ assert_eq!(ev, pv);
+ }
+ }
+
+ #[test]
+ fn test_len() {
+ let msg = MessageFixture::new();
+ msg.message.add_property(&"foo", &"a").unwrap();
+ msg.message.add_property(&"foo", &"b").unwrap();
+ msg.message.add_property(&"bar", &"a").unwrap();
+
+ let num_props = msg.message.properties(&"", false).count();
+ assert_eq!(num_props, 3);
+
+ let mut prop_keys: Vec<String> = msg.message.properties(&"", false).map(|x| x.0).collect();
+ prop_keys.sort();
+ prop_keys.dedup();
+ assert_eq!(prop_keys.len(), 2);
+
+ let mut prop_vals: Vec<String> = msg.message.properties(&"", false).map(|x| x.1).collect();
+ prop_vals.sort();
+ prop_vals.dedup();
+ assert_eq!(prop_vals.len(), 2);
+ }
+
+ #[test]
+ fn test_remove() {
+ let msg = MessageFixture::new();
+ msg.message.add_property(&"foo", &"a").unwrap();
+ msg.message.add_property(&"foo", &"b").unwrap();
+
+ msg.message.remove_property(&"foo", &"a").unwrap();
+
+ assert_eq!(msg.message.property(&"foo", true).unwrap(), "b");
+
+ }
+
+}
+
+
+
+
+// def test_del(self, props):
+// props.add('foo', 'a')
+// props.add('foo', 'b')
+// del props['foo']
+// with pytest.raises(KeyError):
+// props['foo']
+
+// def test_remove(self, props):
+// props.add('foo', 'a')
+// props.add('foo', 'b')
+// props.remove('foo', 'a')
+// assert props['foo'] == 'b'
+
+// def test_view_abcs(self, props):
+// assert isinstance(props.keys(), collections.abc.KeysView)
+// assert isinstance(props.values(), collections.abc.ValuesView)
+// assert isinstance(props.items(), collections.abc.ItemsView)
+
+// def test_pop(self, props):
+// props.add('foo', 'a')
+// props.add('foo', 'b')
+// val = props.pop('foo')
+// assert val == 'a'
+
+// def test_pop_default(self, props):
+// with pytest.raises(KeyError):
+// props.pop('foo')
+// assert props.pop('foo', 'default') == 'default'
+
+// def test_popitem(self, props):
+// props.add('foo', 'a')
+// assert props.popitem() == ('foo', 'a')
+// with pytest.raises(KeyError):
+// props.popitem()
+
+// def test_clear(self, props):
+// props.add('foo', 'a')
+// props.clear()
+// assert len(props) == 0
+
+// def test_getall(self, props):
+// props.add('foo', 'a')
+// assert set(props.getall('foo')) == {('foo', 'a')}
+
+// def test_getall_prefix(self, props):
+// props.add('foo', 'a')
+// props.add('foobar', 'b')
+// assert set(props.getall('foo')) == {('foo', 'a'), ('foobar', 'b')}
+
+// def test_getall_exact(self, props):
+// props.add('foo', 'a')
+// props.add('foobar', 'b')
+// assert set(props.getall('foo', exact=True)) == {('foo', 'a')}
diff --git a/tests/test_thread.rs b/tests/test_thread.rs
new file mode 100644
index 0000000..0909082
--- /dev/null
+++ b/tests/test_thread.rs
@@ -0,0 +1,108 @@
+use std::sync::Arc;
+use fixtures::{NotmuchCommand, MailBox};
+
+
+struct ThreadFixture {
+ // Return a single thread with 2 messages
+ pub mailbox: MailBox,
+ pub thread: notmuch::Thread<'static, 'static>,
+}
+
+impl ThreadFixture {
+ pub fn new() -> Self{
+ let mailbox = MailBox::new();
+
+ let (msgid, _) = mailbox.deliver(None, Some("foo".to_string()), None, None, vec![], true, None, false, false, false).unwrap();
+ mailbox.deliver(None, Some("bar".to_string()), None, None, vec![("In-Reply-To".to_string(), format!("<{}>", msgid))], true, None, false, false, false).unwrap();
+
+ let cmd = NotmuchCommand::new(&mailbox.path());
+ cmd.run(vec!["new"]).unwrap();
+
+ let mut threads = {
+ let database = Arc::new(notmuch::Database::open(&mailbox.path(), notmuch::DatabaseMode::ReadWrite).unwrap());
+
+ let query = notmuch::Query::create(database.clone(), &"foo".to_string()).unwrap();
+
+ <notmuch::Query as notmuch::QueryExt>::search_threads(query).unwrap()
+ };
+ let thread = threads.next().unwrap();
+
+ Self {
+ mailbox,
+ thread
+ }
+ }
+}
+
+#[test]
+fn test_threadid() {
+ let thread = ThreadFixture::new();
+ assert!(!thread.thread.id().is_empty());
+}
+
+#[test]
+fn test_len() {
+ let thread = ThreadFixture::new();
+
+ assert_eq!(thread.thread.total_messages(), 2);
+}
+
+#[test]
+fn test_toplevel() {
+ let thread = ThreadFixture::new();
+ let msgs = thread.thread.toplevel_messages();
+
+ assert_eq!(msgs.count(), 1);
+}
+
+
+#[test]
+fn test_toplevel_reply() {
+ let thread = ThreadFixture::new();
+ let msg = thread.thread.toplevel_messages().next().unwrap();
+
+ assert_eq!(msg.replies().count(), 1);
+}
+
+#[test]
+fn test_iter() {
+ let thread = ThreadFixture::new();
+ let msg_count0 = thread.thread.messages().count() as i32;
+ let msg_count1 = thread.thread.total_messages();
+
+ assert_eq!(msg_count0, msg_count1);
+}
+
+#[test]
+fn test_matched() {
+ let thread = ThreadFixture::new();
+ assert_eq!(thread.thread.matched_messages(), 1);
+}
+
+
+#[test]
+fn test_authors() {
+ let thread = ThreadFixture::new();
+
+ assert_eq!(thread.thread.authors(), vec!["src@example.com".to_string()]);
+}
+
+
+#[test]
+fn test_subject() {
+ let thread = ThreadFixture::new();
+
+ println!("{:?}", thread.thread.subject());
+ assert_eq!(thread.thread.subject(), "Test mail");
+}
+
+
+
+#[test]
+fn test_tags() {
+ let thread = ThreadFixture::new();
+
+ let tags: Vec<String> = thread.thread.tags().collect();
+ assert!(tags.iter().any(|x| x == "inbox"));
+}
+ \ No newline at end of file