1 /*
2 SPDX-FileCopyrightText: 2016-2021 Laurent Montel <montel@kde.org>
3 SPDX-FileCopyrightText: 2008 Thomas McGuire <mcguire@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8 #undef QT_USE_FAST_CONCATENATION
9 #undef QT_USE_FAST_OPERATOR_PLUS
10
11 #include "signaturetest.h"
12 #include "qtest.h"
13
14 #include "signature.h"
15
16 #include <KActionCollection>
17 #include <KConfig>
18 #include <KConfigGroup>
19 #include <KShell>
20 #include <QDir>
21 #include <QStandardPaths>
22
23 #include <kpimtextedit/richtextcomposer.h>
24 #include <kpimtextedit/richtextcomposercontroler.h>
25 #include <kpimtextedit/richtextcomposerimages.h>
26 using namespace KIdentityManagement;
27 using namespace KPIMTextEdit;
28
QTEST_MAIN(SignatureTester)29 QTEST_MAIN(SignatureTester)
30
31 void SignatureTester::testEqualSignatures()
32 {
33 Signature sig1;
34 sig1.setText(QStringLiteral("Hello World"));
35 sig1.setEnabledSignature(true);
36 Signature sig2(sig1);
37 QVERIFY(sig1 == sig2);
38 QCOMPARE(sig2.text(), QStringLiteral("Hello World"));
39 QCOMPARE(sig2.type(), Signature::Inlined);
40 QCOMPARE(sig2.rawText(), QStringLiteral("Hello World"));
41 QVERIFY(!sig2.isInlinedHtml());
42 QCOMPARE(sig2.withSeparator(), QStringLiteral("-- \nHello World"));
43 QVERIFY(sig2.isEnabledSignature());
44
45 Signature sig3 = sig1;
46 QVERIFY(sig1 == sig3);
47 QCOMPARE(sig3.text(), QStringLiteral("Hello World"));
48 QCOMPARE(sig3.type(), Signature::Inlined);
49 QCOMPARE(sig3.rawText(), QStringLiteral("Hello World"));
50 QVERIFY(!sig3.isInlinedHtml());
51 QCOMPARE(sig3.withSeparator(), QStringLiteral("-- \nHello World"));
52 QVERIFY(sig3.isEnabledSignature());
53 }
54
testSignatures()55 void SignatureTester::testSignatures()
56 {
57 Signature sig1;
58 sig1.setText(QStringLiteral("Hello World"));
59 QCOMPARE(sig1.text(), QStringLiteral("Hello World"));
60 QCOMPARE(sig1.type(), Signature::Inlined);
61 QCOMPARE(sig1.rawText(), QStringLiteral("Hello World"));
62 QVERIFY(!sig1.isInlinedHtml());
63 QCOMPARE(sig1.withSeparator(), QStringLiteral("-- \nHello World"));
64 QVERIFY(!sig1.isEnabledSignature());
65
66 Signature sig2;
67 sig2.setText(QStringLiteral("<b>Hello</b> World"));
68 sig2.setInlinedHtml(true);
69 QVERIFY(sig2.isInlinedHtml());
70 QCOMPARE(sig2.type(), Signature::Inlined);
71 QCOMPARE(sig2.rawText(), QStringLiteral("<b>Hello</b> World"));
72 QCOMPARE(sig2.withSeparator(), QStringLiteral("-- <br><b>Hello</b> World"));
73 QVERIFY(!sig2.isEnabledSignature());
74
75 const QString dataFilePath = QStringLiteral(SIGNATURETEST_DATA_FILE);
76 // Read this very file in, we use it for the tests
77 QFile thisFile(dataFilePath);
78 thisFile.open(QIODevice::ReadOnly);
79 QString fileContent = QString::fromUtf8(thisFile.readAll());
80
81 if (!QStandardPaths::findExecutable(QStringLiteral("cat")).isEmpty()) {
82 Signature sig3;
83 sig3.setPath(QStringLiteral("cat ") + KShell::quoteArg(dataFilePath), true);
84 QCOMPARE(sig3.rawText(), fileContent);
85 QVERIFY(!sig3.isInlinedHtml());
86 QVERIFY(sig3.text().isEmpty());
87 QCOMPARE(sig3.type(), Signature::FromCommand);
88 QCOMPARE(sig3.withSeparator(), QString(QStringLiteral("-- \n") + fileContent));
89 QVERIFY(!sig3.isEnabledSignature());
90 }
91
92 Signature sig4;
93 sig4.setPath(dataFilePath, false);
94 QCOMPARE(sig4.rawText(), fileContent);
95 QVERIFY(!sig4.isInlinedHtml());
96 QVERIFY(sig4.text().isEmpty());
97 QCOMPARE(sig4.type(), Signature::FromFile);
98 QCOMPARE(sig4.withSeparator(), QString(QStringLiteral("-- \n") + fileContent));
99 QVERIFY(!sig4.isEnabledSignature());
100 }
101
setCursorPos(QTextEdit & edit,int pos)102 static void setCursorPos(QTextEdit &edit, int pos)
103 {
104 QTextCursor cursor(edit.document());
105 cursor.setPosition(pos);
106 edit.setTextCursor(cursor);
107 }
108
testTextEditInsertion()109 void SignatureTester::testTextEditInsertion()
110 {
111 KPIMTextEdit::RichTextComposer edit;
112 edit.createActions(new KActionCollection(this));
113 Signature sig;
114 sig.setEnabledSignature(true);
115 sig.setText(QStringLiteral("Hello World"));
116
117 // Test inserting signature at start, with separators. Make sure two new
118 // lines are inserted before the signature
119
120 edit.setPlainText(QStringLiteral("Bla Bla"));
121 sig.insertIntoTextEdit(Signature::Start, Signature::AddSeparator | Signature::AddNewLines, &edit);
122 QVERIFY(edit.textMode() == KPIMTextEdit::RichTextComposer::Plain);
123 QCOMPARE(edit.toPlainText(), QStringLiteral("\n\n-- \nHello World\nBla Bla"));
124
125 // Test inserting signature at end. make sure cursor position is preserved
126 edit.clear();
127 edit.setPlainText(QStringLiteral("Bla Bla"));
128 setCursorPos(edit, 4);
129 sig.insertIntoTextEdit(Signature::End, Signature::AddSeparator | Signature::AddNewLines, &edit);
130 QCOMPARE(edit.toPlainText(), QStringLiteral("Bla Bla\n-- \nHello World"));
131 QCOMPARE(edit.textCursor().position(), 4);
132
133 // test inserting a signature at cursor position. make sure the signature is inserted
134 // to the beginning of the line and make sure modified state is preserved
135 edit.clear();
136 edit.setPlainText(QStringLiteral("Bla Bla"));
137 setCursorPos(edit, 4);
138 edit.document()->setModified(false);
139 sig.insertIntoTextEdit(Signature::AtCursor, Signature::AddSeparator | Signature::AddNewLines, &edit);
140 QCOMPARE(edit.toPlainText(), QStringLiteral("-- \nHello World\nBla Bla"));
141 QCOMPARE(edit.textCursor().position(), 20);
142 QVERIFY(!edit.document()->isModified());
143
144 // make sure undo undoes everything in one go
145 edit.undo();
146 QCOMPARE(edit.toPlainText(), QStringLiteral("Bla Bla"));
147
148 // test inserting signature without separator.
149 // make sure cursor position and modified state is preserved.
150 edit.clear();
151 edit.setPlainText(QStringLiteral("Bla Bla"));
152 setCursorPos(edit, 4);
153 edit.document()->setModified(true);
154 sig.insertIntoTextEdit(Signature::End, Signature::AddNewLines, &edit);
155 QCOMPARE(edit.toPlainText(), QStringLiteral("Bla Bla\nHello World"));
156 QCOMPARE(edit.textCursor().position(), 4);
157 QVERIFY(edit.document()->isModified());
158
159 sig.setText(QStringLiteral("Hello<br>World"));
160 sig.setInlinedHtml(true);
161
162 // test that html signatures turn html on and have correct line endings (<br> vs \n)
163 edit.clear();
164 edit.setPlainText(QStringLiteral("Bla Bla"));
165 sig.insertIntoTextEdit(Signature::End, Signature::AddSeparator | Signature::AddNewLines, &edit);
166 QVERIFY(edit.textMode() == KPIMTextEdit::RichTextComposer::Rich);
167 QCOMPARE(edit.toPlainText(), QStringLiteral("Bla Bla\n-- \nHello\nWorld"));
168 }
169
testBug167961()170 void SignatureTester::testBug167961()
171 {
172 KPIMTextEdit::RichTextComposer edit;
173 edit.createActions(new KActionCollection(this));
174 Signature sig;
175 sig.setEnabledSignature(true);
176 sig.setText(QStringLiteral("BLA"));
177
178 // Test that the cursor is still at the start when appending a sig into
179 // an empty text edit
180 sig.insertIntoTextEdit(Signature::End, Signature::AddSeparator | Signature::AddNewLines, &edit);
181 QCOMPARE(edit.textCursor().position(), 0);
182
183 // When prepending a sig, the cursor should also be at the start, see bug 211634
184 edit.clear();
185 sig.insertIntoTextEdit(Signature::Start, Signature::AddSeparator | Signature::AddNewLines, &edit);
186 QCOMPARE(edit.textCursor().position(), 0);
187 }
188
189 // Make writeConfig() public, we need it
190 class MySignature : public Signature
191 {
192 public:
193 using Signature::readConfig;
194 using Signature::writeConfig;
195 };
196
testImages()197 void SignatureTester::testImages()
198 {
199 KPIMTextEdit::RichTextComposer edit;
200 edit.createActions(new KActionCollection(this));
201
202 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
203 img.fill(Qt::green);
204 QString image1Path = QCoreApplication::applicationDirPath() + QLatin1String("/image.png");
205 img.save(image1Path);
206
207 QImage image1;
208 QImage image2;
209 QVERIFY(image1.load(image1Path));
210 QVERIFY(image2.load(image1Path));
211 QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/emailidentities/unittest/");
212 QDir().mkpath(path);
213 QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/signaturetest");
214 QDir().mkpath(configPath);
215 KConfig config(configPath);
216 KConfigGroup group1 = config.group("Signature1");
217
218 MySignature sig;
219 sig.setEnabledSignature(true);
220 sig.setImageLocation(path);
221 sig.setInlinedHtml(true);
222 sig.setText(QStringLiteral("Bla<img src=\"folder-new.png\">Bla"));
223 sig.addImage(image1, QStringLiteral("folder-new.png"));
224 sig.writeConfig(group1);
225
226 // OK, signature saved, the image should be saved as well
227 QDir dir(path);
228 QStringList entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
229 QCOMPARE(entryList.count(), 1);
230 QCOMPARE(entryList.first(), QStringLiteral("folder-new.png"));
231
232 // Now, set the text of the signature to something without images, then save it.
233 // The signature class should have removed the images.
234 sig.setText(QStringLiteral("ascii ribbon campaign - against html mail"));
235 sig.writeConfig(group1);
236 entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
237 QCOMPARE(entryList.count(), 0);
238
239 // Enable images again, this time with two of the buggers
240 sig.setText(QStringLiteral("Bla<img src=\"folder-new.png\">Bla<img src=\"arrow-up.png\">Bla"));
241 sig.addImage(image1, QStringLiteral("folder-new.png"));
242 sig.addImage(image2, QStringLiteral("arrow-up.png"));
243 sig.writeConfig(group1);
244 entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
245 QCOMPARE(entryList.count(), 2);
246 QCOMPARE(entryList.first(), QStringLiteral("arrow-up.png"));
247 QCOMPARE(entryList.last(), QStringLiteral("folder-new.png"));
248
249 // Now, create a second signature instance from the same config, and make sure it can still
250 // read the images, and it does not mess up
251 MySignature sig2;
252 sig2.readConfig(group1);
253 sig2.insertIntoTextEdit(KIdentityManagement::Signature::End, Signature::AddSeparator | Signature::AddNewLines, &edit);
254 QCOMPARE(edit.composerControler()->composerImages()->embeddedImages().count(), 2);
255 QCOMPARE(sig2.text(), QStringLiteral("Bla<img src=\"folder-new.png\">Bla<img src=\"arrow-up.png\">Bla"));
256 sig2.writeConfig(group1);
257 entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
258 QCOMPARE(entryList.count(), 2);
259 QCOMPARE(entryList.first(), QStringLiteral("arrow-up.png"));
260 QCOMPARE(entryList.last(), QStringLiteral("folder-new.png"));
261
262 // Remove one image from the signature, and make sure only 1 file is left one file system.
263 sig2.setText(QStringLiteral("<img src=\"folder-new.png\">"));
264 sig2.writeConfig(group1);
265 edit.clear();
266 sig2.insertIntoTextEdit(Signature::End, Signature::AddSeparator | Signature::AddNewLines, &edit);
267 QCOMPARE(edit.composerControler()->composerImages()->embeddedImages().size(), 1);
268 entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
269 QCOMPARE(entryList.count(), 1);
270 }
271
testLinebreaks()272 void SignatureTester::testLinebreaks()
273 {
274 Signature sig;
275 sig.setEnabledSignature(true);
276 sig.setType(Signature::Inlined);
277 sig.setInlinedHtml(true);
278 sig.setText(QStringLiteral("Hans Mustermann<br>Musterstr. 42"));
279
280 KPIMTextEdit::RichTextComposer edit;
281 edit.createActions(new KActionCollection(this));
282 sig.insertIntoTextEdit(Signature::Start, Signature::AddNothing, &edit);
283 QCOMPARE(edit.toPlainText(), QStringLiteral("Hans Mustermann\nMusterstr. 42"));
284
285 edit.clear();
286 sig.setText(QStringLiteral("<p>Hans Mustermann</p><br>Musterstr. 42"));
287 sig.insertIntoTextEdit(Signature::Start, Signature::AddSeparator, &edit);
288 QEXPECT_FAIL("", "This test is probably bogus, since Qt doesn't seem to produce HTML like this anymore.", Continue);
289 QCOMPARE(edit.toPlainText(), QStringLiteral("-- \nHans Mustermann\nMusterstr. 42"));
290 }
291