File indexing completed on 2025-03-09 04:53:55
0001 /* 0002 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "maintextjobtest.h" 0008 0009 #include <QStandardPaths> 0010 // #include <QTextCodec> 0011 #include <QStringDecoder> 0012 0013 #include <QDebug> 0014 #include <QTest> 0015 0016 #include <KMime/Content> 0017 using namespace KMime; 0018 0019 #include <KPIMTextEdit/RichTextComposerControler> 0020 #include <KPIMTextEdit/RichTextComposerImages> 0021 #include <MessageComposer/Composer> 0022 #include <MessageComposer/GlobalPart> 0023 #include <MessageComposer/MainTextJob> 0024 #include <MessageComposer/RichTextComposerNg> 0025 #include <MessageComposer/TextPart> 0026 0027 #include <KActionCollection> 0028 0029 using namespace MessageComposer; 0030 0031 QTEST_MAIN(MainTextJobTest) 0032 0033 void MainTextJobTest::initTestCase() 0034 { 0035 QStandardPaths::setTestModeEnabled(true); 0036 } 0037 0038 void MainTextJobTest::testPlainText() 0039 { 0040 auto composer = Composer(); 0041 composer.globalPart()->setGuiEnabled(false); 0042 QList<QByteArray> charsets; 0043 charsets << "us-ascii" 0044 << "utf-8"; 0045 composer.globalPart()->setCharsets(charsets); 0046 auto textPart = new TextPart; 0047 QString data = QStringLiteral("they said their never they slept their dream"); 0048 textPart->setWrappedPlainText(data); 0049 auto mjob = new MainTextJob(textPart, &composer); 0050 QVERIFY(mjob->exec()); 0051 Content *result = mjob->content(); 0052 result->assemble(); 0053 qDebug() << result->encodedContent(); 0054 QVERIFY(result->contentType(false)); 0055 QCOMPARE(result->contentType()->mimeType(), QByteArray("text/plain")); 0056 QCOMPARE(result->contentType()->charset(), QByteArray("us-ascii")); 0057 QCOMPARE(QString::fromLatin1(result->body()), data); 0058 delete textPart; 0059 } 0060 0061 void MainTextJobTest::testWrappingErrors() 0062 { 0063 { 0064 auto composer = Composer(); 0065 composer.globalPart()->setGuiEnabled(false); 0066 composer.globalPart()->setFallbackCharsetEnabled(true); 0067 auto textPart = new TextPart; 0068 QString data = QStringLiteral("they said their never they slept their dream"); 0069 textPart->setWordWrappingEnabled(false); 0070 textPart->setWrappedPlainText(data); 0071 auto mjob = new MainTextJob(textPart, &composer); 0072 QVERIFY(!mjob->exec()); // error: not UseWrapping but given only wrapped text 0073 QCOMPARE(mjob->error(), int(JobBase::BugError)); 0074 delete textPart; 0075 } 0076 { 0077 auto composer = Composer(); 0078 composer.globalPart()->setGuiEnabled(false); 0079 composer.globalPart()->setFallbackCharsetEnabled(true); 0080 auto textPart = new TextPart; 0081 textPart->setWordWrappingEnabled(true); 0082 QString data = QStringLiteral("they said their never they slept their dream"); 0083 textPart->setCleanPlainText(data); 0084 auto mjob = new MainTextJob(textPart, &composer); 0085 QVERIFY(!mjob->exec()); // error: UseWrapping but given only clean text 0086 QCOMPARE(mjob->error(), int(JobBase::BugError)); 0087 delete textPart; 0088 } 0089 } 0090 0091 void MainTextJobTest::testCustomCharset() 0092 { 0093 auto composer = Composer(); 0094 composer.globalPart()->setGuiEnabled(false); 0095 QByteArray charset("iso-8859-2"); 0096 composer.globalPart()->setCharsets(QList<QByteArray>() << charset); 0097 auto textPart = new TextPart; 0098 QString data = QStringLiteral("şi el o să se-nchidă cu o frunză de pelin"); 0099 textPart->setWrappedPlainText(data); 0100 auto mjob = new MainTextJob(textPart, &composer); 0101 QVERIFY(mjob->exec()); 0102 Content *result = mjob->content(); 0103 result->assemble(); 0104 qDebug() << result->encodedContent(); 0105 QVERIFY(result->contentType(false)); 0106 QCOMPARE(result->contentType()->mimeType(), QByteArray("text/plain")); 0107 QCOMPARE(result->contentType()->charset(), charset); 0108 QByteArray outData = result->body(); 0109 #if 0 // Remove when we remove all QTextCodec support 0110 QTextCodec *codec = QTextCodec::codecForName(charset); 0111 QVERIFY(codec); 0112 QCOMPARE(codec->toUnicode(outData), data); 0113 #endif 0114 QStringDecoder dec(charset.constData()); 0115 QVERIFY(dec.isValid()); 0116 QCOMPARE(dec.decode(outData), data); 0117 0118 delete textPart; 0119 } 0120 0121 void MainTextJobTest::testNoCharset() 0122 { 0123 auto composer = Composer(); 0124 QVERIFY(!composer.globalPart()->isFallbackCharsetEnabled()); 0125 composer.globalPart()->setGuiEnabled(false); 0126 auto textPart = new TextPart; 0127 QString data = QStringLiteral("do you still play the accordion?"); 0128 textPart->setWrappedPlainText(data); 0129 auto mjob = new MainTextJob(textPart, &composer); 0130 QSKIP("This tests has been failing for a long time, please someone fix it", SkipSingle); 0131 QVERIFY(!mjob->exec()); // Error. 0132 QCOMPARE(mjob->error(), int(JobBase::BugError)); 0133 qDebug() << mjob->errorString(); 0134 delete textPart; 0135 } 0136 0137 void MainTextJobTest::testBadCharset() 0138 { 0139 auto composer = Composer(); 0140 composer.globalPart()->setGuiEnabled(false); 0141 QByteArray charset("us-ascii"); // Cannot handle Romanian chars. 0142 composer.globalPart()->setCharsets(QList<QByteArray>() << charset); 0143 auto textPart = new TextPart; 0144 QString data = QStringLiteral("el a plâns peste ţară cu lacrima limbii noastre"); 0145 textPart->setWrappedPlainText(data); 0146 auto mjob = new MainTextJob(textPart, &composer); 0147 QSKIP("This tests has been failing for a long time, please someone fix it", SkipSingle); 0148 QVERIFY(!mjob->exec()); // Error. 0149 QCOMPARE(mjob->error(), int(JobBase::UserError)); 0150 qDebug() << mjob->errorString(); 0151 delete textPart; 0152 } 0153 0154 void MainTextJobTest::testFallbackCharset() 0155 { 0156 auto composer = Composer(); 0157 composer.globalPart()->setGuiEnabled(false); 0158 composer.globalPart()->setFallbackCharsetEnabled(true); 0159 auto textPart = new TextPart; 0160 QString data = QStringLiteral("and when he falleth..."); 0161 textPart->setWrappedPlainText(data); 0162 auto mjob = new MainTextJob(textPart, &composer); 0163 QVERIFY(mjob->exec()); 0164 Content *result = mjob->content(); 0165 result->assemble(); 0166 qDebug() << result->encodedContent(); 0167 QVERIFY(result->contentType(false)); 0168 QCOMPARE(result->contentType()->mimeType(), QByteArray("text/plain")); 0169 QCOMPARE(result->contentType()->charset(), QByteArray("us-ascii")); // Fallback is us-ascii or utf8. 0170 QCOMPARE(QString::fromLatin1(result->body()), data); 0171 delete textPart; 0172 } 0173 0174 void MainTextJobTest::testHtml() 0175 { 0176 QLatin1StringView originalHtml("<html><head></head><body>Test <em>with</em> formatting...<br>The end.</body></html>"); 0177 MessageComposer::RichTextComposerNg editor; 0178 editor.createActions(new KActionCollection(this)); 0179 editor.setTextOrHtml(originalHtml); 0180 QVERIFY(editor.composerControler()->isFormattingUsed()); 0181 0182 auto composer = new Composer; 0183 composer->globalPart()->setGuiEnabled(false); 0184 composer->globalPart()->setFallbackCharsetEnabled(true); 0185 auto textPart = new TextPart; 0186 textPart->setWordWrappingEnabled(false); 0187 textPart->setCleanPlainText(editor.composerControler()->toCleanPlainText()); 0188 textPart->setCleanHtml(editor.toCleanHtml()); 0189 auto mjob = new MainTextJob(textPart, composer); 0190 QVERIFY(mjob->exec()); 0191 Content *result = mjob->content(); 0192 result->assemble(); 0193 qDebug() << result->encodedContent(); 0194 0195 // multipart/alternative 0196 { 0197 QVERIFY(result->contentType(false)); 0198 QCOMPARE(result->contentType()->mimeType(), QByteArray("multipart/alternative")); 0199 QCOMPARE(result->contents().count(), 2); 0200 // text/plain 0201 { 0202 Content *plain = result->contents().at(0); 0203 QVERIFY(plain->contentType(false)); 0204 QCOMPARE(plain->contentType()->mimeType(), QByteArray("text/plain")); 0205 QCOMPARE(QString::fromLatin1(plain->body()), editor.composerControler()->toCleanPlainText()); 0206 } 0207 // text/html 0208 { 0209 Content *html = result->contents().at(1); 0210 QVERIFY(html->contentType(false)); 0211 QCOMPARE(html->contentType()->mimeType(), QByteArray("text/html")); 0212 // The editor adds extra Html stuff, so we can't compare to originalHtml. 0213 QCOMPARE(QLatin1StringView(html->body()), editor.toCleanHtml()); 0214 } 0215 } 0216 delete composer; 0217 } 0218 0219 void MainTextJobTest::testHtmlWithImages() 0220 { 0221 KActionCollection ac(this); 0222 MessageComposer::RichTextComposerNg editor; 0223 editor.createActions(new KActionCollection(this)); 0224 0225 QImage image1(16, 16, QImage::Format_ARGB32_Premultiplied); 0226 image1.fill(Qt::red); 0227 const QString image1Path = QCoreApplication::applicationDirPath() + QLatin1StringView("/image1.png"); 0228 image1.save(image1Path); 0229 0230 QImage image2(16, 16, QImage::Format_ARGB32_Premultiplied); 0231 image2.fill(Qt::blue); 0232 const QString image2Path = QCoreApplication::applicationDirPath() + QLatin1StringView("/image2.png"); 0233 image2.save(image2Path); 0234 0235 QString data = QStringLiteral("dust in the wind"); 0236 editor.setTextOrHtml(data); 0237 editor.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path)); 0238 editor.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path)); 0239 editor.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image2Path)); 0240 editor.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image2Path)); 0241 0242 auto composer = new Composer; 0243 composer->globalPart()->setGuiEnabled(false); 0244 composer->globalPart()->setFallbackCharsetEnabled(true); 0245 auto textPart = new TextPart; 0246 textPart->setWordWrappingEnabled(false); 0247 textPart->setCleanPlainText(editor.composerControler()->toCleanPlainText()); 0248 textPart->setCleanHtml(editor.composerControler()->toCleanHtml()); 0249 // only get once, are regenerated on call with new contentID each time 0250 const KPIMTextEdit::ImageList images = editor.composerControler()->composerImages()->embeddedImages(); 0251 QCOMPARE(images.count(), 2); 0252 const QString cid1 = images[0]->contentID; 0253 const QString cid2 = images[1]->contentID; 0254 const QString name1 = images[0]->imageName; 0255 const QString name2 = images[1]->imageName; 0256 textPart->setEmbeddedImages(images); 0257 auto mjob = new MainTextJob(textPart, composer); 0258 QVERIFY(mjob->exec()); 0259 Content *result = mjob->content(); 0260 result->assemble(); 0261 qDebug() << result->encodedContent(); 0262 0263 // multipart/related 0264 { 0265 QVERIFY(result->contentType(false)); 0266 QCOMPARE(result->contentType()->mimeType(), QByteArray("multipart/related")); 0267 QCOMPARE(result->contents().count(), 3); 0268 // multipart/alternative 0269 { 0270 Content *alternative = result->contents().at(0); 0271 QVERIFY(alternative->contentType(false)); 0272 QCOMPARE(alternative->contentType()->mimeType(), QByteArray("multipart/alternative")); 0273 QCOMPARE(alternative->contents().count(), 2); 0274 // text/plain 0275 { 0276 Content *plain = alternative->contents().at(0); 0277 QCOMPARE(plain->contentType()->mimeType(), QByteArray("text/plain")); 0278 QCOMPARE(QString::fromLatin1(plain->body()), data); 0279 } 0280 // text/html 0281 { 0282 Content *html = alternative->contents().at(1); 0283 QCOMPARE(html->contentType()->mimeType(), QByteArray("text/html")); 0284 QString data = QString::fromLatin1(html->body()); 0285 const int idx1 = data.indexOf(QStringLiteral("cid:%1").arg(cid1)); 0286 const int idx2 = data.indexOf(QStringLiteral("cid:%1").arg(cid2)); 0287 // qDebug() << " cid1 " << cid1 << "cid2 " << cid2 << " data " << data; 0288 QVERIFY(idx1 > 0); 0289 QVERIFY(idx2 > 0); 0290 QVERIFY(idx1 < idx2); 0291 } 0292 } 0293 // First image/png 0294 { 0295 Content *image = result->contents().at(1); 0296 QVERIFY(image->contentType(false)); 0297 QCOMPARE(image->contentType()->mimeType(), QByteArray("image/png")); 0298 QCOMPARE(image->contentType()->name(), name1); 0299 const Headers::ContentID *cid = image->header<Headers::ContentID>(); 0300 QVERIFY(cid); 0301 QCOMPARE(cid->identifier(), cid1.toLatin1()); 0302 } 0303 // Second image/png 0304 { 0305 Content *image = result->contents().at(2); 0306 QVERIFY(image->contentType(false)); 0307 QCOMPARE(image->contentType()->mimeType(), QByteArray("image/png")); 0308 QCOMPARE(image->contentType()->name(), name2); 0309 const Headers::ContentID *cid = image->header<Headers::ContentID>(); 0310 QVERIFY(cid); 0311 QCOMPARE(cid->identifier(), cid2.toLatin1()); 0312 } 0313 } 0314 delete textPart; 0315 delete composer; 0316 } 0317 0318 #include "moc_maintextjobtest.cpp"