diff options
| author | Dirk Van Haerenborgh <vhdirk@gmail.com> | 2019-11-14 19:22:38 +0100 |
|---|---|---|
| committer | Dirk Van Haerenborgh <vhdirk@gmail.com> | 2019-11-14 19:22:38 +0100 |
| commit | cc6896cca0839f5d97c5daee8ffba824c3c0d229 (patch) | |
| tree | 991e348c590f3da671a1acc9ebd4f57cd497f974 | |
| parent | 1e060f14736922bfbd065a2ac611c64b9e2f5104 (diff) | |
| download | mail-cc6896cca0839f5d97c5daee8ffba824c3c0d229.tar.gz | |
add more tests
| -rw-r--r-- | .travis.yml | 11 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/ffi.rs | 18 | ||||
| -rw-r--r-- | src/message.rs | 65 | ||||
| -rw-r--r-- | src/thread.rs | 4 | ||||
| -rw-r--r-- | tests/fixtures.rs | 18 | ||||
| -rw-r--r-- | tests/lib.rs | 2 | ||||
| -rw-r--r-- | tests/test_database.rs | 44 | ||||
| -rw-r--r-- | tests/test_message.rs | 316 | ||||
| -rw-r--r-- | tests/test_thread.rs | 108 |
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 @@ -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" } @@ -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 |
