File indexing completed on 2024-11-10 04:40:17

0001 /*
0002     SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "imapparsertest.h"
0008 #include "private/imapparser_p.h"
0009 #include <QTest>
0010 
0011 #include <QBuffer>
0012 
0013 Q_DECLARE_METATYPE(QList<QByteArray>)
0014 Q_DECLARE_METATYPE(QList<int>)
0015 
0016 using namespace Akonadi;
0017 
0018 QTEST_MAIN(ImapParserTest)
0019 
0020 void ImapParserTest::testStripLeadingSpaces()
0021 {
0022     QByteArray input = "  a  ";
0023     int result;
0024 
0025     // simple leading spaces at the beginning
0026     result = ImapParser::stripLeadingSpaces(input, 0);
0027     QCOMPARE(result, 2);
0028 
0029     // simple leading spaces in the middle
0030     result = ImapParser::stripLeadingSpaces(input, 1);
0031     QCOMPARE(result, 2);
0032 
0033     // no leading spaces
0034     result = ImapParser::stripLeadingSpaces(input, 2);
0035     QCOMPARE(result, 2);
0036 
0037     // trailing spaces
0038     result = ImapParser::stripLeadingSpaces(input, 3);
0039     QCOMPARE(result, 5);
0040 
0041     // out of bounds access
0042     result = ImapParser::stripLeadingSpaces(input, input.length());
0043     QCOMPARE(result, input.length());
0044 }
0045 
0046 void ImapParserTest::testParseQuotedString()
0047 {
0048     QByteArray input = R"("quoted \"NIL\"   string inside")";
0049     QByteArray result;
0050     int consumed;
0051 
0052     // the whole thing
0053     consumed = ImapParser::parseQuotedString(input, result, 0);
0054     QCOMPARE(result, QByteArray("quoted \"NIL\"   string inside"));
0055     QCOMPARE(consumed, 32);
0056 
0057     // unquoted string
0058     consumed = ImapParser::parseQuotedString(input, result, 1);
0059     QCOMPARE(result, QByteArray("quoted"));
0060     QCOMPARE(consumed, 7);
0061 
0062     // whitespaces in quoted string
0063     consumed = ImapParser::parseQuotedString(input, result, 14);
0064     QCOMPARE(result, QByteArray("   string inside"));
0065     QCOMPARE(consumed, 32);
0066 
0067     // whitespaces before unquoted string
0068     consumed = ImapParser::parseQuotedString(input, result, 15);
0069     QCOMPARE(result, QByteArray("string"));
0070     QCOMPARE(consumed, 24);
0071 
0072     // NIL and emptiness tests
0073     input = R"(NIL "NIL" "")";
0074 
0075     // unquoted NIL
0076     consumed = ImapParser::parseQuotedString(input, result, 0);
0077     QVERIFY(result.isNull());
0078     QCOMPARE(consumed, 3);
0079 
0080     // quoted NIL
0081     consumed = ImapParser::parseQuotedString(input, result, 3);
0082     QCOMPARE(result, QByteArray("NIL"));
0083     QCOMPARE(consumed, 9);
0084 
0085     // quoted empty string
0086     consumed = ImapParser::parseQuotedString(input, result, 9);
0087     QCOMPARE(result, QByteArray(""));
0088     QCOMPARE(consumed, 12);
0089 
0090     // unquoted string at input end
0091     input = "some string";
0092     consumed = ImapParser::parseQuotedString(input, result, 4);
0093     QCOMPARE(result, QByteArray("string"));
0094     QCOMPARE(consumed, 11);
0095 
0096     // out of bounds access
0097     consumed = ImapParser::parseQuotedString(input, result, input.length());
0098     QVERIFY(result.isEmpty());
0099     QCOMPARE(consumed, input.length());
0100 
0101     // de-quoting
0102     input = R"("\"some \\ quoted stuff\"")";
0103     consumed = ImapParser::parseQuotedString(input, result, 0);
0104     QCOMPARE(result, QByteArray("\"some \\ quoted stuff\""));
0105     QCOMPARE(consumed, input.length());
0106 
0107     // linebreak as separator
0108     input = "LOGOUT\nFOO";
0109     consumed = ImapParser::parseQuotedString(input, result, 0);
0110     QCOMPARE(result, QByteArray("LOGOUT"));
0111     QCOMPARE(consumed, 6);
0112 }
0113 
0114 void ImapParserTest::testParseString()
0115 {
0116     QByteArray input = "\"quoted\" unquoted {7}\nliteral {0}\n empty literal";
0117     QByteArray result;
0118     int consumed;
0119 
0120     // quoted strings
0121     consumed = ImapParser::parseString(input, result, 0);
0122     QCOMPARE(result, QByteArray("quoted"));
0123     QCOMPARE(consumed, 8);
0124 
0125     // unquoted string
0126     consumed = ImapParser::parseString(input, result, 8);
0127     QCOMPARE(result, QByteArray("unquoted"));
0128     QCOMPARE(consumed, 17);
0129 
0130     // literal string
0131     consumed = ImapParser::parseString(input, result, 17);
0132     QCOMPARE(result, QByteArray("literal"));
0133     QCOMPARE(consumed, 29);
0134 
0135     // empty literal string
0136     consumed = ImapParser::parseString(input, result, 29);
0137     QCOMPARE(result, QByteArray(""));
0138     QCOMPARE(consumed, 34);
0139 
0140     // out of bounds access
0141     consumed = ImapParser::parseString(input, result, input.length());
0142     QCOMPARE(result, QByteArray());
0143     QCOMPARE(consumed, input.length());
0144 }
0145 
0146 void ImapParserTest::testParseParenthesizedList_data()
0147 {
0148     QTest::addColumn<QByteArray>("input");
0149     QTest::addColumn<QList<QByteArray>>("result");
0150     QTest::addColumn<int>("consumed");
0151 
0152     QList<QByteArray> reference;
0153 
0154     QTest::newRow("null") << QByteArray() << reference << 0;
0155     QTest::newRow("empty") << QByteArray("()") << reference << 2;
0156     QTest::newRow("empty with space") << QByteArray(" ( )") << reference << 4;
0157     QTest::newRow("no list") << QByteArray("some list-less text") << reference << 0;
0158     QTest::newRow("\n") << QByteArray() << reference << 0;
0159 
0160     reference << "entry1";
0161     reference << "entry2()";
0162     reference << "(sub list)";
0163     reference << ")))";
0164     reference << "entry3";
0165     QTest::newRow("complex") << QByteArray("(entry1 \"entry2()\" (sub list) \")))\" {6}\nentry3) end") << reference << 47;
0166 
0167     reference.clear();
0168     reference << "foo";
0169     reference << "\n\nbar\n";
0170     reference << "bla";
0171     QTest::newRow("newline literal") << QByteArray("(foo {6}\n\n\nbar\n bla)") << reference << 20;
0172 
0173     reference.clear();
0174     reference << "partid";
0175     reference << "body";
0176     QTest::newRow("CRLF literal separator") << QByteArray("(partid {4}\r\nbody)") << reference << 18;
0177 
0178     reference.clear();
0179     reference << "partid";
0180     reference << "\n\rbody\n\r";
0181     QTest::newRow("CRLF literal separator 2") << QByteArray("(partid {8}\r\n\n\rbody\n\r)") << reference << 22;
0182 
0183     reference.clear();
0184     reference << "NAME";
0185     reference << "net)";
0186     QTest::newRow("spurious newline") << QByteArray("(NAME \"net)\"\n)") << reference << 14;
0187 
0188     reference.clear();
0189     reference << "(42 \"net)\")";
0190     reference << "(0 \"\")";
0191     QTest::newRow("list of lists") << QByteArray("((42 \"net)\") (0 \"\"))") << reference << 20;
0192 }
0193 
0194 void ImapParserTest::testParseParenthesizedList()
0195 {
0196     QFETCH(QByteArray, input);
0197     QFETCH(QList<QByteArray>, result);
0198     QFETCH(int, consumed);
0199 
0200     QList<QByteArray> realResult;
0201 
0202     int reallyConsumed = ImapParser::parseParenthesizedList(input, realResult, 0);
0203     QCOMPARE(realResult, result);
0204     QCOMPARE(reallyConsumed, consumed);
0205 
0206     // briefly also test the other overload
0207     QVarLengthArray<QByteArray, 16> realVLAResult;
0208     reallyConsumed = ImapParser::parseParenthesizedList(input, realVLAResult, 0);
0209     QCOMPARE(reallyConsumed, consumed);
0210 
0211     // newline literal (based on itemappendtest bug)
0212     input = "(foo {6}\n\n\nbar\n bla)";
0213     ImapParser::parseParenthesizedList(input, result);
0214 }
0215 
0216 void ImapParserTest::testParseNumber()
0217 {
0218     QByteArray input = " 1a23.4";
0219     qint64 result;
0220     int pos;
0221     bool ok;
0222 
0223     // empty string
0224     pos = ImapParser::parseNumber(QByteArray(), result, &ok);
0225     QCOMPARE(ok, false);
0226     QCOMPARE(pos, 0);
0227 
0228     // leading spaces at the beginning
0229     pos = ImapParser::parseNumber(input, result, &ok, 0);
0230     QCOMPARE(ok, true);
0231     QCOMPARE(pos, 2);
0232     QCOMPARE(result, 1LL);
0233 
0234     // multiple digits
0235     pos = ImapParser::parseNumber(input, result, &ok, 3);
0236     QCOMPARE(ok, true);
0237     QCOMPARE(pos, 5);
0238     QCOMPARE(result, 23LL);
0239 
0240     // number at input end
0241     pos = ImapParser::parseNumber(input, result, &ok, 6);
0242     QCOMPARE(ok, true);
0243     QCOMPARE(pos, 7);
0244     QCOMPARE(result, 4LL);
0245 
0246     // out of bounds access
0247     pos = ImapParser::parseNumber(input, result, &ok, input.length());
0248     QCOMPARE(ok, false);
0249     QCOMPARE(pos, input.length());
0250 }
0251 
0252 void ImapParserTest::testQuote_data()
0253 {
0254     QTest::addColumn<QByteArray>("unquoted");
0255     QTest::addColumn<QByteArray>("quoted");
0256 
0257     QTest::newRow("empty") << QByteArray("") << QByteArray("\"\"");
0258     QTest::newRow("simple") << QByteArray("bla") << QByteArray("\"bla\"");
0259     QTest::newRow("double-quotes") << QByteArray(R"("test"test")") << QByteArray(R"("\"test\"test\"")");
0260     QTest::newRow("backslash") << QByteArray("\\") << QByteArray(R"("\\")");
0261     QByteArray binaryNonEncoded;
0262     binaryNonEncoded += '\000';
0263     QByteArray binaryEncoded("\"");
0264     binaryEncoded += '\000';
0265     binaryEncoded += '"';
0266     QTest::newRow("binary") << binaryNonEncoded << binaryEncoded;
0267 
0268     QTest::newRow("LF") << QByteArray("\n") << QByteArray(R"("\n")");
0269     QTest::newRow("CR") << QByteArray("\r") << QByteArray(R"("\r")");
0270     QTest::newRow("double quote") << QByteArray("\"") << QByteArray(R"("\"")");
0271     QTest::newRow("mixed 1") << QByteArray("a\nb\\c") << QByteArray(R"("a\nb\\c")");
0272     QTest::newRow("mixed 2") << QByteArray("\"a\rb\"") << QByteArray(R"("\"a\rb\"")");
0273 }
0274 
0275 void ImapParserTest::testQuote()
0276 {
0277     QFETCH(QByteArray, unquoted);
0278     QFETCH(QByteArray, quoted);
0279     QCOMPARE(ImapParser::quote(unquoted), quoted);
0280 }
0281 
0282 void ImapParserTest::testMessageParser_data()
0283 {
0284     QTest::addColumn<QList<QByteArray>>("input");
0285     QTest::addColumn<QByteArray>("tag");
0286     QTest::addColumn<QByteArray>("data");
0287     QTest::addColumn<bool>("complete");
0288     QTest::addColumn<QList<int>>("continuations");
0289 
0290     QList<QByteArray> input;
0291     QList<int> continuations;
0292     QTest::newRow("empty") << input << QByteArray() << QByteArray() << false << continuations;
0293 
0294     input << "*";
0295     QTest::newRow("tag-only") << input << QByteArray("*") << QByteArray() << true << continuations;
0296 
0297     input.clear();
0298     input << "20 UID FETCH (foo)";
0299     QTest::newRow("simple") << input << QByteArray("20") << QByteArray("UID FETCH (foo)") << true << continuations;
0300 
0301     input.clear();
0302     input << "1 (bla ("
0303           << ") blub)";
0304     QTest::newRow("parenthesis") << input << QByteArray("1") << QByteArray("(bla () blub)") << true << continuations;
0305 
0306     input.clear();
0307     input << "1 {3}"
0308           << "bla";
0309     continuations << 0;
0310     QTest::newRow("literal") << input << QByteArray("1") << QByteArray("{3}bla") << true << continuations;
0311 
0312     input.clear();
0313     input << "1 FETCH (UID 5 DATA {3}"
0314           << "bla"
0315           << " RID 5)";
0316     QTest::newRow("parenthesisEnclosedLiteral") << input << QByteArray("1") << QByteArray("FETCH (UID 5 DATA {3}bla RID 5)") << true << continuations;
0317 
0318     input.clear();
0319     input << "1 {3}"
0320           << "bla {4}"
0321           << "blub";
0322     continuations.clear();
0323     continuations << 0 << 1;
0324     QTest::newRow("2literal") << input << QByteArray("1") << QByteArray("{3}bla {4}blub") << true << continuations;
0325 
0326     input.clear();
0327     input << "1 {4}"
0328           << "A{9}";
0329     continuations.clear();
0330     continuations << 0;
0331     QTest::newRow("literal in literal") << input << QByteArray("1") << QByteArray("{4}A{9}") << true << continuations;
0332 
0333     input.clear();
0334     input << "* FETCH (UID 1 DATA {3}"
0335           << "bla"
0336           << " ENVELOPE {4}"
0337           << "blub"
0338           << " RID 5)";
0339     continuations.clear();
0340     continuations << 0 << 2;
0341     QTest::newRow("enclosed2literal") << input << QByteArray("*") << QByteArray("FETCH (UID 1 DATA {3}bla ENVELOPE {4}blub RID 5)") << true << continuations;
0342 
0343     input.clear();
0344     input << "1 DATA {0}";
0345     continuations.clear();
0346     QTest::newRow("empty literal") << input << QByteArray("1") << QByteArray("DATA {0}") << true << continuations;
0347 }
0348 
0349 void ImapParserTest::testMessageParser()
0350 {
0351     QFETCH(QList<QByteArray>, input);
0352     QFETCH(QByteArray, tag);
0353     QFETCH(QByteArray, data);
0354     QFETCH(bool, complete);
0355     QFETCH(QList<int>, continuations);
0356     QList<int> cont = continuations;
0357 
0358     auto parser = new ImapParser();
0359     QVERIFY(parser->tag().isEmpty());
0360     QVERIFY(parser->data().isEmpty());
0361 
0362     for (int i = 0; i < input.count(); ++i) {
0363         bool res = parser->parseNextLine(input.at(i));
0364         if (i != input.count() - 1) {
0365             QVERIFY(!res);
0366         } else {
0367             QCOMPARE(res, complete);
0368         }
0369         if (parser->continuationStarted()) {
0370             QVERIFY(cont.contains(i));
0371             cont.removeAll(i);
0372         }
0373     }
0374 
0375     QCOMPARE(parser->tag(), tag);
0376     QCOMPARE(parser->data(), data);
0377     QVERIFY(cont.isEmpty());
0378 
0379     // try again, this time with a not fresh parser
0380     parser->reset();
0381     QVERIFY(parser->tag().isEmpty());
0382     QVERIFY(parser->data().isEmpty());
0383     cont = continuations;
0384 
0385     for (int i = 0; i < input.count(); ++i) {
0386         bool res = parser->parseNextLine(input.at(i));
0387         if (i != input.count() - 1) {
0388             QVERIFY(!res);
0389         } else {
0390             QCOMPARE(res, complete);
0391         }
0392         if (parser->continuationStarted()) {
0393             QVERIFY(cont.contains(i));
0394             cont.removeAll(i);
0395         }
0396     }
0397 
0398     QCOMPARE(parser->tag(), tag);
0399     QCOMPARE(parser->data(), data);
0400     QVERIFY(cont.isEmpty());
0401 
0402     delete parser;
0403 }
0404 
0405 void ImapParserTest::testParseSequenceSet_data()
0406 {
0407     QTest::addColumn<QByteArray>("data");
0408     QTest::addColumn<int>("begin");
0409     QTest::addColumn<ImapInterval::List>("result");
0410     QTest::addColumn<int>("end");
0411 
0412     QByteArray data(" 1 0:* 3:4,8:* *:5,1");
0413 
0414     QTest::newRow("empty") << QByteArray() << 0 << ImapInterval::List() << 0;
0415     QTest::newRow("input end") << data << 20 << ImapInterval::List() << 20;
0416 
0417     ImapInterval::List result;
0418     result << ImapInterval(1, 1);
0419     QTest::newRow("single value 1") << data << 0 << result << 2;
0420     QTest::newRow("single value 2") << data << 1 << result << 2;
0421     QTest::newRow("single value 3") << data << 19 << result << 20;
0422 
0423     result.clear();
0424     result << ImapInterval();
0425     QTest::newRow("full interval") << data << 2 << result << 6;
0426 
0427     result.clear();
0428     result << ImapInterval(3, 4) << ImapInterval(8);
0429     QTest::newRow("complex 1") << data << 7 << result << 14;
0430 
0431     result.clear();
0432     result << ImapInterval(0, 5) << ImapInterval(1, 1);
0433     QTest::newRow("complex 2") << data << 14 << result << 20;
0434 }
0435 
0436 void ImapParserTest::testParseSequenceSet()
0437 {
0438     QFETCH(QByteArray, data);
0439     QFETCH(int, begin);
0440     QFETCH(ImapInterval::List, result);
0441     QFETCH(int, end);
0442 
0443     ImapSet res;
0444     int pos = ImapParser::parseSequenceSet(data, res, begin);
0445     QCOMPARE(res.intervals(), result);
0446     QCOMPARE(pos, end);
0447 }
0448 
0449 void ImapParserTest::testParseDateTime_data()
0450 {
0451     QTest::addColumn<QByteArray>("data");
0452     QTest::addColumn<int>("begin");
0453     QTest::addColumn<QDateTime>("result");
0454     QTest::addColumn<int>("end");
0455 
0456     QTest::newRow("empty") << QByteArray() << 0 << QDateTime() << 0;
0457 
0458     QByteArray data(" \"28-May-2006 01:03:35 +0200\"");
0459     QByteArray data2("22-Jul-2008 16:31:48 +0000");
0460 
0461     QDateTime dt(QDate(2006, 5, 27), QTime(23, 3, 35), QTimeZone::UTC);
0462     QDateTime dt2(QDate(2008, 7, 22), QTime(16, 31, 48), QTimeZone::UTC);
0463 
0464     QTest::newRow("quoted 1") << data << 0 << dt << 29;
0465     QTest::newRow("quoted 2") << data << 1 << dt << 29;
0466     QTest::newRow("unquoted") << data << 2 << dt << 28;
0467     QTest::newRow("unquoted2") << data2 << 0 << dt2 << 26;
0468     QTest::newRow("invalid") << data << 4 << QDateTime() << 4;
0469 }
0470 
0471 void ImapParserTest::testParseDateTime()
0472 {
0473     QFETCH(QByteArray, data);
0474     QFETCH(int, begin);
0475     QFETCH(QDateTime, result);
0476     QFETCH(int, end);
0477 
0478     QDateTime actualResult;
0479     int actualEnd = ImapParser::parseDateTime(data, actualResult, begin);
0480     QCOMPARE(actualResult, result);
0481     QCOMPARE(actualEnd, end);
0482 }
0483 
0484 void ImapParserTest::testBulkParser_data()
0485 {
0486     QTest::addColumn<QByteArray>("input");
0487     QTest::addColumn<QByteArray>("data");
0488 
0489     QTest::newRow("empty") << QByteArray("* PRE {0} POST\n") << QByteArray("PRE {0} POST\n");
0490     QTest::newRow("small block") << QByteArray("* PRE {2}\nXX POST\n") << QByteArray("PRE {2}\nXX POST\n");
0491     QTest::newRow("small block 2") << QByteArray("* (PRE {2}\nXX\n POST)\n") << QByteArray("(PRE {2}\nXX\n POST)\n");
0492     QTest::newRow("large block") << QByteArray("* PRE {10}\n0123456789\n") << QByteArray("PRE {10}\n0123456789\n");
0493     QTest::newRow("store failure") << QByteArray("3 UID STORE (FOO bar ENV {3}\n(a) HEAD {3}\na\n\n BODY {3}\nabc)\n")
0494                                    << QByteArray("UID STORE (FOO bar ENV {3}\n(a) HEAD {3}\na\n\n BODY {3}\nabc)\n");
0495 }
0496 
0497 void ImapParserTest::testBulkParser()
0498 {
0499     QFETCH(QByteArray, input);
0500     QFETCH(QByteArray, data);
0501 
0502     auto parser = new ImapParser();
0503     QBuffer buffer;
0504     buffer.setData(input);
0505     QVERIFY(buffer.open(QBuffer::ReadOnly));
0506 
0507     // reading continuation as a single block
0508     for (;;) {
0509         if (buffer.atEnd()) {
0510             break;
0511         }
0512         if (parser->continuationSize() > 0) {
0513             parser->parseBlock(buffer.read(parser->continuationSize()));
0514         } else if (buffer.canReadLine()) {
0515             const QByteArray line = buffer.readLine();
0516             bool res = parser->parseNextLine(line);
0517             QCOMPARE(res, buffer.atEnd());
0518         }
0519     }
0520     QCOMPARE(parser->data(), data);
0521 
0522     // reading continuations as smaller blocks
0523     buffer.reset();
0524     parser->reset();
0525     for (;;) {
0526         if (buffer.atEnd()) {
0527             break;
0528         }
0529         if (parser->continuationSize() > 4) {
0530             parser->parseBlock(buffer.read(4));
0531         } else if (parser->continuationSize() > 0) {
0532             parser->parseBlock(buffer.read(parser->continuationSize()));
0533         } else if (buffer.canReadLine()) {
0534             bool res = parser->parseNextLine(buffer.readLine());
0535             QCOMPARE(res, buffer.atEnd());
0536         }
0537     }
0538 
0539     delete parser;
0540 }
0541 
0542 void ImapParserTest::testJoin_data()
0543 {
0544     QTest::addColumn<QList<QByteArray>>("list");
0545     QTest::addColumn<QByteArray>("joined");
0546     QTest::newRow("empty") << QList<QByteArray>() << QByteArray();
0547     QTest::newRow("one") << (QList<QByteArray>() << "abab") << QByteArray("abab");
0548     QTest::newRow("two") << (QList<QByteArray>() << "abab"
0549                                                  << "cdcd")
0550                          << QByteArray("abab cdcd");
0551     QTest::newRow("three") << (QList<QByteArray>() << "abab"
0552                                                    << "cdcd"
0553                                                    << "efef")
0554                            << QByteArray("abab cdcd efef");
0555 }
0556 
0557 void ImapParserTest::testJoin()
0558 {
0559     QFETCH(QList<QByteArray>, list);
0560     QFETCH(QByteArray, joined);
0561     QCOMPARE(ImapParser::join(list, " "), joined);
0562 }
0563 
0564 void ImapParserTest::benchParseQuotedString_data()
0565 {
0566     QTest::addColumn<QByteArray>("data");
0567     QTest::addColumn<QByteArray>("expectedResult");
0568     QTest::addColumn<int>("expectedConsumed");
0569 
0570     QTest::newRow("quoted") << QByteArray("\"foo bar asdf\"") << QByteArray("foo bar asdf") << 14;
0571     QTest::newRow("unquoted") << QByteArray("foo bar asdf") << QByteArray("foo") << 3;
0572 }
0573 
0574 void ImapParserTest::benchParseQuotedString()
0575 {
0576     QFETCH(QByteArray, data);
0577     QFETCH(QByteArray, expectedResult);
0578     QFETCH(int, expectedConsumed);
0579 
0580     QByteArray result;
0581     QBENCHMARK {
0582         int consumed = ImapParser::parseQuotedString(data, result, 0);
0583         // use data, to prevent it from getting optimized away
0584         if (consumed != expectedConsumed || result != expectedResult) {
0585             // NOTE: don't use QCOMPARE in the outer hot loop, it's quite slow
0586             //       just do it when something fails
0587             QCOMPARE(result, expectedResult);
0588             QCOMPARE(consumed, expectedConsumed);
0589         }
0590     }
0591 }
0592 
0593 #include "moc_imapparsertest.cpp"