1 /*
2  * Copyright (C) 2008-2020 The Communi Project
3  *
4  * This test is free, and not covered by the BSD license. There is no
5  * restriction applied to their modification, redistribution, using and so on.
6  * You can study them, modify them, use them in your own program - either
7  * completely or partially.
8  */
9 
10 #include "ircmessage.h"
11 #include "ircconnection.h"
12 #include "ircprotocol.h"
13 #include <QtTest/QtTest>
14 #include <QTextCodec>
15 #include <QtCore/QScopedPointer>
16 
17 #ifdef Q_OS_LINUX
18 #include "ircmessagedecoder_p.h"
19 #endif // Q_OS_LINUX
20 
21 class tst_IrcMessage : public QObject
22 {
23     Q_OBJECT
24 
25 private slots:
26     void testDefaults();
27 
28     void testToData();
29 
30     void testPrefix_data();
31     void testPrefix();
32 
33     void testParameters_data();
34     void testParameters();
35 
36     void testFlags();
37 
38     void testEncoding_data();
39     void testEncoding();
40 
41     void testDecoder_data();
42     void testDecoder();
43 
44     void testTags();
45     void testServerTime();
46 
47     void testAccount_data();
48     void testAccount();
49 
50     void testAccountMessage_data();
51     void testAccountMessage();
52     void testAwayMessage_data();
53     void testAwayMessage();
54     void testCapabilityMessage_data();
55     void testCapabilityMessage();
56     void testErrorMessage_data();
57     void testErrorMessage();
58     void testHostChangeMessage_data();
59     void testHostChangeMessage();
60     void testInviteMessage_data();
61     void testInviteMessage();
62     void testJoinMessage_data();
63     void testJoinMessage();
64     void testKickMessage_data();
65     void testKickMessage();
66     void testNamesMessage();
67     void testNickMessage_data();
68     void testNickMessage();
69     void testNoticeMessage_data();
70     void testNoticeMessage();
71     void testNumericMessage_data();
72     void testNumericMessage();
73     void testModeMessage_data();
74     void testModeMessage();
75     void testMotdMessage();
76     void testPartMessage_data();
77     void testPartMessage();
78     void testPingMessage();
79     void testPongMessage();
80     void testPrivateMessage_data();
81     void testPrivateMessage();
82     void testQuitMessage_data();
83     void testQuitMessage();
84     void testTopicMessage_data();
85     void testTopicMessage();
86     void testWhoReplyMessage_data();
87     void testWhoReplyMessage();
88 
89     void testClone();
90     void testNullConnection();
91 
92     void testDebug();
93 };
94 
testDefaults()95 void tst_IrcMessage::testDefaults()
96 {
97     IrcMessage msg(nullptr);
98     QVERIFY(!msg.isValid());
99     QVERIFY(!msg.connection());
100     QCOMPARE(msg.type(), IrcMessage::Unknown);
101     QCOMPARE(msg.flags(), IrcMessage::None);
102     QCOMPARE(msg.encoding(), QByteArray("ISO-8859-15"));
103     QVERIFY(msg.prefix().isNull());
104     QVERIFY(msg.nick().isNull());
105     QVERIFY(msg.ident().isNull());
106     QVERIFY(msg.host().isNull());
107     QVERIFY(msg.command().isNull());
108     QVERIFY(msg.parameters().isEmpty());
109     QVERIFY(msg.toData().isEmpty());
110 }
111 
testToData()112 void tst_IrcMessage::testToData()
113 {
114     IrcConnection connection;
115     IrcMessage* msg = IrcMessage::fromData(":nick!ident@host PRIVMSG user :hello there", &connection);
116     QCOMPARE(msg->toData(), QByteArray(":nick!ident@host PRIVMSG user :hello there"));
117 
118     msg = IrcMessage::fromData(":nick!ident@host PRIVMSG user ::)", &connection);
119     QCOMPARE(msg->toData(), QByteArray(":nick!ident@host PRIVMSG user ::)"));
120 
121     msg = IrcMessage::fromData(":nick!ident@host TOPIC #channel :", &connection);
122     QCOMPARE(msg->toData(), QByteArray(":nick!ident@host TOPIC #channel :"));
123 
124     msg = IrcMessage::fromParameters("nick!ident@host", "PRIVMSG", QStringList() << "user" << "hello there", &connection);
125     QCOMPARE(msg->toData(), QByteArray(":nick!ident@host PRIVMSG user :hello there"));
126 
127     msg = IrcMessage::fromParameters("nick!ident@host", "PRIVMSG", QStringList() << "user" << ":)", &connection);
128     QCOMPARE(msg->toData(), QByteArray(":nick!ident@host PRIVMSG user ::)"));
129 
130     msg = IrcMessage::fromParameters("nick!ident@host", "TOPIC", QStringList() << "#channel" << "", &connection);
131     QCOMPARE(msg->toData(), QByteArray(":nick!ident@host TOPIC #channel :"));
132 }
133 
testPrefix_data()134 void tst_IrcMessage::testPrefix_data()
135 {
136     QTest::addColumn<QString>("prefix");
137     QTest::addColumn<QString>("expected");
138     QTest::addColumn<QString>("nick");
139     QTest::addColumn<QString>("ident");
140     QTest::addColumn<QString>("host");
141 
142     QTest::newRow("null") << QString() << QString() << QString() << QString() << QString();
143     QTest::newRow("empty") << QString("") << QString("") << QString() << QString() << QString();
144     QTest::newRow("space") << QString(" ") << QString(" ") << QString() << QString() << QString();
145     QTest::newRow("nick!ident@host") << QString("nick!ident@host") << QString("nick!ident@host") << QString("nick") << QString("ident") << QString("host");
146 }
147 
testPrefix()148 void tst_IrcMessage::testPrefix()
149 {
150     QFETCH(QString, prefix);
151     QFETCH(QString, expected);
152     QFETCH(QString, nick);
153     QFETCH(QString, ident);
154     QFETCH(QString, host);
155 
156     IrcMessage msg(nullptr);
157     msg.setPrefix(prefix);
158     QCOMPARE(msg.prefix(), expected);
159     QCOMPARE(msg.nick(), nick);
160     QCOMPARE(msg.ident(), ident);
161     QCOMPARE(msg.host(), host);
162 }
163 
testParameters_data()164 void tst_IrcMessage::testParameters_data()
165 {
166     Irc::registerMetaTypes();
167 
168     QTest::addColumn<QString>("prefix");
169     QTest::addColumn<QString>("command");
170     QTest::addColumn<QStringList>("params");
171     QTest::addColumn<IrcMessage::Type>("type");
172 
173     QTest::newRow("null") << QString() << QString() << QStringList() << IrcMessage::Unknown;
174     QTest::newRow("message") << QString("nick!ident@host") << QString("PRIVMSG") << QStringList("p") << IrcMessage::Private;
175     QTest::newRow("notice") << QString("nick!ident@host") << QString("NOTICE") << QStringList("p") << IrcMessage::Notice;
176 }
177 
testParameters()178 void tst_IrcMessage::testParameters()
179 {
180     QFETCH(QString, prefix);
181     QFETCH(QString, command);
182     QFETCH(QStringList, params);
183     QFETCH(IrcMessage::Type, type);
184 
185     IrcConnection connection;
186     QScopedPointer<IrcMessage> message(IrcMessage::fromParameters(prefix, command, params, &connection));
187     QCOMPARE(message->type(), type);
188     QCOMPARE(message->prefix(), prefix);
189     QCOMPARE(message->command(), command);
190     QCOMPARE(message->parameters(), params);
191 
192     for (int i = 0; i < params.count(); ++i)
193         QCOMPARE(message->parameter(i), params.at(i));
194 
195     message->setParameter(5, "foo");
196     QCOMPARE(message->parameter(4), QString());
197     QCOMPARE(message->parameter(5), QString("foo"));
198 }
199 
testFlags()200 void tst_IrcMessage::testFlags()
201 {
202     IrcMessage msg(nullptr);
203     msg.setPrefix("a!b@c");
204     QCOMPARE(msg.flags(), IrcMessage::None);
205 
206     QVERIFY(!msg.testFlag(IrcMessage::Playback));
207     msg.setFlag(IrcMessage::Playback);
208     QVERIFY(msg.testFlag(IrcMessage::Playback));
209     QCOMPARE(msg.flags(), IrcMessage::Playback);
210 
211     QVERIFY(!msg.testFlag(IrcMessage::Implicit));
212     msg.setFlag(IrcMessage::Implicit);
213     QVERIFY(msg.testFlag(IrcMessage::Implicit));
214     QCOMPARE(msg.flags(), IrcMessage::Playback | IrcMessage::Implicit);
215 
216     msg.setFlag(IrcMessage::Playback, false);
217     QVERIFY(!msg.testFlag(IrcMessage::Playback));
218     QCOMPARE(msg.flags(), IrcMessage::Implicit);
219 
220     msg.setFlags(IrcMessage::None);
221     QVERIFY(!msg.testFlag(IrcMessage::Implicit));
222     QVERIFY(!msg.testFlag(IrcMessage::Playback));
223     QCOMPARE(msg.flags(), IrcMessage::None);
224 }
225 
testEncoding_data()226 void tst_IrcMessage::testEncoding_data()
227 {
228     QTest::addColumn<QByteArray>("encoding");
229     QTest::addColumn<QByteArray>("actual");
230     QTest::addColumn<bool>("supported");
231 
232     QTest::newRow("null") << QByteArray() << QByteArray("ISO-8859-15") << false;
233     QTest::newRow("empty") << QByteArray("") << QByteArray("ISO-8859-15") << false;
234     QTest::newRow("space") << QByteArray(" ") << QByteArray("ISO-8859-15") << false;
235     QTest::newRow("invalid") << QByteArray("invalid") << QByteArray("ISO-8859-15") << false;
236     foreach (const QByteArray& codec, QTextCodec::availableCodecs())
237         QTest::newRow(codec) << codec << codec << true;
238 }
239 
testEncoding()240 void tst_IrcMessage::testEncoding()
241 {
242     QFETCH(QByteArray, encoding);
243     QFETCH(QByteArray, actual);
244     QFETCH(bool, supported);
245 
246     if (!supported)
247         QTest::ignoreMessage(QtWarningMsg, "IrcMessage::setEncoding(): unsupported encoding \"" + encoding + "\" ");
248 
249     IrcMessage msg(nullptr);
250     msg.setEncoding(encoding);
251     QCOMPARE(msg.encoding(), actual);
252 }
253 
testDecoder_data()254 void tst_IrcMessage::testDecoder_data()
255 {
256     QTest::addColumn<QByteArray>("encoding");
257     QTest::addColumn<QByteArray>("base64");
258 
259     QTest::newRow("windows-1251") << QByteArray("windows-1251") << QByteArray("7+Xt8eju7eXw4Owg7+7k5OXr/O375Q==");
260     QTest::newRow("EUC-JP") << QByteArray("EUC-JP") << QByteArray("pKSkxKTHpOKkyaSzpMek4qGhpbml3qXbyMc=");
261     QTest::newRow("Shift-JIS") << QByteArray("Shift-JIS") << QByteArray("lbaOmoNSgVuDaJVcg1aDdINn");
262     QTest::newRow("ISO-8859-15") << QByteArray("ISO-8859-15") << QByteArray("5Gl0aWVucORpduQ="); // TODO: QByteArray("5OQ=");
263 }
264 
testDecoder()265 void tst_IrcMessage::testDecoder()
266 {
267     QFETCH(QByteArray, encoding);
268     QFETCH(QByteArray, base64);
269 
270 #ifdef Q_OS_LINUX
271     // others have problems with symbols (win) or private headers (osx frameworks)
272     IrcMessageDecoder decoder;
273     QString actual = decoder.decode(QByteArray::fromBase64(base64), encoding);
274     QString expected = QTextCodec::codecForName(encoding)->toUnicode(QByteArray::fromBase64(base64));
275     QCOMPARE(actual, expected);
276 #endif // Q_OS_LINUX
277 }
278 
testTags()279 void tst_IrcMessage::testTags()
280 {
281     QVariantMap tags;
282     tags.insert("aaa", "bbb");
283     tags.insert("ccc", "");
284     tags.insert("example.com/ddd", "eee");
285 
286     IrcConnection connection;
287     IrcMessage* message = IrcMessage::fromData("@aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me :Hello", &connection);
288     QCOMPARE(message->tags(), tags);
289 
290     tags.insert("ccc", "xyz");
291     message->setTag("ccc", "xyz");
292 
293     QCOMPARE(message->tags(), tags);
294     QCOMPARE(message->toData(), QByteArray("@aaa=bbb;ccc=xyz;example.com/ddd=eee :nick!ident@host.com PRIVMSG me Hello"));
295 
296     tags.insert("fff", "ggg");
297     message->setTag("fff", "ggg");
298     QCOMPARE(message->tags(), tags);
299     QCOMPARE(message->toData(), QByteArray("@aaa=bbb;ccc=xyz;example.com/ddd=eee;fff=ggg :nick!ident@host.com PRIVMSG me Hello"));
300 
301     tags.clear();
302     tags.insert("foo", "bar");
303     message->setTags(tags);
304     QCOMPARE(message->tags(), tags);
305     QCOMPARE(message->toData(), QByteArray("@foo=bar :nick!ident@host.com PRIVMSG me Hello"));
306 }
307 
testServerTime()308 void tst_IrcMessage::testServerTime()
309 {
310     IrcConnection connection;
311     IrcMessage* message = IrcMessage::fromData("@time=2011-10-19T16:40:51.620Z :Angel!angel@example.org PRIVMSG Wiz :Hello", &connection);
312     QCOMPARE(message->timeStamp(), QDateTime(QDate(2011, 10, 19), QTime(16, 40, 51, 620), Qt::UTC));
313 }
314 
testAccount_data()315 void tst_IrcMessage::testAccount_data()
316 {
317     QTest::addColumn<QByteArray>("data");
318     QTest::addColumn<QString>("account");
319 
320     QTest::newRow("no account") << QByteArray(":nick!ident@host.com PRIVMSG me :Hello") << QString();
321     QTest::newRow("has account") << QByteArray("@account=jpnurmi :nick!ident@host.com PRIVMSG me :Hello") << QString("jpnurmi");
322 }
323 
testAccount()324 void tst_IrcMessage::testAccount()
325 {
326     QFETCH(QByteArray, data);
327     QFETCH(QString, account);
328 
329     IrcConnection connection;
330     IrcMessage* message = IrcMessage::fromData(data, &connection);
331     QCOMPARE(message->account(), account);
332 }
333 
testAccountMessage_data()334 void tst_IrcMessage::testAccountMessage_data()
335 {
336     QTest::addColumn<bool>("valid");
337     QTest::addColumn<QByteArray>("data");
338     QTest::addColumn<QString>("account");
339 
340     QTest::newRow("no prefix") << false << QByteArray("ACCOUNT") << QString();
341     QTest::newRow("empty prefix") << false << QByteArray(": ACCOUNT") << QString();
342     QTest::newRow("no params") << false << QByteArray(":nick!ident@host ACCOUNT") << QString();
343     QTest::newRow("identified") << true << QByteArray(":nick!ident@host ACCOUNT account") << QString("account");
344     QTest::newRow("unidentified") << true << QByteArray(":nick!ident@host ACCOUNT *") << QString();
345 }
346 
testAccountMessage()347 void tst_IrcMessage::testAccountMessage()
348 {
349     QFETCH(bool, valid);
350     QFETCH(QByteArray, data);
351     QFETCH(QString, account);
352 
353     IrcConnection connection;
354     IrcMessage* message = IrcMessage::fromData(data, &connection);
355     QCOMPARE(message->type(), IrcMessage::Account);
356     QCOMPARE(message->command(), QString("ACCOUNT"));
357     QCOMPARE(message->property("valid").toBool(), valid);
358     QCOMPARE(message->property("account").toString(), account);
359 
360     IrcAccountMessage* accountMessage = qobject_cast<IrcAccountMessage*>(message);
361     QVERIFY(accountMessage);
362     QCOMPARE(accountMessage->isValid(), valid);
363     QCOMPARE(accountMessage->account(), account);
364 }
365 
testAwayMessage_data()366 void tst_IrcMessage::testAwayMessage_data()
367 {
368     QTest::addColumn<bool>("valid");
369     QTest::addColumn<QByteArray>("data");
370     QTest::addColumn<QString>("content");
371 
372     QTest::newRow("no prefix") << true << QByteArray("AWAY") << QString();
373     QTest::newRow("empty prefix") << false << QByteArray(": AWAY") << QString();
374     QTest::newRow("away") << true << QByteArray(":nick!ident@host AWAY :gone far away") << QString("gone far away");
375     QTest::newRow("back") << true << QByteArray(":nick!ident@host AWAY") << QString();
376 }
377 
testAwayMessage()378 void tst_IrcMessage::testAwayMessage()
379 {
380     QFETCH(bool, valid);
381     QFETCH(QByteArray, data);
382     QFETCH(QString, content);
383 
384     IrcConnection connection;
385     IrcMessage* message = IrcMessage::fromData(data, &connection);
386     QCOMPARE(message->type(), IrcMessage::Away);
387     QCOMPARE(message->command(), QString("AWAY"));
388     QCOMPARE(message->property("valid").toBool(), valid);
389     QCOMPARE(message->property("content").toString(), content);
390     QCOMPARE(message->property("away").toBool(), !content.isEmpty());
391     QVERIFY(!message->property("reply").toBool());
392 
393     IrcAwayMessage* awayMessage = qobject_cast<IrcAwayMessage*>(message);
394     QVERIFY(awayMessage);
395     QCOMPARE(awayMessage->isValid(), valid);
396     QCOMPARE(awayMessage->content(), content);
397     QCOMPARE(awayMessage->isAway(), !content.isEmpty());
398     QVERIFY(!awayMessage->isReply());
399 }
400 
testCapabilityMessage_data()401 void tst_IrcMessage::testCapabilityMessage_data()
402 {
403     QTest::addColumn<bool>("valid");
404     QTest::addColumn<QByteArray>("data");
405     QTest::addColumn<QString>("subCommand");
406     QTest::addColumn<QStringList>("capabilities");
407 
408     QTest::newRow("no prefix") << true << QByteArray("CAP") << QString() << QStringList();
409     QTest::newRow("empty prefix") << false << QByteArray(": CAP") << QString() << QStringList();
410     QTest::newRow("no params") << true << QByteArray(":server CAP") << QString() << QStringList();
411 
412     QTest::newRow("ls") << true << QByteArray(":server CAP * LS :identify-msg sasl") << QString("LS") << (QStringList() << "identify-msg" << "sasl");
413     QTest::newRow("ack") << true << QByteArray(":server CAP communi ACK :identify-msg") << QString("ACK") << (QStringList() << "identify-msg");
414     QTest::newRow("nak") << true << QByteArray(":server CAP communi NAK :sasl") << QString("NAK") << (QStringList() << "sasl");
415 }
416 
testCapabilityMessage()417 void tst_IrcMessage::testCapabilityMessage()
418 {
419     QFETCH(bool, valid);
420     QFETCH(QByteArray, data);
421     QFETCH(QString, subCommand);
422     QFETCH(QStringList, capabilities);
423 
424     IrcConnection connection;
425     IrcMessage* message = IrcMessage::fromData(data, &connection);
426     QCOMPARE(message->type(), IrcMessage::Capability);
427     QCOMPARE(message->command(), QString("CAP"));
428     QCOMPARE(message->property("valid").toBool(), valid);
429     QCOMPARE(message->property("subCommand").toString(), subCommand);
430     QCOMPARE(message->property("capabilities").toStringList(), capabilities);
431 
432     IrcCapabilityMessage* capabilityMessage = qobject_cast<IrcCapabilityMessage*>(message);
433     QVERIFY(capabilityMessage);
434     QCOMPARE(capabilityMessage->isValid(), valid);
435     QCOMPARE(capabilityMessage->subCommand(), subCommand);
436     QCOMPARE(capabilityMessage->capabilities(), capabilities);
437 }
438 
testErrorMessage_data()439 void tst_IrcMessage::testErrorMessage_data()
440 {
441     QTest::addColumn<bool>("valid");
442     QTest::addColumn<QByteArray>("data");
443     QTest::addColumn<QString>("error");
444 
445     QTest::newRow("no prefix") << true << QByteArray("ERROR error1") << QString("error1");
446     QTest::newRow("empty prefix") << false << QByteArray(": ERROR error1") << QString("error1");
447     QTest::newRow("no params") << false << QByteArray(":server ERROR") << QString();
448     QTest::newRow("all ok") << true << QByteArray(":server ERROR error1") << QString("error1");
449 }
450 
testErrorMessage()451 void tst_IrcMessage::testErrorMessage()
452 {
453     QFETCH(bool, valid);
454     QFETCH(QByteArray, data);
455     QFETCH(QString, error);
456 
457     IrcConnection connection;
458     IrcMessage* message = IrcMessage::fromData(data, &connection);
459     QCOMPARE(message->type(), IrcMessage::Error);
460     QCOMPARE(message->command(), QString("ERROR"));
461     QCOMPARE(message->property("valid").toBool(), valid);
462     QCOMPARE(message->property("error").toString(), error);
463 
464     IrcErrorMessage* errorMessage = qobject_cast<IrcErrorMessage*>(message);
465     QVERIFY(errorMessage);
466     QCOMPARE(errorMessage->isValid(), valid);
467     QCOMPARE(errorMessage->error(), error);
468 }
469 
testHostChangeMessage_data()470 void tst_IrcMessage::testHostChangeMessage_data()
471 {
472     QTest::addColumn<bool>("valid");
473     QTest::addColumn<QByteArray>("data");
474     QTest::addColumn<QString>("user");
475     QTest::addColumn<QString>("host");
476 
477     QTest::newRow("no prefix") << true << QByteArray("CHGHOST newuser newhost") << QString("newuser") << QString("newhost");
478     QTest::newRow("empty prefix") << false << QByteArray(": CHGHOST newuser newhost") << QString("newuser") << QString("newhost");
479     QTest::newRow("no params") << false << QByteArray(":nick!user@host CHGHOST") << QString() << QString();
480     QTest::newRow("all ok") << true << QByteArray(":nick!user@host CHGHOST newuser newhost") << QString("newuser") << QString("newhost");
481 }
482 
testHostChangeMessage()483 void tst_IrcMessage::testHostChangeMessage()
484 {
485     QFETCH(bool, valid);
486     QFETCH(QByteArray, data);
487     QFETCH(QString, user);
488     QFETCH(QString, host);
489 
490     IrcConnection connection;
491     IrcMessage* message = IrcMessage::fromData(data, &connection);
492     QCOMPARE(message->type(), IrcMessage::HostChange);
493     QCOMPARE(message->command(), QString("CHGHOST"));
494     QCOMPARE(message->property("valid").toBool(), valid);
495     QCOMPARE(message->property("user").toString(), user);
496     QCOMPARE(message->property("host").toString(), host);
497 
498     IrcHostChangeMessage* chghostMessage = qobject_cast<IrcHostChangeMessage*>(message);
499     QVERIFY(chghostMessage);
500     QCOMPARE(chghostMessage->isValid(), valid);
501     QCOMPARE(chghostMessage->user(), user);
502     QCOMPARE(chghostMessage->host(), host);
503 }
504 
testInviteMessage_data()505 void tst_IrcMessage::testInviteMessage_data()
506 {
507     QTest::addColumn<bool>("valid");
508     QTest::addColumn<QByteArray>("data");
509     QTest::addColumn<QString>("user");
510     QTest::addColumn<QString>("channel");
511 
512     QTest::newRow("no prefix") << true << QByteArray("INVITE Wiz #Dust") << QString("Wiz") << QString("#Dust");
513     QTest::newRow("empty prefix") << false << QByteArray(": INVITE Wiz #Dust") << QString("Wiz") << QString("#Dust");
514     QTest::newRow("no params") << false << QByteArray(":Angel INVITE") << QString() << QString();
515     QTest::newRow("no channel") << false << QByteArray(":Angel INVITE Wiz") << QString("Wiz") << QString();
516     QTest::newRow("all ok") << true << QByteArray(":Angel INVITE Wiz #Dust") << QString("Wiz") << QString("#Dust");
517 }
518 
testInviteMessage()519 void tst_IrcMessage::testInviteMessage()
520 {
521     QFETCH(bool, valid);
522     QFETCH(QByteArray, data);
523     QFETCH(QString, channel);
524     QFETCH(QString, user);
525 
526     IrcConnection connection;
527     IrcMessage* message = IrcMessage::fromData(data, &connection);
528     QCOMPARE(message->type(), IrcMessage::Invite);
529     QCOMPARE(message->command(), QString("INVITE"));
530     QCOMPARE(message->property("valid").toBool(), valid);
531     QCOMPARE(message->property("channel").toString(), channel);
532     QCOMPARE(message->property("user").toString(), user);
533 
534     IrcInviteMessage* inviteMessage = qobject_cast<IrcInviteMessage*>(message);
535     QVERIFY(inviteMessage);
536     QCOMPARE(inviteMessage->isValid(), valid);
537     QCOMPARE(inviteMessage->channel(), channel);
538     QCOMPARE(inviteMessage->user(), user);
539 }
540 
testJoinMessage_data()541 void tst_IrcMessage::testJoinMessage_data()
542 {
543     QTest::addColumn<bool>("valid");
544     QTest::addColumn<QByteArray>("data");
545     QTest::addColumn<QString>("channel");
546     QTest::addColumn<QString>("account");
547     QTest::addColumn<QString>("realName");
548 
549     QTest::newRow("no prefix") << true << QByteArray("JOIN #Twilight_zone") << QString("#Twilight_zone") << QString() << QString();
550     QTest::newRow("empty prefix") << false << QByteArray(": JOIN #Twilight_zone") << QString("#Twilight_zone") << QString() << QString();
551     QTest::newRow("no params") << false << QByteArray(":WiZ JOIN") << QString() << QString() << QString();
552     QTest::newRow("all ok") << true << QByteArray(":WiZ JOIN #Twilight_zone") << QString("#Twilight_zone") << QString() << QString();
553 
554     QTest::newRow("extended-join") << true << QByteArray(":nick!user@host JOIN #channelname accountname :Real Name") << QString("#channelname") << QString("accountname") << QString("Real Name");
555     QTest::newRow("unidentified") << true << QByteArray(":nick!user@host JOIN #channelname * :Real Name") << QString("#channelname") << QString() << QString("Real Name");
556 }
557 
testJoinMessage()558 void tst_IrcMessage::testJoinMessage()
559 {
560     QFETCH(bool, valid);
561     QFETCH(QByteArray, data);
562     QFETCH(QString, channel);
563     QFETCH(QString, account);
564     QFETCH(QString, realName);
565 
566     IrcConnection connection;
567     IrcMessage* message = IrcMessage::fromData(data, &connection);
568     QCOMPARE(message->type(), IrcMessage::Join);
569     QCOMPARE(message->command(), QString("JOIN"));
570     QCOMPARE(message->property("valid").toBool(), valid);
571     QCOMPARE(message->property("channel").toString(), channel);
572     QCOMPARE(message->property("account").toString(), account);
573     QCOMPARE(message->property("realName").toString(), realName);
574 
575     IrcJoinMessage* joinMessage = qobject_cast<IrcJoinMessage*>(message);
576     QVERIFY(joinMessage);
577     QCOMPARE(joinMessage->isValid(), valid);
578     QCOMPARE(joinMessage->channel(), channel);
579     QCOMPARE(joinMessage->account(), account);
580     QCOMPARE(joinMessage->realName(), realName);
581 }
582 
testKickMessage_data()583 void tst_IrcMessage::testKickMessage_data()
584 {
585     QTest::addColumn<bool>("valid");
586     QTest::addColumn<QByteArray>("data");
587     QTest::addColumn<QString>("channel");
588     QTest::addColumn<QString>("user");
589     QTest::addColumn<QString>("reason");
590 
591     QTest::newRow("no prefix") << true << QByteArray("KICK #Finnish John") << QString("#Finnish") << QString("John") << QString();
592     QTest::newRow("empty prefix") << false << QByteArray(": KICK #Finnish John") << QString("#Finnish") << QString("John") << QString();
593     QTest::newRow("no params") << false << QByteArray(":WiZ KICK") << QString() << QString() << QString();
594     QTest::newRow("no user") << false << QByteArray(":WiZ KICK #Finnish") << QString("#Finnish") << QString() << QString();
595     QTest::newRow("no reason") << true << QByteArray(":WiZ KICK #Finnish John") << QString("#Finnish") << QString("John") << QString();
596     QTest::newRow("all ok") << true << QByteArray(":WiZ KICK #Finnish John :Another reason") << QString("#Finnish") << QString("John") << QString("Another reason");
597 }
598 
testKickMessage()599 void tst_IrcMessage::testKickMessage()
600 {
601     QFETCH(bool, valid);
602     QFETCH(QByteArray, data);
603     QFETCH(QString, channel);
604     QFETCH(QString, user);
605     QFETCH(QString, reason);
606 
607     IrcConnection connection;
608     IrcMessage* message = IrcMessage::fromData(data, &connection);
609     QCOMPARE(message->type(), IrcMessage::Kick);
610     QCOMPARE(message->command(), QString("KICK"));
611     QCOMPARE(message->property("valid").toBool(), valid);
612     QCOMPARE(message->property("channel").toString(), channel);
613     QCOMPARE(message->property("user").toString(), user);
614     QCOMPARE(message->property("reason").toString(), reason);
615 
616     IrcKickMessage* kickMessage = qobject_cast<IrcKickMessage*>(message);
617     QVERIFY(kickMessage);
618     QCOMPARE(kickMessage->isValid(), valid);
619     QCOMPARE(kickMessage->channel(), channel);
620     QCOMPARE(kickMessage->user(), user);
621     QCOMPARE(kickMessage->reason(), reason);
622 }
623 
testNamesMessage()624 void tst_IrcMessage::testNamesMessage()
625 {
626     IrcConnection connection;
627     IrcNamesMessage message(&connection);
628     message.setPrefix("nick!ident@host");
629     message.setParameters(QStringList() << "chan" << "usr1" << "usr2" << "usr3");
630     QVERIFY(message.isValid());
631     QCOMPARE(message.type(), IrcMessage::Names);
632     QCOMPARE(message.command(), QString("NAMES"));
633     QCOMPARE(message.channel(), QString("chan"));
634     QCOMPARE(message.names(), QStringList() << "usr1" << "usr2" << "usr3");
635 }
636 
testNickMessage_data()637 void tst_IrcMessage::testNickMessage_data()
638 {
639     QTest::addColumn<bool>("valid");
640     QTest::addColumn<QByteArray>("data");
641     QTest::addColumn<QString>("oldNick");
642     QTest::addColumn<QString>("newNick");
643 
644     QTest::newRow("no prefix") << true << QByteArray("NICK Kilroy") << QString() << QString("Kilroy");
645     QTest::newRow("empty prefix") << false << QByteArray(": NICK Kilroy") << QString() << QString("Kilroy");
646     QTest::newRow("no params") << false << QByteArray(":WiZ NICK") << QString("WiZ") << QString();
647     QTest::newRow("all ok") << true << QByteArray(":WiZ NICK Kilroy") << QString("WiZ") << QString("Kilroy");
648 }
649 
testNickMessage()650 void tst_IrcMessage::testNickMessage()
651 {
652     QFETCH(bool, valid);
653     QFETCH(QByteArray, data);
654     QFETCH(QString, oldNick);
655     QFETCH(QString, newNick);
656 
657     IrcConnection connection;
658     IrcMessage* message = IrcMessage::fromData(data, &connection);
659     QCOMPARE(message->type(), IrcMessage::Nick);
660     QCOMPARE(message->command(), QString("NICK"));
661     QCOMPARE(message->property("valid").toBool(), valid);
662     QCOMPARE(message->property("oldNick").toString(), oldNick);
663     QCOMPARE(message->property("newNick").toString(), newNick);
664 
665     IrcNickMessage* nickMessage = qobject_cast<IrcNickMessage*>(message);
666     QVERIFY(nickMessage);
667     QCOMPARE(nickMessage->isValid(), valid);
668     QCOMPARE(nickMessage->oldNick(), oldNick);
669     QCOMPARE(nickMessage->newNick(), newNick);
670 }
671 
testNoticeMessage_data()672 void tst_IrcMessage::testNoticeMessage_data()
673 {
674     QTest::addColumn<bool>("valid");
675     QTest::addColumn<QByteArray>("data");
676     QTest::addColumn<QString>("target");
677     QTest::addColumn<QString>("content");
678     QTest::addColumn<bool>("priv");
679     QTest::addColumn<bool>("reply");
680 
681     QTest::newRow("no prefix") << true << QByteArray("NOTICE Wiz :Hello are you receiving this message ?") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false;
682     QTest::newRow("empty prefix") << false << QByteArray(": NOTICE Wiz :Hello are you receiving this message ?") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false;
683     QTest::newRow("no params") << false << QByteArray(":Angel NOTICE Wiz") << QString("Wiz") << QString() << false << false;
684     QTest::newRow("all ok") << true << QByteArray(":Angel NOTICE Wiz :Hello are you receiving this message ?") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false;
685     QTest::newRow("private") << true << QByteArray(":Angel NOTICE communi :Hello are you receiving this message ?") << QString("communi") << QString("Hello are you receiving this message ?") << true << false;
686     QTest::newRow("reply") << true << QByteArray(":Angel NOTICE Wiz :\1Hello are you receiving this message ?\1") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << true;
687 }
688 
testNoticeMessage()689 void tst_IrcMessage::testNoticeMessage()
690 {
691     QFETCH(bool, valid);
692     QFETCH(QByteArray, data);
693     QFETCH(QString, target);
694     QFETCH(QString, content);
695     QFETCH(bool, priv);
696     QFETCH(bool, reply);
697 
698     IrcConnection connection;
699     connection.setNickName("communi");
700     IrcMessage* message = IrcMessage::fromData(data, &connection);
701     QCOMPARE(message->type(), IrcMessage::Notice);
702     QCOMPARE(message->command(), QString("NOTICE"));
703     QCOMPARE(message->property("valid").toBool(), valid);
704     QCOMPARE(message->property("target").toString(), target);
705     QCOMPARE(message->property("content").toString(), content);
706     QCOMPARE(message->property("private").toBool(), priv);
707     QCOMPARE(message->property("reply").toBool(), reply);
708 
709     IrcNoticeMessage* noticeMessage = qobject_cast<IrcNoticeMessage*>(message);
710     QVERIFY(noticeMessage);
711     QCOMPARE(noticeMessage->isValid(), valid);
712     QCOMPARE(noticeMessage->target(), target);
713     QCOMPARE(noticeMessage->content(), content);
714     QCOMPARE(noticeMessage->isPrivate(), priv);
715     QCOMPARE(noticeMessage->isReply(), reply);
716 }
717 
testNumericMessage_data()718 void tst_IrcMessage::testNumericMessage_data()
719 {
720     QTest::addColumn<bool>("valid");
721     QTest::addColumn<QByteArray>("data");
722     QTest::addColumn<int>("code");
723     QTest::addColumn<bool>("composed");
724 
725     QTest::newRow("no prefix") << true << QByteArray("123 Kilroy") << 123 << false;
726     QTest::newRow("empty prefix") << false << QByteArray(": 123 Kilroy") << 123 << false;
727     QTest::newRow("no params") << true << QByteArray(":WiZ 456") << 456 << false;
728     QTest::newRow("all ok") << true << QByteArray(":WiZ 789 Kilroy") << 789 << false;
729     QTest::newRow("composed") << true << QByteArray(":server 352 me someone ...") << 352 << true;
730 }
731 
testNumericMessage()732 void tst_IrcMessage::testNumericMessage()
733 {
734     QFETCH(bool, valid);
735     QFETCH(QByteArray, data);
736     QFETCH(int, code);
737     QFETCH(bool, composed);
738 
739     IrcConnection connection;
740     IrcMessage* message = IrcMessage::fromData(data, &connection);
741     QCOMPARE(message->type(), IrcMessage::Numeric);
742     QVERIFY(message->command().toInt() > 0);
743     QCOMPARE(message->property("valid").toBool(), valid);
744     QCOMPARE(message->property("code").toInt(), code);
745     QCOMPARE(message->property("composed").toBool(), composed);
746 
747     IrcNumericMessage* numericMessage = qobject_cast<IrcNumericMessage*>(message);
748     QVERIFY(numericMessage);
749     QCOMPARE(numericMessage->isValid(), valid);
750     QCOMPARE(numericMessage->code(), code);
751     QCOMPARE(numericMessage->isComposed(), composed);
752 }
753 
testModeMessage_data()754 void tst_IrcMessage::testModeMessage_data()
755 {
756     QTest::addColumn<bool>("valid");
757     QTest::addColumn<QByteArray>("data");
758     QTest::addColumn<QString>("target");
759     QTest::addColumn<QString>("mode");
760     QTest::addColumn<QString>("argument");
761 
762     QTest::newRow("no prefix") << true << QByteArray("MODE Kilroy -w") << QString("Kilroy") << QString("-w") << QString();
763     QTest::newRow("empty prefix") << false << QByteArray(": MODE Kilroy -w") << QString("Kilroy") << QString("-w") << QString();
764     QTest::newRow("no params") << false << QByteArray(":WiZ MODE Kilroy") << QString("Kilroy") << QString() << QString();
765     QTest::newRow("all ok") << true << QByteArray(":WiZ MODE Kilroy -w") << QString("Kilroy") << QString("-w") << QString();
766 
767     QTest::newRow("1") << true << QByteArray(":WiZ MODE #Finnish +im") << QString("#Finnish") << QString("+im") << QString();
768     QTest::newRow("2") << true << QByteArray(":Angel MODE #Finnish +o Kilroy") << QString("#Finnish") << QString("+o") << QString("Kilroy");
769     QTest::newRow("3") << true << QByteArray(":Kilroy MODE #Finnish +v Wiz") << QString("#Finnish") << QString("+v") << QString("Wiz");
770     QTest::newRow("4a") << true << QByteArray("MODE #Fins -s") << QString("#Fins") << QString("-s") << QString();
771     QTest::newRow("4b") << false << QByteArray(": MODE #Fins -s") << QString("#Fins") << QString("-s") << QString();
772     QTest::newRow("5") << true << QByteArray(":WiZ MODE #42 +k oulu") << QString("#42") << QString("+k") << QString("oulu");
773     QTest::newRow("6a") << true << QByteArray("MODE #eu-opers +l 10") << QString("#eu-opers") << QString("+l") << QString("10");
774     QTest::newRow("6b") << false << QByteArray(": MODE #eu-opers +l 10") << QString("#eu-opers") << QString("+l") << QString("10");
775     QTest::newRow("7") << true << QByteArray(":nobody MODE &oulu +b") << QString("&oulu") << QString("+b") << QString();
776     QTest::newRow("8") << true << QByteArray(":someone MODE &oulu +b *!*@*") << QString("&oulu") << QString("+b") << QString("*!*@*");
777     QTest::newRow("9") << true << QByteArray(":anyone MODE &oulu +b *!*@*.edu") << QString("&oulu") << QString("+b") << QString("*!*@*.edu");
778     QTest::newRow("10a") << true << QByteArray("MODE WiZ -w") << QString("WiZ") << QString("-w") << QString();
779     QTest::newRow("10b") << false << QByteArray(": MODE WiZ -w") << QString("WiZ") << QString("-w") << QString();
780     QTest::newRow("11") << true << QByteArray(":Angel MODE Angel +i") << QString("Angel") << QString("+i") << QString();
781     QTest::newRow("12") << true << QByteArray(":WiZ MODE WiZ -o") << QString("WiZ") << QString("-o") << QString();
782 
783     QTest::newRow("args") << true << QByteArray(":someone MODE #chan +lk 10 secret") << QString("#chan") << QString("+lk") << QString("10 secret");
784 }
785 
testModeMessage()786 void tst_IrcMessage::testModeMessage()
787 {
788     QFETCH(bool, valid);
789     QFETCH(QByteArray, data);
790     QFETCH(QString, target);
791     QFETCH(QString, mode);
792     QFETCH(QString, argument);
793 
794 #if (QT_VERSION) >= (QT_VERSION_CHECK(5, 14, 0))
795     const QString arg = argument.split(" ", Qt::SkipEmptyParts).value(0);
796     const QStringList args = argument.split(" ", Qt::SkipEmptyParts);
797 #else
798     const QString arg = argument.split(" ", QString::SkipEmptyParts).value(0);
799     const QStringList args = argument.split(" ", QString::SkipEmptyParts);
800 #endif
801 
802     IrcConnection connection;
803     IrcMessage* message = IrcMessage::fromData(data, &connection);
804     QCOMPARE(message->type(), IrcMessage::Mode);
805     QCOMPARE(message->command(), QString("MODE"));
806     QCOMPARE(message->property("valid").toBool(), valid);
807     QCOMPARE(message->property("target").toString(), target);
808     QCOMPARE(message->property("mode").toString(), mode);
809     QCOMPARE(message->property("argument").toString(), arg);
810     QCOMPARE(message->property("arguments").toStringList(), args);
811 
812     IrcModeMessage* modeMessage = qobject_cast<IrcModeMessage*>(message);
813     QVERIFY(modeMessage);
814     QCOMPARE(modeMessage->isValid(), valid);
815     QCOMPARE(modeMessage->target(), target);
816     QCOMPARE(modeMessage->mode(), mode);
817     QCOMPARE(modeMessage->argument(), arg);
818     QCOMPARE(modeMessage->arguments(), args);
819 }
820 
testMotdMessage()821 void tst_IrcMessage::testMotdMessage()
822 {
823     IrcConnection connection;
824     IrcMotdMessage message(&connection);
825     message.setPrefix("nick!ident@host");
826     QStringList params;
827     params += "user";
828     params += ":server 375 user :- server Message of the Day";
829     params += ":server 372 user :- Welcome...";
830     params += ":server 376 user :End of /MOTD command";
831     message.setParameters(params);
832     QVERIFY(message.isValid());
833     QCOMPARE(message.type(), IrcMessage::Motd);
834     QCOMPARE(message.command(), QString("MOTD"));
835     QCOMPARE(message.lines(), QStringList(params.mid(1)));
836 }
837 
testPartMessage_data()838 void tst_IrcMessage::testPartMessage_data()
839 {
840     QTest::addColumn<bool>("valid");
841     QTest::addColumn<QByteArray>("data");
842     QTest::addColumn<QString>("channel");
843     QTest::addColumn<QString>("reason");
844 
845     QTest::newRow("no prefix") << true << QByteArray("PART #Twilight_zone") << QString("#Twilight_zone") << QString();
846     QTest::newRow("empty prefix") << false << QByteArray(": PART #Twilight_zone") << QString("#Twilight_zone") << QString();
847     QTest::newRow("no params") << false << QByteArray(":WiZ PART") << QString() << QString();
848     QTest::newRow("no reason") << true << QByteArray(":WiZ PART #Twilight_zone") << QString("#Twilight_zone") << QString();
849     QTest::newRow("all ok") << true << QByteArray(":WiZ PART #Twilight_zone :Gone to have lunch") << QString("#Twilight_zone") << QString("Gone to have lunch");
850 }
851 
testPartMessage()852 void tst_IrcMessage::testPartMessage()
853 {
854     QFETCH(bool, valid);
855     QFETCH(QByteArray, data);
856     QFETCH(QString, channel);
857     QFETCH(QString, reason);
858 
859     IrcConnection connection;
860     IrcMessage* message = IrcMessage::fromData(data, &connection);
861     QCOMPARE(message->type(), IrcMessage::Part);
862     QCOMPARE(message->command(), QString("PART"));
863     QCOMPARE(message->property("valid").toBool(), valid);
864     QCOMPARE(message->property("channel").toString(), channel);
865     QCOMPARE(message->property("reason").toString(), reason);
866 
867     IrcPartMessage* partMessage = qobject_cast<IrcPartMessage*>(message);
868     QVERIFY(partMessage);
869     QCOMPARE(partMessage->isValid(), valid);
870     QCOMPARE(partMessage->channel(), channel);
871     QCOMPARE(partMessage->reason(), reason);
872 }
873 
testPingMessage()874 void tst_IrcMessage::testPingMessage()
875 {
876     IrcConnection connection;
877     IrcMessage* message = IrcMessage::fromData("PING :arg", &connection);
878     QCOMPARE(message->type(), IrcMessage::Ping);
879     QCOMPARE(message->command(), QString("PING"));
880     QCOMPARE(message->property("command").toString(), QString("PING"));
881     QVERIFY(message->property("valid").toBool());
882     QCOMPARE(message->property("argument").toString(), QString("arg"));
883 
884     IrcPingMessage* pingMessage = qobject_cast<IrcPingMessage*>(message);
885     QVERIFY(pingMessage);
886     QVERIFY(pingMessage->isValid());
887     QCOMPARE(pingMessage->argument(), QString("arg"));
888 }
889 
testPongMessage()890 void tst_IrcMessage::testPongMessage()
891 {
892     IrcConnection connection;
893     IrcMessage* message = IrcMessage::fromData("PONG tgt :arg", &connection);
894     QCOMPARE(message->type(), IrcMessage::Pong);
895     QCOMPARE(message->command(), QString("PONG"));
896     QCOMPARE(message->property("command").toString(), QString("PONG"));
897     QVERIFY(message->property("valid").toBool());
898     QCOMPARE(message->property("argument").toString(), QString("arg"));
899 
900     IrcPongMessage* pongMessage = qobject_cast<IrcPongMessage*>(message);
901     QVERIFY(pongMessage);
902     QVERIFY(pongMessage->isValid());
903     QCOMPARE(pongMessage->argument(), QString("arg"));
904 }
905 
testPrivateMessage_data()906 void tst_IrcMessage::testPrivateMessage_data()
907 {
908     QTest::addColumn<bool>("valid");
909     QTest::addColumn<QString>("cap");
910     QTest::addColumn<QByteArray>("data");
911     QTest::addColumn<QString>("target");
912     QTest::addColumn<QString>("content");
913     QTest::addColumn<bool>("priv");
914     QTest::addColumn<bool>("action");
915     QTest::addColumn<bool>("request");
916     QTest::addColumn<uint>("flags");
917 
918     QTest::newRow("no prefix") << true << QString() << QByteArray("PRIVMSG Wiz :Hello are you receiving this message ?") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false << false << static_cast<uint>(IrcMessage::None);
919     QTest::newRow("empty prefix") << false << QString() << QByteArray(": PRIVMSG Wiz :Hello are you receiving this message ?") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false << false << static_cast<uint>(IrcMessage::None);
920     QTest::newRow("no params") << false << QString() << QByteArray(":Angel PRIVMSG Wiz") << QString("Wiz") << QString() << false << false << false << static_cast<uint>(IrcMessage::None);
921     QTest::newRow("all ok") << true << QString() << QByteArray(":Angel PRIVMSG Wiz :Hello are you receiving this message ?") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false << false << static_cast<uint>(IrcMessage::None);
922     QTest::newRow("private") << true << QString() << QByteArray(":Angel PRIVMSG communi :Hello are you receiving this message ?") << QString("communi") << QString("Hello are you receiving this message ?") << true << false << false << static_cast<uint>(IrcMessage::None);
923     QTest::newRow("action") << true << QString() << QByteArray(":Angel PRIVMSG Wiz :\1ACTION Hello are you receiving this message ?\1") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << true << false << static_cast<uint>(IrcMessage::None);
924     QTest::newRow("request") << true << QString() << QByteArray(":Angel PRIVMSG Wiz :\1Hello are you receiving this message ?\1") << QString("Wiz") << QString("Hello are you receiving this message ?") << false << false << true << static_cast<uint>(IrcMessage::None);
925 }
926 
927 class TestProtocol : public IrcProtocol
928 {
929 public:
TestProtocol(const QString & cap,IrcConnection * connection)930     TestProtocol(const QString& cap, IrcConnection* connection) : IrcProtocol(connection)
931     {
932         QSet<QString> caps;
933         caps.insert(cap);
934         setAvailableCapabilities(caps);
935         setActiveCapabilities(caps);
936     }
937 };
938 
939 class FriendConnection : public IrcConnection
940 {
941     friend class tst_IrcMessage;
942 };
943 
testPrivateMessage()944 void tst_IrcMessage::testPrivateMessage()
945 {
946     QFETCH(bool, valid);
947     QFETCH(QString, cap);
948     QFETCH(QByteArray, data);
949     QFETCH(QString, target);
950     QFETCH(QString, content);
951     QFETCH(bool, priv);
952     QFETCH(bool, action);
953     QFETCH(bool, request);
954     QFETCH(uint, flags);
955 
956     IrcConnection connection;
957     connection.setNickName("communi");
958     TestProtocol protocol(cap, &connection);
959     static_cast<FriendConnection*>(&connection)->setProtocol(&protocol);
960 
961     IrcMessage* message = IrcMessage::fromData(data, &connection);
962     QCOMPARE(message->type(), IrcMessage::Private);
963     QCOMPARE(message->command(), QString("PRIVMSG"));
964     QCOMPARE(message->property("valid").toBool(), valid);
965     QCOMPARE(message->property("target").toString(), target);
966     QCOMPARE(message->property("content").toString(), content);
967     QCOMPARE(message->property("private").toBool(), priv);
968     QCOMPARE(message->property("action").toBool(), action);
969     QCOMPARE(message->property("request").toBool(), request);
970     QCOMPARE(message->property("flags").toUInt(), flags);
971 
972     IrcPrivateMessage* privateMessage = qobject_cast<IrcPrivateMessage*>(message);
973     QVERIFY(privateMessage);
974     QCOMPARE(privateMessage->isValid(), valid);
975     QCOMPARE(privateMessage->target(), target);
976     QCOMPARE(privateMessage->content(), content);
977     QCOMPARE(privateMessage->isPrivate(), priv);
978     QCOMPARE(privateMessage->isAction(), action);
979     QCOMPARE(privateMessage->isRequest(), request);
980     QCOMPARE(static_cast<uint>(privateMessage->flags()), flags);
981 }
982 
testQuitMessage_data()983 void tst_IrcMessage::testQuitMessage_data()
984 {
985     QTest::addColumn<bool>("valid");
986     QTest::addColumn<QByteArray>("data");
987     QTest::addColumn<QString>("reason");
988 
989     QTest::newRow("no prefix") << true << QByteArray("QUIT :Gone to have lunch") << QString("Gone to have lunch");
990     QTest::newRow("empty prefix") << false << QByteArray(": QUIT :Gone to have lunch") << QString("Gone to have lunch");
991     QTest::newRow("no params") << true << QByteArray(":WiZ QUIT") << QString();
992     QTest::newRow("all ok") << true << QByteArray(":WiZ QUIT :Gone to have lunch") << QString("Gone to have lunch");
993 }
994 
testQuitMessage()995 void tst_IrcMessage::testQuitMessage()
996 {
997     QFETCH(bool, valid);
998     QFETCH(QByteArray, data);
999     QFETCH(QString, reason);
1000 
1001     IrcConnection connection;
1002     IrcMessage* message = IrcMessage::fromData(data, &connection);
1003     QCOMPARE(message->type(), IrcMessage::Quit);
1004     QCOMPARE(message->command(), QString("QUIT"));
1005     QCOMPARE(message->property("valid").toBool(), valid);
1006     QCOMPARE(message->property("reason").toString(), reason);
1007 
1008     IrcQuitMessage* quitMessage = qobject_cast<IrcQuitMessage*>(message);
1009     QVERIFY(quitMessage);
1010     QCOMPARE(quitMessage->isValid(), valid);
1011     QCOMPARE(quitMessage->reason(), reason);
1012 }
1013 
testTopicMessage_data()1014 void tst_IrcMessage::testTopicMessage_data()
1015 {
1016     QTest::addColumn<bool>("valid");
1017     QTest::addColumn<QByteArray>("data");
1018     QTest::addColumn<QString>("channel");
1019     QTest::addColumn<QString>("topic");
1020     QTest::addColumn<bool>("reply");
1021 
1022     QTest::newRow("no prefix") << true << QByteArray("TOPIC #test") << QString("#test") << QString() << false;
1023     QTest::newRow("empty prefix") << false << QByteArray(": TOPIC #test") << QString("#test") << QString() << false;
1024     QTest::newRow("no params") << false << QByteArray(":WiZ TOPIC") << QString() << QString() << false;
1025     QTest::newRow("no topic") << true << QByteArray(":WiZ TOPIC #test") << QString("#test") << QString() << false;
1026     QTest::newRow("all ok") << true << QByteArray(":WiZ TOPIC #test :another topic") << QString("#test") << QString("another topic") << false;
1027     // TODO: QTest::newRow("numeric") << true << QByteArray(":server 332 user #test :foo bar") << QString("#test") << QString("foo bar") << true;
1028 }
1029 
testTopicMessage()1030 void tst_IrcMessage::testTopicMessage()
1031 {
1032     QFETCH(bool, valid);
1033     QFETCH(QByteArray, data);
1034     QFETCH(QString, channel);
1035     QFETCH(QString, topic);
1036     QFETCH(bool, reply);
1037 
1038     IrcConnection connection;
1039     IrcMessage* message = IrcMessage::fromData(data, &connection);
1040     QCOMPARE(message->type(), IrcMessage::Topic);
1041     QCOMPARE(message->command(), QString("TOPIC"));
1042     QCOMPARE(message->property("valid").toBool(), valid);
1043     QCOMPARE(message->property("channel").toString(), channel);
1044     QCOMPARE(message->property("topic").toString(), topic);
1045     QCOMPARE(message->property("reply").toBool(), reply);
1046 
1047     IrcTopicMessage* topicMessage = qobject_cast<IrcTopicMessage*>(message);
1048     QVERIFY(topicMessage);
1049     QCOMPARE(topicMessage->isValid(), valid);
1050     QCOMPARE(topicMessage->channel(), channel);
1051     QCOMPARE(topicMessage->topic(), topic);
1052     QCOMPARE(topicMessage->isReply(), reply);
1053 }
1054 
testWhoReplyMessage_data()1055 void tst_IrcMessage::testWhoReplyMessage_data()
1056 {
1057     QTest::addColumn<bool>("valid");
1058     QTest::addColumn<QString>("prefix");
1059     QTest::addColumn<QStringList>("params");
1060     QTest::addColumn<QString>("mask");
1061     QTest::addColumn<QString>("server");
1062     QTest::addColumn<bool>("away");
1063     QTest::addColumn<bool>("servOp");
1064     QTest::addColumn<QString>("realName");
1065 
1066     QTest::newRow("normal") << true << "nick!ident@host"
1067                             << (QStringList() << "#mask" << "irc.ser.ver" << "H@" << "real name")
1068                             << "#mask" << "irc.ser.ver" << false << false << "real name";
1069 
1070     QTest::newRow("away") << true << "nick!ident@host"
1071                           << (QStringList() << "*" << "127.0.0.1" << "G@" << "real name")
1072                           << "*" << "127.0.0.1" << true << false << "real name";
1073 
1074     QTest::newRow("serv op") << true << "nick!ident@host"
1075                              << (QStringList() << "*" << "127.0.0.1" << "H*@" << "real name")
1076                              << "*" << "127.0.0.1" << false << true << "real name";
1077 
1078     QTest::newRow("no name") << true << "nick!ident@host"
1079                              << (QStringList() << "#mask" << "irc.ser.ver" << "H@" << "")
1080                              << "#mask" << "irc.ser.ver" << false << false << "";
1081 }
1082 
testWhoReplyMessage()1083 void tst_IrcMessage::testWhoReplyMessage()
1084 {
1085     QFETCH(bool, valid);
1086     QFETCH(QString, prefix);
1087     QFETCH(QStringList, params);
1088     QFETCH(QString, mask);
1089     QFETCH(QString, server);
1090     QFETCH(bool, away);
1091     QFETCH(bool, servOp);
1092     QFETCH(QString, realName);
1093 
1094     IrcConnection connection;
1095     IrcWhoReplyMessage message(&connection);
1096     message.setPrefix(prefix);
1097     message.setParameters(params);
1098     QCOMPARE(message.isValid(), valid);
1099     QCOMPARE(message.type(), IrcMessage::WhoReply);
1100     // TODO: QCOMPARE(message.command(), QString::number(Irc::RPL_WHOREPLY));
1101     QCOMPARE(message.mask(), mask);
1102     QCOMPARE(message.server(), server);
1103     QCOMPARE(message.isAway(), away);
1104     QCOMPARE(message.isServOp(), servOp);
1105     QCOMPARE(message.realName(), realName);
1106 
1107     QCOMPARE(message.property("valid").toBool(), valid);
1108     QCOMPARE(message.property("mask").toString(), mask);
1109     QCOMPARE(message.property("server").toString(), server);
1110     QCOMPARE(message.property("away").toBool(), away);
1111     QCOMPARE(message.property("servOp").toBool(), servOp);
1112     QCOMPARE(message.property("realName").toString(), realName);
1113 }
1114 
testClone()1115 void tst_IrcMessage::testClone()
1116 {
1117     IrcConnection connection;
1118     IrcMessage* pm = IrcMessage::fromData("@a=b;c=d :nick!ident@host PRIVMSG me :hello", &connection);
1119     QVERIFY(pm);
1120     IrcMessage* clone = pm->clone(this);
1121     QVERIFY(clone);
1122     QVERIFY(clone->isValid());
1123     QCOMPARE(clone->parent(), this);
1124     QCOMPARE(clone->connection(), &connection);
1125     QCOMPARE(clone->type(), pm->type());
1126     QCOMPARE(clone->flags(), pm->flags());
1127     QCOMPARE(clone->tags(), pm->tags());
1128     QCOMPARE(clone->prefix(), pm->prefix());
1129     QCOMPARE(clone->nick(), pm->nick());
1130     QCOMPARE(clone->ident(), pm->ident());
1131     QCOMPARE(clone->host(), pm->host());
1132     QCOMPARE(clone->command(), pm->command());
1133     QCOMPARE(clone->parameters(), pm->parameters());
1134     QCOMPARE(clone->timeStamp(), pm->timeStamp());
1135     QCOMPARE(clone->account(), pm->account());
1136 }
1137 
testNullConnection()1138 void tst_IrcMessage::testNullConnection()
1139 {
1140     IrcMessage* pm = IrcMessage::fromData(":nick!ident@host PRIVMSG me :hello", nullptr);
1141     QCOMPARE(pm->type(), IrcMessage::Private);
1142     QCOMPARE(pm->property("target").toString(), QString("me"));
1143     QVERIFY(pm->property("statusPrefix").toString().isEmpty());
1144     QVERIFY(!pm->property("private").toBool());
1145     QCOMPARE(pm->flags(), IrcMessage::None);
1146     delete pm;
1147 
1148     IrcMessage* nm = IrcMessage::fromData(":nick!ident@host NOTICE me :hello", nullptr);
1149     QCOMPARE(nm->type(), IrcMessage::Notice);
1150     QCOMPARE(nm->property("target").toString(), QString("me"));
1151     QVERIFY(nm->property("statusPrefix").toString().isEmpty());
1152     QVERIFY(!nm->property("private").toBool());
1153     QCOMPARE(nm->flags(), IrcMessage::None);
1154     delete nm;
1155 }
1156 
testDebug()1157 void tst_IrcMessage::testDebug()
1158 {
1159     QString str;
1160     QDebug dbg(&str);
1161 
1162     dbg << static_cast<IrcMessage*>(nullptr);
1163     QCOMPARE(str.trimmed(), QString::fromLatin1("IrcMessage(0x0)"));
1164     str.clear();
1165 
1166     IrcMessage message(nullptr);
1167     dbg << &message;
1168     QVERIFY(QRegularExpression("IrcMessage\\(0x[0-9A-Fa-f]+, flags=\\(None\\)\\) ").match(str).hasMatch());
1169     str.clear();
1170 
1171     message.setObjectName("foo");
1172     dbg << &message;
1173     QVERIFY(QRegularExpression("IrcMessage\\(0x[0-9A-Fa-f]+, name=foo, flags=\\(None\\)\\) ").match(str).hasMatch());
1174     str.clear();
1175 
1176     message.setPrefix("nick!ident@host");
1177     dbg << &message;
1178     QVERIFY(QRegularExpression("IrcMessage\\(0x[0-9A-Fa-f]+, name=foo, flags=\\(None\\), prefix=nick!ident@host\\) ").match(str).hasMatch());
1179     str.clear();
1180 
1181     message.setCommand("COMMAND");
1182     dbg << &message;
1183     QVERIFY(QRegularExpression("IrcMessage\\(0x[0-9A-Fa-f]+, name=foo, flags=\\(None\\), prefix=nick!ident@host, command=COMMAND\\) ").match(str).hasMatch());
1184     str.clear();
1185 
1186     message.setFlags(IrcMessage::Own | IrcMessage::Playback | IrcMessage::Implicit);
1187     dbg << &message;
1188     QVERIFY(QRegularExpression("IrcMessage\\(0x[0-9A-Fa-f]+, name=foo, flags=\\(Own\\|Playback\\|Implicit\\), prefix=nick!ident@host, command=COMMAND\\) ").match(str).hasMatch());
1189     str.clear();
1190 
1191     dbg << IrcMessage::None;
1192     QCOMPARE(str.trimmed(), QString::fromLatin1("None"));
1193     str.clear();
1194 
1195     dbg << IrcMessage::Join;
1196     QCOMPARE(str.trimmed(), QString::fromLatin1("Join"));
1197     str.clear();
1198 
1199     dbg << IrcModeMessage::Channel;
1200     QCOMPARE(str.trimmed(), QString::fromLatin1("Channel"));
1201     str.clear();
1202 }
1203 
1204 QTEST_MAIN(tst_IrcMessage)
1205 
1206 #include "tst_ircmessage.moc"
1207