File indexing completed on 2024-05-19 04:39:59

0001 /*
0002     SPDX-FileCopyrightText: 2014 Kevin Funk <kfunk@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "test_stringhandler.h"
0008 
0009 #include "kdevstringhandler.h"
0010 
0011 #include <QTest>
0012 #include <QStandardPaths>
0013 
0014 QTEST_MAIN(TestStringHandler)
0015 
0016 using namespace KDevelop;
0017 
0018 Q_DECLARE_METATYPE(HtmlToPlainTextMode)
0019 
0020 void TestStringHandler::initTestCase()
0021 {
0022     QStandardPaths::setTestModeEnabled(true);
0023 }
0024 
0025 void TestStringHandler::testHtmlToPlainText()
0026 {
0027     QFETCH(QString, html);
0028     QFETCH(HtmlToPlainTextMode, mode);
0029     QFETCH(QString, expectedPlainText);
0030 
0031     QString plainText = htmlToPlainText(html, mode);
0032     QCOMPARE(plainText, expectedPlainText);
0033 }
0034 
0035 void TestStringHandler::testHtmlToPlainText_data()
0036 {
0037     QTest::addColumn<QString>("html");
0038     QTest::addColumn<HtmlToPlainTextMode>("mode");
0039     QTest::addColumn<QString>("expectedPlainText");
0040 
0041     QTest::newRow("simple-fast")
0042         << "<p>bar() </p><dl><dt class=\"param-name-index-0\">a</dt><dd class=\"param-descr-index-0\"> foo</dd></dl>"
0043         << KDevelop::FastMode << "bar() a foo";
0044     QTest::newRow("simple-complete")
0045         << "<p>bar() </p><dl><dt class=\"param-name-index-0\">a</dt><dd class=\"param-descr-index-0\"> foo</dd></dl>"
0046         << KDevelop::CompleteMode << "bar() \na\nfoo";
0047 }
0048 
0049 void TestStringHandler::testEscapeJavaScriptString()
0050 {
0051     QFETCH(QByteArray, unescaped);
0052     QFETCH(QByteArray, escaped);
0053 
0054     const auto actual = escapeJavaScriptString(unescaped);
0055     QCOMPARE(actual, escaped);
0056 }
0057 
0058 void TestStringHandler::testEscapeJavaScriptString_data()
0059 {
0060     QTest::addColumn<QByteArray>("unescaped");
0061     QTest::addColumn<QByteArray>("escaped");
0062 
0063     const auto nothingToEscape = QByteArrayLiteral("html { background: white !important; }");
0064     QTest::newRow("nothing to escape") << nothingToEscape << nothingToEscape;
0065 
0066     QTest::newRow("newlines and single quotes")
0067         << QByteArrayLiteral("body {\nfont-family: 'Liberation Serif', sans-serif;\n }\n")
0068         << QByteArrayLiteral("body {\\nfont-family: \\'Liberation Serif\\', sans-serif;\\n }\\n");
0069 
0070     QTest::newRow("HTML and double quotes") << QByteArrayLiteral(R"(<img src="my-icon (2).png" alt="[app icon]">)")
0071                                             << QByteArrayLiteral(R"(<img src=\"my-icon (2).png\" alt=\"[app icon]\">)");
0072 
0073     // Prevent '\0' from terminating the string.
0074     constexpr char allUnescaped[] = "\\ \0\" \b\f\n\r\t\v '";
0075     const auto allUnescapedSize = sizeof(allUnescaped) / sizeof(char) - 1;
0076     constexpr char allEscaped[] = "\\\\ \\0\\\" \\b\\f\\n\\r\\t\\v \\'";
0077     const auto allEscapedSize = sizeof(allEscaped) / sizeof(char) - 1;
0078     QTest::newRow("all special characters") << QByteArray(allUnescaped, allUnescapedSize)
0079                                             << QByteArray(allEscaped, allEscapedSize);
0080 }
0081 
0082 namespace {
0083 void addAsciiIdentifierData()
0084 {
0085     QTest::addColumn<QString>("str");
0086     QTest::addColumn<int>("identifierBegin");
0087     QTest::addColumn<int>("identifierEnd");
0088 
0089     QString str;
0090 
0091     str = "u0_cBQp.ad";
0092     const auto indexOfPeriod = str.indexOf('.');
0093     QTest::newRow("identifier at index 0") << str << 0 << indexOfPeriod;
0094     QTest::newRow("identifier ends at string end") << str << indexOfPeriod + 1 << str.size();
0095     QTest::newRow("one letter at string end") << str << indexOfPeriod + 2 << str.size();
0096     QTest::newRow("string end") << str << str.size() << str.size();
0097 
0098     str = "AbcD901z95-24";
0099     QTest::newRow("identifier after a letter") << str << 2 << str.indexOf('-');
0100 
0101     str = "a=$B+c";
0102     QTest::newRow("identifier after a dollar") << str << 3 << str.indexOf('+');
0103 
0104     str = "-_,";
0105     QTest::newRow("underscore identifier") << str << 1 << 2;
0106 
0107     str = "_aBt_9";
0108     QTest::newRow("entire-string identifier") << str << 0 << str.size();
0109 }
0110 
0111 void addUnmatchedAsciiIdentifierData()
0112 {
0113     QTest::addColumn<QString>("str");
0114     QTest::addColumn<int>("unmatchedCharsBegin");
0115     QTest::addColumn<int>("unmatchedCharsEnd");
0116 
0117     QString str;
0118 
0119     str = "12970abC3D5";
0120     QTest::newRow("a digit") << str << 0 << str.indexOf('a');
0121     auto indexOfDigit = str.indexOf('3');
0122     QTest::newRow("a digit between letters") << str << indexOfDigit << indexOfDigit + 1;
0123     indexOfDigit = str.indexOf('5');
0124     QTest::newRow("a digit at string end") << str << indexOfDigit << indexOfDigit + 1;
0125 
0126     str = ".,-[/\\]$&{(=*+!#\r\n)~%`}\0\t |@^?;:<>\"'";
0127     QTest::newRow("a non-ID character") << str << 0 << str.size();
0128 
0129     str = QString::fromUtf8("\u5c07\u4f0a\u00f8\u00e5\ub418\uc9c0\u0414\u041b\u0407"
0130                             "\u062c\u0628\u062a\u044a\u044b\u043c\u00ae\u00bf\u00ab"
0131                             "\u00bb\u00b6\u00fc\u00a7\u201c\u201d\u6d77\u9b5a\u300d\u3232");
0132     QTest::newRow("a non-ASCII character") << str << 0 << str.size();
0133 }
0134 }
0135 
0136 void TestStringHandler::testFindAsciiIdentifierLength()
0137 {
0138     QFETCH(QString, str);
0139     QFETCH(int, identifierBegin);
0140     QFETCH(int, identifierEnd);
0141 
0142     const auto length = identifierEnd - identifierBegin;
0143     Q_ASSERT_X(length >= 0, Q_FUNC_INFO, "Wrong data.");
0144     QCOMPARE(findAsciiIdentifierLength(str.midRef(identifierBegin)), length);
0145 }
0146 
0147 void TestStringHandler::testFindAsciiIdentifierLength_data()
0148 {
0149     addAsciiIdentifierData();
0150 }
0151 
0152 void TestStringHandler::testFindAsciiIdentifierLengthNoMatch()
0153 {
0154     QFETCH(QString, str);
0155     QFETCH(int, unmatchedCharsBegin);
0156     QFETCH(int, unmatchedCharsEnd);
0157 
0158     Q_ASSERT_X(unmatchedCharsBegin < unmatchedCharsEnd, Q_FUNC_INFO,
0159                "Nothing to test. A mistake in our data?");
0160     for (int i = unmatchedCharsBegin; i < unmatchedCharsEnd; ++i) {
0161         QCOMPARE(findAsciiIdentifierLength(str.midRef(i)), 0);
0162     }
0163 }
0164 
0165 void TestStringHandler::testFindAsciiIdentifierLengthNoMatch_data()
0166 {
0167     addUnmatchedAsciiIdentifierData();
0168 }
0169 
0170 void TestStringHandler::testMatchUnbracedAsciiVariable()
0171 {
0172     QFETCH(QString, str);
0173     QFETCH(int, identifierBegin);
0174     QFETCH(int, identifierEnd);
0175 
0176     const auto length = identifierEnd - identifierBegin;
0177     Q_ASSERT_X(length >= 0, Q_FUNC_INFO, "Wrong data.");
0178     const auto match = matchPossiblyBracedAsciiVariable(str.midRef(identifierBegin));
0179     QCOMPARE(match.length, length);
0180     QCOMPARE(match.name, str.mid(identifierBegin, length));
0181 }
0182 
0183 void TestStringHandler::testMatchUnbracedAsciiVariable_data()
0184 {
0185     addAsciiIdentifierData();
0186 
0187     QString str;
0188 
0189     str = "a{b";
0190     QTest::newRow("no closing brace") << str << 1 << 1;
0191 
0192     str = "1x}";
0193     QTest::newRow("no opening brace") << str << 1 << 2;
0194 
0195     str = "{{u}}";
0196     QTest::newRow("nested braces") << str << 0 << 0;
0197 }
0198 
0199 void TestStringHandler::testUnmatchedAsciiVariable()
0200 {
0201     QFETCH(QString, str);
0202     QFETCH(int, unmatchedCharsBegin);
0203     QFETCH(int, unmatchedCharsEnd);
0204 
0205     Q_ASSERT_X(unmatchedCharsBegin < unmatchedCharsEnd, Q_FUNC_INFO,
0206                "Nothing to test. A mistake in our data?");
0207     for (int i = unmatchedCharsBegin; i < unmatchedCharsEnd; ++i) {
0208         const auto match = matchPossiblyBracedAsciiVariable(str.midRef(i));
0209         QCOMPARE(match.length, 0);
0210         QCOMPARE(match.name, QString{});
0211     }
0212 }
0213 
0214 void TestStringHandler::testUnmatchedAsciiVariable_data()
0215 {
0216     addUnmatchedAsciiIdentifierData();
0217 
0218     QTest::newRow("empty braces") << QStringLiteral("{}a}") << 0 << 2;
0219     QTest::newRow("a digit inside braces") << QStringLiteral("{4}") << 0 << 3;
0220     QTest::newRow("a non-ID character inside braces") << QStringLiteral("a{!}b") << 1 << 4;
0221 }
0222 
0223 void TestStringHandler::testMatchBracedAsciiVariable()
0224 {
0225     QFETCH(QString, str);
0226     QFETCH(int, openingBraceIndex);
0227     QFETCH(int, closingBraceIndex);
0228 
0229     const auto variableLength = closingBraceIndex - openingBraceIndex - 1;
0230     Q_ASSERT_X(variableLength > 0, Q_FUNC_INFO, "Wrong data.");
0231     const auto match = matchPossiblyBracedAsciiVariable(str.midRef(openingBraceIndex));
0232     QCOMPARE(match.length, variableLength + 2);
0233     QCOMPARE(match.name, str.mid(openingBraceIndex + 1, variableLength));
0234 }
0235 
0236 void TestStringHandler::testMatchBracedAsciiVariable_data()
0237 {
0238     QTest::addColumn<QString>("str");
0239     QTest::addColumn<int>("openingBraceIndex");
0240     QTest::addColumn<int>("closingBraceIndex");
0241 
0242     QString str;
0243 
0244     str = "{a1}-a{_}";
0245     QTest::newRow("variable at index 0") << str << 0 << str.indexOf('}');
0246     QTest::newRow("variable ends at string end") << str << str.lastIndexOf('{') << str.size() - 1;
0247 
0248     str = "{a2_bDX__45Ek}";
0249     QTest::newRow("entire-string variable") << str << 0 << str.size() - 1;
0250 }
0251 
0252 void TestStringHandler::testStripAnsiSequences()
0253 {
0254     QFETCH(QString, input);
0255     QFETCH(QString, expectedOutput);
0256 
0257     const auto output = stripAnsiSequences(input);
0258     QCOMPARE(output, expectedOutput);
0259 }
0260 
0261 void TestStringHandler::testStripAnsiSequences_data()
0262 {
0263     QTest::addColumn<QString>("input");
0264     QTest::addColumn<QString>("expectedOutput");
0265 
0266     QTest::newRow("simple")
0267         << QStringLiteral("foo bar:")
0268         << "foo bar:";
0269 }
0270 
0271 void TestStringHandler::testNormalizeLineEndings()
0272 {
0273     QFETCH(QByteArray, text);
0274     QFETCH(QByteArray, expectedOutput);
0275 
0276     normalizeLineEndings(text);
0277     QCOMPARE(text, expectedOutput);
0278 }
0279 
0280 void TestStringHandler::testNormalizeLineEndings_data()
0281 {
0282     QTest::addColumn<QByteArray>("text");
0283     QTest::addColumn<QByteArray>("expectedOutput");
0284 
0285     QTest::newRow("trivial")
0286         << QByteArray("foo\nbar\n")
0287         << QByteArray("foo\nbar\n");
0288     QTest::newRow("dos")
0289         << QByteArray("foo\r\nbar\r\n")
0290         << QByteArray("foo\nbar\n");
0291     QTest::newRow("macos_classic")
0292         << QByteArray("foo\rbar\r")
0293         << QByteArray("foo\nbar\n");
0294     QTest::newRow("mess")
0295         << QByteArray("\r\n\n\r\r\r\n\r")
0296         << QByteArray("\n\n\n\n\n\n");
0297 }
0298 
0299 #include "moc_test_stringhandler.cpp"