1 /*
2 SPDX-FileCopyrightText: 2015-2021 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "richtextcomposertest.h"
8 #include "../richtextcomposer.h"
9 #include <KCodecs>
10 #include <QSignalSpy>
11 #include <QTest>
12
13 #include <KActionCollection>
14 #include <KIconLoader>
15 #include <QAction>
16
17 #include <QBuffer>
18 #include <QStandardPaths>
19 #include <QTextBlock>
20 #include <QTextCursor>
21 #include <kpimtextedit/richtextcomposer.h>
22 #include <kpimtextedit/richtextcomposercontroler.h>
23 #include <kpimtextedit/richtextcomposerimages.h>
24
25 using namespace KPIMTextEdit;
26
Q_DECLARE_METATYPE(KPIMTextEdit::RichTextComposer::Mode)27 Q_DECLARE_METATYPE(KPIMTextEdit::RichTextComposer::Mode)
28 RichTextComposerTest::RichTextComposerTest(QObject *parent)
29 : QObject(parent)
30 {
31 qRegisterMetaType<KPIMTextEdit::RichTextComposer::Mode>();
32 QIcon::setThemeName(QStringLiteral("breeze"));
33 QStandardPaths::setTestModeEnabled(true);
34 }
35
~RichTextComposerTest()36 RichTextComposerTest::~RichTextComposerTest()
37 {
38 }
39
testFormattingUsed()40 void RichTextComposerTest::testFormattingUsed()
41 {
42 // This method tries to test everything that krichtextedit makes available, so
43 // we can sure that in KMail, when the user uses some formatting, the mail is actually
44 // sent as HTML mail
45
46 KPIMTextEdit::RichTextComposer textEdit;
47 textEdit.createActions(new KActionCollection(this));
48
49 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
50
51 // Insert some text.
52 QTextCursor cursor(textEdit.document());
53 cursor.insertText(QStringLiteral("Hello World!!"));
54 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
55 cursor.setPosition(1);
56 textEdit.setTextCursor(cursor);
57
58 //
59 // Test link
60 //
61 QString someUrl = QStringLiteral("www.test.de");
62 QString altText = QStringLiteral("Hello");
63 textEdit.composerControler()->updateLink(someUrl, altText);
64 QVERIFY(textEdit.composerControler()->isFormattingUsed());
65 QCOMPARE(textEdit.composerControler()->currentLinkUrl(), someUrl);
66 QCOMPARE(textEdit.composerControler()->currentLinkText(), altText);
67
68 cursor.setPosition(1);
69 textEdit.setTextCursor(cursor);
70 textEdit.composerControler()->updateLink(QString(), QStringLiteral("Hello"));
71 QVERIFY(textEdit.composerControler()->currentLinkUrl().isEmpty());
72 QVERIFY(!textEdit.composerControler()->currentLinkText().isEmpty());
73 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
74
75 //
76 // Test alignment
77 //
78 cursor.setPosition(1);
79 textEdit.setTextCursor(cursor);
80 textEdit.composerControler()->alignRight();
81 QVERIFY(textEdit.composerControler()->isFormattingUsed());
82 QCOMPARE(textEdit.alignment(), Qt::AlignRight);
83 textEdit.composerControler()->alignLeft();
84 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
85 textEdit.composerControler()->alignCenter();
86 QCOMPARE(textEdit.alignment(), Qt::AlignHCenter);
87 QVERIFY(textEdit.composerControler()->isFormattingUsed());
88 textEdit.composerControler()->alignJustify();
89 QCOMPARE(textEdit.alignment(), Qt::AlignJustify);
90 QVERIFY(textEdit.composerControler()->isFormattingUsed());
91 textEdit.composerControler()->alignLeft();
92 QCOMPARE(textEdit.alignment(), Qt::AlignLeft);
93 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
94
95 //
96 // Test layout direction
97 //
98 textEdit.selectAll();
99 QTextCharFormat direction;
100 direction.setLayoutDirection(Qt::RightToLeft);
101 textEdit.mergeCurrentCharFormat(direction);
102 QVERIFY(textEdit.composerControler()->isFormattingUsed());
103 direction.setLayoutDirection(Qt::LeftToRight);
104 textEdit.mergeCurrentCharFormat(direction);
105 QVERIFY(textEdit.composerControler()->isFormattingUsed());
106
107 //
108 // Test lists
109 //
110 textEdit.composerControler()->setListStyle(QTextListFormat::ListCircle);
111 QVERIFY(textEdit.composerControler()->isFormattingUsed());
112 textEdit.composerControler()->setListStyle(0);
113 QVERIFY(textEdit.composerControler()->isFormattingUsed());
114
115 //
116 // Test font attributes
117 //
118 textEdit.setFontFamily(QStringLiteral("Times"));
119 QVERIFY(textEdit.composerControler()->isFormattingUsed());
120 textEdit.setFontFamily(textEdit.document()->defaultFont().family());
121 QVERIFY(textEdit.composerControler()->isFormattingUsed());
122 textEdit.composerControler()->setFontSize(48);
123 QVERIFY(textEdit.composerControler()->isFormattingUsed());
124 textEdit.composerControler()->setFontSize(textEdit.document()->defaultFont().pointSize());
125 QVERIFY(textEdit.composerControler()->isFormattingUsed());
126 QFont myFont = textEdit.document()->defaultFont();
127 myFont.setStyle(QFont::StyleOblique);
128 textEdit.composerControler()->setFont(myFont);
129 QVERIFY(textEdit.composerControler()->isFormattingUsed());
130 textEdit.composerControler()->setFont(textEdit.document()->defaultFont());
131 QVERIFY(textEdit.composerControler()->isFormattingUsed());
132
133 //
134 // Test bold, italic, underline and strikeout
135 //
136 textEdit.composerControler()->setTextBold(true);
137 QVERIFY(textEdit.composerControler()->isFormattingUsed());
138 textEdit.composerControler()->setTextBold(false);
139 QVERIFY(textEdit.composerControler()->isFormattingUsed());
140 textEdit.composerControler()->setTextUnderline(true);
141 QVERIFY(textEdit.composerControler()->isFormattingUsed());
142 textEdit.composerControler()->setTextUnderline(false);
143 QVERIFY(textEdit.composerControler()->isFormattingUsed());
144 textEdit.composerControler()->setTextItalic(true);
145 QVERIFY(textEdit.composerControler()->isFormattingUsed());
146 textEdit.composerControler()->setTextItalic(false);
147 QVERIFY(textEdit.composerControler()->isFormattingUsed());
148 textEdit.composerControler()->setTextStrikeOut(true);
149 QVERIFY(textEdit.composerControler()->isFormattingUsed());
150 textEdit.composerControler()->setTextStrikeOut(false);
151 QVERIFY(textEdit.composerControler()->isFormattingUsed());
152
153 //
154 // Color
155 //
156 QColor oldForeground = textEdit.document()->firstBlock().charFormat().foreground().color();
157 textEdit.composerControler()->setTextForegroundColor(Qt::red);
158 QVERIFY(textEdit.composerControler()->isFormattingUsed());
159 textEdit.composerControler()->setTextForegroundColor(oldForeground);
160 QVERIFY(textEdit.composerControler()->isFormattingUsed());
161 QColor oldBackground = textEdit.document()->firstBlock().charFormat().background().color();
162 textEdit.composerControler()->setTextBackgroundColor(Qt::red);
163 QVERIFY(textEdit.composerControler()->isFormattingUsed());
164 textEdit.composerControler()->setTextBackgroundColor(oldBackground);
165 QVERIFY(textEdit.composerControler()->isFormattingUsed());
166
167 //
168 // Horizontal rule
169 //
170 textEdit.composerControler()->insertHorizontalRule();
171 QVERIFY(textEdit.composerControler()->isFormattingUsed());
172 // No way to easily remove the horizontal line, so clear the text edit and start over
173 textEdit.clear();
174 cursor.insertText(QStringLiteral("Hello World!!"));
175 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
176 cursor.setPosition(1);
177 textEdit.setTextCursor(cursor);
178
179 //
180 // Sub and superscript
181 //
182 textEdit.composerControler()->setTextSuperScript(true);
183 QVERIFY(textEdit.composerControler()->isFormattingUsed());
184 textEdit.composerControler()->setTextSuperScript(false);
185 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
186 textEdit.composerControler()->setTextSubScript(true);
187 QVERIFY(textEdit.composerControler()->isFormattingUsed());
188 textEdit.composerControler()->setTextSubScript(false);
189 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
190
191 //
192 // Image
193 //
194 const QString imagePath = KIconLoader::global()->iconPath(QStringLiteral("folder-new"), KIconLoader::Small, false);
195 textEdit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(imagePath));
196 QVERIFY(textEdit.composerControler()->isFormattingUsed());
197 cursor = textEdit.textCursor();
198 cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
199 cursor.removeSelectedText();
200 QVERIFY(!textEdit.composerControler()->isFormattingUsed());
201 }
202
testQuoting()203 void RichTextComposerTest::testQuoting()
204 {
205 KPIMTextEdit::RichTextComposer edit;
206 edit.createActions(new KActionCollection(this));
207 QVERIFY(edit.isLineQuoted(QStringLiteral("> Hello")));
208 QVERIFY(edit.isLineQuoted(QStringLiteral(">Hello")));
209 QVERIFY(!edit.isLineQuoted(QStringLiteral("Hello")));
210 QCOMPARE(edit.quoteLength(QStringLiteral("Hello")), 0);
211 QCOMPARE(edit.quoteLength(QStringLiteral(">Hello")), 1);
212 QCOMPARE(edit.quoteLength(QStringLiteral("> Hello")), 2);
213 QCOMPARE(edit.quoteLength(QStringLiteral(">>>Hello")), 3);
214 QCOMPARE(edit.quoteLength(QStringLiteral("> > > Hello")), 6);
215 QCOMPARE(edit.quoteLength(QStringLiteral("|Hello")), 1);
216 QCOMPARE(edit.quoteLength(QStringLiteral("| |Hello")), 3);
217 }
218
testCleanText()219 void RichTextComposerTest::testCleanText()
220 {
221 KPIMTextEdit::RichTextComposer edit;
222 edit.createActions(new KActionCollection(this));
223 QString html(QStringLiteral("<html><head></head><body>Heelllo World<br>Bye!</body></html>"));
224 QString plain(QStringLiteral("Heelllo World\nBye!"));
225 edit.setTextOrHtml(html);
226 edit.composerControler()->composerImages()->addImage(
227 QUrl::fromLocalFile(KIconLoader::global()->iconPath(QStringLiteral("folder-new"), KIconLoader::Small, false)));
228 QVERIFY(edit.textMode() == KPIMTextEdit::RichTextComposer::Rich);
229 QCOMPARE(edit.composerControler()->toCleanPlainText(), plain);
230
231 edit.show(); // < otherwise toWrappedPlainText can't work, it needs a layout
232 QCOMPARE(edit.composerControler()->toWrappedPlainText(), plain);
233 }
234
testEnter_data()235 void RichTextComposerTest::testEnter_data()
236 {
237 QTest::addColumn<QString>("initalText");
238 QTest::addColumn<QString>("expectedText");
239 QTest::addColumn<int>("cursorPos");
240
241 QTest::newRow("") << QStringLiteral("> Hello World") << QStringLiteral("> Hello \n> World") << 8;
242 QTest::newRow("") << QStringLiteral("Hello World") << QStringLiteral("Hello \nWorld") << 6;
243 QTest::newRow("") << QStringLiteral("> Hello World") << QStringLiteral("> Hello World\n") << 13;
244 QTest::newRow("") << QStringLiteral(">Hello World") << QStringLiteral(">Hello \n>World") << 7;
245 QTest::newRow("") << QStringLiteral("> > Hello World") << QStringLiteral("> > Hello \n> > World") << 10;
246 QTest::newRow("") << QStringLiteral("| | Hello World") << QStringLiteral("| | Hello \n| | World") << 10;
247 }
248
testEnter()249 void RichTextComposerTest::testEnter()
250 {
251 QFETCH(QString, initalText);
252 QFETCH(QString, expectedText);
253 QFETCH(int, cursorPos);
254
255 KPIMTextEdit::RichTextComposer edit;
256 edit.createActions(new KActionCollection(this));
257 edit.setPlainText(initalText);
258 QTextCursor textCursor(edit.document());
259 textCursor.setPosition(cursorPos);
260 edit.setTextCursor(textCursor);
261
262 QTest::keyClick(&edit, Qt::Key_Return);
263 QCOMPARE(edit.toPlainText(), expectedText);
264 }
265
testImages()266 void RichTextComposerTest::testImages()
267 {
268 KPIMTextEdit::RichTextComposer edit;
269 edit.createActions(new KActionCollection(this));
270 QString image1Path = KIconLoader::global()->iconPath(QStringLiteral("folder-new"), KIconLoader::Small, false);
271 QString image2Path = KIconLoader::global()->iconPath(QStringLiteral("arrow-up"), KIconLoader::Small, false);
272
273 // Add one image, check that embeddedImages() returns the right stuff
274 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path));
275 KPIMTextEdit::ImageList images = edit.composerControler()->composerImages()->embeddedImages();
276 KPIMTextEdit::ImageWithNameList imagesWithNames = edit.composerControler()->composerImages()->imagesWithName();
277 QCOMPARE(images.size(), 1);
278 QCOMPARE(imagesWithNames.size(), 1);
279 EmbeddedImage *image = images.first().data();
280 ImageWithName *imageWithName = imagesWithNames.first().data();
281 QCOMPARE(image->imageName, QString::fromLatin1("folder-new.png"));
282 QCOMPARE(imageWithName->name, QString::fromLatin1("folder-new.png"));
283
284 // Also check that it loads the correct image
285 QImage diskImage(image1Path);
286 QBuffer buffer;
287 buffer.open(QIODevice::WriteOnly);
288 diskImage.save(&buffer, "PNG");
289 QBuffer imageWithNameBuffer;
290 imageWithNameBuffer.open(QIODevice::WriteOnly);
291 imageWithName->image.save(&imageWithNameBuffer, "PNG");
292 QByteArray encodedImage = KCodecs::Codec::codecForName("base64")->encode(buffer.buffer());
293 QCOMPARE(image->image, encodedImage);
294 QCOMPARE(buffer.buffer(), imageWithNameBuffer.buffer());
295
296 // No image should be there after clearing
297 edit.clear();
298 QVERIFY(edit.composerControler()->composerImages()->embeddedImages().isEmpty());
299 QVERIFY(edit.composerControler()->composerImages()->imagesWithName().isEmpty());
300
301 // Check that manually removing the image also empties the image list
302 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path));
303 QCOMPARE(edit.composerControler()->composerImages()->embeddedImages().size(), 1);
304 QCOMPARE(edit.composerControler()->composerImages()->imagesWithName().size(), 1);
305 QTextCursor cursor = edit.textCursor();
306 cursor.setPosition(0, QTextCursor::MoveAnchor);
307 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
308 cursor.removeSelectedText();
309 QVERIFY(edit.composerControler()->composerImages()->embeddedImages().isEmpty());
310 QVERIFY(edit.composerControler()->composerImages()->imagesWithName().isEmpty());
311
312 // Check that adding the identical image two times only adds the image once
313 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path));
314 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path));
315 QCOMPARE(edit.composerControler()->composerImages()->embeddedImages().size(), 1);
316 QCOMPARE(edit.composerControler()->composerImages()->imagesWithName().size(), 1);
317
318 // Another different image added, and we should have two images
319 edit.clear();
320 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path));
321 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image2Path));
322 images = edit.composerControler()->composerImages()->embeddedImages();
323 imagesWithNames = edit.composerControler()->composerImages()->imagesWithName();
324 QCOMPARE(images.size(), 2);
325 QCOMPARE(imagesWithNames.size(), 2);
326 KPIMTextEdit::EmbeddedImage *image1 = images.first().data();
327 KPIMTextEdit::EmbeddedImage *image2 = images.last().data();
328 KPIMTextEdit::ImageWithName *imageWithName1 = imagesWithNames.first().data();
329 KPIMTextEdit::ImageWithName *imageWithName2 = imagesWithNames.last().data();
330 QCOMPARE(image1->imageName,
331 QString::fromLatin1("folder-new2.png")); // ### FIXME: should be folder-new.png, but QTextEdit provides no way to remove cached resources!
332 QCOMPARE(imageWithName1->name, QString::fromLatin1("folder-new2.png"));
333 QCOMPARE(image2->imageName, QString::fromLatin1("arrow-up.png"));
334 QCOMPARE(imageWithName2->name, QString::fromLatin1("arrow-up.png"));
335 QVERIFY(image1->contentID != image2->contentID);
336 }
337
testImageHtmlCode()338 void RichTextComposerTest::testImageHtmlCode()
339 {
340 KPIMTextEdit::RichTextComposer edit;
341 edit.createActions(new KActionCollection(this));
342 QString image1Path = KIconLoader::global()->iconPath(QStringLiteral("folder-new"), KIconLoader::Small, false);
343 QString image2Path = KIconLoader::global()->iconPath(QStringLiteral("arrow-up"), KIconLoader::Small, false);
344 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image1Path));
345 edit.composerControler()->composerImages()->addImage(QUrl::fromLocalFile(image2Path));
346 KPIMTextEdit::ImageList images = edit.composerControler()->composerImages()->embeddedImages();
347 QCOMPARE(images.size(), 2);
348 KPIMTextEdit::EmbeddedImage *image1 = images.first().data();
349 KPIMTextEdit::EmbeddedImage *image2 = images.last().data();
350 QString startHtml = QStringLiteral("<img src=\"arrow-up.png\"><img src=\"folder-new.png\">Bla<b>Blub</b>");
351 QString endHtml = QStringLiteral("<img src=\"cid:%1\"><img src=\"cid:%2\">Bla<b>Blub</b>").arg(image2->contentID, image1->contentID);
352 QCOMPARE(KPIMTextEdit::RichTextComposerImages::imageNamesToContentIds(startHtml.toLatin1(), images), endHtml.toLatin1());
353 }
354
testDeleteLine_data()355 void RichTextComposerTest::testDeleteLine_data()
356 {
357 QTest::addColumn<QString>("initalText");
358 QTest::addColumn<QString>("expectedText");
359 QTest::addColumn<int>("cursorPos");
360
361 QTest::newRow("delete1") << QStringLiteral("line1\nline2\nline3") << QStringLiteral("line1\nline3") << 6;
362 QTest::newRow("delete2") << QStringLiteral("line1\nline2\nline3") << QStringLiteral("line2\nline3") << 5;
363 QTest::newRow("delete3") << QStringLiteral("line1\nline2\nline3") << QStringLiteral("line1\nline3") << 11;
364 QTest::newRow("delete4") << QStringLiteral("line1\nline2\nline3") << QStringLiteral("line2\nline3") << 0;
365 QTest::newRow("delete5") << QStringLiteral("line1\nline2\nline3") << QStringLiteral("line1\nline2") << 17;
366 QTest::newRow("delete6") << QStringLiteral("line1") << QString() << 0;
367 QTest::newRow("delete7") << QStringLiteral("line1") << QString() << 5;
368
369 // Now, test deletion with word wrapping. The line with the Ms is so long that it will get wrapped
370 QTest::newRow("delete8") << QStringLiteral("line1\nMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\nline3")
371 << QStringLiteral("line1\nMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\nline3") << 6;
372 QTest::newRow("delete9") << QStringLiteral("line1\nMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\nline3")
373 << QStringLiteral("line1\nMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\nline3") << 13;
374 }
375
testDeleteLine()376 void RichTextComposerTest::testDeleteLine()
377 {
378 #if 0
379 QFETCH(QString, initalText);
380 QFETCH(QString, expectedText);
381 QFETCH(int, cursorPos);
382
383 KPIMTextEdit::RichTextComposer edit;
384 edit.createActions(new KActionCollection(this));
385 edit.setPlainText(initalText);
386 QTextCursor cursor = edit.textCursor();
387 cursor.setPosition(cursorPos);
388 edit.setTextCursor(cursor);
389
390 edit.show(); // we need a layout for this to work
391
392 edit.composerControler()->deleteCurrentLine();
393 QCOMPARE(edit.toPlainText(), expectedText);
394 #endif
395 }
396
testLoadImage()397 void RichTextComposerTest::testLoadImage()
398 {
399 KPIMTextEdit::RichTextComposer edit;
400 edit.createActions(new KActionCollection(this));
401 QString image1Path = KIconLoader::global()->iconPath(QStringLiteral("folder-new"), KIconLoader::Small, false);
402 QString image2Path = KIconLoader::global()->iconPath(QStringLiteral("arrow-up"), KIconLoader::Small, false);
403 QImage image1;
404 QImage image2;
405 QVERIFY(image1.load(image1Path));
406 QVERIFY(image2.load(image2Path));
407
408 edit.setHtml(QStringLiteral("Bla<img src=\"folder-new.png\">Bla"));
409
410 // First try to load an image with a name that doesn't match, it should fail
411 edit.composerControler()->composerImages()->loadImage(image1, QStringLiteral("doesntmatch"), QStringLiteral("folder-new"));
412 QVERIFY(!edit.document()->resource(QTextDocument::ImageResource, QUrl(QStringLiteral("folder-new"))).isValid());
413
414 // Now, load the image for real
415 edit.composerControler()->composerImages()->loadImage(image1, QStringLiteral("folder-new.png"), QStringLiteral("folder-new"));
416 QVERIFY(edit.document()->resource(QTextDocument::ImageResource, QUrl(QStringLiteral("folder-new"))).isValid());
417
418 // New test with a new textedit (so that we don't use the cached resources
419 // This example has two images in the same text block, make sure that doesn't crash (bug 204214)
420 KPIMTextEdit::RichTextComposer edit2;
421 edit2.createActions(new KActionCollection(this));
422 edit2.setHtml(QStringLiteral("<img src=\"folder-new.png\"><img src=\"folder-new.png\">"));
423 edit2.composerControler()->composerImages()->loadImage(image1, QStringLiteral("folder-new.png"), QStringLiteral("folder-new"));
424 QVERIFY(edit.document()->resource(QTextDocument::ImageResource, QUrl(QStringLiteral("folder-new"))).isValid());
425 QCOMPARE(edit.composerControler()->composerImages()->embeddedImages().size(), 1);
426 }
427
testWrappedPlainText_data()428 void RichTextComposerTest::testWrappedPlainText_data()
429 {
430 QTest::addColumn<QString>("input");
431 QTest::addColumn<QString>("output");
432
433 QString defaultStr = QStringLiteral(
434 "http://example.org/test-test-test-test-test-test-test-test-test-test-test-test-test\n "
435 "https://example.org/test-test-test-test-test-test-test-test-test-test-test-test-test\ntest "
436 "ftp://example.org/test-test-test-test-test-test-test-test-test-test-test-test-test\nftps://example.org/"
437 "test-test-test-test-test-test-test-test-test-test-test-test-test\n "
438 "ldap://example.org/test-test-test-test-test-test-test-test-test-test-test-test-test");
439 QTest::newRow("default") << defaultStr << defaultStr;
440 QTest::newRow("empty") << QString() << QString();
441 QTest::newRow("wrap") << QStringLiteral("foosdfsdf sdsf sdfsdfsfs fsf sdfs df sfsdf dsf sdfsdf sf sf sfsdf sdsdf")
442 << QStringLiteral("foosdfsdf sdsf sdfsdfsfs fsf sdfs df sfsdf \ndsf sdfsdf sf sf sfsdf sdsdf");
443 QTest::newRow("wrap-2") << QStringLiteral("test-test-test-test-test-test-test-test-test-test-test-test-test")
444 << QStringLiteral("test-test-test-test-test-test-test-test-\ntest-test-test-test-test");
445 QTest::newRow("wrap-3") << QStringLiteral("test-test-test-test-test-test-test-test-test-test-test-test-test\n\n")
446 << QStringLiteral("test-test-test-test-test-test-test-test-\ntest-test-test-test-test\n\n");
447 }
448
testWrappedPlainText()449 void RichTextComposerTest::testWrappedPlainText()
450 {
451 QFETCH(QString, input);
452 QFETCH(QString, output);
453 KPIMTextEdit::RichTextComposer edit;
454 edit.createActions(new KActionCollection(this));
455 edit.setPlainText(input);
456
457 edit.show(); // < otherwise toWrappedPlainText can't work, it needs a layout
458
459 QCOMPARE(edit.composerControler()->toWrappedPlainText(), output);
460 }
461
testEnableDisableActions()462 void RichTextComposerTest::testEnableDisableActions()
463 {
464 KPIMTextEdit::RichTextComposer composer;
465 KActionCollection *actionCollection = new KActionCollection(&composer);
466 composer.createActions(actionCollection);
467 bool enableAction = true;
468 composer.setEnableActions(enableAction);
469 for (QAction *act : composer.actions()) {
470 QCOMPARE(act->isEnabled(), enableAction);
471 }
472
473 enableAction = false;
474 composer.setEnableActions(enableAction);
475 for (QAction *act : composer.actions()) {
476 QCOMPARE(act->isEnabled(), enableAction);
477 }
478 }
479
shouldHaveDefaultValue()480 void RichTextComposerTest::shouldHaveDefaultValue()
481 {
482 KPIMTextEdit::RichTextComposer composer;
483 KActionCollection *actionCollection = new KActionCollection(&composer);
484 composer.createActions(actionCollection);
485 QCOMPARE(composer.linePosition(), 0);
486 QCOMPARE(composer.columnNumber(), 0);
487 QCOMPARE(composer.textMode(), KPIMTextEdit::RichTextComposer::Plain);
488 QVERIFY(!composer.acceptRichText());
489 QVERIFY(!composer.quotePrefixName().isEmpty());
490 }
491
shouldChangeMode()492 void RichTextComposerTest::shouldChangeMode()
493 {
494 KPIMTextEdit::RichTextComposer composer;
495 KActionCollection *actionCollection = new KActionCollection(&composer);
496 composer.createActions(actionCollection);
497 QSignalSpy spy(&composer, &RichTextComposer::textModeChanged);
498 composer.activateRichText();
499 QCOMPARE(composer.textMode(), KPIMTextEdit::RichTextComposer::Rich);
500 QVERIFY(composer.acceptRichText());
501 QCOMPARE(spy.count(), 1);
502 }
503
504 QTEST_MAIN(RichTextComposerTest)
505