2022-02-23 08:29:37 +01:00
|
|
|
/*
|
2023-09-17 08:59:38 +02:00
|
|
|
** Copyright (C) 2022-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
2022-02-23 08:29:37 +01:00
|
|
|
**
|
|
|
|
** This program is free software; you can redistribute it and/or modify it
|
|
|
|
** under the terms of the GNU General Public License as published by the
|
|
|
|
** Free Software Foundation; either version 3, or (at your option) any
|
|
|
|
** later version.
|
|
|
|
**
|
|
|
|
** This program is distributed in the hope that it will be useful,
|
|
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
** GNU General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU General Public License
|
|
|
|
** along with this program; if not, write to the Free Software Foundation,
|
|
|
|
** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2022-03-19 17:56:10 +01:00
|
|
|
#include "mu-fields.hh"
|
|
|
|
#include "mu-flags.hh"
|
2022-02-23 08:29:37 +01:00
|
|
|
|
2022-08-10 07:20:58 +02:00
|
|
|
#include "utils/mu-test-utils.hh"
|
|
|
|
|
2022-02-23 08:29:37 +01:00
|
|
|
using namespace Mu;
|
|
|
|
|
2022-03-03 23:02:52 +01:00
|
|
|
std::string
|
2022-03-19 17:56:10 +01:00
|
|
|
Field::xapian_term(const std::string& s) const
|
2022-02-23 08:29:37 +01:00
|
|
|
{
|
2022-04-28 21:53:31 +02:00
|
|
|
const auto start{std::string(1U, xapian_prefix())};
|
|
|
|
if (const auto& size = s.size(); size == 0)
|
|
|
|
return start;
|
2022-02-23 08:29:37 +01:00
|
|
|
|
2022-04-28 21:53:31 +02:00
|
|
|
std::string res{start};
|
|
|
|
res.reserve(s.size() + 10);
|
|
|
|
|
|
|
|
/* slightly optimized common pure-ascii. */
|
|
|
|
if (G_LIKELY(g_str_is_ascii(s.c_str()))) {
|
|
|
|
res += s;
|
|
|
|
for (auto i = 1; res[i]; ++i)
|
|
|
|
res[i] = g_ascii_tolower(res[i]);
|
|
|
|
} else
|
|
|
|
res += utf8_flatten(s);
|
2022-03-03 23:02:52 +01:00
|
|
|
|
2022-04-28 21:53:31 +02:00
|
|
|
if (G_UNLIKELY(res.size() > MaxTermLength))
|
|
|
|
res.erase(MaxTermLength);
|
2022-03-03 23:02:52 +01:00
|
|
|
|
2022-04-28 21:53:31 +02:00
|
|
|
return res;
|
|
|
|
}
|
2022-02-23 08:29:37 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* compile-time checks
|
|
|
|
*/
|
|
|
|
constexpr bool
|
2022-03-19 17:56:10 +01:00
|
|
|
validate_field_ids()
|
2022-02-23 08:29:37 +01:00
|
|
|
{
|
2022-03-19 17:56:10 +01:00
|
|
|
for (auto id = 0U; id != Field::id_size(); ++id) {
|
|
|
|
const auto field_id = static_cast<Field::Id>(id);
|
|
|
|
if (field_from_id(field_id).id != field_id)
|
2022-02-23 08:29:37 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool
|
2022-03-19 17:56:10 +01:00
|
|
|
validate_field_shortcuts()
|
2022-02-23 08:29:37 +01:00
|
|
|
{
|
2022-04-28 21:53:31 +02:00
|
|
|
#ifdef BUILD_TESTS
|
|
|
|
std::array<size_t, 26> no_dups = {0};
|
|
|
|
#endif /*BUILD_TESTS*/
|
2022-03-19 17:56:10 +01:00
|
|
|
for (auto id = 0U; id != Field::id_size(); ++id) {
|
|
|
|
const auto field_id = static_cast<Field::Id>(id);
|
|
|
|
const auto shortcut = field_from_id(field_id).shortcut;
|
2022-02-23 08:29:37 +01:00
|
|
|
if (shortcut != 0 &&
|
|
|
|
(shortcut < 'a' || shortcut > 'z'))
|
|
|
|
return false;
|
2022-04-28 21:53:31 +02:00
|
|
|
#ifdef BUILD_TESTS
|
|
|
|
if (shortcut != 0) {
|
|
|
|
if (++no_dups[static_cast<size_t>(shortcut-'a')] > 1) {
|
2023-07-05 22:10:13 +02:00
|
|
|
mu_critical("shortcut '{}' is duplicated", shortcut);
|
2022-04-28 21:53:31 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-02-23 08:29:37 +01:00
|
|
|
}
|
2022-04-28 21:53:31 +02:00
|
|
|
|
2022-02-23 08:29:37 +01:00
|
|
|
return true;
|
|
|
|
}
|
2022-03-19 17:41:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
constexpr /*static*/ bool
|
2022-03-19 17:56:10 +01:00
|
|
|
validate_field_flags()
|
2022-03-19 17:41:05 +01:00
|
|
|
{
|
2022-03-19 17:56:10 +01:00
|
|
|
for (auto&& field: Fields) {
|
2023-09-17 08:59:38 +02:00
|
|
|
/* - A field has at most one of Phrasable, Boolean */
|
2022-03-19 17:41:05 +01:00
|
|
|
size_t flagnum{};
|
2022-06-08 23:02:37 +02:00
|
|
|
|
2023-09-17 08:59:38 +02:00
|
|
|
if (field.is_phrasable_term())
|
2022-03-19 17:41:05 +01:00
|
|
|
++flagnum;
|
|
|
|
if (field.is_boolean_term())
|
|
|
|
++flagnum;
|
|
|
|
|
|
|
|
if (flagnum > 1) {
|
2023-07-05 22:10:13 +02:00
|
|
|
//mu_warning("invalid field {}", field.name);
|
2022-03-19 17:41:05 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-23 08:29:37 +01:00
|
|
|
/*
|
|
|
|
* tests... also build as runtime-tests, so we can get coverage info
|
|
|
|
*/
|
|
|
|
#ifdef BUILD_TESTS
|
|
|
|
#define static_assert g_assert_true
|
|
|
|
#endif /*BUILD_TESTS*/
|
|
|
|
|
|
|
|
|
|
|
|
[[maybe_unused]]
|
|
|
|
static void
|
|
|
|
test_ids()
|
|
|
|
{
|
2022-03-19 17:56:10 +01:00
|
|
|
static_assert(validate_field_ids());
|
2022-02-23 08:29:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
[[maybe_unused]]
|
|
|
|
static void
|
|
|
|
test_shortcuts()
|
|
|
|
{
|
2022-03-19 17:56:10 +01:00
|
|
|
static_assert(validate_field_shortcuts());
|
2022-02-23 08:29:37 +01:00
|
|
|
}
|
|
|
|
|
2022-03-03 23:02:52 +01:00
|
|
|
[[maybe_unused]]
|
|
|
|
static void
|
|
|
|
test_prefix()
|
|
|
|
{
|
2022-03-19 17:56:10 +01:00
|
|
|
static_assert(field_from_id(Field::Id::Subject).xapian_prefix() == 'S');
|
2022-03-03 23:02:52 +01:00
|
|
|
}
|
|
|
|
|
2022-03-19 17:41:05 +01:00
|
|
|
[[maybe_unused]]
|
|
|
|
static void
|
|
|
|
test_field_flags()
|
|
|
|
{
|
2022-03-19 17:56:10 +01:00
|
|
|
static_assert(validate_field_flags());
|
2022-03-19 17:41:05 +01:00
|
|
|
}
|
|
|
|
|
2022-02-23 08:29:37 +01:00
|
|
|
#ifdef BUILD_TESTS
|
2022-03-03 23:02:52 +01:00
|
|
|
|
2022-04-28 21:53:31 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
test_field_from_name()
|
|
|
|
{
|
|
|
|
g_assert_true(field_from_name("s")->id == Field::Id::Subject);
|
|
|
|
g_assert_true(field_from_name("subject")->id == Field::Id::Subject);
|
|
|
|
g_assert_false(!!field_from_name("8"));
|
|
|
|
g_assert_false(!!field_from_name(""));
|
|
|
|
|
|
|
|
g_assert_true(field_from_name("").value_or(field_from_id(Field::Id::Bcc)).id ==
|
|
|
|
Field::Id::Bcc);
|
|
|
|
}
|
|
|
|
|
2022-03-03 23:02:52 +01:00
|
|
|
static void
|
|
|
|
test_xapian_term()
|
|
|
|
{
|
|
|
|
using namespace std::string_literals;
|
|
|
|
using namespace std::literals;
|
|
|
|
|
2022-03-19 17:56:10 +01:00
|
|
|
assert_equal(field_from_id(Field::Id::Subject).xapian_term(""s), "S");
|
|
|
|
assert_equal(field_from_id(Field::Id::Subject).xapian_term("boo"s), "Sboo");
|
2022-03-03 23:02:52 +01:00
|
|
|
|
2022-03-19 17:56:10 +01:00
|
|
|
assert_equal(field_from_id(Field::Id::From).xapian_term('x'), "Fx");
|
|
|
|
assert_equal(field_from_id(Field::Id::To).xapian_term("boo"sv), "Tboo");
|
2022-04-28 21:53:31 +02:00
|
|
|
|
|
|
|
auto s1 = field_from_id(Field::Id::Subject).xapian_term(std::string(MaxTermLength - 1, 'x'));
|
|
|
|
auto s2 = field_from_id(Field::Id::Subject).xapian_term(std::string(MaxTermLength, 'x'));
|
|
|
|
g_assert_cmpuint(s1.length(), ==, s2.length());
|
2022-03-03 23:02:52 +01:00
|
|
|
}
|
|
|
|
|
2022-02-23 08:29:37 +01:00
|
|
|
int
|
|
|
|
main(int argc, char* argv[])
|
|
|
|
{
|
2022-08-10 07:20:58 +02:00
|
|
|
mu_test_init(&argc, &argv);
|
2022-02-23 08:29:37 +01:00
|
|
|
|
|
|
|
g_test_add_func("/message/fields/ids", test_ids);
|
|
|
|
g_test_add_func("/message/fields/shortcuts", test_shortcuts);
|
2022-04-28 21:53:31 +02:00
|
|
|
g_test_add_func("/message/fields/from-name", test_field_from_name);
|
2022-03-03 23:02:52 +01:00
|
|
|
g_test_add_func("/message/fields/prefix", test_prefix);
|
|
|
|
g_test_add_func("/message/fields/xapian-term", test_xapian_term);
|
2022-03-19 17:41:05 +01:00
|
|
|
g_test_add_func("/message/fields/flags", test_field_flags);
|
2022-02-23 08:29:37 +01:00
|
|
|
|
|
|
|
return g_test_run();
|
|
|
|
}
|
|
|
|
#endif /*BUILD_TESTS*/
|