aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test_config.cpp33
-rw-r--r--tests/test_mailsync.cpp52
-rw-r--r--tests/test_threadlistmodel.cpp43
3 files changed, 128 insertions, 0 deletions
diff --git a/tests/test_config.cpp b/tests/test_config.cpp
index 4d92891..dc85968 100644
--- a/tests/test_config.cpp
+++ b/tests/test_config.cpp
@@ -51,6 +51,8 @@ private slots:
void extraMimetypesAppendToBuiltins();
void extraMimetypeDescriptionMayContainComma();
void malformedExtraMimetypeIsSkipped();
+ void syncChannelDefaultsToTheAccountKey();
+ void syncChannelIsActuallyRead();
};
static QString writeIni(const QTemporaryDir &dir, const QString &body)
@@ -524,5 +526,36 @@ void TestConfig::malformedExtraMimetypeIsSkipped()
QVERIFY(!config.problems().isEmpty());
}
+void TestConfig::syncChannelDefaultsToTheAccountKey()
+{
+ // Most accounts name their mbsync channel exactly as their section key, so
+ // the common case must need no config edit at all.
+ QTemporaryDir dir;
+ Config config;
+ config.load(writeIni(dir, QStringLiteral(
+ "[account.work]\n"
+ "maildir = work\n")));
+
+ QCOMPARE(config.accounts().size(), 1);
+ QCOMPARE(config.accounts().at(0).syncChannel(), QStringLiteral("work"));
+}
+
+void TestConfig::syncChannelIsActuallyRead()
+{
+ // The key exists because the two names genuinely diverge: a QSettings
+ // section key may carry dots that the mbsync channel does not, and passing
+ // the section key to mbsync would name a channel that does not exist.
+ QTemporaryDir dir;
+ Config config;
+ config.load(writeIni(dir, QStringLiteral(
+ "[account.mail-first.last]\n"
+ "maildir = mail-first.last\n"
+ "channel = mail-firstlast\n")));
+
+ QCOMPARE(config.accounts().size(), 1);
+ QCOMPARE(config.accounts().at(0).syncChannel(),
+ QStringLiteral("mail-firstlast"));
+}
+
QTEST_MAIN(TestConfig)
#include "test_config.moc"
diff --git a/tests/test_mailsync.cpp b/tests/test_mailsync.cpp
index 6c93e8d..e91de3e 100644
--- a/tests/test_mailsync.cpp
+++ b/tests/test_mailsync.cpp
@@ -43,6 +43,9 @@ private slots:
void missingBinaryReportsFailureNotSilence();
void startDoesNotBlock();
void argumentsAreNotShellInterpreted();
+ void channelsAreAppendedToTheCommand();
+ void noChannelsMeansNoExtraArguments();
+ void channelNamesAreNotShellInterpreted();
void phaseStartsAsMbsync();
void notmuchLineSwitchesPhase();
@@ -262,6 +265,55 @@ void TestMailSync::argumentsAreNotShellInterpreted()
QVERIFY(sync.log().contains(QStringLiteral("; touch")));
}
+void TestMailSync::channelsAreAppendedToTheCommand()
+{
+ // Item 49: a sync that knows which accounts were touched passes their
+ // channel names, and they must reach the script as separate arguments
+ // after whatever the config line already carries.
+ const QString script = makeScript(QStringLiteral("chan.sh"),
+ QStringLiteral("echo \"[$@]\""));
+
+ MailSync sync(script);
+ QSignalSpy spy(&sync, &MailSync::finished);
+ QVERIFY(sync.start({ QStringLiteral("work"), QStringLiteral("personal") }));
+ QVERIFY(spy.wait(5000));
+
+ QVERIFY(sync.log().contains(QStringLiteral("[work personal]")));
+}
+
+void TestMailSync::noChannelsMeansNoExtraArguments()
+{
+ // Empty means "sync everything", which is the script's own default. It must
+ // not become an empty string argument: mbsync would read that as a channel
+ // named "" and fail the run.
+ const QString script = makeScript(QStringLiteral("nochan.sh"),
+ QStringLiteral("echo \"count=$#\""));
+
+ MailSync sync(script);
+ QSignalSpy spy(&sync, &MailSync::finished);
+ QVERIFY(sync.start());
+ QVERIFY(spy.wait(5000));
+
+ QVERIFY(sync.log().contains(QStringLiteral("count=0")));
+}
+
+void TestMailSync::channelNamesAreNotShellInterpreted()
+{
+ // Channel names are derived from config, same trust boundary as the command
+ // itself, and reach the same QProcess argument list. The injection test
+ // above covers the command; this covers the half added for item 49.
+ const QString script = makeScript(QStringLiteral("chanargs.sh"),
+ QStringLiteral("echo \"$1\""));
+
+ MailSync sync(script);
+ QSignalSpy spy(&sync, &MailSync::finished);
+ QVERIFY(sync.start({ QStringLiteral("; touch %1/chanpwned")
+ .arg(m_dir.path()) }));
+ QVERIFY(spy.wait(5000));
+
+ QVERIFY(!QFile::exists(m_dir.filePath(QStringLiteral("chanpwned"))));
+}
+
void TestMailSync::phaseStartsAsMbsync()
{
// A fresh tracker has nothing to report until it is fed, and a run is
diff --git a/tests/test_threadlistmodel.cpp b/tests/test_threadlistmodel.cpp
index 82686e5..f84bbab 100644
--- a/tests/test_threadlistmodel.cpp
+++ b/tests/test_threadlistmodel.cpp
@@ -28,6 +28,9 @@ class TestThreadListModel : public QObject
Q_OBJECT
private slots:
void startsEmpty();
+ void accountKeysComeFromTheAccountTags();
+ void accountKeysCoverAThreadSpanningTwoAccounts();
+ void accountKeysAreEmptyForAnUnknownThread();
void appendsBatches();
void appendingEmptyBatchIsNoOp();
void clearResetsModel();
@@ -73,6 +76,46 @@ static ThreadSummary makeThread(const QString &id, const QString &subject)
return t;
}
+void TestThreadListModel::accountKeysComeFromTheAccountTags()
+{
+ // Item 49 reads this to decide which mbsync channels a sync needs. Only
+ // account tags count: a functional tag names no mailbox.
+ ThreadListModel model;
+ ThreadSummary t = makeThread(QStringLiteral("t1"), QStringLiteral("Hi"));
+ t.tags.append(TagColors::tagForAccountKey(QStringLiteral("work")));
+ model.appendBatch({ t });
+
+ QCOMPARE(model.accountKeysForThread(QStringLiteral("t1")),
+ QStringList{ QStringLiteral("work") });
+}
+
+void TestThreadListModel::accountKeysCoverAThreadSpanningTwoAccounts()
+{
+ // The row shows one chip, but tagging this thread touches files under both
+ // mailboxes. Returning only the first would strand the other's edits.
+ ThreadListModel model;
+ ThreadSummary t = makeThread(QStringLiteral("t1"), QStringLiteral("Hi"));
+ t.tags.append(TagColors::tagForAccountKey(QStringLiteral("work")));
+ t.tags.append(TagColors::tagForAccountKey(QStringLiteral("personal")));
+ model.appendBatch({ t });
+
+ QStringList keys = model.accountKeysForThread(QStringLiteral("t1"));
+ keys.sort();
+ QCOMPARE(keys, (QStringList{ QStringLiteral("personal"),
+ QStringLiteral("work") }));
+}
+
+void TestThreadListModel::accountKeysAreEmptyForAnUnknownThread()
+{
+ // A thread the model no longer holds must yield nothing rather than
+ // matching some other row.
+ ThreadListModel model;
+ model.appendBatch({ makeThread(QStringLiteral("t1"),
+ QStringLiteral("Hi")) });
+
+ QVERIFY(model.accountKeysForThread(QStringLiteral("nope")).isEmpty());
+}
+
void TestThreadListModel::startsEmpty()
{
ThreadListModel model;