diff --git a/libkopete/kopetemessage.cpp b/libkopete/kopetemessage.cpp index 460661176..50397bbc7 100644 --- a/libkopete/kopetemessage.cpp +++ b/libkopete/kopetemessage.cpp @@ -1,833 +1,834 @@ /* kopetemessage.cpp - Base class for Kopete messages Copyright (c) 2002-2003 by Martijn Klingens Copyright (c) 2002-2006 by Olivier Goffart Copyright (c) 2006-2007 by Charles Connell Copyright (c) 2007 by MichaĆ«l Larouche Copyright (c) 2008 by Roman Jarosz Kopete (c) 2002-2008 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "kopetemessage.h" #include #include #include #include #include #include #include #include #include "libkopete_debug.h" #include #include "kopetemetacontact.h" #include "kopeteprotocol.h" #include "kopetechatsession.h" #include "kopetecontact.h" #include "kopeteemoticons.h" namespace Kopete { class Message::Private : public QSharedData { public: Private() //assign next message id, it can't be changed later : id(nextId++) , direction(Internal) , format(Qt::PlainText) , type(TypeNormal) , importance(Normal) , state(StateUnknown) , delayed(false) , formattingOverride(false) , forceHtml(false) , isRightToLeft(false) , timeStamp(QDateTime::currentDateTime()) , body(new QTextDocument) , parsedBodyDirty(true) , escapedBodyDirty(true) , fileTransfer(0) { } Private (const Private &other); ~Private(); const uint id; QPointer from; ContactPtrList to; QPointer manager; MessageDirection direction; Qt::TextFormat format; MessageType type; QString requestedPlugin; MessageImportance importance; MessageState state; bool delayed; bool formattingOverride, forceHtml; bool isRightToLeft; QDateTime timeStamp; QFont font; QStringList classes; QColor foregroundColor; QColor backgroundColor; QString subject; QTextDocument *body; mutable QString parsedBody; mutable bool parsedBodyDirty; mutable QString escapedBody; mutable bool escapedBodyDirty; class FileTransferInfo { public: FileTransferInfo() : disabled(false) , fileSize(0) { } bool disabled; QString fileName; unsigned long fileSize; QPixmap filePreview; }; FileTransferInfo *fileTransfer; static uint nextId; }; // Start with 1 as 0 is reserved for invalid id; uint Message::Private::nextId = 1; Message::Private::Private (const Message::Private &other) : QSharedData(other) , id(other.id) { from = other.from; to = other.to; manager = other.manager; direction = other.direction; format = other.format; type = other.type; requestedPlugin = other.requestedPlugin; importance = other.importance; state = other.state; delayed = other.delayed; formattingOverride = other.formattingOverride; isRightToLeft = other.isRightToLeft; timeStamp = other.timeStamp; font = other.font; classes = other.classes; foregroundColor = other.foregroundColor; backgroundColor = other.backgroundColor; subject = other.subject; body = other.body->clone(); parsedBody = other.parsedBody; parsedBodyDirty = other.parsedBodyDirty; escapedBody = other.escapedBody; escapedBodyDirty = other.escapedBodyDirty; if (other.fileTransfer) { fileTransfer = new FileTransferInfo(*other.fileTransfer); } else { fileTransfer = 0; } } Message::Private::~Private () { delete fileTransfer; delete body; } Message::Message() : d(new Private) { } Message::Message(const Contact *fromKC, const Contact *toKC) : d(new Private) { d->from = const_cast(fromKC); QList contacts; contacts << const_cast(toKC); d->to = contacts; } Message::Message(const Contact *fromKC, const QList &toKC) : d(new Private) { d->from = const_cast(fromKC); d->to = toKC; } Message::Message(const Message &other) : d(other.d) { } Message &Message::operator=(const Message &other) { d = other.d; return *this; } Message::~Message() { } uint Message::id() const { return d->id; } uint Message::nextId() { return Message::Private::nextId++; } void Message::setBackgroundOverride(bool enabled) { setFormattingOverride(enabled); } void Message::setForegroundOverride(bool enabled) { setFormattingOverride(enabled); } void Message::setRichTextOverride(bool enabled) { setFormattingOverride(enabled); } void Message::setFormattingOverride(bool enabled) { d->formattingOverride = enabled; d->parsedBodyDirty = true; d->escapedBodyDirty = true; } void Message::setForegroundColor(const QColor &color) { d->foregroundColor = color; } void Message::setBackgroundColor(const QColor &color) { d->backgroundColor = color; } void Message::setFont(const QFont &font) { d->font = font; } void Message::setPlainBody(const QString &body) { doSetBody(body, Qt::PlainText); } void Message::setHtmlBody(const QString &body) { doSetBody(body, Qt::RichText); } void Message::setForcedHtmlBody(const QString &body) { setHtmlBody(body); d->forceHtml = true; } void Message::doSetBody(QString body, Qt::TextFormat f) { // Remove ObjectReplacementCharacter because otherwise html text will be empty if (body.contains(QChar(QChar::ObjectReplacementCharacter))) { body.replace(QChar(QChar::ObjectReplacementCharacter), QChar(' ')); } if (f == Qt::PlainText) { d->body->setPlainText(body); } else { d->body->setHtml(body); } d->format = f; d->isRightToLeft = d->body->toPlainText().isRightToLeft(); d->escapedBodyDirty = true; d->parsedBodyDirty = true; } void Message::setBody(const QTextDocument *_body) { doSetBody(_body, Qt::RichText); } void Message::doSetBody(const QTextDocument *body, Qt::TextFormat f) { delete d->body; d->body = body->clone(); // delete the old body and replace it with a *copy* of the new one d->format = f; d->isRightToLeft = d->body->toPlainText().isRightToLeft(); d->escapedBodyDirty = true; d->parsedBodyDirty = true; } void Message::setImportance(Message::MessageImportance i) { d->importance = i; } QString Message::unescape(const QString &xml) { QString data = xml; // Remove linebreak and multiple spaces. First return nbsp's to normal spaces :) data = data.simplified(); int pos; while ((pos = data.indexOf('<')) != -1) { int endPos = data.indexOf('>', pos + 1); if (endPos == -1) { break; // No more complete elements left } // Take the part between < and >, and extract the element name from that int matchWidth = endPos - pos + 1; const QString match = data.mid(pos + 1, matchWidth - 2).simplified(); int elemEndPos = match.indexOf(' '); const QString elem = (elemEndPos == -1 ? match.toLower() : match.left(elemEndPos).toLower()); if (elem == QLatin1String("img")) { // Replace smileys with their original text' const QString attrTitle = QStringLiteral("title=\""); int titlePos = match.indexOf(attrTitle, elemEndPos); int titleEndPos = match.indexOf('"', titlePos + attrTitle.length()); if (titlePos == -1 || titleEndPos == -1) { // Not a smiley but a normal // Don't update pos, we restart at this position :) data.remove(pos, matchWidth); } else { QString orig = match.mid(titlePos + attrTitle.length(), titleEndPos - titlePos - attrTitle.length()); data.replace(pos, matchWidth, orig); pos += orig.length(); } } else if (elem == QLatin1String("/p") || elem == QLatin1String("/div") || elem == QLatin1String("br")) { // Replace paragraph, div and line breaks with a newline data.replace(pos, matchWidth, '\n'); pos++; } else { // Remove all other elements entirely // Don't update pos, we restart at this position :) data.remove(pos, matchWidth); } } // Replace stuff starting with '&' + data.replace(QLatin1String("    "), QLatin1String("\t")); data.replace(QLatin1String(">"), QLatin1String(">")); data.replace(QLatin1String("<"), QLatin1String("<")); data.replace(QLatin1String("""), QLatin1String("\"")); data.replace(QLatin1String(" "), QLatin1String(" ")); data.replace(QLatin1String("&"), QLatin1String("&")); data.replace(QLatin1String(" "), QLatin1String(" ")); //this one is used in jabber: note, we should escape all &#xx; return data; } QString Message::escape(const QString &text) { QString html = text.toHtmlEscaped(); //Replace carriage returns inside the text html.replace(QLatin1Char('\n'), QLatin1String("
")); //Replace a tab with 4 spaces html.replace(QLatin1Char('\t'), QLatin1String("    ")); //Replace multiple spaces with   //do not replace every space so we break the linebreak html.replace(QRegExp(QLatin1String("\\s\\s")), QStringLiteral("  ")); return html; } QString Message::plainBody() const { // Remove ObjectReplacementCharacter which can be there if html text contains img tag. QString plainText = d->body->toPlainText(); plainText.replace(QChar(QChar::ObjectReplacementCharacter), QChar(' ')); return plainText; } QString Message::escapedBody() const { // qCDebug(LIBKOPETE_LOG) << escapedBody() << " " << d->richTextOverride; // the escaped body is cached because QRegExp is very expensive, so it shouldn't be used any more than necessary if (!d->escapedBodyDirty) { return d->escapedBody; } else { QString html; if (d->format == Qt::PlainText || (d->formattingOverride && !d->forceHtml)) { html = Qt::convertFromPlainText(d->body->toPlainText(), Qt::WhiteSpaceNormal); } else { html = d->body->toHtml(); } // all this regex business is to take off the outer HTML document provided by QTextDocument // remove the head QRegExp badStuff("]*>|]*>.*]*>|]*>|]*>"); html = html.remove(badStuff); // remove newlines that may be present, since they end up being displayed in the chat window. real newlines are represented with
, so we know \n's are meaningless html = html.remove('\n'); d->escapedBody = html; d->escapedBodyDirty = false; return html; } } QString Message::parsedBody() const { //qCDebug(LIBKOPETE_LOG) << "messageformat: " << d->format; if (!d->parsedBodyDirty) { return d->parsedBody; } d->parsedBody = Kopete::Emoticons::parseEmoticons(parseLinks(escapedBody(), Qt::RichText)); d->parsedBodyDirty = false; return d->parsedBody; } static QString makeRegExp(const char *pattern) { const QString urlChar = QStringLiteral("\\+\\-\\w\\./#@&;:=\\?~%_,\\!\\$\\*\\(\\)"); const QString boundaryStart = QStringLiteral("(^|[^%1])(").arg(urlChar); const QString boundaryEnd = QStringLiteral(")([^%1]|$)").arg(urlChar); return boundaryStart + QLatin1String(pattern) + boundaryEnd; } const QStringList Message::regexpPatterns() { const QString name = QStringLiteral("[\\w\\+\\-=_\\.]+"); const QString userAndPassword = QStringLiteral("(?:%1(?::%1)?\\@)").arg(name); const QString urlChar = QStringLiteral("\\+\\-\\w\\./#@&;:=\\?~%_,\\!\\$\\*\\(\\)"); const QString urlSection = QStringLiteral("[%1]+").arg(urlChar); const QString domain = QStringLiteral("[\\-\\w_]+(?:\\.[\\-\\w_]+)+"); QStringList patternList; patternList << makeRegExp("\\w+://%1?\\w%2").arg(userAndPassword, urlSection) << makeRegExp("%1?www\\.%2%3").arg(userAndPassword, domain, urlSection) << makeRegExp("%1@%2").arg(name, domain); return patternList; } QString Message::parseLinks(const QString &message, Qt::TextFormat format) { if (format & Qt::RichText) { // < in HTML *always* means start-of-tag QStringList entries = message.split(QChar('<'), QString::KeepEmptyParts); QStringList::Iterator it = entries.begin(); // first one is different: it doesn't start with an HTML tag. if (it != entries.end()) { *it = parseLinks(*it, Qt::PlainText); ++it; } for (; it != entries.end(); ++it) { QString curr = *it; // > in HTML means start-of-tag if and only if it's the first one after a < int tagclose = curr.indexOf(QChar('>')); // no >: the HTML is broken, but we can cope if (tagclose == -1) { continue; } QString tag = curr.left(tagclose + 1); QString body = curr.mid(tagclose + 1); *it = tag + parseLinks(body, Qt::PlainText); } return entries.join(QLatin1String("<")); } QString result = message; // common subpatterns - may not contain matching parens! const QString name = QStringLiteral("[\\w\\+\\-=_\\.]+"); const QString userAndPassword = QStringLiteral("(?:%1(?::%1)?\\@)").arg(name); const QString urlChar = QStringLiteral("\\+\\-\\w\\./#@&;:=\\?~%_,\\!\\$\\*\\(\\)"); const QString urlSection = QStringLiteral("[%1]+").arg(urlChar); const QString domain = QStringLiteral("[\\-\\w_]+(?:\\.[\\-\\w_]+)+"); //Replace http/https/ftp links: // Replace (stuff)://[user:password@](linkstuff) with a link result.replace( QRegExp(makeRegExp("\\w+://%1?\\w%2").arg(userAndPassword, urlSection)), QStringLiteral("\\1\\2\\3")); // Replace www.X.Y(linkstuff) with a http: link result.replace( QRegExp(makeRegExp("%1?www\\.%2%3").arg(userAndPassword, domain, urlSection)), QStringLiteral("\\1\\2\\3")); //Replace Email Links // Replace user@domain with a mailto: link result.replace( QRegExp(makeRegExp("%1@%2").arg(name, domain)), QStringLiteral("\\1\\2\\3")); //Workaround for Bug 85061: Highlighted URLs adds a ' ' after the URL itself // the trailing   is included in the url. result.replace(QRegExp(QLatin1String("(timeStamp; } void Message::setTimestamp(const QDateTime ×tamp) { d->timeStamp = timestamp; } const Contact *Message::from() const { return d->from; } QList Message::to() const { return d->to; } Message::MessageType Message::type() const { return d->type; } void Message::setType(MessageType type) { d->type = type; } QString Message::requestedPlugin() const { return d->requestedPlugin; } void Message::setRequestedPlugin(const QString &requestedPlugin) { d->requestedPlugin = requestedPlugin; } QColor Message::foregroundColor() const { return d->foregroundColor; } QColor Message::backgroundColor() const { return d->backgroundColor; } bool Message::isRightToLeft() const { return d->isRightToLeft; } QFont Message::font() const { return d->font; } QString Message::subject() const { return d->subject; } void Message::setSubject(const QString &subject) { d->subject = subject; } const QTextDocument *Message::body() const { return d->body; } Qt::TextFormat Message::format() const { return d->format; } Message::MessageDirection Message::direction() const { return d->direction; } void Message::setDirection(MessageDirection direction) { d->direction = direction; } Message::MessageImportance Message::importance() const { return d->importance; } Message::MessageState Message::state() const { return d->state; } void Message::setState(MessageState state) { d->state = state; } ChatSession *Message::manager() const { return d->manager; } void Message::setManager(ChatSession *kmm) { d->manager = kmm; } QString Message::getHtmlStyleAttribute() const { QString styleAttribute; styleAttribute = QStringLiteral("style=\""); if (!d->formattingOverride) { // Affect foreground(color) and background color to message. // we only do this if the formatting won't get stripped anyway if (d->foregroundColor.isValid()) { styleAttribute += QStringLiteral("color: %1; ").arg(d->foregroundColor.name()); } if (d->backgroundColor.isValid()) { styleAttribute += QStringLiteral("background-color: %1; ").arg(d->backgroundColor.name()); } // Affect font parameters. if (d->font != QFont()) { QString fontstr; if (!d->font.family().isNull()) { fontstr += QLatin1String("font-family: ")+d->font.family()+QLatin1String("; "); } if (d->font.italic()) { fontstr += QLatin1String("font-style: italic; "); } if (d->font.strikeOut()) { fontstr += QLatin1String("text-decoration: line-through; "); } if (d->font.underline()) { fontstr += QLatin1String("text-decoration: underline; "); } if (d->font.bold()) { fontstr += QLatin1String("font-weight: bold;"); } styleAttribute += fontstr; } } styleAttribute += QLatin1String("\""); return styleAttribute; } void Message::setFileTransferDisabled(bool disabled) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->disabled = disabled; } bool Message::fileTransferDisabled() const { return (d->fileTransfer) ? d->fileTransfer->disabled : false; } void Message::setFileName(const QString &fileName) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->fileName = fileName; } QString Message::fileName() const { return (d->fileTransfer) ? d->fileTransfer->fileName : QString(); } void Message::setFileSize(unsigned long size) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->fileSize = size; } unsigned long Message::fileSize() const { return (d->fileTransfer) ? d->fileTransfer->fileSize : 0; } void Message::setFilePreview(const QPixmap &preview) { if (!d->fileTransfer) { d->fileTransfer = new Message::Private::FileTransferInfo(); } d->fileTransfer->filePreview = preview; } QPixmap Message::filePreview() const { return (d->fileTransfer) ? d->fileTransfer->filePreview : QPixmap(); } // prime candidate for removal #if 0 QString Message::decodeString(const QByteArray &message, const QTextCodec *providedCodec, bool *success) { /* Note to everyone. This function is not the most efficient, that is for sure. However, it *is* the only way we can be guaranteed that a given string is decoded properly. */ if (success) { *success = true; } // Avoid heavy codec tests on empty message. if (message.isEmpty()) { return QString::fromAscii(message); } //Check first 128 chars int charsToCheck = message.length(); charsToCheck = 128 > charsToCheck ? charsToCheck : 128; #ifdef __GNUC__ #warning Rewrite the following code: heuristicContentMatch() do not existe anymore. #endif //They are providing a possible codec. Check if it is valid // if( providedCodec && providedCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. return providedCodec->toUnicode(message); } //NOTE see KEncodingDetector@kdecore //Check if it is UTF if (KStringHandler::isUtf8(message)) { //We have a UTF string almost for sure. At least we know it will be decoded. return QString::fromUtf8(message); } /* //Try codecForContent - exact match QTextCodec *testCodec = QTextCodec::codecForContent(message, charsToCheck); if( testCodec && testCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. return testCodec->toUnicode( message ); } kWarning(14000) << "Unable to decode string using provided codec(s), taking best guesses!"; if( success ) *success = false; //We don't have any clues here. //Try local codec testCodec = QTextCodec::codecForLocale(); if( testCodec && testCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. qCDebug(LIBKOPETE_LOG) << "Using locale's codec"; return testCodec->toUnicode( message ); } //Try latin1 codec testCodec = QTextCodec::codecForMib(4); if( testCodec && testCodec->heuristicContentMatch( message, charsToCheck ) >= charsToCheck ) { //All chars decodable. qCDebug(LIBKOPETE_LOG) << "Using latin1"; return testCodec->toUnicode( message ); } qCDebug(LIBKOPETE_LOG) << "Using latin1 and cleaning string"; //No codec decoded. Just decode latin1, and clean out any junk. QString result = QLatin1String( message ); const uint length = message.length(); for( uint i = 0; i < length; ++i ) { if( !result[i].isPrint() ) result[i] = '?'; } return result; */ return QString(); } #endif QStringList Message::classes() const { return d->classes; } void Message::addClass(const QString &classe) { d->classes.append(classe); } void Message::setClasses(const QStringList &classes) { d->classes = classes; } } bool Kopete::Message::delayed() const { return d->delayed; } void Kopete::Message::setDelayed(bool delay) { d->delayed = delay; } diff --git a/tests/libkopete/CMakeLists.txt b/tests/libkopete/CMakeLists.txt index 6b0601e73..ff783ac7d 100755 --- a/tests/libkopete/CMakeLists.txt +++ b/tests/libkopete/CMakeLists.txt @@ -1,24 +1,26 @@ include_directories( ${KOPETE_INCLUDES} ${CMAKE_SOURCE_DIR}/libkopete ) set(BLACKLIST_LIB kopeteblacklistertest.cpp ${CMAKE_SOURCE_DIR}/libkopete/kopeteblacklister.cpp ) set( KOPETE_TEST_LIBRARIES kopete Qt5::Test KF5::KIOCore ) ecm_add_test(kopetetasktest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopetestatusmessagetest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(${BLACKLIST_LIB} TEST_NAME blacklisttest LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopetecontactlistelementtest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopeteglobaltest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopeteidentitytest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopeteonlinestatusmanagertest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopeteinfoeventtest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) ecm_add_test(kopetecontacttest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) +ecm_add_test(kopetemessagetest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) + diff --git a/tests/libkopete/kopetemessagetest.cpp b/tests/libkopete/kopetemessagetest.cpp new file mode 100644 index 000000000..af300e132 --- /dev/null +++ b/tests/libkopete/kopetemessagetest.cpp @@ -0,0 +1,164 @@ +/* + Tests for Kopete Message + + Copyright (c) 2017 by Vijay Krishnavanshi + + Kopete (c) 2002-2017 by the Kopete developers + + ************************************************************************* + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ************************************************************************* +*/ + + +#include "kopetecontact.h" +#include "kopetemetacontact.h" +#include "kopeteprotocol.h" +#include "kopeteaccount.h" +#include "kopetechatsession.h" + +#include +#include + + +class DummyProtocol : public Kopete::Protocol +{ +public: + DummyProtocol() : Kopete::Protocol(nullptr, false) + { + + } + Kopete::Account *createNewAccount(const QString &accountId) + { + Q_UNUSED(accountId) + return nullptr; + } + AddContactPage *createAddContactWidget(QWidget *parent, Kopete::Account *account) + { + Q_UNUSED(parent) + Q_UNUSED(account) + return nullptr; + } + KopeteEditAccountWidget *createEditAccountWidget(Kopete::Account *account, QWidget *parent) + { + Q_UNUSED(account) + Q_UNUSED(parent) + return nullptr; + } + void setCapability(Protocol::Capabilities capabilities) + { + this->setCapabilities(capabilities); + } +}; + +class DummyAccount : public Kopete::Account +{ + Q_OBJECT +public: + DummyAccount(DummyProtocol *dummyProtocol):Kopete::Account(dummyProtocol, QStringLiteral("Dummy Account")) + { + + } + +protected: + bool createContact(const QString &contactId, Kopete::MetaContact *parentContact) + { + Q_UNUSED(contactId); + Q_UNUSED(parentContact); + return true; + } +public Q_SLOTS: + void connect(const Kopete::OnlineStatus &initialStatus = Kopete::OnlineStatus()) + { + Q_UNUSED(initialStatus); + } + void disconnect() + { + + } + void setOnlineStatus(const Kopete::OnlineStatus &status, const Kopete::StatusMessage &reason = Kopete::StatusMessage(), const OnlineStatusOptions &options = None) + { + Q_UNUSED(status); + Q_UNUSED(reason); + Q_UNUSED(options); + } + void setStatusMessage(const Kopete::StatusMessage &statusMessage) + { + Q_UNUSED(statusMessage); + } + void setSelf(Kopete::Contact *contact) + { + setMyself(contact); + } + void settingAccountLabel(const QString &label) + { + setAccountLabel(label); + } +}; +class DummyContact : public Kopete::Contact +{ +public: + DummyContact(Kopete::Account *account, const QString &contactId, Kopete::MetaContact *parent, const QString &icon) : Kopete::Contact(account, contactId, parent, icon) + { + + }; + + Kopete::ChatSession *manager(CanCreateFlags canCreate = CannotCreate) + { + Q_UNUSED(canCreate); + return nullptr; + } +}; +class MessageTest : public QObject +{ + Q_OBJECT +private slots: + void testMessageCreation(); + void testMessageCreation_data(); +}; + +void MessageTest::testMessageCreation_data() +{ + QTest::addColumn("escapedTest"); + QTest::addColumn("escapedExpected"); + QTest::addColumn("unescapedTest"); + QTest::addColumn("unescapedExpected"); + QTest::addColumn("toContactId"); + QTest::addColumn("fromContactId"); + QTest::addColumn("icon"); + + QTest::newRow("Ideal Case") << QStringLiteral("Hello\nThere") << QStringLiteral("Hello
There") << QStringLiteral("Hello
There") << QStringLiteral("Hello\nThere") << QStringLiteral("Roman") << QStringLiteral("Gaurav") << QStringLiteral("Icon"); + QTest::newRow("Negative Case") << QStringLiteral("Hello\tThere") << QStringLiteral("Hello    There") << QStringLiteral("Hello    There") << QStringLiteral("Hello\tThere") << QStringLiteral("Roman") << QStringLiteral("Gaurav") << QStringLiteral("Icon"); + QTest::newRow("Empty Case") << QString() << QString() << QString() << QString() << QString() << QString() << QString(); +} + +void MessageTest::testMessageCreation() +{ + QFETCH(QString, fromContactId); + QFETCH(QString, toContactId); + QFETCH(QString, icon); + QFETCH(QString, escapedTest); + QFETCH(QString, unescapedTest); + QFETCH(QString, escapedExpected); + QFETCH(QString, unescapedExpected); + + Kopete::MetaContact *parentMetaContact = new Kopete::MetaContact(); + DummyProtocol *dummyProtocol = new DummyProtocol(); + DummyAccount *dummyAccount = new DummyAccount(dummyProtocol); + DummyContact *fromContact = new DummyContact(dummyAccount, fromContactId, parentMetaContact, icon); + DummyContact *toContact = new DummyContact(dummyAccount, toContactId, parentMetaContact, icon); + Kopete::Message msg(fromContact, toContact); + QCOMPARE(escapedExpected, msg.escape(escapedTest)); + QCOMPARE(unescapedExpected, msg.unescape(unescapedTest)); + delete dummyAccount; // Contact gets automatically deleted + delete dummyProtocol; + delete parentMetaContact; +} + +QTEST_MAIN(MessageTest) +#include "kopetemessagetest.moc"