diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-02 17:02:18 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-02 17:02:18 +0200 |
| commit | dd7845d847a3d6f961f0302551c33245d1f12bdc (patch) | |
| tree | f146a0bf84bbd3229e9bf18235314de0bc5f4c5f /tests | |
| parent | 059fa151856293a8b6bdf9b16d1b72f415f59df3 (diff) | |
| download | qtmaildir-dd7845d847a3d6f961f0302551c33245d1f12bdc.tar.gz qtmaildir-dd7845d847a3d6f961f0302551c33245d1f12bdc.zip | |
feat: add KeyMap with defaults and INI overrides
Maps key sequences to action name strings, with hardcoded vim-style
defaults and QSettings-based [keys] overrides. Unknown actions and
unparseable sequences are collected as warnings rather than treated
as fatal, so a typo in the config cannot silently misbind or crash.
Note: QKeySequence::fromString() on Qt 6.11 does not return an empty
sequence for unparseable input (e.g. "NotAKey++") -- it returns a
non-empty sequence whose toString() is empty. Detection uses that
instead of isEmpty().
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | tests/test_keymap.cpp | 131 |
2 files changed, 133 insertions, 0 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3344d4a..d4f0d3f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,3 +4,5 @@ function(add_qtmaildir_test name) target_link_libraries(test_${name} PRIVATE qtmaildir_lib Qt6::Test) add_test(NAME ${name} COMMAND test_${name}) endfunction() + +add_qtmaildir_test(keymap) diff --git a/tests/test_keymap.cpp b/tests/test_keymap.cpp new file mode 100644 index 0000000..10863f2 --- /dev/null +++ b/tests/test_keymap.cpp @@ -0,0 +1,131 @@ +#include <QtTest> +#include <QTemporaryDir> +#include <QSettings> +#include "keymap.h" + +class TestKeyMap : public QObject +{ + Q_OBJECT +private slots: + void defaultsAreLoaded(); + void iniOverridesDefault(); + void iniAddsNewBinding(); + void chordSequenceParses(); + void unknownActionIsReported(); + void invalidSequenceIsReported(); +}; + +void TestKeyMap::defaultsAreLoaded() +{ + KeyMap map; + map.loadDefaults(); + QCOMPARE(map.actionFor(QKeySequence(QStringLiteral("j"))), + QStringLiteral("next_thread")); + QCOMPARE(map.actionFor(QKeySequence(QStringLiteral("a"))), + QStringLiteral("archive")); +} + +void TestKeyMap::iniOverridesDefault() +{ + QTemporaryDir dir; + const QString path = dir.filePath(QStringLiteral("t.conf")); + { + QSettings s(path, QSettings::IniFormat); + s.beginGroup(QStringLiteral("keys")); + s.setValue(QStringLiteral("j"), QStringLiteral("archive")); + s.endGroup(); + } + + KeyMap map; + map.loadDefaults(); + QSettings s(path, QSettings::IniFormat); + map.loadOverrides(s); + + QCOMPARE(map.actionFor(QKeySequence(QStringLiteral("j"))), + QStringLiteral("archive")); + // An untouched default survives. + QCOMPARE(map.actionFor(QKeySequence(QStringLiteral("k"))), + QStringLiteral("prev_thread")); +} + +void TestKeyMap::iniAddsNewBinding() +{ + QTemporaryDir dir; + const QString path = dir.filePath(QStringLiteral("t.conf")); + { + QSettings s(path, QSettings::IniFormat); + s.beginGroup(QStringLiteral("keys")); + s.setValue(QStringLiteral("Ctrl+Shift+A"), QStringLiteral("archive")); + s.endGroup(); + } + + KeyMap map; + map.loadDefaults(); + QSettings s(path, QSettings::IniFormat); + map.loadOverrides(s); + + QCOMPARE(map.actionFor(QKeySequence(QStringLiteral("Ctrl+Shift+A"))), + QStringLiteral("archive")); +} + +void TestKeyMap::chordSequenceParses() +{ + QTemporaryDir dir; + const QString path = dir.filePath(QStringLiteral("t.conf")); + { + QSettings s(path, QSettings::IniFormat); + s.beginGroup(QStringLiteral("keys")); + s.setValue(QStringLiteral("g,i"), QStringLiteral("focus_query")); + s.endGroup(); + } + + KeyMap map; + QSettings s(path, QSettings::IniFormat); + map.loadOverrides(s); + + const QKeySequence chord = QKeySequence::fromString(QStringLiteral("g,i")); + QCOMPARE(chord.count(), 2); + QCOMPARE(map.actionFor(chord), QStringLiteral("focus_query")); +} + +void TestKeyMap::unknownActionIsReported() +{ + QTemporaryDir dir; + const QString path = dir.filePath(QStringLiteral("t.conf")); + { + QSettings s(path, QSettings::IniFormat); + s.beginGroup(QStringLiteral("keys")); + s.setValue(QStringLiteral("z"), QStringLiteral("no_such_action")); + s.endGroup(); + } + + KeyMap map; + QSettings s(path, QSettings::IniFormat); + map.loadOverrides(s); + + // Reported, not fatal, and not bound. + QCOMPARE(map.warnings().size(), 1); + QVERIFY(map.warnings().first().contains(QStringLiteral("no_such_action"))); + QVERIFY(map.actionFor(QKeySequence(QStringLiteral("z"))).isEmpty()); +} + +void TestKeyMap::invalidSequenceIsReported() +{ + QTemporaryDir dir; + const QString path = dir.filePath(QStringLiteral("t.conf")); + { + QSettings s(path, QSettings::IniFormat); + s.beginGroup(QStringLiteral("keys")); + s.setValue(QStringLiteral("NotAKey++"), QStringLiteral("archive")); + s.endGroup(); + } + + KeyMap map; + QSettings s(path, QSettings::IniFormat); + map.loadOverrides(s); + + QCOMPARE(map.warnings().size(), 1); +} + +QTEST_MAIN(TestKeyMap) +#include "test_keymap.moc" |
