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 [31m[34mbar[0m:") 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"