diff options
| -rw-r--r-- | src/signatures.cpp | 25 | ||||
| -rw-r--r-- | tests/test_signatures.cpp | 17 |
2 files changed, 41 insertions, 1 deletions
diff --git a/src/signatures.cpp b/src/signatures.cpp index eb43048..ef631d6 100644 --- a/src/signatures.cpp +++ b/src/signatures.cpp @@ -69,6 +69,20 @@ bool isQuoted(const QString &line) return line.startsWith(QLatin1Char('>')); } +/// \p text with trailing blank lines removed, the same normalisation the block +/// scan below applies. text() returns file content verbatim, so a signature +/// file ends with the newline every editor writes; without this the match +/// compares a block with no trailing newline against a known entry that has +/// one, and the guard silently fails, appending a second signature instead of +/// replacing the first. +QString stripTrailingBlankLines(const QString &text) +{ + QStringList lines = text.split(QLatin1Char('\n')); + while (!lines.isEmpty() && lines.last().trimmed().isEmpty()) + lines.removeLast(); + return lines.join(QLatin1Char('\n')); +} + /// The index of the first line of the quote, or -1 when the buffer has none. /// /// The attribution line ("On Mon, someone wrote:") is deliberately NOT @@ -164,9 +178,18 @@ QStringList withoutSignature(const QStringList &lines, int delimiter) QString replace(const QString &buffer, const QString &signature, const QStringList &known, Position position) { + // Normalise known to the same footing the block scan uses, once here rather + // than per comparison. knownSignatures() passes text() verbatim, trailing + // newline and all, and the match must be newline-insensitive or the guard + // treats every on-disk signature as unknown. + QStringList normalized; + normalized.reserve(known.size()); + for (const QString &entry : known) + normalized.append(stripTrailingBlankLines(entry)); + QStringList lines = buffer.split(QLatin1Char('\n')); - const int existing = existingSignature(lines, known); + const int existing = existingSignature(lines, normalized); if (existing >= 0) lines = withoutSignature(lines, existing); diff --git a/tests/test_signatures.cpp b/tests/test_signatures.cpp index 31f9eb4..47b404b 100644 --- a/tests/test_signatures.cpp +++ b/tests/test_signatures.cpp @@ -40,6 +40,7 @@ private slots: void selectingNoneRemovesAKnownSignature(); void aBlockMatchingNoKnownSignatureIsNotRemoved(); void aDelimiterInsideTheQuoteIsNotTheSignature(); + void aSignatureReadBackFromDiskIsReplaced(); private: /// Writes \p files as name -> content into a fresh temporary directory. @@ -273,5 +274,21 @@ void TestSignatures::aDelimiterInsideTheQuoteIsNotTheSignature() QVERIFY(result.endsWith(QStringLiteral("-- \nJane Doe"))); } +void TestSignatures::aSignatureReadBackFromDiskIsReplaced() +{ + // known here is what knownSignatures() produces: text() verbatim, carrying + // the trailing newline every editor writes into a file. The block scan + // treats a trailing blank line as separation rather than text, so a naive + // match compares "Jane Doe" against "Jane Doe\n" and silently fails, and + // switching then APPENDS a second signature instead of replacing the first. + const QStringList known = { QStringLiteral("Jane Doe\n") }; + const QString buffer = QStringLiteral("Hello.\n\n-- \nJane Doe\n"); + + const QString result = Signatures::replace( + buffer, QStringLiteral("Brief"), known, Signatures::Position::End); + + QCOMPARE(result, QStringLiteral("Hello.\n\n-- \nBrief")); +} + QTEST_MAIN(TestSignatures) #include "test_signatures.moc" |
