diff --git a/lib/mu-msg-doc.cc b/lib/mu-msg-doc.cc index 09c0b6da..21c3c8b0 100644 --- a/lib/mu-msg-doc.cc +++ b/lib/mu-msg-doc.cc @@ -29,6 +29,7 @@ #include "utils/mu-util.h" #include "utils/mu-str.h" #include "utils/mu-date.h" +#include "utils/mu-utils.hh" struct _MuMsgDoc { diff --git a/lib/mu-msg-iter.cc b/lib/mu-msg-iter.cc index 84efa9c2..a401976f 100644 --- a/lib/mu-msg-iter.cc +++ b/lib/mu-msg-iter.cc @@ -33,6 +33,8 @@ #include #include "utils/mu-util.h" +#include "utils/mu-utils.hh" + #include "mu-msg.h" #include "mu-msg-iter.h" #include "mu-threader.h" diff --git a/lib/utils/mu-error.hh b/lib/utils/mu-error.hh index c69b368d..18692c9e 100644 --- a/lib/utils/mu-error.hh +++ b/lib/utils/mu-error.hh @@ -29,6 +29,7 @@ namespace Mu { struct Error final: public std::runtime_error { enum struct Code { AccessDenied, + File, Internal, InvalidArgument, NotFound, diff --git a/lib/utils/mu-util.h b/lib/utils/mu-util.h index eae74d49..d6ef31a4 100644 --- a/lib/utils/mu-util.h +++ b/lib/utils/mu-util.h @@ -294,85 +294,6 @@ typedef gpointer XapianEnquire; } while (0) -/** - * - * don't repeat these catch blocks everywhere... - * - */ - -#define MU_STORE_CATCH_BLOCK_RETURN(GE,R) \ - catch (const MuStoreError& merr) { \ - mu_util_g_set_error ((GE), \ - merr.mu_error(), "%s", \ - merr.what().c_str()); \ - return (R); \ - } \ - - -#define MU_XAPIAN_CATCH_BLOCK \ - catch (const Xapian::Error &xerr) { \ - g_critical ("%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const std::runtime_error& re) { \ - g_critical ("%s: error: %s", __func__, re.what()); \ - } catch (...) { \ - g_critical ("%s: caught exception", __func__); \ - } - -#define MU_XAPIAN_CATCH_BLOCK_G_ERROR(GE,E) \ - catch (const Xapian::DatabaseLockError &xerr) { \ - mu_util_g_set_error ((GE), \ - MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK, \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const Xapian::DatabaseError &xerr) { \ - mu_util_g_set_error ((GE),MU_ERROR_XAPIAN, \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const Xapian::Error &xerr) { \ - mu_util_g_set_error ((GE),(E), \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - } catch (const std::runtime_error& ex) { \ - mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ - "%s: error: %s", __func__, ex.what()); \ - \ - } catch (...) { \ - mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ - "%s: caught exception", __func__); \ - } - - -#define MU_XAPIAN_CATCH_BLOCK_RETURN(R) \ - catch (const Xapian::Error &xerr) { \ - g_critical ("%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - return (R); \ - } catch (const std::runtime_error& ex) { \ - g_critical("%s: error: %s", __func__, ex.what()); \ - return (R); \ - } catch (...) { \ - g_critical ("%s: caught exception", __func__); \ - return (R); \ - } - -#define MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(GE,E,R) \ - catch (const Xapian::Error &xerr) { \ - mu_util_g_set_error ((GE),(E), \ - "%s: xapian error '%s'", \ - __func__, xerr.get_msg().c_str()); \ - return (R); \ - } catch (const std::runtime_error& ex) { \ - mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ - "%s: error: %s", __func__, ex.what()); \ - return (R); \ - } catch (...) { \ - if ((GE)&&!(*(GE))) \ - mu_util_g_set_error ((GE), \ - (MU_ERROR_INTERNAL), \ - "%s: caught exception", __func__); \ - return (R); \ - } /** * log something in the log file; note, we use G_LOG_LEVEL_INFO diff --git a/lib/utils/mu-utils.cc b/lib/utils/mu-utils.cc index 7a1629ea..e21b032d 100644 --- a/lib/utils/mu-utils.cc +++ b/lib/utils/mu-utils.cc @@ -443,3 +443,30 @@ Mu::size_to_string (const std::string& val, bool is_first) return str; } + + +void +Mu::assert_equal(const std::string& s1, const std::string& s2) +{ + g_assert_cmpstr (s1.c_str(), ==, s2.c_str()); +} + +void +Mu::assert_equal (const Mu::StringVec& v1, const Mu::StringVec& v2) +{ + g_assert_cmpuint(v1.size(), ==, v2.size()); + + for (auto i = 0U; i != v1.size(); ++i) + assert_equal(v1[i], v2[i]); +} + + +void +Mu::allow_warnings() +{ + g_test_log_set_fatal_handler( + [](const char*, GLogLevelFlags, const char*, gpointer) { + return FALSE; + },{}); + +} diff --git a/lib/utils/mu-utils.hh b/lib/utils/mu-utils.hh index 78d18056..77ca897d 100644 --- a/lib/utils/mu-utils.hh +++ b/lib/utils/mu-utils.hh @@ -23,9 +23,12 @@ #include #include #include +#include namespace Mu { +using StringVec = std::vector; + /** * Flatten a string -- downcase and fold diacritics etc. * @@ -89,7 +92,6 @@ std::string format (const char *frm, ...) __attribute__((format(printf, 1, 2))); std::string format (const char *frm, va_list args) __attribute__((format(printf, 1, 0))); - /** * Convert an ISO date to the corresponding time expressed as a string * with a 10-digit time_t @@ -133,6 +135,125 @@ std::string size_to_string (const std::string& sizestr, bool first); */ std::string size_to_string (int64_t size); + +/** + * + * don't repeat these catch blocks everywhere... + * + */ + +#define MU_STORE_CATCH_BLOCK_RETURN(GE,R) \ + catch (const MuStoreError& merr) { \ + mu_util_g_set_error ((GE), \ + merr.mu_error(), "%s", \ + merr.what().c_str()); \ + return (R); \ + } \ + + +#define MU_XAPIAN_CATCH_BLOCK \ + catch (const Xapian::Error &xerr) { \ + g_critical ("%s: xapian error '%s'", \ + __func__, xerr.get_msg().c_str()); \ + } catch (const std::runtime_error& re) { \ + g_critical ("%s: error: %s", __func__, re.what()); \ + } catch (...) { \ + g_critical ("%s: caught exception", __func__); \ + } + +#define MU_XAPIAN_CATCH_BLOCK_G_ERROR(GE,E) \ + catch (const Xapian::DatabaseLockError &xerr) { \ + mu_util_g_set_error ((GE), \ + MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK, \ + "%s: xapian error '%s'", \ + __func__, xerr.get_msg().c_str()); \ + } catch (const Xapian::DatabaseError &xerr) { \ + mu_util_g_set_error ((GE),MU_ERROR_XAPIAN, \ + "%s: xapian error '%s'", \ + __func__, xerr.get_msg().c_str()); \ + } catch (const Xapian::Error &xerr) { \ + mu_util_g_set_error ((GE),(E), \ + "%s: xapian error '%s'", \ + __func__, xerr.get_msg().c_str()); \ + } catch (const std::runtime_error& ex) { \ + mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ + "%s: error: %s", __func__, ex.what()); \ + \ + } catch (...) { \ + mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ + "%s: caught exception", __func__); \ + } + + +#define MU_XAPIAN_CATCH_BLOCK_RETURN(R) \ + catch (const Xapian::Error &xerr) { \ + g_critical ("%s: xapian error '%s'", \ + __func__, xerr.get_msg().c_str()); \ + return (R); \ + } catch (const std::runtime_error& ex) { \ + g_critical("%s: error: %s", __func__, ex.what()); \ + return (R); \ + } catch (...) { \ + g_critical ("%s: caught exception", __func__); \ + return (R); \ + } + +#define MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(GE,E,R) \ + catch (const Xapian::Error &xerr) { \ + mu_util_g_set_error ((GE),(E), \ + "%s: xapian error '%s'", \ + __func__, xerr.get_msg().c_str()); \ + return (R); \ + } catch (const std::runtime_error& ex) { \ + mu_util_g_set_error ((GE),(MU_ERROR_INTERNAL), \ + "%s: error: %s", __func__, ex.what()); \ + return (R); \ + } catch (...) { \ + if ((GE)&&!(*(GE))) \ + mu_util_g_set_error ((GE), \ + (MU_ERROR_INTERNAL), \ + "%s: caught exception", __func__); \ + return (R); \ + } + + + + +/// Allow using enum structs as bitflags +#define MU_TO_NUM(ET,ELM) std::underlying_type_t(ELM) +#define MU_TO_ENUM(ET,NUM) static_cast(NUM) +#define MU_ENABLE_BITOPS(ET) \ + constexpr ET operator& (ET e1, ET e2) { return MU_TO_ENUM(ET,MU_TO_NUM(ET,e1)&MU_TO_NUM(ET,e2)); } \ + constexpr ET operator| (ET e1, ET e2) { return MU_TO_ENUM(ET,MU_TO_NUM(ET,e1)|MU_TO_NUM(ET,e2)); } \ + constexpr ET operator~ (ET e) { return MU_TO_ENUM(ET,~(MU_TO_NUM(ET, e))); } \ + constexpr bool any_of(ET e) { return MU_TO_NUM(ET,e) != 0; } \ + constexpr bool none_of(ET e) { return MU_TO_NUM(ET,e) == 0; } \ + static inline ET& operator&=(ET& e1, ET e2) { return e1 = e1 & e2;} \ + static inline ET& operator|=(ET& e1, ET e2) { return e1 = e1 | e2;} + + +/** + * For unit tests, assert two std::string's are equal. + * + * @param s1 string1 + * @param s2 string2 + */ +void assert_equal(const std::string& s1, const std::string& s2); +/** + * For unit tests, assert that to containers are the same. + * + * @param c1 container1 + * @param c2 container2 + */ +void assert_equal (const StringVec& v1, const StringVec& v2); + +/** + * For unit-tests, allow warnings in the current function. + * + */ +void allow_warnings(); + } // namespace Mu + #endif /* __MU_UTILS_HH__ */ diff --git a/lib/utils/test-utils.cc b/lib/utils/test-utils.cc index c43c2530..27ef3873 100644 --- a/lib/utils/test-utils.cc +++ b/lib/utils/test-utils.cc @@ -156,6 +156,39 @@ test_format () "hello world, 123"); } + +enum struct Bits { None = 0, Bit1 = 1 << 0, Bit2 = 1 << 1 }; +MU_ENABLE_BITOPS(Bits); + +static void +test_define_bitmap() +{ + g_assert_cmpuint((guint)Bits::None,==,(guint)0); + g_assert_cmpuint((guint)Bits::Bit1,==,(guint)1); + g_assert_cmpuint((guint)Bits::Bit2,==,(guint)2); + + g_assert_cmpuint((guint)(Bits::Bit1|Bits::Bit2),==,(guint)3); + g_assert_cmpuint((guint)(Bits::Bit1&Bits::Bit2),==,(guint)0); + + g_assert_cmpuint((guint)(Bits::Bit1&(~Bits::Bit2)),==,(guint)1); + + { + Bits b{Bits::Bit1}; + b|=Bits::Bit2; + g_assert_cmpuint((guint)b,==,(guint)3); + } + + { + Bits b{Bits::Bit1}; + b&=Bits::Bit1; + g_assert_cmpuint((guint)b,==,(guint)1); + } + + +} + + + int main (int argc, char *argv[]) { @@ -167,6 +200,7 @@ main (int argc, char *argv[]) g_test_add_func ("/utils/flatten", test_flatten); g_test_add_func ("/utils/clean", test_clean); g_test_add_func ("/utils/format", test_format); + g_test_add_func ("/utils/define-bitmap", test_define_bitmap); return g_test_run (); }