mirror of https://github.com/djcb/mu.git
parent
63521300a3
commit
13f0e24241
|
@ -88,9 +88,10 @@ coverage: $(COVERAGE_BUILDDIR)
|
||||||
$(NINJA) -C $(COVERAGE_BUILDDIR) test
|
$(NINJA) -C $(COVERAGE_BUILDDIR) test
|
||||||
lcov --capture --directory . --output-file $(covfile)
|
lcov --capture --directory . --output-file $(covfile)
|
||||||
@lcov --remove $(covfile) '/usr/*' '*guile*' '*thirdparty*' '*/tests/*' '*mime-object*' --output $(covfile)
|
@lcov --remove $(covfile) '/usr/*' '*guile*' '*thirdparty*' '*/tests/*' '*mime-object*' --output $(covfile)
|
||||||
|
@lcov --remove $(covfile) '*mu/*' --output $(covfile)
|
||||||
@mkdir -p $(COVERAGE_BUILDDIR)/meson-logs/coverage
|
@mkdir -p $(COVERAGE_BUILDDIR)/meson-logs/coverage
|
||||||
@genhtml $(covfile) --output-directory $(COVERAGE_BUILDDIR)/meson-logs/coverage/
|
@genhtml $(covfile) --output-directory $(COVERAGE_BUILDDIR)/meson-logs/coverage/
|
||||||
@echo "coverage report at: file://$(COVERAGE_BUILDDIR)/meson/logs/coverage/index.html"
|
@echo "coverage report at: file://$(COVERAGE_BUILDDIR)/meson-logs/coverage/index.html"
|
||||||
dist: $(BUILDDIR)
|
dist: $(BUILDDIR)
|
||||||
@cd $(BUILDDIR); $(MESON) dist
|
@cd $(BUILDDIR); $(MESON) dist
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,30 @@ test_encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_sender()
|
||||||
|
{
|
||||||
|
Contact c{"aa@example.com", "Anders Ångström",
|
||||||
|
Contact::Type::Sender, 54321};
|
||||||
|
|
||||||
|
assert_equal(c.email, "aa@example.com");
|
||||||
|
assert_equal(c.name, "Anders Ångström");
|
||||||
|
g_assert_false(c.personal);
|
||||||
|
g_assert_cmpuint(c.frequency,==,1);
|
||||||
|
g_assert_cmpuint(c.message_date,==,54321);
|
||||||
|
|
||||||
|
g_assert_false(!!c.field_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_misc()
|
||||||
|
{
|
||||||
|
g_assert_false(!!contact_type_from_field_id(Field::Id::Subject));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
@ -180,6 +204,9 @@ main(int argc, char* argv[])
|
||||||
g_test_add_func("/message/contact/ctor-cleanup", test_ctor_cleanup);
|
g_test_add_func("/message/contact/ctor-cleanup", test_ctor_cleanup);
|
||||||
g_test_add_func("/message/contact/encode", test_encode);
|
g_test_add_func("/message/contact/encode", test_encode);
|
||||||
|
|
||||||
|
g_test_add_func("/message/contact/sender", test_sender);
|
||||||
|
g_test_add_func("/message/contact/misc", test_misc);
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
#endif /*BUILD_TESTS*/
|
#endif /*BUILD_TESTS*/
|
||||||
|
|
|
@ -124,12 +124,17 @@ Message::Message(const std::string& text, const std::string& path,
|
||||||
Message::Options opts):
|
Message::Options opts):
|
||||||
priv_{std::make_unique<Private>(opts)}
|
priv_{std::make_unique<Private>(opts)}
|
||||||
{
|
{
|
||||||
|
if (text.empty())
|
||||||
|
throw Error{Error::Code::InvalidArgument, "text must not be empty"};
|
||||||
|
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
auto xpath{to_string_opt_gchar(g_canonicalize_filename(path.c_str(), {}))};
|
auto xpath{to_string_opt_gchar(g_canonicalize_filename(path.c_str(), {}))};
|
||||||
if (xpath)
|
if (xpath)
|
||||||
priv_->doc.add(Field::Id::Path, std::move(xpath.value()));
|
priv_->doc.add(Field::Id::Path, std::move(xpath.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv_->ctime = ::time({});
|
||||||
|
|
||||||
priv_->doc.add(Field::Id::Size, static_cast<int64_t>(text.size()));
|
priv_->doc.add(Field::Id::Size, static_cast<int64_t>(text.size()));
|
||||||
|
|
||||||
init_gmime();
|
init_gmime();
|
||||||
|
@ -727,9 +732,10 @@ fill_document(Message::Private& priv)
|
||||||
case Field::Id::XBodyHtml:
|
case Field::Id::XBodyHtml:
|
||||||
doc.add(field.id, priv.body_html);
|
doc.add(field.id, priv.body_html);
|
||||||
break;
|
break;
|
||||||
/* ignore */
|
/* LCOV_EXCL_START */
|
||||||
case Field::Id::_count_:
|
case Field::Id::_count_:
|
||||||
break;
|
break;
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
@ -739,27 +745,21 @@ fill_document(Message::Private& priv)
|
||||||
Option<std::string>
|
Option<std::string>
|
||||||
Message::header(const std::string& header_field) const
|
Message::header(const std::string& header_field) const
|
||||||
{
|
{
|
||||||
if (!load_mime_message())
|
load_mime_message();
|
||||||
return Nothing;
|
|
||||||
|
|
||||||
return priv_->mime_msg->header(header_field);
|
return priv_->mime_msg->header(header_field);
|
||||||
}
|
}
|
||||||
|
|
||||||
Option<std::string>
|
Option<std::string>
|
||||||
Message::body_text() const
|
Message::body_text() const
|
||||||
{
|
{
|
||||||
if (!load_mime_message())
|
load_mime_message();
|
||||||
return {};
|
|
||||||
|
|
||||||
return priv_->body_txt;
|
return priv_->body_txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Option<std::string>
|
Option<std::string>
|
||||||
Message::body_html() const
|
Message::body_html() const
|
||||||
{
|
{
|
||||||
if (!load_mime_message())
|
load_mime_message();
|
||||||
return {};
|
|
||||||
|
|
||||||
return priv_->body_html;
|
return priv_->body_html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,9 +77,13 @@ public:
|
||||||
return Ok(Message{path,opts});
|
return Ok(Message{path,opts});
|
||||||
} catch (Error& err) {
|
} catch (Error& err) {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
} catch (...) {
|
|
||||||
return Err(Mu::Error(Error::Code::Message, "failed to create message"));
|
|
||||||
}
|
}
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
catch (...) {
|
||||||
|
return Err(Mu::Error(Error::Code::Message,
|
||||||
|
"failed to create message from path"));
|
||||||
|
}
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a message based on a Xapian::Document
|
* Construct a message based on a Xapian::Document
|
||||||
|
@ -92,13 +96,18 @@ public:
|
||||||
return Ok(Message{std::move(doc)});
|
return Ok(Message{std::move(doc)});
|
||||||
} catch (Error& err) {
|
} catch (Error& err) {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
} catch (...) {
|
|
||||||
return Err(Mu::Error(Error::Code::Message, "failed to create message"));
|
|
||||||
}
|
}
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
catch (...) {
|
||||||
|
return Err(Mu::Error(Error::Code::Message,
|
||||||
|
"failed to create message from document"));
|
||||||
|
}
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a message from a string. This is mostly useful for testing.
|
* Construct a message from a string. This is mostly useful for testing.
|
||||||
|
*
|
||||||
* @param text message text
|
* @param text message text
|
||||||
* @param path path to message - optional; path does not have to exist.
|
* @param path path to message - optional; path does not have to exist.
|
||||||
* @param opts options
|
* @param opts options
|
||||||
|
@ -111,10 +120,13 @@ public:
|
||||||
return Ok(Message{text, path, opts});
|
return Ok(Message{text, path, opts});
|
||||||
} catch (Error& err) {
|
} catch (Error& err) {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
} catch (...) {
|
}
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
catch (...) {
|
||||||
return Err(Mu::Error(Error::Code::Message,
|
return Err(Mu::Error(Error::Code::Message,
|
||||||
"failed to create message from text"));
|
"failed to create message from text"));
|
||||||
}
|
}
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DTOR
|
* DTOR
|
||||||
|
@ -233,9 +245,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the last change-time (ctime) for this message
|
* get the last change-time this message. For path/document-based
|
||||||
|
* messages this corresponds with the ctime of the underlying file; for
|
||||||
|
* the text-based ones (as used for testing) it is the creation time.
|
||||||
*
|
*
|
||||||
* @return chnage time or 0 if unknown
|
* @return last-change time or 0 if unknown
|
||||||
*/
|
*/
|
||||||
::time_t changed() const {
|
::time_t changed() const {
|
||||||
return static_cast<::time_t>(document().integer_value(Field::Id::Changed));
|
return static_cast<::time_t>(document().integer_value(Field::Id::Changed));
|
||||||
|
|
|
@ -65,7 +65,6 @@ goto * instructions[pOp->opcode];
|
||||||
test_message_1,
|
test_message_1,
|
||||||
"/home/test/Maildir/inbox/cur/1649279256.107710_1.evergrey:2,S")};
|
"/home/test/Maildir/inbox/cur/1649279256.107710_1.evergrey:2,S")};
|
||||||
g_assert_true(!!message);
|
g_assert_true(!!message);
|
||||||
|
|
||||||
assert_equal(message->path(),
|
assert_equal(message->path(),
|
||||||
"/home/test/Maildir/inbox/cur/1649279256.107710_1.evergrey:2,S");
|
"/home/test/Maildir/inbox/cur/1649279256.107710_1.evergrey:2,S");
|
||||||
g_assert_true(message->maildir().empty());
|
g_assert_true(message->maildir().empty());
|
||||||
|
@ -99,6 +98,10 @@ goto * instructions[pOp->opcode];
|
||||||
g_assert_true(message->priority() == Priority::Low);
|
g_assert_true(message->priority() == Priority::Low);
|
||||||
g_assert_cmpuint(message->size(),==,::strlen(test_message_1));
|
g_assert_cmpuint(message->size(),==,::strlen(test_message_1));
|
||||||
|
|
||||||
|
/* text-based message use time({}) as their changed-time */
|
||||||
|
g_assert_cmpuint(message->changed() - ::time({}), >=, 0);
|
||||||
|
g_assert_cmpuint(message->changed() - ::time({}), <=, 2);
|
||||||
|
|
||||||
g_assert_true(message->references().empty());
|
g_assert_true(message->references().empty());
|
||||||
|
|
||||||
assert_equal(message->subject(),
|
assert_equal(message->subject(),
|
||||||
|
@ -177,7 +180,7 @@ World!
|
||||||
|
|
||||||
auto message{Message::make_from_text(msg_text)};
|
auto message{Message::make_from_text(msg_text)};
|
||||||
g_assert_true(!!message);
|
g_assert_true(!!message);
|
||||||
|
g_assert_true(message->has_mime_message());
|
||||||
g_assert_true(message->path().empty());
|
g_assert_true(message->path().empty());
|
||||||
|
|
||||||
g_assert_true(message->bcc().empty());
|
g_assert_true(message->bcc().empty());
|
||||||
|
@ -202,6 +205,10 @@ World!
|
||||||
g_assert_true(message->priority() == Priority::Normal);
|
g_assert_true(message->priority() == Priority::Normal);
|
||||||
g_assert_cmpuint(message->size(),==,::strlen(msg_text));
|
g_assert_cmpuint(message->size(),==,::strlen(msg_text));
|
||||||
|
|
||||||
|
/* text-based message use time({}) as their changed-time */
|
||||||
|
g_assert_cmpuint(message->changed() - ::time({}), >=, 0);
|
||||||
|
g_assert_cmpuint(message->changed() - ::time({}), <=, 2);
|
||||||
|
|
||||||
assert_equal(message->subject(), "ättächmeñts");
|
assert_equal(message->subject(), "ättächmeñts");
|
||||||
|
|
||||||
const auto cache_path{message->cache_path()};
|
const auto cache_path{message->cache_path()};
|
||||||
|
@ -565,6 +572,20 @@ Moi,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_message_fail ()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto msg = Message::make_from_path("/root/non-existent-path-12345");
|
||||||
|
g_assert_false(!!msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto msg = Message::make_from_text("", "");
|
||||||
|
g_assert_false(!!msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
@ -582,6 +603,9 @@ main(int argc, char* argv[])
|
||||||
test_message_multipart_mixed_rfc822);
|
test_message_multipart_mixed_rfc822);
|
||||||
g_test_add_func("/message/message/detect-attachment",
|
g_test_add_func("/message/message/detect-attachment",
|
||||||
test_message_detect_attachment);
|
test_message_detect_attachment);
|
||||||
|
g_test_add_func("/message/message/fail",
|
||||||
|
test_message_fail);
|
||||||
|
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,9 +308,6 @@ ContactsCache::for_each(const EachContactFunc& each_contact) const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l_{priv_->mtx_};
|
std::lock_guard<std::mutex> l_{priv_->mtx_};
|
||||||
|
|
||||||
if (!each_contact)
|
|
||||||
return; // nothing to do
|
|
||||||
|
|
||||||
// first sort them for 'rank'
|
// first sort them for 'rank'
|
||||||
ContactSet sorted;
|
ContactSet sorted;
|
||||||
for (const auto& item : priv_->contacts_)
|
for (const auto& item : priv_->contacts_)
|
||||||
|
@ -409,6 +406,39 @@ test_mu_contacts_cache_personal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_mu_contacts_cache_foreach()
|
||||||
|
{
|
||||||
|
Mu::ContactsCache ccache("");
|
||||||
|
ccache.add(Mu::Contact{"a@example.com", "a", 123, true, 1000, 0});
|
||||||
|
ccache.add(Mu::Contact{"b@example.com", "b", 456, true, 1000, 0});
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t n{};
|
||||||
|
g_assert_false(ccache.empty());
|
||||||
|
g_assert_cmpuint(ccache.size(),==,2);
|
||||||
|
ccache.for_each([&](auto&& contact) { ++n; return false; });
|
||||||
|
g_assert_cmpuint(n,==,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t n{};
|
||||||
|
g_assert_false(ccache.empty());
|
||||||
|
g_assert_cmpuint(ccache.size(),==,2);
|
||||||
|
ccache.for_each([&](auto&& contact) { ++n; return true; });
|
||||||
|
g_assert_cmpuint(n,==,2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t n{};
|
||||||
|
ccache.clear();
|
||||||
|
g_assert_true(ccache.empty());
|
||||||
|
g_assert_cmpuint(ccache.size(),==,0);
|
||||||
|
ccache.for_each([&](auto&& contact) { ++n; return true; });
|
||||||
|
g_assert_cmpuint(n,==,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -418,6 +448,7 @@ test_mu_contacts_cache_sort()
|
||||||
std::string str;
|
std::string str;
|
||||||
if (g_test_verbose())
|
if (g_test_verbose())
|
||||||
g_print("contacts-cache:\n");
|
g_print("contacts-cache:\n");
|
||||||
|
|
||||||
ccache.for_each([&](auto&& contact) {
|
ccache.for_each([&](auto&& contact) {
|
||||||
if (g_test_verbose())
|
if (g_test_verbose())
|
||||||
g_print("\t- %s\n", contact.display_name().c_str());
|
g_print("\t- %s\n", contact.display_name().c_str());
|
||||||
|
@ -427,7 +458,6 @@ test_mu_contacts_cache_sort()
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const auto now{std::time({})};
|
const auto now{std::time({})};
|
||||||
|
|
||||||
// "first" means more relevant
|
// "first" means more relevant
|
||||||
|
@ -473,6 +503,7 @@ main(int argc, char* argv[])
|
||||||
|
|
||||||
g_test_add_func("/lib/contacts-cache/base", test_mu_contacts_cache_base);
|
g_test_add_func("/lib/contacts-cache/base", test_mu_contacts_cache_base);
|
||||||
g_test_add_func("/lib/contacts-cache/personal", test_mu_contacts_cache_personal);
|
g_test_add_func("/lib/contacts-cache/personal", test_mu_contacts_cache_personal);
|
||||||
|
g_test_add_func("/lib/contacts-cache/for-each", test_mu_contacts_cache_foreach);
|
||||||
g_test_add_func("/lib/contacts-cache/sort", test_mu_contacts_cache_sort);
|
g_test_add_func("/lib/contacts-cache/sort", test_mu_contacts_cache_sort);
|
||||||
|
|
||||||
g_log_set_handler(
|
g_log_set_handler(
|
||||||
|
|
|
@ -383,7 +383,6 @@ public:
|
||||||
*
|
*
|
||||||
* @return iterator
|
* @return iterator
|
||||||
*/
|
*/
|
||||||
iterator begin() { return QueryResultsIterator(mset_.begin(), query_matches_); }
|
|
||||||
const iterator begin() const { return QueryResultsIterator(mset_.begin(), query_matches_); }
|
const iterator begin() const { return QueryResultsIterator(mset_.begin(), query_matches_); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -391,7 +390,6 @@ public:
|
||||||
*
|
*
|
||||||
* @return iterator
|
* @return iterator
|
||||||
*/
|
*/
|
||||||
iterator end() { return QueryResultsIterator(mset_.end(), query_matches_); }
|
|
||||||
const_iterator end() const { return QueryResultsIterator(mset_.end(), query_matches_); }
|
const_iterator end() const { return QueryResultsIterator(mset_.end(), query_matches_); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -70,9 +70,13 @@ public:
|
||||||
|
|
||||||
} catch (const Mu::Error& me) {
|
} catch (const Mu::Error& me) {
|
||||||
return Err(me);
|
return Err(me);
|
||||||
} catch (...) {
|
}
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
catch (...) {
|
||||||
return Err(Error::Code::Internal, "failed to create store");
|
return Err(Error::Code::Internal, "failed to create store");
|
||||||
}
|
}
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
size_t max_message_size{};
|
size_t max_message_size{};
|
||||||
|
@ -99,9 +103,12 @@ public:
|
||||||
|
|
||||||
} catch (const Mu::Error& me) {
|
} catch (const Mu::Error& me) {
|
||||||
return Err(me);
|
return Err(me);
|
||||||
} catch (...) {
|
|
||||||
return Err(Error::Code::Internal, "failed to create store");
|
|
||||||
}
|
}
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
catch (...) {
|
||||||
|
return Err(Error::Code::Internal, "failed to create new store");
|
||||||
|
}
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move CTOR
|
* Move CTOR
|
||||||
|
|
|
@ -278,6 +278,77 @@ test_determine_target_ok(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_determine_target_fail(void)
|
||||||
|
{
|
||||||
|
struct TestCase {
|
||||||
|
std::string old_path;
|
||||||
|
std::string root_maildir;
|
||||||
|
std::string target_maildir;
|
||||||
|
Flags new_flags;
|
||||||
|
bool new_name;
|
||||||
|
std::string expected;
|
||||||
|
};
|
||||||
|
const std::vector<TestCase> testcases = {
|
||||||
|
TestCase{ /* fail: no absolute path */
|
||||||
|
"../foo/Maildir/test/cur/123456:2,FR-not-absolute",
|
||||||
|
"/home/foo/Maildir",
|
||||||
|
{},
|
||||||
|
Flags::Seen | Flags::Passed,
|
||||||
|
false,
|
||||||
|
"/home/foo/Maildir/test/cur/123456:2,PS"
|
||||||
|
},
|
||||||
|
|
||||||
|
TestCase{ /* fail: no absolute root */
|
||||||
|
"/home/foo/Maildir/test/cur/123456:2,FR",
|
||||||
|
"../foo/Maildir-not-absolute",
|
||||||
|
{},
|
||||||
|
Flags::New,
|
||||||
|
false,
|
||||||
|
"/home/foo/Maildir/test/new/123456"
|
||||||
|
},
|
||||||
|
|
||||||
|
TestCase{ /* fail: maildir must start with '/' */
|
||||||
|
"/home/foo/Maildir/test/cur/123456",
|
||||||
|
"/home/foo/Maildir",
|
||||||
|
"mymaildirwithoutslash",
|
||||||
|
Flags::Seen | Flags::Flagged,
|
||||||
|
false,
|
||||||
|
"/home/foo/Maildir/test/cur/123456:2,FS"
|
||||||
|
},
|
||||||
|
|
||||||
|
TestCase{ /* fail: path must be below maildir */
|
||||||
|
"/home/foo/Maildir/test/cur/123456:2,FR",
|
||||||
|
"/home/bar/Maildir",
|
||||||
|
"/test2",
|
||||||
|
Flags::Flagged | Flags::Replied,
|
||||||
|
false,
|
||||||
|
"/home/foo/Maildir/test2/cur/123456:2,FR"
|
||||||
|
},
|
||||||
|
TestCase{ /* fail: New cannot be combined */
|
||||||
|
"/home/foo/Maildir/test/new/123456",
|
||||||
|
"/home/foo/Maildir",
|
||||||
|
{},
|
||||||
|
Flags::New | Flags::Replied,
|
||||||
|
false,
|
||||||
|
"/home/foo/Maildir/test/cur/123456:2,"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto&& testcase: testcases) {
|
||||||
|
const auto res = maildir_determine_target(
|
||||||
|
testcase.old_path,
|
||||||
|
testcase.root_maildir,
|
||||||
|
testcase.target_maildir,
|
||||||
|
testcase.new_flags,
|
||||||
|
testcase.new_name);
|
||||||
|
g_assert_false(!!res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_maildir_get_new_path_01(void)
|
test_maildir_get_new_path_01(void)
|
||||||
{
|
{
|
||||||
|
@ -428,6 +499,8 @@ main(int argc, char* argv[])
|
||||||
|
|
||||||
g_test_add_func("/mu-maildir/mu-maildir-determine-target-ok",
|
g_test_add_func("/mu-maildir/mu-maildir-determine-target-ok",
|
||||||
test_determine_target_ok);
|
test_determine_target_ok);
|
||||||
|
g_test_add_func("/mu-maildir/mu-maildir-determine-target-fail",
|
||||||
|
test_determine_target_fail);
|
||||||
|
|
||||||
// /* get/set flags */
|
// /* get/set flags */
|
||||||
g_test_add_func("/mu-maildir/mu-maildir-get-new-path-01", test_maildir_get_new_path_01);
|
g_test_add_func("/mu-maildir/mu-maildir-get-new-path-01", test_maildir_get_new_path_01);
|
||||||
|
|
|
@ -139,6 +139,12 @@ goto * instructions[pOp->opcode];
|
||||||
assert_valid_result(docid);
|
assert_valid_result(docid);
|
||||||
g_assert_cmpuint(store->size(),==, 1);
|
g_assert_cmpuint(store->size(),==, 1);
|
||||||
|
|
||||||
|
/* ensure 'update' dtrt, i.e., nothing. */
|
||||||
|
const auto docid2 = store->update_message(*message, *docid);
|
||||||
|
assert_valid_result(docid2);
|
||||||
|
g_assert_cmpuint(store->size(),==, 1);
|
||||||
|
g_assert_cmpuint(*docid,==,*docid2);
|
||||||
|
|
||||||
auto msg2{store->find_message(*docid)};
|
auto msg2{store->find_message(*docid)};
|
||||||
g_assert_true(!!msg2);
|
g_assert_true(!!msg2);
|
||||||
assert_equal(message->path(), msg2->path());
|
assert_equal(message->path(), msg2->path());
|
||||||
|
@ -228,6 +234,11 @@ World!
|
||||||
// for (auto&& term = msg2->document().xapian_document().termlist_begin();
|
// for (auto&& term = msg2->document().xapian_document().termlist_begin();
|
||||||
// term != msg2->document().xapian_document().termlist_end(); ++term)
|
// term != msg2->document().xapian_document().termlist_end(); ++term)
|
||||||
// g_message(">>> %s", (*term).c_str());
|
// g_message(">>> %s", (*term).c_str());
|
||||||
|
|
||||||
|
const auto stats{store->statistics()};
|
||||||
|
g_assert_cmpuint(stats.size,==,store->size());
|
||||||
|
g_assert_cmpuint(stats.last_index,==,0);
|
||||||
|
g_assert_cmpuint(stats.last_change,>=,::time({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,6 +330,23 @@ Yes, that would be excellent.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_store_fail()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto store = Store::make("/root/non-existent-path/12345");
|
||||||
|
g_assert_false(!!store);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto store = Store::make_new("/../../root/non-existent-path/12345",
|
||||||
|
"/../../root/non-existent-path/54321",
|
||||||
|
{}, {});
|
||||||
|
g_assert_false(!!store);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
|
@ -331,8 +359,8 @@ main(int argc, char* argv[])
|
||||||
test_message_mailing_list);
|
test_message_mailing_list);
|
||||||
g_test_add_func("/store/message/attachments",
|
g_test_add_func("/store/message/attachments",
|
||||||
test_message_attachments);
|
test_message_attachments);
|
||||||
g_test_add_func("/store/index/move",
|
g_test_add_func("/store/index/move", test_index_move);
|
||||||
test_index_move);
|
g_test_add_func("/store/index/fail", test_store_fail);
|
||||||
|
|
||||||
if (!g_test_verbose())
|
if (!g_test_verbose())
|
||||||
g_log_set_handler(
|
g_log_set_handler(
|
||||||
|
|
|
@ -531,7 +531,8 @@ Mu::parse_size(const std::string& val, bool is_first)
|
||||||
if (val.empty())
|
if (val.empty())
|
||||||
return is_first ? 0 : std::numeric_limits<int64_t>::max();
|
return is_first ? 0 : std::numeric_limits<int64_t>::max();
|
||||||
|
|
||||||
rx = g_regex_new("(\\d+)(b|k|kb|m|mb|g|gb)?", G_REGEX_CASELESS, (GRegexMatchFlags)0, NULL);
|
rx = g_regex_new("^(\\d+)(b|k|kb|m|mb|g|gb)?$",
|
||||||
|
G_REGEX_CASELESS, (GRegexMatchFlags)0, NULL);
|
||||||
minfo = NULL;
|
minfo = NULL;
|
||||||
if (g_regex_match(rx, val.c_str(), (GRegexMatchFlags)0, &minfo)) {
|
if (g_regex_match(rx, val.c_str(), (GRegexMatchFlags)0, &minfo)) {
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ test_date_basic()
|
||||||
}
|
}
|
||||||
|
|
||||||
g_setenv("TZ", hki, TRUE);
|
g_setenv("TZ", hki, TRUE);
|
||||||
constexpr std::array<std::tuple<const char*, bool, int64_t>, 9> cases = {{
|
constexpr std::array<std::tuple<const char*, bool/*is_first*/, int64_t>, 13> cases = {{
|
||||||
{"2015-09-18T09:10:23", true, 1442556623},
|
{"2015-09-18T09:10:23", true, 1442556623},
|
||||||
{"1972-12-14T09:10:23", true, 93165023},
|
{"1972-12-14T09:10:23", true, 93165023},
|
||||||
{"1854-11-18T17:10:23", true, 0},
|
{"1854-11-18T17:10:23", true, 0},
|
||||||
|
@ -73,6 +73,12 @@ test_date_basic()
|
||||||
{"2000-02-31T09:10:23", true, 951861599},
|
{"2000-02-31T09:10:23", true, 951861599},
|
||||||
{"2000-02-29T23:59:59", true, 951861599},
|
{"2000-02-29T23:59:59", true, 951861599},
|
||||||
|
|
||||||
|
{"20220602", true, 1654117200},
|
||||||
|
{"20220605", false, 1654462799},
|
||||||
|
|
||||||
|
{"202206", true, 1654030800},
|
||||||
|
{"202206", false, 1656622799},
|
||||||
|
|
||||||
{"2016", true, 1451599200},
|
{"2016", true, 1451599200},
|
||||||
{"2016", false, 1483221599},
|
{"2016", false, 1483221599},
|
||||||
|
|
||||||
|
@ -94,44 +100,55 @@ test_date_basic()
|
||||||
static void
|
static void
|
||||||
test_date_ymwdhMs(void)
|
test_date_ymwdhMs(void)
|
||||||
{
|
{
|
||||||
struct {
|
struct testcase {
|
||||||
std::string expr;
|
std::string expr;
|
||||||
long diff;
|
int64_t diff;
|
||||||
int tolerance;
|
int tolerance;
|
||||||
} tests[] = {{"3h", 3 * 60 * 60, 1},
|
};
|
||||||
|
|
||||||
|
std::array<testcase, 7> cases = {{
|
||||||
|
{"7s", 7, 1},
|
||||||
|
{"3M", 3 * 60, 1},
|
||||||
|
{"3h", 3 * 60 * 60, 1},
|
||||||
{"21d", 21 * 24 * 60 * 60, 3600 + 1},
|
{"21d", 21 * 24 * 60 * 60, 3600 + 1},
|
||||||
{"2w", 2 * 7 * 24 * 60 * 60, 3600 + 1},
|
{"2w", 2 * 7 * 24 * 60 * 60, 3600 + 1},
|
||||||
|
|
||||||
{"2y", 2 * 365 * 24 * 60 * 60, 24 * 3600 + 1},
|
{"2y", 2 * 365 * 24 * 60 * 60, 24 * 3600 + 1},
|
||||||
{"3m", 3 * 30 * 24 * 60 * 60, 3 * 24 * 3600 + 1}};
|
{"3m", 3 * 30 * 24 * 60 * 60, 3 * 24 * 3600 + 1}
|
||||||
|
}};
|
||||||
|
|
||||||
for (auto i = 0; i != G_N_ELEMENTS(tests); ++i) {
|
for (auto&& tcase: cases) {
|
||||||
const auto diff = ::time({}) -
|
const auto date = parse_date_time(tcase.expr, true);
|
||||||
parse_date_time(tests[i].expr, true).value_or(-1);
|
g_assert_true(date);
|
||||||
|
const auto diff = ::time({}) - *date;
|
||||||
if (g_test_verbose())
|
if (g_test_verbose())
|
||||||
std::cerr << tests[i].expr << ' ' << diff << ' ' << tests[i].diff
|
std::cerr << tcase.expr << ' ' << diff << ' ' << tcase.diff << '\n';
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
g_assert_true(tests[i].diff - diff <= tests[i].tolerance);
|
g_assert_true(tcase.diff - diff <= tcase.tolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
//g_assert_true(strtol(Mu::date_to_time_t_string("-1y", true).c_str(), NULL, 10) == 0);
|
// note: perhaps it'd be nice if we'd detect this error;
|
||||||
|
// currently we're being rather tolerant
|
||||||
|
// g_assert_false(!!parse_date_time("25q", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_parse_size()
|
test_parse_size()
|
||||||
{
|
{
|
||||||
constexpr std::array<std::tuple<const char*, bool, int64_t>, 5> cases = {{
|
constexpr std::array<std::tuple<const char*, bool, int64_t>, 6> cases = {{
|
||||||
{ "456", false, 456 },
|
{ "456", false, 456 },
|
||||||
{ "", false, G_MAXINT64 },
|
{ "", false, G_MAXINT64 },
|
||||||
{ "", true, 0 },
|
{ "", true, 0 },
|
||||||
{ "2K", false, 2048 },
|
{ "2K", false, 2048 },
|
||||||
{ "2M", true, 2097152 }
|
{ "2M", true, 2097152 },
|
||||||
|
{ "5G", true, 5368709120 }
|
||||||
}};
|
}};
|
||||||
for(auto&& test: cases) {
|
for(auto&& test: cases) {
|
||||||
g_assert_cmpint(parse_size(std::get<0>(test), std::get<1>(test))
|
g_assert_cmpint(parse_size(std::get<0>(test), std::get<1>(test))
|
||||||
.value_or(-1), ==, std::get<2>(test));
|
.value_or(-1), ==, std::get<2>(test));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_assert_false(!!parse_size("-1", true));
|
||||||
|
g_assert_false(!!parse_size("scoobydoobydoo", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue