aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_tagdialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_tagdialog.cpp')
-rw-r--r--tests/test_tagdialog.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/tests/test_tagdialog.cpp b/tests/test_tagdialog.cpp
index 5289599..9b12109 100644
--- a/tests/test_tagdialog.cpp
+++ b/tests/test_tagdialog.cpp
@@ -47,6 +47,7 @@ private slots:
void acceptingACandidateKeepsTheOtherTags();
void removeCompletesOnlyTheSelectionsOwnTags();
void removeStillAcceptsATagItDoesNotSuggest();
+ void aTagWithASpaceCanStillBeRemoved();
};
void TestTagDialog::validNamesAreAccepted()
@@ -166,6 +167,62 @@ void TestTagDialog::multipleTagsSeparateOnComma()
QStringLiteral("three") }));
}
+void TestTagDialog::aTagWithASpaceCanStillBeRemoved()
+{
+ // validateTagName() rejects a space, and that rule is right: it stops a
+ // troublesome tag being CREATED. It ran on the removal list too, which is
+ // not the same question. A tag that already exists is a fact, and refusing
+ // to remove it because it breaks a naming rule leaves the user with a tag
+ // they can see and cannot get rid of.
+ //
+ // Reached by a real Maildir: a folder named "Inbox/SlackBuilds users"
+ // produced `deleted-from:Inbox/SlackBuilds users`, and the one dialog that
+ // could have cleared it refused the only text that names it.
+ //
+ // Only the TYPED route was blocked. Unchecking appends to the removal list
+ // after validation has run, so it worked throughout; that asymmetry is why
+ // both routes are asserted here rather than just the one that failed.
+ const QString spaced =
+ QStringLiteral("deleted-from:Inbox/SlackBuilds users");
+ QHash<QString, int> current;
+ current.insert(spaced, 1);
+
+ // Typed into the remove field, which is what a user does for a tag they
+ // can see on the message. Before the fix this raised a modal warning and
+ // returned without accepting, so the dialog simply would not close.
+ TagDialog typed({ spaced }, current, 1);
+ const QList<QLineEdit *> edits = typed.findChildren<QLineEdit *>();
+ QCOMPARE(edits.size(), 2);
+ edits.at(1)->setText(spaced);
+ typed.accept();
+
+ QCOMPARE(typed.tagsToRemove(), QStringList{ spaced });
+ QVERIFY(typed.tagsToAdd().isEmpty());
+
+ // And unchecking it in the list, the other way to the same place.
+ TagDialog unchecked({ spaced }, current, 1);
+ auto *list = unchecked.findChild<QListWidget *>();
+ QVERIFY(list);
+ QCOMPARE(list->count(), 1);
+ QCOMPARE(list->item(0)->data(Qt::UserRole).toString(), spaced);
+ list->item(0)->setCheckState(Qt::Unchecked);
+ unchecked.accept();
+
+ QCOMPARE(unchecked.tagsToRemove(), QStringList{ spaced });
+
+ // ADDING one is still refused, which is the rule this must not have
+ // weakened. accept() returns without setting the lists, so the dialog
+ // stays open with the text there to fix.
+ TagDialog added({}, {}, 1);
+ const QList<QLineEdit *> addEdits = added.findChildren<QLineEdit *>();
+ QCOMPARE(addEdits.size(), 2);
+ addEdits.at(0)->setText(QStringLiteral("two words"));
+ // Not calling accept(): it would raise a modal warning and block. The
+ // validator is the thing under test and is asked directly.
+ QVERIFY(validateTagName(QStringLiteral("two words"))
+ != TagNameProblem::Ok);
+}
+
void TestTagDialog::uncheckingACurrentTagRemovesIt()
{
// Every selected thread carries "inbox", so its box starts checked.