summaryrefslogtreecommitdiff
path: root/kimap/tests
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 23:43:13 (GMT)
committerChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 23:43:13 (GMT)
commite21e62c14f5aae99d46643065fcb86e2e3abe230 (patch)
tree71d79d2de0b0f82f8b0a6ca3b8b09308d198ed33 /kimap/tests
parent172803b38237e38a494aca62fffda918e5799d20 (diff)
downloadlibcalendaring-e21e62c14f5aae99d46643065fcb86e2e3abe230.tar.gz
initial import of kimap from
commit b54a325116b194da090f900c9a538710759eb303 Author: Stephen Kelly <steveire@gmail.com> Date: Sun May 6 20:44:53 2012 +0200 Revert "Port to const QRegExp API." This reverts commit 0ca0dfc7e0ca8095efd0b060d1d5e26ac9ceb379. The qtbase commit requiring this was reverted.
Diffstat (limited to 'kimap/tests')
-rw-r--r--kimap/tests/CMakeLists.txt52
-rw-r--r--kimap/tests/capabilitiesjobtest.cpp99
-rw-r--r--kimap/tests/createjobtest.cpp88
-rw-r--r--kimap/tests/deletejobtest.cpp95
-rw-r--r--kimap/tests/fakeserverscenario.log6
-rw-r--r--kimap/tests/fakeservertest.cpp68
-rw-r--r--kimap/tests/fetchjobtest.cpp296
-rw-r--r--kimap/tests/idlejobtest.cpp216
-rw-r--r--kimap/tests/imapsettest.cpp76
-rw-r--r--kimap/tests/kimaptest/CMakeLists.txt24
-rw-r--r--kimap/tests/kimaptest/fakeserver.cpp223
-rw-r--r--kimap/tests/kimaptest/fakeserver.h222
-rw-r--r--kimap/tests/kimaptest/mockjob.cpp79
-rw-r--r--kimap/tests/kimaptest/mockjob.h75
-rw-r--r--kimap/tests/listjobtest.cpp237
-rw-r--r--kimap/tests/loginjobtest.cpp154
-rw-r--r--kimap/tests/logoutjobtest.cpp81
-rw-r--r--kimap/tests/quotarootjobtest.cpp187
-rw-r--r--kimap/tests/renamejobtest.cpp91
-rw-r--r--kimap/tests/selectjobtest.cpp147
-rw-r--r--kimap/tests/storejobtest.cpp100
-rw-r--r--kimap/tests/subscribejobtest.cpp87
-rw-r--r--kimap/tests/testimapidle.cpp130
-rw-r--r--kimap/tests/testimapserver.cpp604
-rw-r--r--kimap/tests/testrfccodecs.cpp79
-rw-r--r--kimap/tests/testrfccodecs.h35
-rw-r--r--kimap/tests/testsession.cpp330
-rw-r--r--kimap/tests/unsubscribejobtest.cpp87
28 files changed, 3968 insertions, 0 deletions
diff --git a/kimap/tests/CMakeLists.txt b/kimap/tests/CMakeLists.txt
new file mode 100644
index 0000000..8aa657a
--- /dev/null
+++ b/kimap/tests/CMakeLists.txt
@@ -0,0 +1,52 @@
+add_subdirectory(kimaptest)
+
+include_directories( ${CMAKE_SOURCE_DIR}/kimap ${Boost_INCLUDE_DIR})
+set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
+
+MACRO(KIMAP_UNIT_TESTS)
+ FOREACH(_testname ${ARGN})
+ kde4_add_unit_test(${_testname} TESTNAME kimap-${_testname} NOGUI ${_testname}.cpp)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
+ target_link_libraries(${_testname} ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY}
+ kimap kimaptest kmime)
+ add_definitions(-DTEST_DATA="\\"${CMAKE_CURRENT_SOURCE_DIR}\\"")
+ ENDFOREACH(_testname)
+ENDMACRO(KIMAP_UNIT_TESTS)
+
+MACRO(KIMAP_EXECUTABLE_TESTS)
+ FOREACH(_testname ${ARGN})
+ kde4_add_executable(${_testname} NOGUI TEST ${_testname}.cpp)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
+ target_link_libraries(${_testname} ${KDE4_KDECORE_LIBS} kimap kmime)
+ ENDFOREACH(_testname)
+ENDMACRO(KIMAP_EXECUTABLE_TESTS)
+
+########### automated tests ###############
+
+KIMAP_UNIT_TESTS(
+ fakeservertest
+ testrfccodecs
+ testsession
+ loginjobtest
+ logoutjobtest
+ capabilitiesjobtest
+ selectjobtest
+ createjobtest
+ deletejobtest
+ fetchjobtest
+ renamejobtest
+ subscribejobtest
+ unsubscribejobtest
+ listjobtest
+ storejobtest
+ imapsettest
+ idlejobtest
+ quotarootjobtest
+)
+
+########### manual tests ###############
+
+KIMAP_EXECUTABLE_TESTS(
+ testimapidle
+ testimapserver
+)
diff --git a/kimap/tests/capabilitiesjobtest.cpp b/kimap/tests/capabilitiesjobtest.cpp
new file mode 100644
index 0000000..d4ad29d
--- /dev/null
+++ b/kimap/tests/capabilitiesjobtest.cpp
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/capabilitiesjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+
+class CapabilitiesJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testCapabilities_data() {
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+ QTest::addColumn<QStringList>( "capabilities" );
+ QList<QByteArray> scenario;
+ scenario << "S: * PREAUTH"
+ << "C: A000001 CAPABILITY"
+ << "S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI"
+ << "S: A000001 OK CAPABILITY completed";
+
+ QStringList capabilities;
+ capabilities << "IMAP4REV1" << "STARTTLS" << "AUTH=GSSAPI";
+ QTest::newRow( "good" ) << scenario << capabilities;
+
+
+
+ scenario.clear();
+ capabilities.clear();
+ scenario << "S: * PREAUTH"
+ << "C: A000001 CAPABILITY"
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << scenario << capabilities;
+
+
+
+ scenario.clear();
+ capabilities.clear();
+ scenario << "S: * PREAUTH"
+ << "C: A000001 CAPABILITY"
+ << "S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=PLAIN"
+ << "S: * some response"
+ << "S: A000001 OK CAPABILITY completed";
+
+ capabilities << "IMAP4REV1" << "STARTTLS" << "AUTH=PLAIN";
+ QTest::newRow( "extra-untagged" ) << scenario << capabilities;;
+}
+
+void testCapabilities()
+{
+ QFETCH( QList<QByteArray>, scenario );
+ QFETCH( QStringList, capabilities );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::CapabilitiesJob *job = new KIMAP::CapabilitiesJob(&session);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
+ QVERIFY(result);
+ if (result) {
+ QCOMPARE(job->capabilities(), capabilities);
+ }
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( CapabilitiesJobTest )
+
+#include "capabilitiesjobtest.moc"
diff --git a/kimap/tests/createjobtest.cpp b/kimap/tests/createjobtest.cpp
new file mode 100644
index 0000000..09f50c7
--- /dev/null
+++ b/kimap/tests/createjobtest.cpp
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/createjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class CreateJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testCreate_data() {
+ QTest::addColumn<QString>( "mailbox" );
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 CREATE \"INBOX\""
+ << "S: A000001 OK CREATE completed";
+ QTest::newRow( "good" ) << "INBOX" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 CREATE \"INBOX-FAIL-BAD\""
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << "INBOX-FAIL-BAD" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 CREATE \"INBOX-FAIL-NO\""
+ << "S: A000001 NO create failure";
+ QTest::newRow( "no" ) << "INBOX-FAIL-NO" << scenario;
+}
+
+void testCreate()
+{
+ QFETCH( QString, mailbox );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::CreateJob *job = new KIMAP::CreateJob(&session);
+ job->setMailBox(mailbox);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO response", Continue);
+ QVERIFY(result);
+ if (result) {
+ QCOMPARE(job->mailBox(), mailbox);
+ }
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( CreateJobTest )
+
+#include "createjobtest.moc"
diff --git a/kimap/tests/deletejobtest.cpp b/kimap/tests/deletejobtest.cpp
new file mode 100644
index 0000000..3c8ed46
--- /dev/null
+++ b/kimap/tests/deletejobtest.cpp
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/deletejob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class DeleteJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testDelete_data() {
+ QTest::addColumn<QString>( "mailbox" );
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 DELETE \"foo\""
+ << "S: A000001 OK DELETE completed";
+ QTest::newRow( "good" ) << "foo" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 DELETE \"foo-BAD\""
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << "foo-BAD" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 DELETE \"foo\""
+ << "S: A000001 Name \"foo\" has inferior hierarchical names";
+ QTest::newRow( "no" ) << "foo" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 DELETE \"foo/bar\""
+ << "S: A000001 OK DELETE completed";
+ QTest::newRow( "hierarchical" ) << "foo/bar" << scenario;
+}
+
+void testDelete()
+{
+ QFETCH( QString, mailbox );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::DeleteJob *job = new KIMAP::DeleteJob(&session);
+ job->setMailBox(mailbox);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO response", Continue);
+ QVERIFY(result);
+ if (result) {
+ QCOMPARE(job->mailBox(), mailbox);
+ }
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( DeleteJobTest )
+
+#include "deletejobtest.moc"
diff --git a/kimap/tests/fakeserverscenario.log b/kimap/tests/fakeserverscenario.log
new file mode 100644
index 0000000..f7d3f97
--- /dev/null
+++ b/kimap/tests/fakeserverscenario.log
@@ -0,0 +1,6 @@
+C: A000001 LIST "" *
+S: * LIST ( \HasChildren ) / INBOX
+S: * LIST ( \HasNoChildren ) / INBOX/&AOQ- &APY- &APw- @ &IKw-
+S: * LIST ( \HasChildren ) / INBOX/lost+found
+S: * LIST ( \HasNoChildren ) / "INBOX/lost+found/Calendar Public-20080128"
+S: A000001 OK LIST completed
diff --git a/kimap/tests/fakeservertest.cpp b/kimap/tests/fakeservertest.cpp
new file mode 100644
index 0000000..1399615
--- /dev/null
+++ b/kimap/tests/fakeservertest.cpp
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/listjob.h"
+
+#include <QtTest>
+
+class FakeServerTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testLoadScenario() {
+ KIMAP::MailBoxDescriptor descriptor;
+ QList<KIMAP::MailBoxDescriptor> listresult;
+
+ descriptor.separator = '/';
+ descriptor.name = "INBOX";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = QString::fromUtf8( "INBOX/ä ö ü @ €" );
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found/Calendar Public-20080128";
+ listresult << descriptor;
+
+ FakeServer fakeServer;
+ fakeServer.addScenarioFromFile( TEST_DATA "/fakeserverscenario.log" );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::ListJob *job = new KIMAP::ListJob(&session);
+ job->setIncludeUnsubscribed(true);
+ QVERIFY(job->exec());
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( FakeServerTest )
+
+#include "fakeservertest.moc"
diff --git a/kimap/tests/fetchjobtest.cpp b/kimap/tests/fetchjobtest.cpp
new file mode 100644
index 0000000..749234c
--- /dev/null
+++ b/kimap/tests/fetchjobtest.cpp
@@ -0,0 +1,296 @@
+/*
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/fetchjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+Q_DECLARE_METATYPE(KIMAP::FetchJob::FetchScope)
+
+class FetchJobTest: public QObject {
+ Q_OBJECT
+
+private:
+ QStringList m_signals;
+
+ QMap<qint64, qint64> m_uids;
+ QMap<qint64, qint64> m_sizes;
+ QMap<qint64, KIMAP::MessageFlags> m_flags;
+ QMap<qint64, KIMAP::MessagePtr> m_messages;
+ QMap<qint64, KIMAP::MessageParts> m_parts;
+
+public slots:
+void onHeadersReceived( const QString &/*mailBox*/,
+ const QMap<qint64, qint64> &uids,
+ const QMap<qint64, qint64> &sizes,
+ const QMap<qint64, KIMAP::MessageFlags> &flags,
+ const QMap<qint64, KIMAP::MessagePtr> &messages )
+ {
+ m_signals << "headersReceived";
+ m_uids.unite( uids );
+ m_sizes.unite( sizes );
+ m_flags.unite( flags );
+ m_messages.unite( messages );
+ }
+
+void onMessagesReceived( QString, const QMap<qint64, qint64> uids, const QMap<qint64, KIMAP::MessagePtr> messages )
+{
+ m_signals << "messagesReceived";
+ m_uids.unite( uids );
+ m_messages.unite( messages );
+}
+
+void onPartsReceived( QString, QMap<qint64,qint64> /*uids*/, QMap<qint64, KIMAP::MessageParts> parts)
+{
+ m_signals << "partsReceived";
+ m_parts.unite( parts );
+}
+
+private Q_SLOTS:
+
+void testFetch_data() {
+ qRegisterMetaType<KIMAP::FetchJob::FetchScope>();
+
+ QTest::addColumn<bool>( "uidBased" );
+ QTest::addColumn< KIMAP::ImapSet >( "set" );
+ QTest::addColumn<int>( "expectedMessageCount" );
+ QTest::addColumn< QList<QByteArray> >( "scenario" );
+ QTest::addColumn<KIMAP::FetchJob::FetchScope>( "scope" );
+
+ KIMAP::FetchJob::FetchScope scope;
+ scope.mode = KIMAP::FetchJob::FetchScope::Flags;
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 FETCH 1:4 (FLAGS UID)"
+ << "S: * 1 FETCH ( FLAGS () UID 1 )"
+ << "S: * 2 FETCH ( FLAGS () UID 2 )"
+ << "S: * 3 FETCH ( FLAGS () UID 3 )"
+ << "S: * 4 FETCH ( FLAGS () UID 4 )"
+ << "S: A000001 OK fetch done";
+
+ QTest::newRow( "messages have empty flags" ) << false << KIMAP::ImapSet( 1, 4 ) << 4
+ << scenario << scope;
+
+ scenario.clear();
+ // kill the connection part-way through a list, with carriage returns at end
+ // BUG 253619
+ // this should fail, but it shouldn't crash
+ scenario << FakeServer::preauth()
+ << "C: A000001 FETCH 11 (RFC822.SIZE INTERNALDATE BODY.PEEK[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] FLAGS UID)"
+ << "S: * 11 FETCH (RFC822.SIZE 770 INTERNALDATE \"11-Oct-2010 03:33:50 +0100\" BODY[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] {246}"
+ << "S: From: John Smith <jonathanr.smith@foobarbaz.com>\r\nTo: \"amagicemailaddress@foobarbazbarfoo.com\"\r\n\t<amagicemailaddress@foobarbazbarfoo.com>\r\nDate: Mon, 11 Oct 2010 03:34:48 +0100\r\nSubject: unsubscribe\r\nMessage-ID: <ASDFFDSASDFFDS@foobarbaz.com>\r\n\r\n"
+ << "X";
+ scope.mode = KIMAP::FetchJob::FetchScope::Headers;
+ QTest::newRow( "connection drop" ) << false << KIMAP::ImapSet( 11, 11 ) << 1 << scenario << scope;
+
+
+ scenario.clear();
+ // Important bit here if "([127.0.0.1])" which used to crash the stream parser
+ scenario << FakeServer::preauth()
+ << "C: A000001 FETCH 11 (RFC822.SIZE INTERNALDATE BODY.PEEK[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] FLAGS UID)"
+ << "S: * 11 FETCH (RFC822.SIZE 770 INTERNALDATE \"11-Oct-2010 03:33:50 +0100\" BODY[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] {246}"
+ << "S: ([127.0.0.1])\r\nDate: Mon, 11 Oct 2010 03:34:48 +0100\r\nSubject: unsubscribe\r\nMessage-ID: <ASDFFDSASDFFDS@foobarbaz.com>\r\n\r\n"
+ << "X";
+ scope.mode = KIMAP::FetchJob::FetchScope::Headers;
+ QTest::newRow( "buffer overwrite" ) << false << KIMAP::ImapSet( 11, 11 ) << 1 << scenario << scope;
+
+
+ scenario.clear();
+ // We're assuming a buffer overwrite here which made us miss the opening parenthesis
+ // for the properties list
+ scenario << FakeServer::preauth()
+ << "C: A000001 FETCH 11 (RFC822.SIZE INTERNALDATE BODY.PEEK[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] FLAGS UID)"
+ << "S: * 11 FETCH {10}doh!\r\n\r\n\r\n)\r\n"
+ << "X";
+ scope.mode = KIMAP::FetchJob::FetchScope::Headers;
+ QTest::newRow( "buffer overwrite 2" ) << false << KIMAP::ImapSet( 11, 11 ) << 1 << scenario << scope;
+}
+
+void testFetch()
+{
+ QFETCH( bool, uidBased );
+ QFETCH( KIMAP::ImapSet, set );
+ QFETCH( int, expectedMessageCount );
+ QFETCH( QList<QByteArray>, scenario );
+ QFETCH( KIMAP::FetchJob::FetchScope, scope );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::FetchJob *job = new KIMAP::FetchJob(&session);
+ job->setUidBased( uidBased );
+ job->setSequenceSet( set );
+ job->setScope( scope );
+
+ connect( job, SIGNAL(headersReceived(QString,
+ QMap<qint64, qint64>,
+ QMap<qint64, qint64>,
+ QMap<qint64, KIMAP::MessageFlags>,
+ QMap<qint64, KIMAP::MessagePtr>)),
+ this, SLOT(onHeadersReceived(QString,
+ QMap<qint64, qint64>,
+ QMap<qint64, qint64>,
+ QMap<qint64, KIMAP::MessageFlags>,
+ QMap<qint64, KIMAP::MessagePtr>)) );
+
+
+ bool result = job->exec();
+ QEXPECT_FAIL("connection drop", "Expected failure on connection drop", Continue);
+ QEXPECT_FAIL("buffer overwrite", "Expected failure on confused list", Continue);
+ QEXPECT_FAIL("buffer overwrite 2", "Expected beginning of message missing", Continue);
+ QVERIFY( result );
+ if ( result ) {
+ QVERIFY( m_signals.count()>0 );
+ QCOMPARE( m_uids.count(), expectedMessageCount );
+ }
+
+ QVERIFY( fakeServer.isAllScenarioDone() );
+ fakeServer.quit();
+
+ m_signals.clear();
+ m_uids.clear();
+ m_sizes.clear();
+ m_flags.clear();
+ m_messages.clear();
+ m_parts.clear();
+}
+
+void testFetchStructure()
+{
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 FETCH 1:2 (BODYSTRUCTURE UID)"
+ << "S: * 1 FETCH (UID 10 BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" 5 1 NIL NIL NIL))"
+ << "S: * 2 FETCH (UID 20 BODYSTRUCTURE ((((\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" 72 4 NIL NIL NIL)(\"TEXT\" \"HTML\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"QUOTED-PRINTABLE\" 281 5 NIL NIL NIL) \"ALTERNATIVE\" (\"BOUNDARY\" \"0001\") NIL NIL)(\"IMAGE\" \"GIF\" (\"NAME\" \"B56.gif\") \"<B56@goomoji.gmail>\" NIL \"BASE64\" 528 NIL NIL NIL) \"RELATED\" (\"BOUNDARY\" \"0002\") NIL NIL)(\"IMAGE\" \"JPEG\" (\"NAME\" \"photo.jpg\") NIL NIL \"BASE64\" 53338 NIL (\"ATTACHMENT\" (\"FILENAME\" \"photo.jpg\")) NIL) \"MIXED\" (\"BOUNDARY\" \"0003\") NIL NIL))"
+ << "S: A000001 OK fetch done";
+
+ KIMAP::FetchJob::FetchScope scope;
+ scope.mode = KIMAP::FetchJob::FetchScope::Structure;
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::FetchJob *job = new KIMAP::FetchJob(&session);
+ job->setUidBased( false );
+ job->setSequenceSet( KIMAP::ImapSet( 1, 2 ) );
+ job->setScope( scope );
+
+ connect( job, SIGNAL(messagesReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessagePtr>)),
+ SLOT(onMessagesReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessagePtr>)) );
+
+ bool result = job->exec();
+ QVERIFY( result );
+ QVERIFY( m_signals.count() > 0 );
+ QCOMPARE( m_uids.count(), 2 );
+ QCOMPARE( m_messages[1]->attachments().count(), 0 );
+ QCOMPARE( m_messages[2]->attachments().count(), 3 );
+ QCOMPARE( m_messages[2]->attachments().at(2)->contentDisposition()->filename(), QString("photo.jpg") );
+
+ fakeServer.quit();
+
+ m_signals.clear();
+ m_uids.clear();
+ m_sizes.clear();
+ m_flags.clear();
+ m_messages.clear();
+ m_parts.clear();
+}
+
+void testFetchParts()
+{
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 FETCH 2 (BODY.PEEK[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] BODY.PEEK[1.1.1.MIME] BODY.PEEK[1.1.1] FLAGS UID)"
+ << "S: * 2 FETCH (UID 20 FLAGS (\\Seen) BODY[HEADER.FIELDS (TO FROM MESSAGE-ID REFERENCES IN-REPLY-TO SUBJECT DATE)] {154}\r\nFrom: Joe Smith <smith@example.com>\r\nDate: Wed, 2 Mar 2011 11:33:24 +0700\r\nMessage-ID: <1234@example.com>\r\nSubject: hello\r\nTo: Jane <jane@example.com>\r\n\r\n BODY[1.1.1] {28}\r\nHi Jane, nice to meet you!\r\n BODY[1.1.1.MIME] {48}\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\n)\r\n"
+ << "S: A000001 OK fetch done";
+
+ KIMAP::FetchJob::FetchScope scope;
+ scope.mode = KIMAP::FetchJob::FetchScope::HeaderAndContent;
+ scope.parts.clear();
+ scope.parts.append("1.1.1");
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::FetchJob *job = new KIMAP::FetchJob(&session);
+ job->setUidBased( false );
+ job->setSequenceSet( KIMAP::ImapSet( 2, 2 ) );
+ job->setScope( scope );
+
+ connect ( job, SIGNAL(headersReceived(QString,QMap<qint64,qint64>,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageFlags>,QMap<qint64,KIMAP::MessagePtr>)),
+ SLOT(onHeadersReceived(QString,QMap<qint64,qint64>,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageFlags>,QMap<qint64,KIMAP::MessagePtr>)) );
+ connect( job, SIGNAL(partsReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageParts>)),
+ SLOT(onPartsReceived(QString,QMap<qint64,qint64>,QMap<qint64,KIMAP::MessageParts>)));
+
+ bool result = job->exec();
+
+ QVERIFY( result );
+ QVERIFY( m_signals.count() > 0 );
+ QCOMPARE( m_uids.count(), 1 );
+ QCOMPARE (m_parts.count(), 1 );
+
+ // Check that we received the message header
+ QCOMPARE( m_messages[2]->messageID()->identifier(), QByteArray("1234@example.com") );
+
+ // Check that we recieved the flags
+ QMap<qint64, KIMAP::MessageFlags> expectedFlags;
+ expectedFlags.insert(2, KIMAP::MessageFlags() << "\\Seen");
+ QCOMPARE( m_flags, expectedFlags );
+
+ // Check that we didn't received the full message body, since we only requested a specific part
+ QCOMPARE( m_messages[2]->decodedText().length(), 0 );
+ QCOMPARE( m_messages[2]->attachments().count(), 0);
+
+ // Check that we received the part we requested
+ QByteArray partId = m_parts[2].keys().first();
+ QString text = m_parts[2].value(partId)->decodedText(true, true);
+ QCOMPARE( partId, QByteArray("1.1.1"));
+ QCOMPARE( text, QString("Hi Jane, nice to meet you!")) ;
+
+ fakeServer.quit();
+
+ m_signals.clear();
+ m_uids.clear();
+ m_sizes.clear();
+ m_flags.clear();
+ m_messages.clear();
+ m_parts.clear();
+}
+
+};
+
+QTEST_KDEMAIN_CORE( FetchJobTest )
+
+#include "fetchjobtest.moc"
diff --git a/kimap/tests/idlejobtest.cpp b/kimap/tests/idlejobtest.cpp
new file mode 100644
index 0000000..0c35f49
--- /dev/null
+++ b/kimap/tests/idlejobtest.cpp
@@ -0,0 +1,216 @@
+/*
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/selectjob.h"
+#include "kimap/idlejob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(KIMAP::IdleJob*)
+
+class IdleJobTest: public QObject {
+ Q_OBJECT
+
+public:
+explicit IdleJobTest( QObject *parent = 0 )
+ : QObject( parent )
+{
+ qRegisterMetaType<KIMAP::IdleJob*>();
+}
+
+private Q_SLOTS:
+void shouldReactToIdle_data()
+{
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+ QTest::addColumn<QString>( "expectedMailBox" );
+ QTest::addColumn< QList<int> >( "expectedMessageCounts" );
+ QTest::addColumn< QList<int> >( "expectedRecentCounts" );
+
+ QList<QByteArray> scenario;
+ QString expectedMailBox;
+ QList<int> expectedMessageCounts;
+ QList<int> expectedRecentCounts;
+
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX/Foo\""
+ << "S: A000001 OK SELECT done"
+ << "C: A000002 IDLE"
+ << "S: + OK"
+ << "S: * 0 RECENT"
+ << "S: * 1 EXISTS"
+ << "S: * 1 RECENT"
+ << "S: * 2 EXISTS"
+ << "S: A000002 OK done idling";
+
+ expectedMailBox = "INBOX/Foo";
+
+ expectedMessageCounts.clear();
+ expectedRecentCounts.clear();
+
+ expectedMessageCounts << 1 << 2;
+ expectedRecentCounts << 0 << 1;
+
+ QTest::newRow( "normal" ) << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts;
+
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX/Foo\""
+ << "S: A000001 OK SELECT done"
+ << "C: A000002 IDLE"
+ << "S: + OK"
+ << "S: * 0 RECENT"
+ << "S: * 1 RECENT"
+ << "S: A000002 OK done idling";
+
+ expectedMailBox = "INBOX/Foo";
+
+ expectedMessageCounts.clear();
+ expectedRecentCounts.clear();
+
+ expectedMessageCounts << -1 << -1;
+ expectedRecentCounts << 0 << 1;
+
+ QTest::newRow( "only RECENT" ) << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts;
+
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX/Foo\""
+ << "S: A000001 OK SELECT done"
+ << "C: A000002 IDLE"
+ << "S: + OK"
+ << "S: * 1 EXISTS"
+ << "S: * 2 EXISTS"
+ << "S: A000002 OK done idling";
+
+ expectedMailBox = "INBOX/Foo";
+
+ expectedMessageCounts.clear();
+ expectedRecentCounts.clear();
+
+ expectedMessageCounts << 1 << 2;
+ expectedRecentCounts << -1 << -1;
+
+ QTest::newRow( "only EXISTS" ) << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts;
+
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX/Foo\""
+ << "S: A000001 OK SELECT done"
+ << "C: A000002 IDLE"
+ << "S: + OK"
+ << "S: * 2 EXISTS"
+ << "W: 150"
+ << "S: * 1 RECENT"
+ << "S: A000002 OK done idling";
+
+ expectedMailBox = "INBOX/Foo";
+
+ expectedMessageCounts.clear();
+ expectedRecentCounts.clear();
+
+ expectedMessageCounts << 2;
+ expectedRecentCounts << 1;
+
+ QTest::newRow( "under 200ms, same notification" ) << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts;
+
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX/Foo\""
+ << "S: A000001 OK SELECT done"
+ << "C: A000002 IDLE"
+ << "S: + OK"
+ << "S: * 2 EXISTS"
+ << "W: 250"
+ << "S: * 1 RECENT"
+ << "S: A000002 OK done idling";
+
+ expectedMailBox = "INBOX/Foo";
+
+ expectedMessageCounts.clear();
+ expectedRecentCounts.clear();
+
+ expectedMessageCounts << 2 << -1;
+ expectedRecentCounts << -1 << 1;
+
+ QTest::newRow( "above 200ms, two notifications" ) << scenario << expectedMailBox << expectedMessageCounts << expectedRecentCounts;
+}
+
+void shouldReactToIdle()
+{
+ QFETCH( QList<QByteArray>, scenario );
+ QFETCH( QString, expectedMailBox );
+ QFETCH( QList<int>, expectedMessageCounts );
+ QFETCH( QList<int>, expectedRecentCounts );
+
+ QVERIFY( expectedMessageCounts.size() == expectedRecentCounts.size() );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session( "127.0.0.1", 5989 );
+
+ KIMAP::SelectJob *select = new KIMAP::SelectJob( &session );
+ select->setMailBox( expectedMailBox );
+ QVERIFY( select->exec() );
+
+ KIMAP::IdleJob *idle = new KIMAP::IdleJob( &session );
+
+ QSignalSpy spy( idle, SIGNAL(mailBoxStats(KIMAP::IdleJob*,QString,int,int)) );
+
+ bool result = idle->exec();
+
+ if ( result ) {
+ QCOMPARE( spy.count(), expectedMessageCounts.size() );
+
+ for ( int i=0; i<spy.count(); i++ ) {
+ const KIMAP::IdleJob *job = spy.at( i ).at( 0 ).value<KIMAP::IdleJob*>();
+ const QString mailBox = spy.at( i ).at( 1 ).toString();
+ const int messageCount = spy.at( i ).at( 2 ).toInt();
+ const int recentCount = spy.at( i ).at( 3 ).toInt();
+
+ QCOMPARE( job, idle );
+ QCOMPARE( mailBox, expectedMailBox );
+ QCOMPARE( messageCount, expectedMessageCounts.at( i ) );
+ QCOMPARE( recentCount, expectedRecentCounts.at( i ) );
+ }
+ }
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( IdleJobTest )
+
+#include "idlejobtest.moc"
diff --git a/kimap/tests/imapsettest.cpp b/kimap/tests/imapsettest.cpp
new file mode 100644
index 0000000..56795f5
--- /dev/null
+++ b/kimap/tests/imapsettest.cpp
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimap/imapset.h"
+
+#include <QtTest>
+#include <KDebug>
+
+using namespace KIMAP;
+
+class ImapSetTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void shouldConvertToAndFromByteArray_data()
+ {
+ ImapSet set;
+
+ QTest::addColumn<ImapSet>( "imapSet" );
+ QTest::addColumn<QByteArray>( "byteArray" );
+
+ QTest::newRow( "empty set" ) << ImapSet() << QByteArray();
+ QTest::newRow( "unique value" ) << ImapSet( 7 ) << QByteArray( "7" );
+ QTest::newRow( "single interval" ) << ImapSet( 7, 10 ) << QByteArray( "7:10" );
+ QTest::newRow( "single interval with no upper bound" ) << ImapSet( 1, 0 ) << QByteArray( "1:*" );
+
+ set = ImapSet( 7, 10 );
+ set.add( ImapInterval( 12, 14 ) );
+ QTest::newRow( "two intervals" ) << set << QByteArray( "7:10,12:14" );
+
+ set = ImapSet( 7, 10 );
+ set.add( ImapInterval( 12 ) );
+ QTest::newRow( "two intervals with an infinite one" ) << set << QByteArray( "7:10,12:*" );
+
+ set = ImapSet( 7, 10 );
+ set.add( 5 );
+ QTest::newRow( "one interval and a value" ) << set << QByteArray( "7:10,5" );
+
+ set = ImapSet( 7, 10 );
+ set.add( QList<ImapSet::Id>() << 5 << 3 );
+ QTest::newRow( "one interval and two values" ) << set << QByteArray( "7:10,3,5" );
+ }
+
+ void shouldConvertToAndFromByteArray()
+ {
+ QFETCH( ImapSet, imapSet );
+ QFETCH( QByteArray, byteArray );
+
+ QCOMPARE( QString::fromUtf8( imapSet.toImapSequenceSet() ),
+ QString::fromUtf8( byteArray ) );
+ //qDebug() << "Expects" << imapSet << "got" << ImapSet::fromImapSequenceSet( byteArray );
+ QCOMPARE( ImapSet::fromImapSequenceSet( byteArray ), imapSet );
+ }
+};
+
+QTEST_KDEMAIN_CORE( ImapSetTest )
+
+#include "imapsettest.moc"
diff --git a/kimap/tests/kimaptest/CMakeLists.txt b/kimap/tests/kimaptest/CMakeLists.txt
new file mode 100644
index 0000000..80723fa
--- /dev/null
+++ b/kimap/tests/kimaptest/CMakeLists.txt
@@ -0,0 +1,24 @@
+project(kimaptest)
+
+if(KDE4_BUILD_TESTS)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
+
+set(kimaptest_LIB_SRCS
+ fakeserver.cpp
+ mockjob.cpp
+)
+
+kde4_add_library(kimaptest STATIC ${kimaptest_LIB_SRCS})
+target_link_libraries(kimaptest ${KDE4_KDECORE_LIBS} ${QT_QTNETWORK_LIBRARY} ${QT_QTTEST_LIBRARY} kimap)
+install(TARGETS kimaptest ${INSTALL_TARGETS_DEFAULT_ARGS})
+
+########### install files ###############
+
+install(FILES
+ fakeserver.h
+ mockjob.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/kimaptest COMPONENT Devel)
+
+endif()
+
diff --git a/kimap/tests/kimaptest/fakeserver.cpp b/kimap/tests/kimaptest/fakeserver.cpp
new file mode 100644
index 0000000..816f80f
--- /dev/null
+++ b/kimap/tests/kimaptest/fakeserver.cpp
@@ -0,0 +1,223 @@
+/*
+ Copyright (C) 2008 Omat Holding B.V. <info@omat.nl>
+
+ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+// Own
+#include "fakeserver.h"
+
+// Qt
+#include <QDebug>
+#include <QTcpServer>
+
+// KDE
+#include <KDebug>
+#include <qtest_kde.h>
+
+#include "kimap/imapstreamparser.h"
+
+QByteArray FakeServer::preauth()
+{
+ return "S: * PREAUTH localhost Test Library server ready";
+}
+
+QByteArray FakeServer::greeting()
+{
+ return "S: * OK localhost Test Library server ready";
+}
+
+FakeServer::FakeServer( QObject* parent ) : QThread( parent )
+{
+ moveToThread(this);
+}
+
+
+FakeServer::~FakeServer()
+{
+ quit();
+ wait();
+}
+
+void FakeServer::startAndWait()
+{
+ start();
+ // this will block until the event queue starts
+ QMetaObject::invokeMethod( this, "started", Qt::BlockingQueuedConnection );
+}
+
+void FakeServer::dataAvailable()
+{
+ QMutexLocker locker(&m_mutex);
+
+ QTcpSocket *socket = qobject_cast<QTcpSocket*>( sender() );
+ Q_ASSERT( socket!=0 );
+
+ int scenarioNumber = m_clientSockets.indexOf( socket );
+
+ QVERIFY( !m_scenarios[scenarioNumber].isEmpty() );
+
+ readClientPart( scenarioNumber );
+ writeServerPart( scenarioNumber );
+}
+
+void FakeServer::newConnection()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_clientSockets << m_tcpServer->nextPendingConnection();
+ connect(m_clientSockets.last(), SIGNAL(readyRead()), this, SLOT(dataAvailable()));
+ m_clientParsers << new KIMAP::ImapStreamParser( m_clientSockets.last(), true );
+
+ QVERIFY( m_clientSockets.size() <= m_scenarios.size() );
+
+ writeServerPart( m_clientSockets.size() - 1 );
+}
+
+void FakeServer::run()
+{
+ m_tcpServer = new QTcpServer();
+ if ( !m_tcpServer->listen( QHostAddress( QHostAddress::LocalHost ), 5989 ) ) {
+ kFatal() << "Unable to start the server";
+ }
+
+ connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
+
+ exec();
+
+ qDeleteAll( m_clientParsers );
+ qDeleteAll( m_clientSockets );
+
+ delete m_tcpServer;
+}
+
+void FakeServer::started()
+{
+ // do nothing: this is a dummy slot used by startAndWait()
+}
+
+void FakeServer::setScenario( const QList<QByteArray> &scenario )
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_scenarios.clear();
+ m_scenarios << scenario;
+}
+
+void FakeServer::addScenario( const QList<QByteArray> &scenario )
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_scenarios << scenario;
+}
+
+void FakeServer::addScenarioFromFile( const QString &fileName )
+{
+ QFile file( fileName );
+ file.open( QFile::ReadOnly );
+
+ QList<QByteArray> scenario;
+
+ // When loading from files we never have the authentication phase
+ // force jumping directly to authenticated state.
+ scenario << preauth();
+
+ while ( !file.atEnd() ) {
+ scenario << file.readLine().trimmed();
+ }
+
+ file.close();
+
+ addScenario( scenario );
+}
+
+bool FakeServer::isScenarioDone( int scenarioNumber ) const
+{
+ QMutexLocker locker(&m_mutex);
+
+ if ( scenarioNumber < m_scenarios.size() ) {
+ return m_scenarios[scenarioNumber].isEmpty();
+ } else {
+ return true; // Non existent hence empty, right?
+ }
+}
+
+bool FakeServer::isAllScenarioDone() const
+{
+ QMutexLocker locker( &m_mutex );
+
+ foreach ( const QList<QByteArray> &scenario, m_scenarios ) {
+ if ( !scenario.isEmpty() ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void FakeServer::writeServerPart( int scenarioNumber )
+{
+ QList<QByteArray> scenario = m_scenarios[scenarioNumber];
+ QTcpSocket *clientSocket = m_clientSockets[scenarioNumber];
+
+ while ( !scenario.isEmpty()
+ && ( scenario.first().startsWith( "S: " ) || scenario.first().startsWith( "W: " ) ) ) {
+ QByteArray rule = scenario.takeFirst();
+
+ if ( rule.startsWith( "S: " ) ) {
+ QByteArray payload = rule.mid( 3 );
+ clientSocket->write( payload + "\r\n" );
+ } else {
+ int timeout = rule.mid( 3 ).toInt();
+ QTest::qWait( timeout );
+ }
+ }
+
+ if ( !scenario.isEmpty()
+ && scenario.first().startsWith( "X" ) ) {
+ scenario.takeFirst();
+ clientSocket->close();
+ }
+
+ if ( !scenario.isEmpty() ) {
+ QVERIFY( scenario.first().startsWith( "C: " ) );
+ }
+
+ m_scenarios[scenarioNumber] = scenario;
+}
+
+void FakeServer::readClientPart( int scenarioNumber )
+{
+ QList<QByteArray> scenario = m_scenarios[scenarioNumber];
+ KIMAP::ImapStreamParser *clientParser = m_clientParsers[scenarioNumber];
+
+ while ( !scenario.isEmpty()
+ && scenario.first().startsWith( "C: " ) ) {
+ QByteArray received = "C: "+clientParser->readUntilCommandEnd().trimmed();
+ QByteArray expected = scenario.takeFirst();
+ QCOMPARE( QString::fromUtf8( received ), QString::fromUtf8( expected ) );
+ QCOMPARE( received, expected );
+ }
+
+ if ( !scenario.isEmpty() ) {
+ QVERIFY( scenario.first().startsWith( "S: " ) );
+ }
+
+ m_scenarios[scenarioNumber] = scenario;
+}
+
diff --git a/kimap/tests/kimaptest/fakeserver.h b/kimap/tests/kimaptest/fakeserver.h
new file mode 100644
index 0000000..22b970c
--- /dev/null
+++ b/kimap/tests/kimaptest/fakeserver.h
@@ -0,0 +1,222 @@
+/*
+ Copyright (C) 2008 Omat Holding B.V. <info@omat.nl>
+
+ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef FAKESERVER_H
+#define FAKESERVER_H
+
+#include <QStringList>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QThread>
+#include <QMutex>
+
+namespace KIMAP
+{
+ class ImapStreamParser;
+}
+
+Q_DECLARE_METATYPE( QList<QByteArray> )
+
+/**
+ * Pretends to be an IMAP server for the purposes of unit tests.
+ *
+ * FakeServer does not really understand the IMAP protocol. Instead,
+ * you give it a script, or scenario, that lists how an IMAP session
+ * exchange should go. When it receives the client parts of the
+ * scenario, it will respond with the following server parts.
+ *
+ * The server can be furnished with several scenarios. The first
+ * scenario will be played out to the first client that connects, the
+ * second scenario to the second client connection and so on.
+ *
+ * The fake server runs as a separate thread in the same process it
+ * is started from, and listens for connections on port 5989 on the
+ * local machine.
+ *
+ * Scenarios are in the form of protocol messages, with a tag at the
+ * start to indicate whether it is message that will be sent by the
+ * client ("C:") or a response that should be sent by the server
+ * ("S:"). For example:
+ * @code
+ * C: A000001 LIST "" *
+ * S: * LIST ( \HasChildren ) / INBOX
+ * S: * LIST ( \HasNoChildren ) / INBOX/&AOQ- &APY- &APw- @ &IKw-
+ * S: * LIST ( \HasChildren ) / INBOX/lost+found
+ * S: * LIST ( \HasNoChildren ) / "INBOX/lost+found/Calendar Public-20080128"
+ * S: A000001 OK LIST completed
+ * @endcode
+ *
+ * A line starting with X indicates that the connection should be
+ * closed by the server. This should be the last line in the
+ * scenario. For example, the following simulates the server closing
+ * the connection after receiving too many bad commands:
+ * @code
+ * C: A000001 madhatter
+ * S: A000001 BAD Command madhatter
+ * X
+ * @endcode
+ *
+ * FakeServer::preauth() and FakeServer::greeting() provide standard
+ * PREAUTH and OK responses, respectively, that can be used (unmodified)
+ * as the first line of a scenario.
+ *
+ * A typical usage is something like
+ * @code
+ * QList<QByteArray> scenario;
+ * scenario << FakeServer::preauth()
+ * << "C: A000001 CAPABILITY"
+ * << "S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI"
+ * << "S: A000001 OK CAPABILITY completed";
+ *
+ * FakeServer fakeServer;
+ * fakeServer.setScenario( scenario );
+ * fakeServer.startAndWait();
+ *
+ * KIMAP::Session session( "127.0.0.1", 5989 );
+ * KIMAP::CapabilitiesJob *job = new KIMAP::CapabilitiesJob(&session);
+ * QVERIFY( job->exec() );
+ * // check the returned capabilities
+ *
+ * fakeServer.quit();
+ * @endcode
+ */
+class FakeServer : public QThread
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Get the default PREAUTH response
+ *
+ * This is the initial PREAUTH message that the server
+ * sends at the start of a session to indicate that the
+ * user is already authenticated by some other mechanism.
+ *
+ * Can be used as the first line in a scenario where
+ * you want to skip the LOGIN stage of the protocol.
+ */
+ static QByteArray preauth();
+ /**
+ * Get the default greeting
+ *
+ * This is the initial OK message that the server sends at the
+ * start of a session to indicate that a LOGIN is required.
+ *
+ * Can be used as the first line in a scenario where
+ * you want to use the LOGIN command.
+ */
+ static QByteArray greeting();
+
+ FakeServer( QObject* parent = 0 );
+ ~FakeServer();
+
+ /**
+ * Starts the server and waits for it to be ready
+ *
+ * You should use this instead of start() to avoid race conditions.
+ */
+ void startAndWait();
+
+ /**
+ * Starts the fake IMAP server
+ *
+ * You should not call this directly. Use start() instead.
+ *
+ * @reimp
+ */
+ virtual void run();
+
+ /**
+ * Removes any previously-added scenarios, and adds a new one
+ *
+ * After this, there will only be one scenario, and so the fake
+ * server will only be able to service a single request. More
+ * scenarios can be added with addScenario, though.
+ *
+ * @see addScenario()\n
+ * addScenarioFromFile()
+ */
+ void setScenario( const QList<QByteArray> &scenario );
+
+ /**
+ * Adds a new scenario
+ *
+ * Note that scenarios will be used in the order that clients
+ * connect. If this is the 5th scenario that has been added
+ * (bearing in mind that setScenario() resets the scenario
+ * count), it will be used to service the 5th client that
+ * connects.
+ *
+ * @see addScenarioFromFile()
+ *
+ * @param scenario the scenario as a list of messages
+ */
+ void addScenario( const QList<QByteArray> &scenario );
+ /**
+ * Adds a new scenario from a local file
+ *
+ * Note that scenarios will be used in the order that clients
+ * connect. If this is the 5th scenario that has been added
+ * (bearing in mind that setScenario() resets the scenario
+ * count), it will be used to service the 5th client that
+ * connects.
+ *
+ * @see addScenario()
+ *
+ * @param fileName the name of the file that contains the
+ * scenario; it will be split at line
+ * boundaries, and excess whitespace will
+ * be trimmed from the start and end of lines
+ */
+ void addScenarioFromFile( const QString &fileName );
+
+ /**
+ * Checks whether a particular scenario has completed
+ *
+ * @param scenarioNumber the number of the scenario to check,
+ * in order of addition/client connection
+ */
+ bool isScenarioDone( int scenarioNumber ) const;
+ /**
+ * Whether all the scenarios that were added to the fake
+ * server have been completed.
+ */
+ bool isAllScenarioDone() const;
+
+private Q_SLOTS:
+ void newConnection();
+ void dataAvailable();
+ void started();
+
+private:
+ void writeServerPart( int scenarioNumber );
+ void readClientPart( int scenarioNumber );
+
+ QList< QList<QByteArray> > m_scenarios;
+ QTcpServer *m_tcpServer;
+ mutable QMutex m_mutex;
+ QList<QTcpSocket*> m_clientSockets;
+ QList<KIMAP::ImapStreamParser*> m_clientParsers;
+};
+
+#endif
+
diff --git a/kimap/tests/kimaptest/mockjob.cpp b/kimap/tests/kimaptest/mockjob.cpp
new file mode 100644
index 0000000..e41257f
--- /dev/null
+++ b/kimap/tests/kimaptest/mockjob.cpp
@@ -0,0 +1,79 @@
+/*
+ This file is part of the KDE project
+ Copyright (C) 2008 Kevin Ottens <ervin@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "mockjob.h"
+
+#include "../../job_p.h"
+#include "../../session.h"
+#include "../../session_p.h"
+
+#include <QtCore/QTimer>
+
+class MockJobPrivate : public KIMAP::JobPrivate
+{
+public:
+ MockJobPrivate( KIMAP::Session *session, const QString& name ) : KIMAP::JobPrivate(session, name) { }
+ ~MockJobPrivate() { }
+
+ QByteArray command;
+};
+
+MockJob::MockJob(KIMAP::Session *session)
+ : KIMAP::Job( *new MockJobPrivate(session, i18n("Mock")) )
+{
+}
+
+void MockJob::doStart()
+{
+ Q_D(MockJob);
+ if ( isNull() ) {
+ QTimer::singleShot(10, this, SLOT(done()));
+ } else {
+ d->sessionInternal()->setSocketTimeout( 10 );
+ d->tags << d->sessionInternal()->sendCommand( d->command );
+ }
+}
+
+void MockJob::done()
+{
+ emitResult();
+}
+
+void MockJob::setCommand(const QByteArray &command)
+{
+ Q_D(MockJob);
+ d->command = command;
+}
+
+QByteArray MockJob::command() const
+{
+ Q_D(const MockJob);
+ return d->command;
+}
+
+bool MockJob::isNull() const
+{
+ Q_D(const MockJob);
+ return d->command.isEmpty();
+}
+
diff --git a/kimap/tests/kimaptest/mockjob.h b/kimap/tests/kimaptest/mockjob.h
new file mode 100644
index 0000000..c5eb4de
--- /dev/null
+++ b/kimap/tests/kimaptest/mockjob.h
@@ -0,0 +1,75 @@
+/*
+ This file is part of the KDE project
+ Copyright (C) 2008 Kevin Ottens <ervin@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MOCKJOB_H
+#define MOCKJOB_H
+
+#include <kimap/job.h>
+
+class MockJobPrivate;
+
+/**
+ * Provides an easy way to send an arbitrary IMAP client command.
+ */
+class MockJob : public KIMAP::Job
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(MockJob)
+
+ public:
+ MockJob(KIMAP::Session *session);
+
+ /**
+ * Sets the command to execute.
+ *
+ * This should not include the command tag.
+ */
+ void setCommand(const QByteArray &command);
+ /**
+ * The command that will be sent.
+ */
+ QByteArray command() const;
+ /**
+ * Whether the command is empty.
+ *
+ * Equivalent to command().isEmpty().
+ *
+ * @return @c true if no command is set, @c false otherwise
+ */
+ bool isNull() const;
+
+ /**
+ * Starts the job.
+ *
+ * Do not call this directly. Use start() instead.
+ *
+ * @reimp
+ */
+ virtual void doStart();
+
+ private slots:
+ void done();
+};
+
+#endif
+
diff --git a/kimap/tests/listjobtest.cpp b/kimap/tests/listjobtest.cpp
new file mode 100644
index 0000000..81fbfc4
--- /dev/null
+++ b/kimap/tests/listjobtest.cpp
@@ -0,0 +1,237 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/listjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+Q_DECLARE_METATYPE(QList<KIMAP::MailBoxDescriptor>)
+Q_DECLARE_METATYPE(QList< QList<QByteArray> >)
+
+class ListJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testList_data() {
+ QTest::addColumn<bool>( "unsubscribed" );
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+ QTest::addColumn<QList<KIMAP::MailBoxDescriptor> >( "listresult" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 LIST \"\" *"
+ << "S: * LIST ( \\HasChildren ) / INBOX"
+ << "S: * LIST ( \\HasNoChildren ) / INBOX/&AOQ- &APY- &APw- @ &IKw-"
+ << "S: * LIST ( \\HasChildren ) / INBOX/lost+found"
+ << "S: * LIST ( \\HasNoChildren ) / \"INBOX/lost+found/Calendar Public-20080128\""
+ << "S: A000001 OK LIST completed";
+ KIMAP::MailBoxDescriptor descriptor;
+ QList<KIMAP::MailBoxDescriptor> listresult;
+
+ descriptor.separator = '/';
+ descriptor.name = "INBOX";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = QString::fromUtf8( "INBOX/ä ö ü @ €" );
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found/Calendar Public-20080128";
+ listresult << descriptor;
+
+ QTest::newRow( "normal" ) << true << scenario << listresult;
+
+ scenario.clear();;
+ scenario << FakeServer::preauth()
+ << "C: A000001 LIST \"\" *"
+ << "S: * LIST ( \\HasChildren ) / Inbox"
+ << "S: * LIST ( \\HasNoChildren ) / Inbox/&AOQ- &APY- &APw- @ &IKw-"
+ << "S: * LIST ( \\HasChildren ) / Inbox/lost+found"
+ << "S: * LIST ( \\HasNoChildren ) / \"Inbox/lost+found/Calendar Public-20080128\""
+ << "S: A000001 OK LIST completed";
+ listresult.clear();
+
+ descriptor.separator = '/';
+ descriptor.name = "INBOX";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = QString::fromUtf8( "INBOX/ä ö ü @ €" );
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found/Calendar Public-20080128";
+ listresult << descriptor;
+
+ QTest::newRow( "lowercase Inbox" ) << true << scenario << listresult;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 LSUB \"\" *"
+ << "S: * LSUB ( \\HasChildren ) / INBOX"
+ << "S: * LSUB ( ) / INBOX/Calendar/3196"
+ << "S: * LSUB ( \\HasChildren ) / INBOX/Calendar/ff"
+ << "S: * LSUB ( ) / INBOX/Calendar/ff/hgh"
+ << "S: * LSUB ( ) / user/test2/Calendar"
+ << "S: A000001 OK LSUB completed";
+ listresult.clear();
+
+ descriptor.separator = '/';
+ descriptor.name = "INBOX";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/Calendar/3196";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/Calendar/ff";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/Calendar/ff/hgh";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "user/test2/Calendar";
+ listresult << descriptor;
+
+ QTest::newRow( "subscribed" ) << false << scenario << listresult;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 LSUB \"\" *"
+ << "S: * LSUB ( \\HasChildren ) / Inbox"
+ << "S: * LSUB ( ) / Inbox/Calendar/3196"
+ << "S: * LSUB ( \\HasChildren ) / Inbox/Calendar/ff"
+ << "S: * LSUB ( ) / Inbox/Calendar/ff/hgh"
+ << "S: * LSUB ( ) / user/test2/Calendar"
+ << "S: A000001 OK LSUB completed";
+ listresult.clear();
+
+ descriptor.separator = '/';
+ descriptor.name = "INBOX";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/Calendar/3196";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/Calendar/ff";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/Calendar/ff/hgh";
+ listresult << descriptor;
+ descriptor.separator = '/';
+ descriptor.name = "user/test2/Calendar";
+ listresult << descriptor;
+
+ QTest::newRow( "subscribed, lowercase Inbox" ) << false << scenario << listresult;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 LIST \"\" *"
+ << "S: * LIST ( \\HasNoChildren ) / INBOX/lost+found/Calendar Public-20080128"
+ << "S: A000001 OK LIST completed";
+ listresult.clear();
+ descriptor.separator = '/';
+ descriptor.name = "INBOX/lost+found/Calendar Public-20080128";
+ listresult << descriptor;
+
+ QTest::newRow( "unquoted-space" ) << true << scenario << listresult;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 LIST \"\" *"
+ << "S: * LIST ( \\NoInferiors ) ( ) INBOX"
+ << "S: A000001 OK LIST completed";
+ listresult.clear();
+ descriptor.separator = '/';
+ descriptor.name = "INBOX";
+ listresult << descriptor;
+
+ QTest::newRow( "separator is empty list" ) << true << scenario << listresult;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 LIST \"\" *"
+ << "S: A000001 BAD command unknown or arguments invalid";
+ listresult.clear();
+ QTest::newRow( "bad" ) << true << scenario << listresult;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 LIST \"\" *"
+ << "S: A000001 NO list failure";
+ QTest::newRow( "no" ) << true << scenario << listresult;
+}
+
+void testList()
+{
+ QFETCH( bool, unsubscribed);
+ QFETCH( QList<QByteArray>, scenario );
+ QFETCH( QList<KIMAP::MailBoxDescriptor>, listresult );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::ListJob *job = new KIMAP::ListJob(&session);
+ job->setIncludeUnsubscribed(unsubscribed);
+
+ QSignalSpy spy( job,
+ SIGNAL(mailBoxesReceived(const QList<KIMAP::MailBoxDescriptor>&,
+ const QList< QList<QByteArray> >&)) );
+
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO response", Continue);
+ QVERIFY(result);
+ if (result) {
+ QVERIFY( spy.count()>0 );
+ QList<KIMAP::MailBoxDescriptor> mailBoxes;
+
+ for ( int i=0; i<spy.count(); i++ ) {
+ mailBoxes+= spy.at( i ).at( 0 ).value< QList<KIMAP::MailBoxDescriptor> >();
+ }
+
+ //kDebug() << mailBoxes.first().name;
+ //kDebug() << listresult.first().name;
+ QCOMPARE(mailBoxes, listresult);
+ }
+// QCOMPARE(job->mailBox(), mailbox);
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( ListJobTest )
+
+#include "listjobtest.moc"
diff --git a/kimap/tests/loginjobtest.cpp b/kimap/tests/loginjobtest.cpp
new file mode 100644
index 0000000..f937f5b
--- /dev/null
+++ b/kimap/tests/loginjobtest.cpp
@@ -0,0 +1,154 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/loginjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class LoginJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void shouldHandleLogin_data()
+{
+ QTest::addColumn<QString>( "user" );
+ QTest::addColumn<QString>( "password" );
+ QTest::addColumn< QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user\" \"password\""
+ << "S: A000001 OK User logged in";
+
+ QTest::newRow( "success" ) << "user" << "password" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user_bad\" \"password\""
+ << "S: A000001 NO Login failed: authentication failure";
+
+ QTest::newRow( "wrong login" ) << "user_bad" << "password" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user\" \"aa\\\"bb\\\\cc[dd ee\""
+ << "S: A000001 OK User logged in";
+
+ QTest::newRow( "special chars" ) << "user" << "aa\"bb\\cc[dd ee" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth();
+
+ QTest::newRow( "already authenticated" ) << "user" << "password" << scenario;
+}
+
+void shouldHandleLogin()
+{
+ QFETCH( QString, user );
+ QFETCH( QString, password );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session *session = new KIMAP::Session("127.0.0.1", 5989);
+
+ KIMAP::LoginJob *login = new KIMAP::LoginJob(session);
+ login->setUserName(user);
+ login->setPassword(password);
+ bool result = login->exec();
+
+ QEXPECT_FAIL("wrong login","Login with bad user name", Continue);
+ QEXPECT_FAIL("already authenticated","Trying to log on an already authenticated session", Continue);
+ QVERIFY(result);
+
+ fakeServer.quit();
+ delete session;
+}
+
+void shouldSaveServerGreeting_data()
+{
+ QTest::addColumn<QString>( "greeting" );
+ QTest::addColumn< QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user\" \"password\""
+ << "S: A000001 OK Welcome John Smith";
+
+ QTest::newRow( "greeting" ) << "Welcome John Smith" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user\" \"password\""
+ << "S: A000001 OK Welcome John Smith (last login: Feb 21, 2010)";
+
+ QTest::newRow( "greeting with parenthesis" ) << "Welcome John Smith (last login: Feb 21, 2010)" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user\" \"password\""
+ << "S: A000001 OK";
+
+ QTest::newRow( "no greeting" ) << "" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::greeting()
+ << "C: A000001 LOGIN \"user\" \"password\""
+ << "S: A000001 NO Login failed: authentication failure";
+
+ QTest::newRow( "login failed" ) << "" << scenario;
+}
+
+void shouldSaveServerGreeting()
+{
+ QFETCH( QString, greeting );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session *session = new KIMAP::Session("127.0.0.1", 5989);
+
+ KIMAP::LoginJob *login = new KIMAP::LoginJob(session);
+ login->setUserName("user");
+ login->setPassword("password");
+ login->exec();
+
+ QCOMPARE(login->serverGreeting(), greeting);
+
+ fakeServer.quit();
+ delete session;
+}
+};
+
+QTEST_KDEMAIN_CORE( LoginJobTest )
+
+#include "loginjobtest.moc"
diff --git a/kimap/tests/logoutjobtest.cpp b/kimap/tests/logoutjobtest.cpp
new file mode 100644
index 0000000..9028265
--- /dev/null
+++ b/kimap/tests/logoutjobtest.cpp
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/logoutjob.h"
+#include "kimap/loginjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class LogoutJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testLogout()
+{
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::preauth()
+ << "C: A000001 LOGOUT"
+ << "S: A000001 OK LOGOUT completed"
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session *session = new KIMAP::Session("127.0.0.1", 5989);
+
+ KIMAP::LogoutJob *logout = new KIMAP::LogoutJob(session);
+ QVERIFY(logout->exec());
+
+ fakeServer.quit();
+ delete session;
+}
+
+void testLogoutUntagged()
+{
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::preauth()
+ << "C: A000001 LOGOUT"
+ << "S: * some untagged response"
+ << "S: A000001 OK LOGOUT completed"
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session *session = new KIMAP::Session("127.0.0.1", 5989);
+
+ KIMAP::LogoutJob *logout = new KIMAP::LogoutJob(session);
+ QVERIFY(logout->exec());
+
+ fakeServer.quit();
+ delete session;
+}
+
+};
+
+QTEST_KDEMAIN_CORE( LogoutJobTest )
+
+#include "logoutjobtest.moc"
diff --git a/kimap/tests/quotarootjobtest.cpp b/kimap/tests/quotarootjobtest.cpp
new file mode 100644
index 0000000..5cf5a4f
--- /dev/null
+++ b/kimap/tests/quotarootjobtest.cpp
@@ -0,0 +1,187 @@
+/*
+ Copyright (C) 2011 Andras Mantia <amantia@kde.org>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/getquotarootjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+Q_DECLARE_METATYPE( QList<qint64> );
+
+class QuotaRootJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testGetQuotaRoot_data() {
+ QTest::addColumn<QString>("mailbox");
+ QTest::addColumn<QList<QByteArray> >( "roots" );
+ QTest::addColumn<QList<QByteArray> >( "resources" );
+ QTest::addColumn<QList<qint64> >( "usages" );
+ QTest::addColumn<QList<qint64> >( "limits" );
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> roots;
+ QList<QByteArray> resources;
+ QList<qint64> usages;
+ QList<qint64> limits;
+ QList<QByteArray> scenario;
+ roots << "";
+ resources << "STORAGE";
+ limits << 512;
+ usages << 10;
+ scenario << FakeServer::preauth()
+ << "C: A000001 GETQUOTAROOT \"INBOX\""
+ << "S: * QUOTAROOT INBOX \"\" "
+ << "S: * QUOTA \"\" (STORAGE 10 512)"
+ << "S: A000001 OK GETQUOTA completed";
+ QTest::newRow( "one root, one resource" ) << "INBOX" << roots << resources << usages << limits << scenario;
+
+ roots.clear();
+ resources.clear();
+ usages.clear();
+ limits.clear();
+ scenario.clear();
+ roots << "";
+ resources << "STORAGE" << "MESSAGE";
+ usages << 10 << 8221;
+ limits << 512 << 20000;
+ scenario << FakeServer::preauth()
+ << "C: A000001 GETQUOTAROOT \"INBOX\""
+ << "S: * QUOTAROOT INBOX \"\" "
+ << "S: * QUOTA \"\" (STORAGE 10 512)"
+ << "S: * QUOTA \"\" ( MESSAGE 8221 20000 ) "
+ << "S: A000001 OK GETQUOTA completed";
+ QTest::newRow( "one root, multiple resource" ) << "INBOX" << roots << resources << usages << limits << scenario;
+
+ roots.clear();
+ resources.clear();
+ usages.clear();
+ limits.clear();
+ scenario.clear();
+ roots << "root1" << "root2";
+ resources << "STORAGE" << "MESSAGE";
+ usages << 10 << 8221 << 30 << 100;
+ limits << 512 << 20000 << 5124 << 120000;
+ scenario << FakeServer::preauth()
+ << "C: A000001 GETQUOTAROOT \"INBOX\""
+ << "S: * QUOTAROOT INBOX \"root1\" root2 "
+ << "S: * QUOTA \"root1\" (STORAGE 10 512)"
+ << "S: * QUOTA \"root1\" ( MESSAGE 8221 20000 ) "
+ << "S: * QUOTA \"root2\" ( MESSAGE 100 120000 ) "
+ << "S: * QUOTA \"root2\" (STORAGE 30 5124)"
+ << "S: A000001 OK GETQUOTA completed";
+ QTest::newRow( "multiple roots, multiple resource" ) << "INBOX" << roots << resources << usages << limits << scenario;
+
+ roots.clear();
+ resources.clear();
+ usages.clear();
+ limits.clear();
+ scenario.clear();
+ roots << "";
+ resources << "STORAGE" << "MESSAGE";
+ usages << 10 << 8221;
+ limits << 512 << 20000;
+ scenario << FakeServer::preauth()
+ << "C: A000001 GETQUOTAROOT \"INBOX\""
+ << "S: * QUOTAROOT INBOX"
+ << "S: * QUOTA (STORAGE 10 512)"
+ << "S: * QUOTA ( MESSAGE 8221 20000 ) "
+ << "S: A000001 OK GETQUOTA completed";
+ QTest::newRow( "no rootname, multiple resource" ) << "INBOX" << roots << resources << usages << limits << scenario;
+
+ roots.clear();
+ resources.clear();
+ usages.clear();
+ limits.clear();
+ scenario.clear();
+ roots << "";
+ resources << "STORAGE";
+ limits << 512;
+ usages << 10;
+ scenario << FakeServer::preauth()
+ << "C: A000001 GETQUOTAROOT \"INBOX\""
+ << "S: * QUOTAROOT INBOX \"\" "
+ << "S: * QUOTA (STORAGE 10 512)"
+ << "S: A000001 OK GETQUOTA completed";
+ QTest::newRow( "no rootname in QUOTA, one resource" ) << "INBOX" << roots << resources << usages << limits << scenario;
+
+ roots.clear();
+ resources.clear();
+ usages.clear();
+ limits.clear();
+ scenario.clear();
+ roots << "";
+ resources << "STORAGE";
+ limits << 512;
+ usages << 10;
+ scenario << FakeServer::preauth()
+ << "C: A000001 GETQUOTAROOT \"INBOX\""
+ << "S: * QUOTAROOT INBOX \"root1\" "
+ << "S: * QUOTA \"root2\" (STORAGE 10 512)"
+ << "S: A000001 OK GETQUOTA completed";
+ QTest::newRow( "rootname missmatch" ) << "INBOX" << roots << resources << usages << limits << scenario;
+}
+
+void testGetQuotaRoot()
+{
+ QFETCH( QString, mailbox );
+ QFETCH( QList<QByteArray>, roots);
+ QFETCH( QList<QByteArray>, resources);
+ QFETCH( QList<qint64>, usages);
+ QFETCH( QList<qint64>, limits);
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::GetQuotaRootJob *job = new KIMAP::GetQuotaRootJob(&session);
+ job->setMailBox(mailbox);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO response", Continue);
+ QVERIFY(result);
+ QEXPECT_FAIL("rootname missmatch" , "Expected failure on rootname missmatch in QUOTAROOT and QUOTA response", Abort);
+ QCOMPARE(job->roots(), roots);
+ for( int rootIdx = 0; rootIdx < roots.size() ;rootIdx++ ) {
+ const QByteArray& root = roots[rootIdx];
+ for( int i = 0; i < resources.size(); i++ ) {
+ int idx = i + rootIdx * roots.size();
+ QByteArray resource = resources[i];
+ QCOMPARE(job->limit(root, resource), limits[idx] );
+ QCOMPARE(job->usage(root, resource), usages[idx] );
+ }
+ }
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( QuotaRootJobTest )
+
+#include "quotarootjobtest.moc"
diff --git a/kimap/tests/renamejobtest.cpp b/kimap/tests/renamejobtest.cpp
new file mode 100644
index 0000000..a139a24
--- /dev/null
+++ b/kimap/tests/renamejobtest.cpp
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/renamejob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class RenameJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testRename_data() {
+ QTest::addColumn<QString>( "mailbox" );
+ QTest::addColumn<QString>( "newname" );
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 RENAME \"INBOX\" \"oldmail\""
+ << "S: A000001 OK RENAME completed";
+ QTest::newRow( "good" ) << "INBOX" << "oldmail" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 RENAME \"INBOX-FAIL-BAD\" \"oldmail-bad\""
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << "INBOX-FAIL-BAD" << "oldmail-bad" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 RENAME \"INBOX-FAIL-NO\" \"oldmail-no\""
+ << "S: A000001 NO rename failure";
+ QTest::newRow( "no" ) << "INBOX-FAIL-NO" << "oldmail-no" << scenario;
+}
+
+void testRename()
+{
+ QFETCH( QString, mailbox );
+ QFETCH( QString, newname );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::RenameJob *job = new KIMAP::RenameJob(&session);
+ job->setSourceMailBox(mailbox);
+ job->setDestinationMailBox(newname);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD response", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO response", Continue);
+ QVERIFY(result);
+ QCOMPARE(job->sourceMailBox(), mailbox);
+ QCOMPARE(job->destinationMailBox(), newname);
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( RenameJobTest )
+
+#include "renamejobtest.moc"
diff --git a/kimap/tests/selectjobtest.cpp b/kimap/tests/selectjobtest.cpp
new file mode 100644
index 0000000..9ee2a80
--- /dev/null
+++ b/kimap/tests/selectjobtest.cpp
@@ -0,0 +1,147 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/loginjob.h"
+#include "kimap/session.h"
+#include "kimap/selectjob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class SelectJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testSingleSelect_data() {
+ QTest::addColumn<QList<QByteArray> >( "scenario" );
+ QTest::addColumn<QList<QByteArray> >( "flags" );
+ QTest::addColumn<QList<QByteArray> >( "permanentflags" );
+ QTest::addColumn<int>( "messagecount" );
+ QTest::addColumn<int>( "recentcount" );
+ QTest::addColumn<int>( "firstUnseenIndex" );
+ QTest::addColumn<qint64>( "uidValidity" );
+ QTest::addColumn<qint64>( "nextUid" );
+
+ QList<QByteArray> scenario;
+ QList<QByteArray> flags;
+ QList<QByteArray> permanentflags;
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX\""
+ << "S: * 172 EXISTS"
+ << "S: * 1 RECENT"
+ << "S: * OK [UNSEEN 12] Message 12 is first unseen"
+ << "S: * OK [UIDVALIDITY 3857529045] UIDs valid"
+ << "S: * OK [UIDNEXT 4392] Predicted next UID"
+ << "S: * FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)"
+ << "S: * OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)] Limited"
+ << "S: A000001 OK [READ-WRITE] SELECT completed";
+
+ flags << "\\Answered" << "\\Flagged" << "\\Deleted" << "\\Seen" << "\\Draft";
+ permanentflags << "\\Deleted" << "\\Seen" << "\\*";
+ QTest::newRow( "good" ) << scenario << flags << permanentflags << 172 << 1 << 12 << (qint64)3857529045 << (qint64)4392;
+
+ scenario.clear();
+ flags.clear();
+ permanentflags.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX\""
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << scenario << flags << permanentflags << 0 << 0 << 0 << (qint64)0 << (qint64)0;
+
+ scenario.clear();
+ flags.clear();
+ permanentflags.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX\""
+ << "S: A000001 NO select failure";
+ QTest::newRow( "no" ) << scenario << flags << permanentflags << 0 << 0 << 0 << (qint64)0 << (qint64)0;
+}
+
+void testSingleSelect()
+{
+ QFETCH( QList<QByteArray>, scenario );
+ QFETCH( QList<QByteArray>, flags );
+ QFETCH( QList<QByteArray>, permanentflags );
+ QFETCH( int, messagecount);
+ QFETCH( int, recentcount);
+ QFETCH( int, firstUnseenIndex);
+ QFETCH( qint64, uidValidity);
+ QFETCH( qint64, nextUid);
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::SelectJob *job = new KIMAP::SelectJob(&session);
+ job->setMailBox("INBOX");
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD scenario", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO scenario", Continue);
+ QVERIFY(result);
+ if (result) {
+ QCOMPARE(job->flags(), flags);
+ QCOMPARE(job->permanentFlags(), permanentflags);
+ QCOMPARE(job->messageCount(), messagecount);
+ QCOMPARE(job->recentCount(), recentcount);
+ QCOMPARE(job->firstUnseenIndex(), firstUnseenIndex);
+ QCOMPARE(job->uidValidity(), uidValidity);
+ QCOMPARE(job->nextUid(), nextUid);
+ }
+
+ fakeServer.quit();
+}
+
+void testSeveralSelect()
+{
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::preauth()
+ << "C: A000001 SELECT \"INBOX\""
+ << "S: A000001 OK [READ-WRITE] SELECT completed"
+ << "C: A000002 SELECT \"INBOX/Foo\""
+ << "S: A000002 OK [READ-WRITE] SELECT completed"
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::SelectJob *job = new KIMAP::SelectJob(&session);
+ job->setMailBox("INBOX");
+ QVERIFY(job->exec());
+
+ job = new KIMAP::SelectJob(&session);
+ job->setMailBox("INBOX/Foo");
+ QVERIFY(job->exec());
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( SelectJobTest )
+
+#include "selectjobtest.moc"
diff --git a/kimap/tests/storejobtest.cpp b/kimap/tests/storejobtest.cpp
new file mode 100644
index 0000000..fca7691
--- /dev/null
+++ b/kimap/tests/storejobtest.cpp
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/storejob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class StoreJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testStore_data() {
+ QTest::addColumn<bool>( "uidBased" );
+ QTest::addColumn<qint64>( "id" );
+ QTest::addColumn<qint64>( "uid" );
+ QTest::addColumn< QList<QByteArray> >( "flags" );
+ QTest::addColumn< QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 STORE 3 FLAGS (\\Seen \\Foo)"
+ << "S: * 3 FETCH (FLAGS (\\Seen \\Foo) UID 1096)"
+ << "S: A000001 OK STORE completed";
+
+ QTest::newRow( "not uid based" ) << false << qint64(3) << qint64(1096)
+ << ( QList<QByteArray>() << "\\Seen" << "\\Foo" )
+ << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 UID STORE 1096 FLAGS (\\Seen \\Foo)"
+ << "S: * 3 FETCH (FLAGS (\\Seen \\Foo) UID 1096)"
+ << "S: A000001 OK STORE completed";
+
+ QTest::newRow( "uid based" ) << true << qint64(3) << qint64(1096)
+ << ( QList<QByteArray>() << "\\Seen" << "\\Foo" )
+ << scenario;
+}
+
+void testStore()
+{
+ QFETCH( bool, uidBased );
+ QFETCH( qint64, id );
+ QFETCH( qint64, uid );
+ QFETCH( QList<QByteArray>, flags );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::StoreJob *job = new KIMAP::StoreJob(&session);
+ job->setUidBased( uidBased );
+ job->setSequenceSet( KIMAP::ImapSet( uidBased ? uid : id ) );
+ job->setFlags( flags );
+ job->setMode( KIMAP::StoreJob::SetFlags );
+ bool result = job->exec();
+ QVERIFY(result);
+ if ( uidBased ) {
+ QVERIFY( job->resultingFlags().contains( uid ) );
+ } else {
+ QVERIFY( job->resultingFlags().contains( id ) );
+ }
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( StoreJobTest )
+
+#include "storejobtest.moc"
diff --git a/kimap/tests/subscribejobtest.cpp b/kimap/tests/subscribejobtest.cpp
new file mode 100644
index 0000000..f314345
--- /dev/null
+++ b/kimap/tests/subscribejobtest.cpp
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/subscribejob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class SubscribeJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testSubscribe_data() {
+ QTest::addColumn<QString>( "mailbox" );
+ QTest::addColumn< QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 SUBSCRIBE \"INBOX/foo\""
+ << "S: A000001 OK CREATE completed";
+ QTest::newRow( "good" ) << "INBOX/foo" << scenario ;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SUBSCRIBE \"INBOX-FAIL-BAD\""
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << "INBOX-FAIL-BAD" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 SUBSCRIBE \"INBOX-FAIL-NO\""
+ << "S: A000001 NO subscribe failure";
+ QTest::newRow( "no" ) << "INBOX-FAIL-NO" << scenario ;
+}
+
+void testSubscribe()
+{
+ QFETCH( QString, mailbox );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::SubscribeJob *job = new KIMAP::SubscribeJob(&session);
+ job->setMailBox(mailbox);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD scenario", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO scenario", Continue);
+ QVERIFY(result);
+ QCOMPARE(job->mailBox(), mailbox);
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( SubscribeJobTest )
+
+#include "subscribejobtest.moc"
diff --git a/kimap/tests/testimapidle.cpp b/kimap/tests/testimapidle.cpp
new file mode 100644
index 0000000..bdf8d69
--- /dev/null
+++ b/kimap/tests/testimapidle.cpp
@@ -0,0 +1,130 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <kcomponentdata.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <qtcpsocket.h>
+#include <QCoreApplication>
+#include <qsignalspy.h>
+
+#include "kimap/session.h"
+#include "kimap/capabilitiesjob.h"
+#include "kimap/idlejob.h"
+#include "kimap/loginjob.h"
+#include "kimap/logoutjob.h"
+#include "kimap/selectjob.h"
+#include "kimap/closejob.h"
+#include "kimap/sessionuiproxy.h"
+
+using namespace KIMAP;
+
+class UiProxy: public SessionUiProxy {
+ public:
+ bool ignoreSslError(const KSslErrorUiData& errorData) {
+ Q_UNUSED( errorData );
+ return true;
+ }
+};
+
+int main( int argc, char **argv )
+{
+ KAboutData about("TestImapIdle", 0, ki18n("TestImapIdle"), "version");
+ KComponentData cData(&about);
+
+ if (argc < 4) {
+ kError() << "Not enough parameters, expecting: <server> <user> <password>";
+ }
+
+ QString server = QString::fromLocal8Bit(argv[1]);
+ int port = 143;
+ if ( server.count( ':' ) == 1 ) {
+ port = server.split( ':' ).last().toInt();
+ server = server.split( ':' ).first();
+ }
+ QString user = QString::fromLocal8Bit(argv[2]);
+ QString password = QString::fromLocal8Bit(argv[3]);
+
+ kDebug() << "Listening:" << server << port << user << password;
+ qDebug();
+
+ QCoreApplication app(argc, argv);
+ Session session(server, port);
+ UiProxy *proxy = new UiProxy();
+ session.setUiProxy(UiProxy::Ptr( proxy ));
+
+ kDebug() << "Logging in...";
+ LoginJob *login = new LoginJob(&session);
+ login->setUserName(user);
+ login->setPassword(password);
+ login->exec();
+ Q_ASSERT_X(login->error()==0, "LoginJob", login->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Authenticated);
+ qDebug();
+
+ kDebug() << "Asking for capabilities:";
+ CapabilitiesJob *capabilities = new CapabilitiesJob(&session);
+ capabilities->exec();
+ Q_ASSERT_X(capabilities->error()==0, "CapabilitiesJob", capabilities->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Authenticated);
+ kDebug() << capabilities->capabilities();
+ qDebug();
+
+ Q_ASSERT(capabilities->capabilities().contains("IDLE"));
+
+ kDebug() << "Selecting INBOX:";
+ SelectJob *select = new SelectJob(&session);
+ select->setMailBox("INBOX");
+ select->exec();
+ Q_ASSERT_X(select->error()==0, "SelectJob", select->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ kDebug() << "Flags:" << select->flags();
+ kDebug() << "Permanent flags:" << select->permanentFlags();
+ kDebug() << "Total Number of Messages:" << select->messageCount();
+ kDebug() << "Number of recent Messages:" << select->recentCount();
+ kDebug() << "First Unseen Message Index:" << select->firstUnseenIndex();
+ kDebug() << "UID validity:" << select->uidValidity();
+ kDebug() << "Next UID:" << select->nextUid();
+ qDebug();
+
+ kDebug() << "Start idling...";
+ IdleJob *idle = new IdleJob(&session);
+ QObject::connect(idle, SIGNAL(mailBoxStats(KIMAP::IdleJob*,QString,int,int)),
+ idle, SLOT(stop()));
+ idle->exec();
+ kDebug() << "Idling done for" << idle->lastMailBox()
+ << "message count:" << idle->lastMessageCount()
+ << "recent count:" << idle->lastRecentCount();
+
+ kDebug() << "Closing INBOX:";
+ CloseJob *close = new CloseJob(&session);
+ close->exec();
+ Q_ASSERT(session.state()==Session::Authenticated);
+ qDebug();
+
+ kDebug() << "Logging out...";
+ LogoutJob *logout = new LogoutJob(&session);
+ logout->exec();
+ Q_ASSERT_X(logout->error()==0, "LogoutJob", logout->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Disconnected);
+
+ return 0;
+}
diff --git a/kimap/tests/testimapserver.cpp b/kimap/tests/testimapserver.cpp
new file mode 100644
index 0000000..c22aee2
--- /dev/null
+++ b/kimap/tests/testimapserver.cpp
@@ -0,0 +1,604 @@
+/**
+ * This file is part of the KDE project
+ * Copyright (C) 2009 Kevin Ottens <ervin@kde.org>
+ * Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <kcomponentdata.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qtcpsocket.h>
+#include <QCoreApplication>
+#include <qsignalspy.h>
+
+#include "kimap/acl.h"
+#include "kimap/session.h"
+#include "kimap/appendjob.h"
+#include "kimap/capabilitiesjob.h"
+#include "kimap/fetchjob.h"
+#include "kimap/listjob.h"
+#include "kimap/loginjob.h"
+#include "kimap/logoutjob.h"
+#include "kimap/selectjob.h"
+#include "kimap/closejob.h"
+#include "kimap/expungejob.h"
+#include "kimap/createjob.h"
+#include "kimap/deletejob.h"
+#include "kimap/namespacejob.h"
+#include "kimap/subscribejob.h"
+#include "kimap/unsubscribejob.h"
+#include "kimap/renamejob.h"
+#include "kimap/storejob.h"
+#include "kimap/sessionuiproxy.h"
+#include "kimap/setacljob.h"
+#include "kimap/getacljob.h"
+#include "kimap/deleteacljob.h"
+#include "kimap/myrightsjob.h"
+#include "kimap/listrightsjob.h"
+#include "kimap/setmetadatajob.h"
+#include "kimap/getmetadatajob.h"
+
+using namespace KIMAP;
+
+class UiProxy: public SessionUiProxy {
+ public:
+ bool ignoreSslError(const KSslErrorUiData& errorData) {
+ return true;
+ }
+};
+
+void dumpContentHelper(KMime::Content *part, const QString &partId = QString())
+{
+ if (partId.isEmpty()) {
+ kDebug() << "** Message root **";
+ } else {
+ kDebug() << "** Part" << partId << "**";
+ }
+
+ kDebug() << part->head();
+
+ KMime::Content::List children = part->contents();
+ for (int i=0; i<children.size(); i++) {
+ QString newId = partId;
+ if (!newId.isEmpty()) {
+ newId+=".";
+ }
+ newId+=QString::number(i+1);
+ dumpContentHelper(children[i], newId);
+ }
+}
+
+void listFolders(Session *session, bool includeUnsubscribed = false, const QString &nameFilter = "")
+{
+ ListJob *list = new ListJob(session);
+ list->setIncludeUnsubscribed(includeUnsubscribed);
+ list->exec();
+ Q_ASSERT_X(list->error()==0, "ListJob", list->errorString().toLocal8Bit());
+ int count = list->mailBoxes().size();
+ for (int i=0; i<count; ++i) {
+ MailBoxDescriptor descriptor = list->mailBoxes()[i];
+ if (descriptor.name.endsWith(nameFilter)) {
+ kDebug() << descriptor.separator << descriptor.name;
+ }
+ }
+
+}
+
+void testMetaData(Session *session)
+{
+ kDebug() << "TESTING: METADATA commands";
+ CreateJob *create = new CreateJob(session);
+ create->setMailBox("INBOX/TestFolder");
+ create->exec();
+
+ SetMetaDataJob *setmetadata = new SetMetaDataJob(session);
+ setmetadata->setMailBox("INBOX/TestFolder");
+ setmetadata->setServerCapability(SetMetaDataJob::Annotatemore);
+ setmetadata->setEntry("/comment");
+ setmetadata->addMetaData("value.priv", "My new comment");
+ setmetadata->exec();
+
+ setmetadata = new SetMetaDataJob(session);
+ setmetadata->setMailBox("INBOX/TestFolder");
+ setmetadata->setServerCapability(SetMetaDataJob::Annotatemore);
+ setmetadata->setEntry("/check");
+ setmetadata->addMetaData("value.priv", "true");
+ setmetadata->exec();
+
+ GetMetaDataJob *getmetadata = new GetMetaDataJob(session);
+ getmetadata->setMailBox("INBOX/TestFolder");
+ getmetadata->setServerCapability(SetMetaDataJob::Annotatemore);
+ getmetadata->addEntry("/*","value.priv");
+ getmetadata->exec();
+ Q_ASSERT_X(getmetadata->metaData("INBOX/TestFolder", "/check", "value.priv") == "true", "", "/check metadata should be true");
+ Q_ASSERT_X(getmetadata->metaData("INBOX/TestFolder", "/comment", "value.priv") == "My new comment", "", "/check metadata should be My new comment");
+
+ //cleanup
+ DeleteJob *deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/TestFolder");
+ deletejob->exec();
+}
+
+void testAcl(Session *session, const QString &user)
+{
+ kDebug() << "TESTING: ACL commands";
+ CreateJob *create = new CreateJob(session);
+ create->setMailBox("INBOX/TestFolder");
+ create->exec();
+
+ ListRightsJob *listRights = new ListRightsJob(session);
+ listRights->setMailBox("INBOX/TestFolder");
+ listRights->setIdentifier(user.toLatin1());
+ listRights->exec();
+ kDebug() << "Default rights on INBOX/TestFolder: " << Acl::rightsToString(listRights->defaultRights());
+ QList<Acl::Rights> possible = listRights->possibleRights();
+ QStringList strList;
+ Q_FOREACH(Acl::Rights r, possible) {
+ strList << Acl::rightsToString(r);
+ }
+ kDebug() << "Possible rights on INBOX/TestFolder: " << strList;
+
+ MyRightsJob *myRights = new MyRightsJob(session);
+ myRights->setMailBox("INBOX/TestFolder");
+ myRights->exec();
+
+ Acl::Rights mine = myRights->rights();
+ kDebug() << "My rights on INBOX/TestFolder: " << Acl::rightsToString(mine);
+ kDebug() << "Reading INBOX/TestFolder is possible: " << myRights->hasRightEnabled(Acl::Read);
+ Q_ASSERT_X(myRights->hasRightEnabled(Acl::Read), "Reading INBOX is NOT possible", "");
+
+ GetAclJob *getAcl= new GetAclJob(session);
+ getAcl->setMailBox("INBOX/TestFolder");
+ getAcl->exec();
+ kDebug() << "Anyone rights on INBOX/TestFolder: " << getAcl->rights("anyone");
+ Acl::Rights users = getAcl->rights(user.toLatin1());
+ kDebug() << user << " rights on INBOX/TestFolder: " << Acl::rightsToString(users);
+ Q_ASSERT_X(mine == users, "GETACL returns different rights for the same user", "");
+
+
+ kDebug() << "Removing Delete right ";
+ mine = Acl::Delete;
+ SetAclJob *setAcl= new SetAclJob(session);
+ setAcl->setMailBox("INBOX/TestFolder");
+ setAcl->setIdentifier(user.toLatin1());
+ setAcl->setRights(AclJobBase::Remove, mine);
+ setAcl->exec();
+
+ getAcl= new GetAclJob(session);
+ getAcl->setMailBox("INBOX/TestFolder");
+ getAcl->exec();
+ users = getAcl->rights(user.toLatin1());
+ kDebug() << user << " rights on INBOX/TestFolder: " << Acl::rightsToString(users);
+
+ kDebug() << "Adding back Delete right ";
+ mine = Acl::Delete;
+ setAcl= new SetAclJob(session);
+ setAcl->setMailBox("INBOX/TestFolder");
+ setAcl->setIdentifier(user.toLatin1());
+ setAcl->setRights(AclJobBase::Add, mine);
+ setAcl->exec();
+
+ getAcl= new GetAclJob(session);
+ getAcl->setMailBox("INBOX/TestFolder");
+ getAcl->exec();
+ users = getAcl->rights(user.toLatin1());
+ kDebug() << user << " rights on INBOX/TestFolder: " << Acl::rightsToString(users);
+
+ //cleanup
+ DeleteJob *deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/TestFolder");
+ deletejob->exec();
+}
+
+void testAppendAndStore(Session *session)
+{
+ kDebug() << "TESTING: APPEND and STORE";
+ //setup
+ CreateJob *create = new CreateJob(session);
+ create->setMailBox("INBOX/TestFolder");
+ create->exec();
+
+ QByteArray testMailContent =
+ "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)\r\n"
+ "From: Fred Foobar <foobar@Blurdybloop.COM>\r\n"
+ "Subject: afternoon meeting\r\n"
+ "To: mooch@owatagu.siam.edu\r\n"
+ "Message-Id: <B27397-0100000@Blurdybloop.COM>\r\n"
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: TEXT/PLAIN; CHARSET=US-ASCII\r\n"
+ "\r\n"
+ "Hello Joe, do you think we can meet at 3:30 tomorrow?\r\n";
+
+ kDebug() << "Append a message in INBOX/TestFolder...";
+ AppendJob *append = new AppendJob(session);
+ append->setMailBox("INBOX/TestFolder");
+ append->setContent(testMailContent);
+ append->exec();
+ Q_ASSERT_X(append->error()==0, "AppendJob", append->errorString().toLocal8Bit());
+
+ kDebug() << "Read the message back and compare...";
+ SelectJob *select = new SelectJob(session);
+ select->setMailBox("INBOX/TestFolder");
+ select->exec();
+
+ FetchJob *fetch = new FetchJob(session);
+ FetchJob::FetchScope scope;
+ fetch->setSequenceSet(ImapSet(1));
+ scope.parts.clear();
+ scope.mode = FetchJob::FetchScope::Content;
+ fetch->setScope(scope);
+ fetch->exec();
+ MessagePtr message = fetch->messages()[1];
+ Q_ASSERT_X(fetch->error()==0, "FetchJob", fetch->errorString().toLocal8Bit());
+ testMailContent.replace( "\r\n", "\n" );
+ Q_ASSERT_X(testMailContent==message->head()+"\n"+message->body(),
+ "Message differs from reference", message->head()+"\n"+message->body());
+
+ fetch = new FetchJob(session);
+ fetch->setSequenceSet(ImapSet(1));
+ scope.parts.clear();
+ scope.mode = FetchJob::FetchScope::Flags;
+ fetch->setScope(scope);
+ fetch->exec();
+ MessageFlags expectedFlags = fetch->flags()[1];
+ kDebug() << "Read the message flags:" << expectedFlags;
+
+ kDebug() << "Add the \\Deleted flag...";
+ expectedFlags << "\\Deleted";
+ qSort(expectedFlags);
+ StoreJob *store = new StoreJob(session);
+ store->setSequenceSet(ImapSet(1));
+ store->setMode(StoreJob::AppendFlags);
+ store->setFlags(QList<QByteArray>() << "\\Deleted");
+ store->exec();
+ Q_ASSERT_X(store->error()==0, "StoreJob", store->errorString().toLocal8Bit());
+
+ QList<QByteArray> resultingFlags = store->resultingFlags()[1];
+ qSort(resultingFlags);
+ if (expectedFlags!=resultingFlags) {
+ kDebug() << resultingFlags;
+ }
+ Q_ASSERT(expectedFlags==resultingFlags);
+
+
+ select = new SelectJob(session);
+ select->setMailBox("INBOX");
+ select->exec();
+
+ //cleanup
+ DeleteJob *deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/TestFolder");
+ deletejob->exec();
+ deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/RenamedTestFolder");
+ deletejob->exec();
+}
+
+void testRename(Session *session)
+{
+ kDebug() << "TESTING: RENAME";
+ //setup
+ CreateJob *create = new CreateJob(session);
+ create->setMailBox("INBOX/TestFolder");
+ create->exec();
+
+ kDebug() << "Listing mailboxes with name TestFolder:";
+ listFolders(session, true, "TestFolder");
+
+ //actual tests
+ kDebug() << "Renaming to RenamedTestFolder";
+ RenameJob *rename = new RenameJob(session);
+ rename->setSourceMailBox("INBOX/TestFolder");
+ rename->setDestinationMailBox("INBOX/RenamedTestFolder");
+ rename->exec();
+
+ kDebug() << "Listing mailboxes with name TestFolder:";
+ listFolders(session, true, "TestFolder");
+ kDebug() << "Listing mailboxes with name RenamedTestFolder:";
+ listFolders(session, true, "RenamedTestFolder");
+
+ //cleanup
+ DeleteJob *deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/TestFolder");
+ deletejob->exec();
+ deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/RenamedTestFolder");
+ deletejob->exec();
+}
+
+
+void testSubscribe(Session *session)
+{
+ kDebug() << "TESTING: SUBSCRIBE/UNSUBSCRIBE";
+ //setup
+ CreateJob *create = new CreateJob(session);
+ create->setMailBox("INBOX/TestFolder");
+ create->exec();
+
+ kDebug() << "Listing subscribed mailboxes with name TestFolder:";
+ listFolders(session, false, "TestFolder");
+
+ //actual tests
+ kDebug() << "Subscribing to INBOX/TestFolder";
+ SubscribeJob *subscribe = new SubscribeJob(session);
+ subscribe->setMailBox("INBOX/TestFolder");
+ subscribe->exec();
+
+ kDebug() << "Listing subscribed mailboxes with name TestFolder:";
+ listFolders(session, false, "TestFolder");
+
+ kDebug() << "Unsubscribing from INBOX/TestFolder";
+ UnsubscribeJob *unsubscribe = new UnsubscribeJob(session);
+ unsubscribe->setMailBox("INBOX/TestFolder");
+ unsubscribe->exec();
+
+ kDebug() << "Listing subscribed mailboxes with name TestFolder:";
+ listFolders(session, false, "TestFolder");
+
+ //cleanup
+ DeleteJob *deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/TestFolder");
+ deletejob->exec();
+}
+
+void testDelete(Session *session)
+{
+ kDebug() << "TESTING: DELETE";
+ kDebug() << "Creating INBOX/TestFolder:";
+ CreateJob *create = new CreateJob(session);
+ create->setMailBox("INBOX/TestFolder");
+ create->exec();
+
+
+ kDebug() << "Listing with name TestFolder before DELETE:";
+ listFolders(session, true, "TestFolder");
+
+ kDebug() << "Deleting INBOX/TestFolder";
+ DeleteJob *deletejob = new DeleteJob(session);
+ deletejob->setMailBox("INBOX/TestFolder");
+ deletejob->exec();
+
+ kDebug() << "Listing with name TestFolder after DELETE:";
+ listFolders(session, true, "TestFolder");
+}
+
+int main( int argc, char **argv )
+{
+ KAboutData about("TestImapServer", 0, ki18n("TestImapServer"), "version");
+ KComponentData cData(&about);
+
+ if (argc < 4) {
+ kError() << "Not enough parameters, expecting: <server> <user> <password>";
+ }
+
+ QString server = QString::fromLocal8Bit(argv[1]);
+ int port = 143;
+ if ( server.count( ':' ) == 1 ) {
+ port = server.split( ':' ).last().toInt();
+ server = server.split( ':' ).first();
+ }
+ QString user = QString::fromLocal8Bit(argv[2]);
+ QString password = QString::fromLocal8Bit(argv[3]);
+
+ kDebug() << "Querying:" << server << port << user << password;
+ qDebug();
+
+ QCoreApplication app(argc, argv);
+ Session session(server, port);
+ UiProxy::Ptr proxy( new UiProxy() );
+ session.setUiProxy(proxy);
+
+ kDebug() << "Logging in...";
+ LoginJob *login = new LoginJob(&session);
+ //login->setEncryptionMode(LoginJob::TlsV1);
+ //login->setAuthenticationMode(LoginJob::Plain);
+ login->setUserName(user);
+ login->setPassword(password);
+ login->exec();
+ qDebug();
+
+ /*if (login->encryptionMode() == LoginJob::Unencrypted)
+ {
+ kDebug() << "Encrypted login not possible, try to log in without encryption";
+ login = new LoginJob(&session);
+ login->setUserName(user);
+ login->setPassword(password);
+ login->exec();
+ Q_ASSERT_X(login->error()==0, "LoginJob", login->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Authenticated);
+ qDebug();
+
+ }*/
+
+ kDebug() << "Server greeting:" << session.serverGreeting();
+
+ kDebug() << "Asking for capabilities:";
+ CapabilitiesJob *capabilities = new CapabilitiesJob(&session);
+ capabilities->exec();
+ Q_ASSERT_X(capabilities->error()==0, "CapabilitiesJob", capabilities->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Authenticated);
+ kDebug() << capabilities->capabilities();
+ qDebug();
+
+ kDebug() << "Asking for namespaces:";
+ NamespaceJob *namespaces = new NamespaceJob(&session);
+ namespaces->exec();
+ Q_ASSERT_X(namespaces->error()==0, "CapabilitiesJob", namespaces->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Authenticated);
+
+ kDebug() << "Contains empty namespace:" << namespaces->containsEmptyNamespace();
+
+ kDebug() << "Personal:";
+ foreach ( MailBoxDescriptor ns, namespaces->personalNamespaces() ) {
+ kDebug() << ns.separator << ns.name;
+ }
+
+ kDebug() << "User: ";
+ foreach ( MailBoxDescriptor ns, namespaces->userNamespaces() ) {
+ kDebug() << ns.separator << ns.name;
+ }
+
+ kDebug() << "Shared: ";
+ foreach ( MailBoxDescriptor ns, namespaces->sharedNamespaces() ) {
+ kDebug() << ns.separator << ns.name;
+ }
+ qDebug();
+
+ kDebug() << "Listing mailboxes:";
+ listFolders(&session);
+ Q_ASSERT(session.state()==Session::Authenticated);
+
+ kDebug() << "Selecting INBOX:";
+ SelectJob *select = new SelectJob(&session);
+ select->setMailBox("INBOX");
+ select->exec();
+ Q_ASSERT_X(select->error()==0, "SelectJob", select->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ kDebug() << "Flags:" << select->flags();
+ kDebug() << "Permanent flags:" << select->permanentFlags();
+ kDebug() << "Total Number of Messages:" << select->messageCount();
+ kDebug() << "Number of recent Messages:" << select->recentCount();
+ kDebug() << "First Unseen Message Index:" << select->firstUnseenIndex();
+ kDebug() << "UID validity:" << select->uidValidity();
+ kDebug() << "Next UID:" << select->nextUid();
+ qDebug();
+
+ kDebug() << "Fetching first 3 messages headers:";
+ FetchJob *fetch = new FetchJob(&session);
+ FetchJob::FetchScope scope;
+ fetch->setSequenceSet(ImapSet(1, 3));
+ scope.parts.clear();
+ scope.mode = FetchJob::FetchScope::Headers;
+ fetch->setScope(scope);
+ fetch->exec();
+ Q_ASSERT_X(fetch->error()==0, "FetchJob", fetch->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ QMap<qint64, MessagePtr> messages = fetch->messages();
+ foreach (qint64 id, messages.keys()) {
+ kDebug() << "* Message" << id << "(" << fetch->sizes()[id] << "bytes )";
+ kDebug() << " From :" << messages[id]->from()->asUnicodeString();
+ kDebug() << " To :" << messages[id]->to()->asUnicodeString();
+ kDebug() << " Date :" << messages[id]->date()->asUnicodeString();
+ kDebug() << " Subject :" << messages[id]->subject()->asUnicodeString();
+ kDebug() << " Message-ID:" << messages[id]->messageID()->asUnicodeString();
+ }
+ qDebug();
+
+
+ kDebug() << "Fetching first 3 messages flags:";
+ fetch = new FetchJob(&session);
+ fetch->setSequenceSet(ImapSet(1, 3));
+ scope.parts.clear();
+ scope.mode = FetchJob::FetchScope::Flags;
+ fetch->setScope(scope);
+ fetch->exec();
+ Q_ASSERT_X(fetch->error()==0, "FetchJob", fetch->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ QMap<qint64, MessageFlags> flags = fetch->flags();
+ foreach (qint64 id, flags.keys()) {
+ kDebug() << "* Message" << id << "flags:" << flags[id];
+ }
+ qDebug();
+
+ kDebug() << "Fetching first message structure:";
+ fetch = new FetchJob(&session);
+ fetch->setSequenceSet(ImapSet(1));
+ scope.parts.clear();
+ scope.mode = FetchJob::FetchScope::Structure;
+ fetch->setScope(scope);
+ fetch->exec();
+ Q_ASSERT_X(fetch->error()==0, "FetchJob", fetch->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ MessagePtr message = fetch->messages()[1];
+ dumpContentHelper(message.get());
+ qDebug();
+
+ kDebug() << "Fetching first message second part headers:";
+ fetch = new FetchJob(&session);
+ fetch->setSequenceSet(ImapSet(1));
+ scope.parts.clear();
+ scope.parts << "2";
+ scope.mode = FetchJob::FetchScope::Headers;
+ fetch->setScope(scope);
+ fetch->exec();
+ Q_ASSERT_X(fetch->error()==0, "FetchJob", fetch->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ QMap<qint64, MessageParts> allParts = fetch->parts();
+ foreach (qint64 id, allParts.keys()) {
+ kDebug() << "* Message" << id << "parts headers";
+ MessageParts parts = allParts[id];
+ foreach (const QByteArray &partId, parts.keys()) {
+ kDebug() << " ** Part" << partId;
+ kDebug() << " Name :" << parts[partId]->contentType()->name();
+ kDebug() << " Mimetype :" << parts[partId]->contentType()->mimeType();
+ kDebug() << " Description:" << parts[partId]->contentDescription()->asUnicodeString().simplified();
+ }
+ }
+ qDebug();
+
+ kDebug() << "Fetching first message second part content:";
+ fetch = new FetchJob(&session);
+ fetch->setSequenceSet(ImapSet(1));
+ scope.parts.clear();
+ scope.parts << "2";
+ scope.mode = FetchJob::FetchScope::Content;
+ fetch->setScope(scope);
+ fetch->exec();
+ Q_ASSERT_X(fetch->error()==0, "FetchJob", fetch->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Selected);
+ allParts = fetch->parts();
+ foreach (int id, allParts.keys()) {
+ MessageParts parts = allParts[id];
+ foreach (const QByteArray &partId, parts.keys()) {
+ kDebug() << "* Message" << id << "part" << partId << "content:";
+ kDebug() << parts[partId]->body();
+ }
+ }
+ qDebug();
+
+ testDelete(&session);
+
+ testSubscribe(&session);
+
+ testRename(&session);
+
+ testAppendAndStore(&session);
+
+ testAcl(&session, user);
+
+ testMetaData(&session);
+
+ kDebug() << "Expunge INBOX:";
+ ExpungeJob *expunge = new ExpungeJob(&session);
+ expunge->exec();
+
+ kDebug() << "Closing INBOX:";
+ CloseJob *close = new CloseJob(&session);
+ close->exec();
+ Q_ASSERT(session.state()==Session::Authenticated);
+ qDebug();
+
+ kDebug() << "Logging out...";
+ LogoutJob *logout = new LogoutJob(&session);
+ logout->exec();
+ Q_ASSERT_X(logout->error()==0, "LogoutJob", logout->errorString().toLocal8Bit());
+ Q_ASSERT(session.state()==Session::Disconnected);
+
+ return 0;
+}
diff --git a/kimap/tests/testrfccodecs.cpp b/kimap/tests/testrfccodecs.cpp
new file mode 100644
index 0000000..38abd34
--- /dev/null
+++ b/kimap/tests/testrfccodecs.cpp
@@ -0,0 +1,79 @@
+/*
+ This file is part of the kimap library.
+ Copyright (C) 2007 Tom Albers <tomalbers@kde.nl>
+ Copyright (c) 2007 Allen Winter <winter@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include <qtest_kde.h>
+
+#include "testrfccodecs.h"
+
+QTEST_KDEMAIN_CORE( RFCCodecsTest )
+
+#include "kimap/rfccodecs.h"
+using namespace KIMAP;
+
+void RFCCodecsTest::testIMAPEncoding()
+{
+ QString encoded, decoded;
+ QByteArray bEncoded, bDecoded;
+
+ encoded = encodeImapFolderName( QString::fromUtf8( "Test.Frode Rønning" ) );
+ QCOMPARE( encoded, QString::fromUtf8("Test.Frode R&APg-nning") );
+ bEncoded = encodeImapFolderName( QString::fromUtf8( "Test.Frode Rønning" ).toUtf8() );
+ QCOMPARE( bEncoded, QString::fromUtf8("Test.Frode R&APg-nning").toUtf8() );
+
+ decoded = decodeImapFolderName( QString( "Test.Frode R&APg-nning" ) );
+ QCOMPARE( decoded, QString::fromUtf8("Test.Frode Rønning"));
+ bDecoded = decodeImapFolderName( QString::fromUtf8("Test.Frode Rønning" ).toUtf8() );
+ QCOMPARE( bDecoded, QString::fromUtf8("Test.Frode Rønning").toUtf8() );
+
+ encoded = encodeImapFolderName( QString::fromUtf8( "Test.tom & jerry" ) );
+ QCOMPARE( encoded, QString::fromUtf8("Test.tom &- jerry") );
+ bEncoded = encodeImapFolderName( QString::fromUtf8( "Test.tom & jerry" ).toUtf8() );
+ QCOMPARE( bEncoded, QString::fromUtf8("Test.tom &- jerry").toUtf8() );
+
+ decoded = decodeImapFolderName( QString::fromUtf8( "Test.tom &- jerry" ) );
+ QCOMPARE( decoded, QString::fromUtf8("Test.tom & jerry") );
+ bDecoded = decodeImapFolderName( QString::fromUtf8( "Test.tom &- jerry" ).toUtf8() );
+ QCOMPARE( bDecoded, QString::fromUtf8("Test.tom & jerry").toUtf8() );
+
+ // Try to feed already encoded
+ encoded = encodeImapFolderName( QString::fromUtf8( "Test.Cl&AOE-udio" ) );
+ QCOMPARE( encoded, QString::fromUtf8("Test.Cl&-AOE-udio") );
+ bEncoded = encodeImapFolderName( QString::fromUtf8( "Test.Cl&AOE-udio" ).toUtf8() );
+ QCOMPARE( bEncoded, QString::fromUtf8("Test.Cl&-AOE-udio").toUtf8() );
+
+ decoded = decodeImapFolderName( QString::fromUtf8( "Test.Cl&-AOE-udio" ) );
+ QCOMPARE( decoded, QString::fromUtf8("Test.Cl&AOE-udio") );
+ bDecoded = decodeImapFolderName( QString::fromUtf8( "Test.Cl&-AOE-udio" ).toUtf8() );
+ QCOMPARE( bDecoded, QString::fromUtf8("Test.Cl&AOE-udio").toUtf8() );
+
+ // With UTF8 characters
+ bEncoded = "INBOX/&AOQ- &APY- &APw- @ &IKw-";
+ QCOMPARE( decodeImapFolderName( bEncoded ), QByteArray( "INBOX/ä ö ü @ €" ) );
+}
+
+void RFCCodecsTest::testQuotes()
+{
+ QString test("tom\"allen");
+ QCOMPARE( quoteIMAP( test ), QString("tom\\\"allen") );
+ test = "tom\'allen";
+ QCOMPARE( quoteIMAP( test ), QString("tom\'allen" ) );
+ test = "tom\\allen";
+ QCOMPARE( quoteIMAP( test ), QString("tom\\\\allen" ) );
+}
+
diff --git a/kimap/tests/testrfccodecs.h b/kimap/tests/testrfccodecs.h
new file mode 100644
index 0000000..58f3c17
--- /dev/null
+++ b/kimap/tests/testrfccodecs.h
@@ -0,0 +1,35 @@
+/*
+ This file is part of the kimap library.
+
+ Copyright (c) 2007 Allen Winter <winter@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef RFCCODECSTEST_H
+#define RFCCODECSTEST_H
+
+#include <QtCore/QObject>
+
+class RFCCodecsTest : public QObject
+{
+ Q_OBJECT
+ private Q_SLOTS:
+ void testIMAPEncoding();
+ void testQuotes();
+};
+
+#endif
diff --git a/kimap/tests/testsession.cpp b/kimap/tests/testsession.cpp
new file mode 100644
index 0000000..2535348
--- /dev/null
+++ b/kimap/tests/testsession.cpp
@@ -0,0 +1,330 @@
+/*
+ This file is part of the KDE project
+ Copyright (C) 2008 Kevin Ottens <ervin@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QObject>
+#include <QtTest/QtTest>
+
+#include "session.h"
+#include "job.h"
+#include "kimaptest/fakeserver.h"
+#include "kimaptest/mockjob.h"
+
+Q_DECLARE_METATYPE(KIMAP::Session::State)
+Q_DECLARE_METATYPE(KJob*)
+
+class SessionTest : public QObject
+{
+ Q_OBJECT
+
+ private slots:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<KIMAP::Session::State>();
+ }
+
+ void shouldStartDisconnected()
+ {
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::greeting()
+ );
+ fakeServer.startAndWait();
+ KIMAP::Session s( "127.0.0.1", 5989 );
+ QSignalSpy spy(&s, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)));
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+ QTest::qWait( 600 );
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::NotAuthenticated );
+ QCOMPARE( spy.count(), 1 ); // NotAuthenticated
+ QList<QVariant> arguments = spy.takeFirst();
+ QCOMPARE( ( int )qvariant_cast<KIMAP::Session::State>(arguments.at(0)), ( int )KIMAP::Session::NotAuthenticated);
+ QCOMPARE( ( int )qvariant_cast<KIMAP::Session::State>(arguments.at(1)), ( int )KIMAP::Session::Disconnected);
+ }
+
+ void shouldFailForInvalidHosts()
+ {
+ KIMAP::Session s( "0.0.0.0", 1234 );
+ s.setTimeout(1); // 1 second timout
+
+ QSignalSpy spyFail(&s, SIGNAL(connectionFailed()));
+ QSignalSpy spyLost(&s, SIGNAL(connectionLost()));
+ QSignalSpy spyState(&s, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)));
+
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+
+ QTest::qWait( 500 );
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+ QCOMPARE ( spyFail.count(), 1 );
+ QEXPECT_FAIL("", "FIXME KDE5: Don't emit connectionLost() on a failed connection", Continue);
+ QCOMPARE ( spyLost.count(), 0 );
+ QCOMPARE ( spyState.count(), 0 );
+
+ // Wait 800ms more. So now it's 1.3 seconds, check that the socket timeout has correctly been
+ // disabled, and that it hadn't fired unexpectedly.
+ QTest::qWait( 800 );
+ QCOMPARE ( spyFail.count(), 1 );
+ }
+
+ /**
+ Checks that the timeout works when the connection succeeds, but the server doesn't sends anything
+ back to the client. This could happen for example if we connected to a non-IMAP server.
+ */
+ void shouldTimeoutOnNoGreeting()
+ {
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>() );
+ fakeServer.startAndWait();
+
+ KIMAP::Session s( "127.0.0.1", 5989 );
+ s.setTimeout(2);
+ QSignalSpy spyFail(&s, SIGNAL(connectionFailed()));
+ QSignalSpy spyLost(&s, SIGNAL(connectionLost()));
+ QSignalSpy spyState(&s, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)));
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+
+ // Wait 1.8 second. Since the timeout is set to 2 seconds, the socket should be still
+ // disconnected at this point, yet the connectionFailed() signal shouldn't have been emitted.
+ QTest::qWait( 1800 );
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+ QCOMPARE ( spyFail.count(), 0 );
+ QCOMPARE ( spyLost.count(), 0 );
+ QCOMPARE ( spyState.count(), 0 );
+
+ // Wait 0.5 second more. Now we are at 2.3 seconds, the socket should have timed out, and the
+ // connectionFailed() signal should have been emitted.
+ QTest::qWait( 500 );
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+ QCOMPARE ( spyFail.count(), 1 );
+ QCOMPARE ( spyLost.count(), 0 );
+ QCOMPARE ( spyState.count(), 0 );
+ }
+
+ void shouldSupportPreauth()
+ {
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::preauth()
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session s( "127.0.0.1", 5989 );
+ QSignalSpy spy(&s, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)));
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Disconnected );
+ QTest::qWait( 500 );
+ QCOMPARE( ( int )s.state(), ( int )KIMAP::Session::Authenticated );
+ QCOMPARE( spy.count(), 1 ); // Authenticated
+ QList<QVariant> arguments = spy.takeFirst();
+ QCOMPARE( ( int )qvariant_cast<KIMAP::Session::State>(arguments.at(0)), ( int )KIMAP::Session::Authenticated);
+ QCOMPARE( ( int )qvariant_cast<KIMAP::Session::State>(arguments.at(1)), ( int )KIMAP::Session::Disconnected);
+ }
+
+ void shouldRespectStartOrder()
+ {
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::greeting()
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session s("127.0.0.1", 5989);
+ MockJob *j1 = new MockJob(&s);
+ connect(j1, SIGNAL(result(KJob*)), this, SLOT(jobDone(KJob*)));
+ MockJob *j2 = new MockJob(&s);
+ connect(j2, SIGNAL(result(KJob*)), this, SLOT(jobDone(KJob*)));
+ MockJob *j3 = new MockJob(&s);
+ connect(j3, SIGNAL(result(KJob*)), this, SLOT(jobDone(KJob*)));
+ MockJob *j4 = new MockJob(&s);
+ connect(j4, SIGNAL(result(KJob*)), this, SLOT(jobDone(KJob*)));
+
+ j4->start();
+ j2->start();
+ j3->start();
+ j1->start();
+
+ m_expectedCalls = 4;
+ m_eventLoop.exec();
+
+ QCOMPARE(m_jobs.size(), 4);
+ QCOMPARE(m_jobs[0], j4);
+ QCOMPARE(m_jobs[1], j2);
+ QCOMPARE(m_jobs[2], j3);
+ QCOMPARE(m_jobs[3], j1);
+ }
+
+ void shouldManageQueueSize()
+ {
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::greeting()
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session s("127.0.0.1", 5989);
+
+ QSignalSpy queueSpy(&s, SIGNAL(jobQueueSizeChanged(int)));
+
+ QCOMPARE( s.jobQueueSize(), 0 );
+
+ MockJob *j1 = new MockJob(&s);
+ MockJob *j2 = new MockJob(&s);
+ MockJob *j3 = new MockJob(&s);
+ MockJob *j4 = new MockJob(&s);
+ connect(j4, SIGNAL(result(KJob*)), &m_eventLoop, SLOT(quit()));
+
+ QCOMPARE( s.jobQueueSize(), 0 );
+
+ j1->start();
+ QCOMPARE( s.jobQueueSize(), 1 );
+ QCOMPARE( queueSpy.size(), 1 );
+ QCOMPARE( queueSpy.at( 0 ).at( 0 ).toInt(), 1 );
+
+ j2->start();
+ QCOMPARE( s.jobQueueSize(), 2 );
+ QCOMPARE( queueSpy.size(), 2 );
+ QCOMPARE( queueSpy.at( 1 ).at( 0 ).toInt(), 2 );
+
+ j3->start();
+ QCOMPARE( s.jobQueueSize(), 3 );
+ QCOMPARE( queueSpy.size(), 3 );
+ QCOMPARE( queueSpy.at( 2 ).at( 0 ).toInt(), 3 );
+
+ j4->start();
+ QCOMPARE( s.jobQueueSize(), 4 );
+ QCOMPARE( queueSpy.size(), 4 );
+ QCOMPARE( queueSpy.at( 3 ).at( 0 ).toInt(), 4 );
+
+ queueSpy.clear();
+ m_eventLoop.exec();
+
+ QCOMPARE( s.jobQueueSize(), 0 );
+
+ QCOMPARE( queueSpy.at( 0 ).at( 0 ).toInt(), 3 );
+ QCOMPARE( queueSpy.at( 1 ).at( 0 ).toInt(), 2 );
+ QCOMPARE( queueSpy.at( 2 ).at( 0 ).toInt(), 1 );
+ QCOMPARE( queueSpy.at( 3 ).at( 0 ).toInt(), 0 );
+ }
+
+ void shouldTimeoutOnNoReply()
+ {
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>()
+ << FakeServer::preauth()
+ << "C: A000001 DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ << "S: * DUMMY"
+ // We never get a OK or anything, so the job can't normally complete
+ );
+ fakeServer.startAndWait();
+
+ KIMAP::Session s( "127.0.0.1", 5989 );
+
+ QSignalSpy spyFail(&s, SIGNAL(connectionFailed()));
+ QSignalSpy spyLost(&s, SIGNAL(connectionLost()));
+ QSignalSpy spyState(&s, SIGNAL(stateChanged(KIMAP::Session::State,KIMAP::Session::State)));
+
+ MockJob *mock = new MockJob(&s);
+ mock->setCommand("DUMMY");
+
+ mock->exec();
+ // We expect to get an error here due to some timeout
+ QVERIFY( mock->error()!=0 );
+ QCOMPARE( spyFail.count(), 0 );
+ QCOMPARE( spyLost.count(), 1 );
+ QCOMPARE( spyState.count(), 2 ); // Authenticated, Disconnected
+ }
+
+ void shouldFailFirstJobOnConnectionFailed()
+ {
+ qRegisterMetaType<KJob*>();
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( QList<QByteArray>() );
+ fakeServer.startAndWait();
+
+ KIMAP::Session s( "127.0.0.1", 5989 );
+ s.setTimeout(1);
+
+ MockJob *j1 = new MockJob(&s);
+ QSignalSpy spyResult1(j1, SIGNAL(result(KJob*)));
+ QSignalSpy spyDestroyed1(j1, SIGNAL(destroyed()));
+
+ MockJob *j2 = new MockJob(&s);
+ QSignalSpy spyResult2(j2, SIGNAL(result(KJob*)));
+ QSignalSpy spyDestroyed2(j2, SIGNAL(destroyed()));
+
+ MockJob *j3 = new MockJob(&s);
+ QSignalSpy spyResult3(j3, SIGNAL(result(KJob*)));
+ QSignalSpy spyDestroyed3(j3, SIGNAL(destroyed()));
+
+ j1->start();
+ j2->start();
+ j3->start();
+
+ QCOMPARE( s.jobQueueSize(), 3);
+
+ QTest::qWait(1100);
+
+ // Check that only the first job has emitted it's result
+ QCOMPARE( spyResult1.count(), 1 );
+ QCOMPARE( spyResult2.count(), 0 );
+ QCOMPARE( spyResult3.count(), 0 );
+
+ // Check that all jobs have been deleted
+ QCOMPARE( spyDestroyed1.count(), 1 );
+ QCOMPARE( spyDestroyed2.count(), 1 );
+ QCOMPARE( spyDestroyed3.count(), 1 );
+
+ QCOMPARE( s.jobQueueSize(), 0);
+ }
+
+ public slots:
+ void jobDone(KJob *job)
+ {
+ m_jobs << job;
+
+ if (m_expectedCalls==m_jobs.size()) {
+ m_eventLoop.quit();
+ }
+ }
+
+ private:
+ QEventLoop m_eventLoop;
+ int m_expectedCalls;
+ QList<KJob*> m_jobs;
+};
+
+QTEST_MAIN(SessionTest)
+
+#include "testsession.moc"
diff --git a/kimap/tests/unsubscribejobtest.cpp b/kimap/tests/unsubscribejobtest.cpp
new file mode 100644
index 0000000..1b4afe4
--- /dev/null
+++ b/kimap/tests/unsubscribejobtest.cpp
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2009 Andras Mantia <amantia@kde.org>
+
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
+ Author: Kevin Ottens <kevin@kdab.com>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest_kde.h>
+
+#include "kimaptest/fakeserver.h"
+#include "kimap/session.h"
+#include "kimap/unsubscribejob.h"
+
+#include <QTcpSocket>
+#include <QtTest>
+#include <KDebug>
+
+class UnsubscribeJobTest: public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+
+void testUnsubscribe_data() {
+ QTest::addColumn<QString>( "mailbox" );
+ QTest::addColumn< QList<QByteArray> >( "scenario" );
+
+ QList<QByteArray> scenario;
+ scenario << FakeServer::preauth()
+ << "C: A000001 UNSUBSCRIBE \"#news.comp.mail.mime\""
+ << "S: A000001 OK UNSUBSCRIBE completed";
+ QTest::newRow( "good" ) << "#news.comp.mail.mime" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 UNSUBSCRIBE \"INBOX-FAIL-BAD\""
+ << "S: A000001 BAD command unknown or arguments invalid";
+ QTest::newRow( "bad" ) << "INBOX-FAIL-BAD" << scenario;
+
+ scenario.clear();
+ scenario << FakeServer::preauth()
+ << "C: A000001 UNSUBSCRIBE \"INBOX-FAIL-NO\""
+ << "S: A000001 NO unsubscribe failure";
+ QTest::newRow( "no" ) << "INBOX-FAIL-NO" << scenario;
+}
+
+void testUnsubscribe()
+{
+ QFETCH( QString, mailbox );
+ QFETCH( QList<QByteArray>, scenario );
+
+ FakeServer fakeServer;
+ fakeServer.setScenario( scenario );
+ fakeServer.startAndWait();
+
+ KIMAP::Session session("127.0.0.1", 5989);
+
+ KIMAP::UnsubscribeJob *job = new KIMAP::UnsubscribeJob(&session);
+ job->setMailBox(mailbox);
+ bool result = job->exec();
+ QEXPECT_FAIL("bad" , "Expected failure on BAD scenario", Continue);
+ QEXPECT_FAIL("no" , "Expected failure on NO scenario", Continue);
+ QVERIFY(result);
+ QCOMPARE(job->mailBox(), mailbox);
+
+ fakeServer.quit();
+}
+
+
+};
+
+QTEST_KDEMAIN_CORE( UnsubscribeJobTest )
+
+#include "unsubscribejobtest.moc"