tests/auto/qversitreader/tst_qversitreader.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "tst_qversitreader.h"
       
    43 #include "qversitreader.h"
       
    44 #include "qversitproperty.h"
       
    45 #ifdef QT_BUILD_INTERNAL
       
    46 #include "qversitreader_p.h"
       
    47 #include "versitutils_p.h"
       
    48 #endif
       
    49 #include <QtTest/QtTest>
       
    50 #include <QSignalSpy>
       
    51 
       
    52 // Copied from tst_qcontactmanager.cpp
       
    53 // Waits until __expr is true and fails if it doesn't happen within 5s.
       
    54 #ifndef QTRY_VERIFY
       
    55 #define QTRY_VERIFY(__expr) \
       
    56         do { \
       
    57         const int __step = 50; \
       
    58         const int __timeout = 5000; \
       
    59         if (!(__expr)) { \
       
    60             QTest::qWait(0); \
       
    61         } \
       
    62         for (int __i = 0; __i < __timeout && !(__expr); __i+=__step) { \
       
    63             QTest::qWait(__step); \
       
    64         } \
       
    65         QVERIFY(__expr); \
       
    66     } while(0)
       
    67 #endif
       
    68 
       
    69 // This says "NOKIA" in Katakana encoded with UTF-8
       
    70 const QByteArray KATAKANA_NOKIA("\xe3\x83\x8e\xe3\x82\xad\xe3\x82\xa2");
       
    71 
       
    72 const static QByteArray SAMPLE_GIF_BASE64(QByteArray(
       
    73         "R0lGODlhEgASAIAAAAAAAP///yH5BAEAAAEALAAAAAASABIAAAIdjI+py+0G"
       
    74         "wEtxUmlPzRDnzYGfN3KBaKGT6rDmGxQAOw=="));
       
    75 
       
    76 const static QByteArray SAMPLE_GIF(QByteArray::fromBase64(SAMPLE_GIF_BASE64));
       
    77 
       
    78 Q_DECLARE_METATYPE(QVersitDocument::VersitType);
       
    79 Q_DECLARE_METATYPE(QVersitProperty);
       
    80 
       
    81 QTM_USE_NAMESPACE
       
    82 
       
    83 void tst_QVersitReader::init()
       
    84 {
       
    85     mInputDevice = new QBuffer;
       
    86     mInputDevice->open(QBuffer::ReadWrite);
       
    87     mReader = new QVersitReader;
       
    88 #ifdef QT_BUILD_INTERNAL    
       
    89     mReaderPrivate = new QVersitReaderPrivate;
       
    90 #endif
       
    91     mSignalCatcher = new SignalCatcher;
       
    92     connect(mReader, SIGNAL(stateChanged(QVersitReader::State)),
       
    93             mSignalCatcher, SLOT(stateChanged(QVersitReader::State)));
       
    94     connect(mReader, SIGNAL(resultsAvailable()),
       
    95             mSignalCatcher, SLOT(resultsAvailable()));
       
    96     mAsciiCodec = QTextCodec::codecForName("ISO 8859-1");
       
    97 }
       
    98 
       
    99 void tst_QVersitReader::cleanup()
       
   100 {
       
   101 #ifdef QT_BUILD_INTERNAL
       
   102     delete mReaderPrivate;
       
   103 #endif
       
   104     delete mReader;
       
   105     delete mInputDevice;
       
   106     delete mSignalCatcher;
       
   107 }
       
   108 
       
   109 void tst_QVersitReader::testDevice()
       
   110 {
       
   111     // No device
       
   112     QVERIFY(mReader->device() == NULL);
       
   113 
       
   114     // Device has been set
       
   115     mReader->setDevice(mInputDevice);
       
   116     QVERIFY(mReader->device() == mInputDevice);
       
   117 
       
   118     delete mInputDevice;
       
   119     QVERIFY(mReader->device() == NULL);
       
   120 
       
   121     mInputDevice = new QBuffer;
       
   122     mInputDevice->open(QBuffer::ReadWrite);
       
   123 
       
   124     QVERIFY(mReader->device() == NULL);
       
   125     mReader->setDevice(mInputDevice);
       
   126     QVERIFY(mReader->device() == mInputDevice);
       
   127 }
       
   128 
       
   129 void tst_QVersitReader::testDefaultCodec()
       
   130 {
       
   131     QVERIFY(mReader->defaultCodec() == QTextCodec::codecForName("UTF-8"));
       
   132     mReader->setDefaultCodec(QTextCodec::codecForName("UTF-16BE"));
       
   133     QVERIFY(mReader->defaultCodec() == QTextCodec::codecForName("UTF-16BE"));
       
   134 }
       
   135 
       
   136 
       
   137 void tst_QVersitReader::testReading()
       
   138 {
       
   139     // No I/O device set
       
   140     QVERIFY(!mReader->startReading());
       
   141     QCOMPARE(mReader->error(), QVersitReader::IOError);
       
   142 
       
   143     // Device set, no data
       
   144     mReader->setDevice(mInputDevice);
       
   145     mInputDevice->open(QBuffer::ReadOnly);
       
   146     QVERIFY(mReader->startReading());
       
   147     QVERIFY(mReader->waitForFinished());
       
   148     QList<QVersitDocument> results(mReader->results());
       
   149     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   150     QCOMPARE(mReader->error(), QVersitReader::NoError);
       
   151     QCOMPARE(results.count(),0);
       
   152 
       
   153     // Device set, one document
       
   154     const QByteArray& oneDocument =
       
   155         "BEGIN:VCARD\r\nVERSION:2.1\r\nFN:John\r\nEND:VCARD\r\n";
       
   156     mInputDevice->close();
       
   157     mInputDevice->setData(oneDocument);
       
   158     mInputDevice->open(QBuffer::ReadOnly);
       
   159     mInputDevice->seek(0);
       
   160     QVERIFY(mReader->startReading());
       
   161     QVERIFY(mReader->waitForFinished());
       
   162     results = mReader->results();
       
   163     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   164     QCOMPARE(mReader->error(), QVersitReader::NoError);
       
   165     QCOMPARE(results.count(),1);
       
   166 
       
   167     // Wide charset with no byte-order mark
       
   168     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
   169     QTextCodec::ConverterState converterState(QTextCodec::IgnoreHeader);
       
   170     QString document = QString::fromAscii("BEGIN:VCARD\r\nVERSION:2.1\r\nFN:John\r\nEND:VCARD\r\n");
       
   171     const QByteArray& wideDocument =
       
   172         codec->fromUnicode(document.data(), document.length(), &converterState);
       
   173     mInputDevice->close();
       
   174     mInputDevice->setData(wideDocument);
       
   175     mInputDevice->open(QBuffer::ReadOnly);
       
   176     mInputDevice->seek(0);
       
   177     mReader->setDefaultCodec(codec);
       
   178     QVERIFY(mReader->startReading());
       
   179     QVERIFY(mReader->waitForFinished());
       
   180     results = mReader->results();
       
   181     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   182     QCOMPARE(mReader->error(), QVersitReader::NoError);
       
   183     QCOMPARE(mReader->results().count(),1);
       
   184     mReader->setDefaultCodec(NULL);
       
   185 
       
   186     // Two documents
       
   187     const QByteArray& twoDocuments =
       
   188         " \r\n BEGIN:VCARD\r\nFN:Jenny\r\nEND:VCARD\r\nBEGIN:VCARD\r\nFN:Jake\r\nEND:VCARD\r\n";
       
   189     mInputDevice->close();
       
   190     mInputDevice->setData(twoDocuments);
       
   191     mInputDevice->open(QBuffer::ReadOnly);
       
   192     mInputDevice->seek(0);
       
   193     QVERIFY(mReader->startReading());
       
   194     QVERIFY(mReader->waitForFinished());
       
   195     results = mReader->results();
       
   196     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   197     QCOMPARE(mReader->error(), QVersitReader::NoError);
       
   198     QCOMPARE(results.count(),2);
       
   199 
       
   200     // Erroneous document (missing property name)
       
   201     mInputDevice->close();
       
   202     mInputDevice->setData(QByteArray(
       
   203             "BEGIN:VCARD\r\nFN:Jenny\r\n;Jenny;;;\r\nEND:VCARD\r\n"
       
   204             "BEGIN:VCARD\r\nFN:Jake\r\nEND:VCARD\r\n"));
       
   205     mInputDevice->open(QBuffer::ReadOnly);
       
   206     mInputDevice->seek(0);
       
   207     QVERIFY(mReader->startReading());
       
   208     QVERIFY(mReader->waitForFinished());
       
   209     results = mReader->results();
       
   210     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   211     QCOMPARE(mReader->error(), QVersitReader::ParseError);
       
   212     QCOMPARE(results.count(), 1);
       
   213 
       
   214     // Valid documents and a grouped document between them
       
   215     const QByteArray& validDocumentsAndGroupedDocument =
       
   216 "BEGIN:VCARD\r\nFN:Jenny\r\nEND:VCARD\r\n\
       
   217 BEGIN:VCARD\r\n\
       
   218 X-GROUPING:pub gang\r\n\
       
   219 BEGIN:VCARD\r\nFN:Jeremy\r\nEND:VCARD\r\n\
       
   220 BEGIN:VCARD\r\nFN:Jeffery\r\nEND:VCARD\r\n\
       
   221 END:VCARD\r\n\
       
   222 BEGIN:VCARD\r\nFN:Jake\r\nEND:VCARD\r\n\
       
   223 BEGIN:VCARD\r\nFN:James\r\nEND:VCARD\r\n\
       
   224 BEGIN:VCARD\r\nFN:Jane\r\nEND:VCARD\r\n";
       
   225     mInputDevice->close();
       
   226     mInputDevice->setData(validDocumentsAndGroupedDocument);
       
   227     mInputDevice->open(QBuffer::ReadWrite);
       
   228     mInputDevice->seek(0);
       
   229     QVERIFY(mReader->startReading());
       
   230     QVERIFY(mReader->waitForFinished());
       
   231     results = mReader->results();
       
   232     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   233     // An error is logged because one failed, but the rest are readable.
       
   234     QCOMPARE(mReader->error(), QVersitReader::ParseError);
       
   235     QCOMPARE(results.count(),4);
       
   236 
       
   237     // Valid documents and a grouped document between them
       
   238     const QByteArray& validDocumentsAndGroupedDocument2 =
       
   239 "BEGIN:VCARD\r\nFN:Jenny\r\nEND:VCARD\r\n\
       
   240 BEGIN:VCARD\r\n\
       
   241 X-GROUPING:pub gang\r\n\
       
   242 BEGIN:VCARD\r\nFN:Jeremy\r\nEND:VCARD\r\n\
       
   243 BEGIN:VCARD\r\nFN:Jeffery\r\nEND:VCARD\r\n\
       
   244 END:VCARD\r\n\
       
   245 BEGIN:VCARD\r\nFN:Jake\r\nEND:VCARD\r\n\
       
   246 BEGIN:VCARD\r\nFN:James\r\nEND:VCARD\r\n\
       
   247 BEGIN:VCARD\r\nFN:Jane\r\nEND:VCARD";
       
   248     mInputDevice->close();
       
   249     mInputDevice->setData(validDocumentsAndGroupedDocument2);
       
   250     mInputDevice->open(QBuffer::ReadWrite);
       
   251     mInputDevice->seek(0);
       
   252     QVERIFY(mReader->startReading());
       
   253     QVERIFY(mReader->waitForFinished());
       
   254     results = mReader->results();
       
   255     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
   256     // An error is logged because one failed, but the rest are readable.
       
   257     QCOMPARE(mReader->error(), QVersitReader::ParseError);
       
   258     QCOMPARE(mReader->results().count(),4);
       
   259 
       
   260     qApp->processEvents(); // clean up before we start sniffing signals
       
   261 
       
   262     // Asynchronous reading
       
   263     mInputDevice->close();
       
   264     mInputDevice->setData(twoDocuments);
       
   265     mInputDevice->open(QBuffer::ReadWrite);
       
   266     mInputDevice->seek(0);
       
   267     mSignalCatcher->mStateChanges.clear();
       
   268     mSignalCatcher->mResultsCount = 0;
       
   269     QVERIFY(mReader->startReading());
       
   270     QTRY_VERIFY(mSignalCatcher->mStateChanges.count() >= 2);
       
   271     QCOMPARE(mSignalCatcher->mStateChanges.at(0), QVersitReader::ActiveState);
       
   272     QCOMPARE(mSignalCatcher->mStateChanges.at(1), QVersitReader::FinishedState);
       
   273     QVERIFY(mSignalCatcher->mResultsCount >= 2);
       
   274     QCOMPARE(mReader->results().size(), 2);
       
   275     QCOMPARE(mReader->error(), QVersitReader::NoError);
       
   276 
       
   277     // Cancelling
       
   278     mInputDevice->close();
       
   279     mInputDevice->setData(twoDocuments);
       
   280     mInputDevice->open(QBuffer::ReadOnly);
       
   281     mInputDevice->seek(0);
       
   282     mSignalCatcher->mStateChanges.clear();
       
   283     mSignalCatcher->mResultsCount = 0;
       
   284     QVERIFY(mReader->startReading());
       
   285     mReader->cancel();
       
   286     mReader->waitForFinished();
       
   287     QTRY_VERIFY(mSignalCatcher->mStateChanges.count() >= 2);
       
   288     QCOMPARE(mSignalCatcher->mStateChanges.at(0), QVersitReader::ActiveState);
       
   289     QVersitReader::State state(mSignalCatcher->mStateChanges.at(1));
       
   290     // It's possible that it finishes before it cancels.
       
   291     QVERIFY(state == QVersitReader::CanceledState
       
   292             || state == QVersitReader::FinishedState);
       
   293 }
       
   294 
       
   295 void tst_QVersitReader::testResult()
       
   296 {
       
   297     QCOMPARE(mReader->results().count(),0);
       
   298 }
       
   299 
       
   300 void tst_QVersitReader::testSetVersionFromProperty()
       
   301 {
       
   302 #ifndef QT_BUILD_INTERNAL
       
   303     QSKIP("Testing private API", SkipSingle);
       
   304 #else
       
   305     QVersitDocument document;
       
   306 
       
   307     // Some other property than VERSION
       
   308     QVersitProperty property;
       
   309     property.setName(QString::fromAscii("N"));
       
   310     QVERIFY(mReaderPrivate->setVersionFromProperty(document,property));
       
   311 
       
   312     // VERSION property with 2.1
       
   313     property.setName(QString::fromAscii("VERSION"));
       
   314     property.setValue(QString::fromAscii("2.1"));
       
   315     QVERIFY(mReaderPrivate->setVersionFromProperty(document,property));
       
   316     QVERIFY(document.type() == QVersitDocument::VCard21Type);
       
   317 
       
   318     // VERSION property with 3.0
       
   319     property.setValue(QString::fromAscii("3.0"));
       
   320     QVERIFY(mReaderPrivate->setVersionFromProperty(document,property));
       
   321     QVERIFY(document.type() == QVersitDocument::VCard30Type);
       
   322 
       
   323     // VERSION property with a not supported value
       
   324     property.setValue(QString::fromAscii("4.0"));
       
   325     QVERIFY(!mReaderPrivate->setVersionFromProperty(document,property));
       
   326 
       
   327     // VERSION property with BASE64 encoded supported value
       
   328     property.setValue(QString::fromAscii(QByteArray("2.1").toBase64()));
       
   329     property.insertParameter(QString::fromAscii("ENCODING"),QString::fromAscii("BASE64"));
       
   330     QVERIFY(mReaderPrivate->setVersionFromProperty(document,property));
       
   331     QVERIFY(document.type() == QVersitDocument::VCard21Type);
       
   332 
       
   333     // VERSION property with BASE64 encoded not supported value
       
   334     property.setValue(QString::fromAscii(QByteArray("4.0").toBase64()));
       
   335     QVERIFY(!mReaderPrivate->setVersionFromProperty(document,property));
       
   336 #endif
       
   337 }
       
   338 
       
   339 void tst_QVersitReader::testParseNextVersitProperty()
       
   340 {
       
   341 #ifndef QT_BUILD_INTERNAL
       
   342     QSKIP("Testing private API", SkipSingle);
       
   343 #else
       
   344     QFETCH(QVersitDocument::VersitType, documentType);
       
   345     QFETCH(QByteArray, input);
       
   346     QFETCH(QVersitProperty, expectedProperty);
       
   347 
       
   348     QBuffer buffer(&input);
       
   349     buffer.open(QIODevice::ReadOnly);
       
   350     LineReader lineReader(&buffer, mAsciiCodec);
       
   351     QVersitProperty property = mReaderPrivate->parseNextVersitProperty(documentType, lineReader);
       
   352     if (property != expectedProperty) {
       
   353         // compare each part of the property separately for easier debugging
       
   354         QCOMPARE(property.groups(), expectedProperty.groups());
       
   355         QCOMPARE(property.name(), expectedProperty.name());
       
   356         QCOMPARE(property.valueType(), expectedProperty.valueType());
       
   357 
       
   358         // QVariant doesn't support == on QVersitDocuments - do it manually
       
   359         if (property.variantValue().userType() == qMetaTypeId<QVersitDocument>()) {
       
   360             QVERIFY(expectedProperty.variantValue().userType() == qMetaTypeId<QVersitDocument>());
       
   361             QCOMPARE(property.value<QVersitDocument>(), expectedProperty.value<QVersitDocument>());
       
   362         }
       
   363         else
       
   364             QCOMPARE(property.variantValue(), expectedProperty.variantValue());
       
   365 
       
   366         // Don't check parameters because the reader can add random parameters of its own (like CHARSET)
       
   367         // QCOMPARE(property.parameters(), expectedProperty.parameters());
       
   368     }
       
   369 #endif
       
   370 }
       
   371 
       
   372 void tst_QVersitReader::testParseNextVersitProperty_data()
       
   373 {
       
   374 #ifdef QT_BUILD_INTERNAL
       
   375     QTest::addColumn<QVersitDocument::VersitType>("documentType");
       
   376     QTest::addColumn<QByteArray>("input");
       
   377     QTest::addColumn<QVersitProperty>("expectedProperty");
       
   378 
       
   379     {
       
   380         QVersitProperty expectedProperty;
       
   381         expectedProperty.setName(QLatin1String("BEGIN"));
       
   382         expectedProperty.setValue(QLatin1String("vcard"));
       
   383         QTest::newRow("begin")
       
   384             << QVersitDocument::VCard21Type
       
   385             << QByteArray("Begin:vcard\r\n")
       
   386             << expectedProperty;
       
   387     }
       
   388 
       
   389     {
       
   390         QVersitProperty expectedProperty;
       
   391         expectedProperty.setName(QLatin1String("VERSION"));
       
   392         expectedProperty.setValue(QLatin1String("2.1"));
       
   393         expectedProperty.setValueType(QVersitProperty::PlainType);
       
   394         QTest::newRow("version")
       
   395             << QVersitDocument::VCard21Type
       
   396             << QByteArray("VERSION:2.1\r\n")
       
   397             << expectedProperty;
       
   398     }
       
   399 
       
   400     {
       
   401         QVersitProperty expectedProperty;
       
   402         expectedProperty.setName(QLatin1String("FN"));
       
   403         expectedProperty.setValue(QLatin1String("John"));
       
   404         expectedProperty.setValueType(QVersitProperty::PlainType);
       
   405         QTest::newRow("fn")
       
   406             << QVersitDocument::VCard21Type
       
   407             << QByteArray("FN:John\r\n")
       
   408             << expectedProperty;
       
   409     }
       
   410 
       
   411     {
       
   412         // "NOTE:\;\,\:\\"
       
   413         QVersitProperty expectedProperty;
       
   414         expectedProperty.setName(QLatin1String("NOTE"));
       
   415         expectedProperty.setValue(QLatin1String("\\;\\,\\:\\\\"));
       
   416         expectedProperty.setValueType(QVersitProperty::PlainType);
       
   417         QTest::newRow("vcard21 note")
       
   418             << QVersitDocument::VCard21Type
       
   419             << QByteArray("NOTE:\\;\\,\\:\\\\\r\n")
       
   420             << expectedProperty;
       
   421 
       
   422         expectedProperty.setValue(QLatin1String(";,:\\"));
       
   423         QTest::newRow("vcard30 note")
       
   424             << QVersitDocument::VCard30Type
       
   425             << QByteArray("NOTE:\\;\\,\\:\\\\\r\n")
       
   426             << expectedProperty;
       
   427     }
       
   428 
       
   429     {
       
   430         // "N:foo\;bar;foo\,bar;foo\:bar;foo\\bar;foo\\\;bar"
       
   431         QVersitProperty expectedProperty;
       
   432         expectedProperty.setName(QLatin1String("N"));
       
   433         QStringList components;
       
   434         components << QLatin1String("foo;bar")
       
   435             << QLatin1String("foo\\,bar")
       
   436             << QLatin1String("foo\\:bar")
       
   437             << QLatin1String("foo\\\\bar")
       
   438             << QLatin1String("foo\\\\;bar");
       
   439         expectedProperty.setValue(components);
       
   440         expectedProperty.setValueType(QVersitProperty::CompoundType);
       
   441         QTest::newRow("vcard21 n")
       
   442             << QVersitDocument::VCard21Type
       
   443             << QByteArray("N:foo\\;bar;foo\\,bar;foo\\:bar;foo\\\\bar;foo\\\\\\;bar\r\n")
       
   444             << expectedProperty;
       
   445 
       
   446         components.clear();
       
   447         components << QLatin1String("foo;bar")
       
   448             << QLatin1String("foo,bar")
       
   449             << QLatin1String("foo:bar")
       
   450             << QLatin1String("foo\\bar")
       
   451             << QLatin1String("foo\\;bar");
       
   452         expectedProperty.setValue(components);
       
   453         QTest::newRow("vcard30 n")
       
   454             << QVersitDocument::VCard30Type
       
   455             << QByteArray("N:foo\\;bar;foo\\,bar;foo\\:bar;foo\\\\bar;foo\\\\\\;bar\r\n")
       
   456             << expectedProperty;
       
   457     }
       
   458 
       
   459     {
       
   460         QVersitProperty expectedProperty;
       
   461         expectedProperty.setName(QLatin1String("ADR"));
       
   462         expectedProperty.setValue(QStringList(QString()));
       
   463         expectedProperty.setValueType(QVersitProperty::CompoundType);
       
   464         QTest::newRow("empty structured")
       
   465             << QVersitDocument::VCard21Type
       
   466             << QByteArray("ADR:\r\n")
       
   467             << expectedProperty;
       
   468     }
       
   469 
       
   470     {
       
   471         QVersitProperty expectedProperty;
       
   472         expectedProperty.setName(QLatin1String("X-CHILDREN"));
       
   473         expectedProperty.setValue(QStringList() << QLatin1String("Child1") << QLatin1String("Child2"));
       
   474         expectedProperty.setValueType(QVersitProperty::ListType);
       
   475         QTest::newRow("children")
       
   476             << QVersitDocument::VCard21Type
       
   477             << QByteArray("X-CHILDREN:Child1,Child2\r\n")
       
   478             << expectedProperty;
       
   479     }
       
   480 
       
   481     {
       
   482         // "NICKNAME:foo\;bar,foo\,bar,foo\:bar,foo\\bar,foo\\\,bar"
       
   483         QVersitProperty expectedProperty;
       
   484         expectedProperty.setName(QLatin1String("NICKNAME"));
       
   485         QStringList components;
       
   486         components << QLatin1String("foo\\;bar")
       
   487             << QLatin1String("foo,bar")
       
   488             << QLatin1String("foo\\:bar")
       
   489             << QLatin1String("foo\\\\bar")
       
   490             << QLatin1String("foo\\\\,bar");
       
   491         expectedProperty.setValue(components);
       
   492         expectedProperty.setValueType(QVersitProperty::ListType);
       
   493         QTest::newRow("vcard21 nickname")
       
   494             << QVersitDocument::VCard21Type
       
   495             << QByteArray("NICKNAME:foo\\;bar,foo\\,bar,foo\\:bar,foo\\\\bar,foo\\\\\\,bar\r\n")
       
   496             << expectedProperty;
       
   497 
       
   498         components.clear();
       
   499         components << QLatin1String("foo;bar")
       
   500             << QLatin1String("foo,bar")
       
   501             << QLatin1String("foo:bar")
       
   502             << QLatin1String("foo\\bar")
       
   503             << QLatin1String("foo\\,bar");
       
   504         expectedProperty.setValue(components);
       
   505         QTest::newRow("vcard30 nickname")
       
   506             << QVersitDocument::VCard30Type
       
   507             << QByteArray("NICKNAME:foo\\;bar,foo\\,bar,foo\\:bar,foo\\\\bar,foo\\\\\\,bar\r\n")
       
   508             << expectedProperty;
       
   509     }
       
   510 
       
   511     {
       
   512         // "CATEGORIES:foo\;bar,foo\,bar,foo\:bar,foo\\bar,foo\\\,bar"
       
   513         QVersitProperty expectedProperty;
       
   514         expectedProperty.setName(QLatin1String("CATEGORIES"));
       
   515         QStringList components;
       
   516         components << QLatin1String("foo\\;bar")
       
   517             << QLatin1String("foo,bar")
       
   518             << QLatin1String("foo\\:bar")
       
   519             << QLatin1String("foo\\\\bar")
       
   520             << QLatin1String("foo\\\\,bar");
       
   521         expectedProperty.setValue(components);
       
   522         expectedProperty.setValueType(QVersitProperty::ListType);
       
   523         QTest::newRow("vcard21 categories")
       
   524             << QVersitDocument::VCard21Type
       
   525             << QByteArray("CATEGORIES:foo\\;bar,foo\\,bar,foo\\:bar,foo\\\\bar,foo\\\\\\,bar\r\n")
       
   526             << expectedProperty;
       
   527 
       
   528         components.clear();
       
   529         components << QLatin1String("foo;bar")
       
   530             << QLatin1String("foo,bar")
       
   531             << QLatin1String("foo:bar")
       
   532             << QLatin1String("foo\\bar")
       
   533             << QLatin1String("foo\\,bar");
       
   534         expectedProperty.setValue(components);
       
   535         QTest::newRow("vcard30 categories")
       
   536             << QVersitDocument::VCard30Type
       
   537             << QByteArray("CATEGORIES:foo\\;bar,foo\\,bar,foo\\:bar,foo\\\\bar,foo\\\\\\,bar\r\n")
       
   538             << expectedProperty;
       
   539 
       
   540         // "CATEGORIES:foobar\\,foobar\\\\,foo\\\\\,bar"
       
   541         components.clear();
       
   542         components << QLatin1String("foobar\\")
       
   543             << QLatin1String("foobar\\\\")
       
   544             << QLatin1String("foo\\\\,bar");
       
   545         expectedProperty.setValue(components);
       
   546         QTest::newRow("vcard30 unescaping")
       
   547             << QVersitDocument::VCard30Type
       
   548             << QByteArray("CATEGORIES:foobar\\\\,foobar\\\\\\\\,foo\\\\\\\\\\,bar")
       
   549             << expectedProperty;
       
   550     }
       
   551 
       
   552     {
       
   553         QVersitProperty expectedProperty;
       
   554         expectedProperty.setName(QLatin1String("ORG"));
       
   555         expectedProperty.setValue(QString::fromUtf8(KATAKANA_NOKIA));
       
   556         expectedProperty.setValueType(QVersitProperty::CompoundType);
       
   557         QTest::newRow("org utf8")
       
   558             << QVersitDocument::VCard21Type
       
   559             << QByteArray("ORG;CHARSET=UTF-8:" + KATAKANA_NOKIA + "\r\n")
       
   560             << expectedProperty;
       
   561     }
       
   562 
       
   563     {
       
   564         QVersitProperty expectedProperty;
       
   565         expectedProperty.setName(QLatin1String("ORG"));
       
   566         expectedProperty.setValue(QString::fromUtf8(KATAKANA_NOKIA));
       
   567         expectedProperty.setValueType(QVersitProperty::CompoundType);
       
   568         QTest::newRow("vcard21 org utf8 qp")
       
   569             << QVersitDocument::VCard21Type
       
   570             << QByteArray("ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E3=83=8E=E3=82=AD=E3=82=A2\r\n")
       
   571             << expectedProperty;
       
   572         QTest::newRow("vcard30 org utf8 qp")
       
   573             << QVersitDocument::VCard30Type
       
   574             << QByteArray("ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E3=83=8E=E3=82=AD=E3=82=A2\r\n")
       
   575             << expectedProperty;
       
   576     }
       
   577 
       
   578     {
       
   579         QVersitProperty expectedProperty;
       
   580         expectedProperty.setName(QLatin1String("PHOTO"));
       
   581         expectedProperty.setValue(SAMPLE_GIF);
       
   582         expectedProperty.setValueType(QVersitProperty::BinaryType);
       
   583         QTest::newRow("vcard21 photo1")
       
   584             << QVersitDocument::VCard21Type
       
   585             << QByteArray("PHOTO;ENCODING=BASE64:") + SAMPLE_GIF_BASE64 + QByteArray("\r\n\r\n")
       
   586             << expectedProperty;
       
   587 
       
   588         QTest::newRow("vcard30 photo1")
       
   589             << QVersitDocument::VCard30Type
       
   590             << QByteArray("PHOTO;ENCODING=B:") + SAMPLE_GIF_BASE64 + QByteArray("\r\n\r\n")
       
   591             << expectedProperty;
       
   592 
       
   593     // Again, but without the explicit "ENCODING" parameter
       
   594         QTest::newRow("vcard21 photo2")
       
   595             << QVersitDocument::VCard21Type
       
   596             << QByteArray("PHOTO;BASE64:") + SAMPLE_GIF_BASE64 + QByteArray("\r\n\r\n")
       
   597             << expectedProperty;
       
   598 
       
   599         QTest::newRow("vcard30 photo2")
       
   600             << QVersitDocument::VCard30Type
       
   601             << QByteArray("PHOTO;B:") + SAMPLE_GIF_BASE64 + QByteArray("\r\n\r\n")
       
   602             << expectedProperty;
       
   603     }
       
   604 
       
   605     {
       
   606         QVersitProperty expectedProperty;
       
   607         expectedProperty.setGroups(QStringList() << QLatin1String("HOME") << QLatin1String("Springfield"));
       
   608         expectedProperty.setName(QLatin1String("EMAIL"));
       
   609         expectedProperty.setValue(QLatin1String("john.citizen@example.com"));
       
   610         expectedProperty.setValueType(QVersitProperty::PlainType);
       
   611         QTest::newRow("email qp")
       
   612             << QVersitDocument::VCard21Type
       
   613             << QByteArray("HOME.Springfield.EMAIL;Encoding=Quoted-Printable:john.citizen=40exam=\r\nple.com\r\n")
       
   614             << expectedProperty;
       
   615     }
       
   616 
       
   617     {
       
   618         QVersitDocument subDocument;
       
   619         subDocument.setType(QVersitDocument::VCard30Type);
       
   620         QVersitProperty subProperty;
       
   621         subProperty.setName(QLatin1String("FN"));
       
   622         subProperty.setValue(QLatin1String("Jenny"));
       
   623         subDocument.addProperty(subProperty);
       
   624 
       
   625         QVersitProperty expectedProperty;
       
   626         expectedProperty.setName(QLatin1String("AGENT"));
       
   627         expectedProperty.setValue(QVariant::fromValue(subDocument));
       
   628         expectedProperty.setValueType(QVersitProperty::VersitDocumentType);
       
   629         QTest::newRow("agent")
       
   630             << QVersitDocument::VCard21Type
       
   631             << QByteArray("AGENT:\r\nBEGIN:VCARD\r\nFN:Jenny\r\nEND:VCARD\r\n\r\n")
       
   632             << expectedProperty;
       
   633     }
       
   634 #endif
       
   635 }
       
   636 
       
   637 void tst_QVersitReader::testParseVersitDocument()
       
   638 {
       
   639 #ifndef QT_BUILD_INTERNAL
       
   640     QSKIP("Testing private API", SkipSingle);
       
   641 #else
       
   642     QFETCH(QByteArray, vCard);
       
   643     QFETCH(bool, expectedSuccess);
       
   644     QFETCH(int, expectedProperties);
       
   645 
       
   646     QBuffer buffer(&vCard);
       
   647     buffer.open(QIODevice::ReadOnly);
       
   648     LineReader lineReader(&buffer, QTextCodec::codecForName("UTF-8"));
       
   649 
       
   650     QVersitDocument document;
       
   651     QCOMPARE(mReaderPrivate->parseVersitDocument(lineReader, document), expectedSuccess);
       
   652     QCOMPARE(document.properties().count(), expectedProperties);
       
   653     QCOMPARE(mReaderPrivate->mDocumentNestingLevel, 0);
       
   654 #endif
       
   655 }
       
   656 
       
   657 void tst_QVersitReader::testParseVersitDocument_data()
       
   658 {
       
   659 #ifdef QT_BUILD_INTERNAL
       
   660     QTest::addColumn<QByteArray>("vCard");
       
   661     QTest::addColumn<bool>("expectedSuccess");
       
   662     QTest::addColumn<int>("expectedProperties");
       
   663 
       
   664     QTest::newRow("Basic vCard 2.1")
       
   665             << QByteArray(
       
   666                     "BEGIN:VCARD\r\n"
       
   667                     "VERSION:2.1\r\n"
       
   668                     "FN:John\r\n"
       
   669                     "END:VCARD\r\n")
       
   670             << true
       
   671             << 1;
       
   672 
       
   673     QTest::newRow("vCard 2.1 with Agent")
       
   674             << QByteArray(
       
   675                     "BEGIN:VCARD\r\n"
       
   676                     "VERSION:2.1\r\n"
       
   677                     "FN:John\r\n"
       
   678                     "AGENT:BEGIN:VCARD\r\nN:Jenny\r\nEND:VCARD\r\n\r\n"
       
   679                     "EMAIL;ENCODING=QUOTED-PRINTABLE:john.citizen=40exam=\r\nple.com\r\n"
       
   680                     "END:VCARD\r\n")
       
   681             << true
       
   682             << 3;
       
   683 
       
   684     QTest::newRow("vCard 3.0 with Agent")
       
   685             << QByteArray(
       
   686                     "BEGIN:VCARD\r\n"
       
   687                     "VERSION:3.0\r\n"
       
   688                     "FN:John\r\n"
       
   689                     "AGENT:BEGIN\\:VCARD\\nN\\:Jenny\\nEND\\:VCARD\\n\r\n"
       
   690                     "EMAIL:john.citizen@example.com\r\n"
       
   691                     "END:VCARD\r\n")
       
   692             << true
       
   693             << 3;
       
   694 
       
   695     QTest::newRow("No BEGIN found")
       
   696             << QByteArray(
       
   697                     "VCARD\r\n"
       
   698                     "VERSION:2.1\r\n"
       
   699                     "FN:Nobody\r\n"
       
   700                     "END:VCARD\r\n")
       
   701             << false
       
   702             << 0;
       
   703 
       
   704     QTest::newRow("Wrong card type")
       
   705             << QByteArray(
       
   706                     "BEGIN:VCAL\r\n"
       
   707                     "END:VCAL\r\n")
       
   708             << false
       
   709             << 0;
       
   710 
       
   711     QTest::newRow("Wrong version")
       
   712             << QByteArray(
       
   713                     "BEGIN:VCARD\r\n"
       
   714                     "VERSION:4.0\r\n"
       
   715                     "FN:Nobody\r\n"
       
   716                     "END:VCARD\r\n")
       
   717             << false
       
   718             << 0;
       
   719 
       
   720     QTest::newRow("No trailing crlf")
       
   721             << QByteArray(
       
   722                     "BEGIN:VCARD\r\n"
       
   723                     "VERSION:2.1\r\n"
       
   724                     "FN:Nobody\r\n"
       
   725                     "END:VCARD")
       
   726             << true
       
   727             << 1;
       
   728 
       
   729     QTest::newRow("No end")
       
   730             << QByteArray(
       
   731                     "BEGIN:VCARD\r\n"
       
   732                     "VERSION:2.1\r\n"
       
   733                     "FN:Nobody\r\n")
       
   734             << false
       
   735             << 0;
       
   736 
       
   737     QTest::newRow("Grouped vCards are not supported. The whole vCard will be discarded.")
       
   738             << QByteArray(
       
   739                     "BEGIN:VCARD\r\n"
       
   740                     "VERSION:2.1\r\n"
       
   741                     "X-EXAMPLES:Family vCard\r\n"
       
   742                     "BEGIN:VCARD\r\n"
       
   743                     "VERSION:2.1\r\n"
       
   744                     "N:Citizen;John\r\n"
       
   745                     "TEL;CELL:1111\r\n"
       
   746                     "EMAIL;ENCODING=QUOTED-PRINTABLE:john.citizen=40example.com\r\n"
       
   747                     "END:VCARD\r\n"
       
   748                     "BEGIN:VCARD\r\n"
       
   749                     "VERSION:2.1\r\n"
       
   750                     "N:Citizen;Jenny\r\n"
       
   751                     "TEL;CELL:7777\r\n"
       
   752                     "END:VCARD\r\n"
       
   753                     "END:VCARD")
       
   754             << false
       
   755             << 0;
       
   756 #endif
       
   757 }
       
   758 
       
   759 void tst_QVersitReader::testDecodeQuotedPrintable()
       
   760 {
       
   761 #ifndef QT_BUILD_INTERNAL
       
   762     QSKIP("Testing private API", SkipSingle);
       
   763 #else
       
   764     QFETCH(QByteArray, encoded);
       
   765 
       
   766     QFETCH(QByteArray, decoded);
       
   767     mReaderPrivate->decodeQuotedPrintable(encoded);
       
   768     QCOMPARE(encoded, decoded);
       
   769 #endif
       
   770 }
       
   771 
       
   772 void tst_QVersitReader::testDecodeQuotedPrintable_data()
       
   773 {
       
   774 #ifdef QT_BUILD_INTERNAL
       
   775     QTest::addColumn<QByteArray>("encoded");
       
   776     QTest::addColumn<QByteArray>("decoded");
       
   777 
       
   778 
       
   779     QTest::newRow("Soft line breaks")
       
   780             << QByteArray("This=\r\n is =\r\none line.")
       
   781             << QByteArray("This is one line.");
       
   782 
       
   783     QTest::newRow("Characters recommended to be encoded according to RFC 1521")
       
   784             << QByteArray("To be decoded: =0A=0D=21=22=23=24=3D=40=5B=5C=5D=5E=60=7B=7C=7D=7E")
       
   785             << QByteArray("To be decoded: \n\r!\"#$=@[\\]^`{|}~");
       
   786 
       
   787     QTest::newRow("Characters recommended to be encoded according to RFC 1521(lower case)")
       
   788             << QByteArray("To be decoded: =0a=0d=21=22=23=24=3d=40=5b=5c=5d=5e=60=7b=7c=7d=7e")
       
   789             << QByteArray("To be decoded: \n\r!\"#$=@[\\]^`{|}~");
       
   790 
       
   791     QTest::newRow("random characters encoded")
       
   792             << QByteArray("=45=6E=63=6F=64=65=64 =64=61=74=61")
       
   793             << QByteArray("Encoded data");
       
   794 
       
   795     QTest::newRow("short string1")
       
   796             << QByteArray("-=_")
       
   797             << QByteArray("-=_");
       
   798 
       
   799     QTest::newRow("short string2")
       
   800             << QByteArray("=0")
       
   801             << QByteArray("=0");
       
   802 
       
   803     QTest::newRow("short string2")
       
   804             << QByteArray("\r")
       
   805             << QByteArray("\r");
       
   806 
       
   807     QTest::newRow("short string2")
       
   808             << QByteArray("\n")
       
   809             << QByteArray("\n");
       
   810 
       
   811     QTest::newRow("short string2")
       
   812             << QByteArray("\n\r")
       
   813             << QByteArray("\n\r");
       
   814 
       
   815     QTest::newRow("White spaces")
       
   816             << QByteArray("=09=20")
       
   817             << QByteArray("\t ");
       
   818 #endif
       
   819 }
       
   820 void tst_QVersitReader::testParamName()
       
   821 {
       
   822 #ifndef QT_BUILD_INTERNAL
       
   823     QSKIP("Testing private API", SkipSingle);
       
   824 #else
       
   825     // Empty value
       
   826     QByteArray param;
       
   827     QCOMPARE(mReaderPrivate->paramName(param, mAsciiCodec),QString());
       
   828 
       
   829     // Only value present
       
   830     param = "WORK";
       
   831     QCOMPARE(mReaderPrivate->paramName(param, mAsciiCodec),
       
   832              QString::fromAscii("TYPE"));
       
   833 
       
   834     // The below tests intentionally use the misspelling TIPE to avoid the default behaviour of
       
   835     // returning TYPE when the name can't be parsed.
       
   836     // Both name and value, spaces after the name
       
   837     param = "TIPE \t =WORK";
       
   838     QCOMPARE(mReaderPrivate->paramName(param, mAsciiCodec),
       
   839              QString::fromAscii("TIPE"));
       
   840 
       
   841     // Both name and value, no spaces after the name
       
   842     param = "TIPE=WORK";
       
   843     QCOMPARE(mReaderPrivate->paramName(param, mAsciiCodec),
       
   844              QString::fromAscii("TIPE"));
       
   845 
       
   846     // Test wide character support.
       
   847     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
   848     param = codec->fromUnicode(QString::fromAscii("TIPE=WORK"));
       
   849     QCOMPARE(mReaderPrivate->paramName(param, codec),
       
   850              QString::fromAscii("TIPE"));
       
   851 #endif
       
   852 }
       
   853 
       
   854 void tst_QVersitReader::testParamValue()
       
   855 {
       
   856 #ifndef QT_BUILD_INTERNAL
       
   857     QSKIP("Testing private API", SkipSingle);
       
   858 #else
       
   859     // Empty value
       
   860     QByteArray param;
       
   861     QCOMPARE(mReaderPrivate->paramValue(param, mAsciiCodec),QString());
       
   862 
       
   863     // Only value present
       
   864     param = "WORK";
       
   865     QCOMPARE(mReaderPrivate->paramValue(param, mAsciiCodec),
       
   866              QString::fromAscii("WORK"));
       
   867 
       
   868     // Name and equals sign, but no value
       
   869     param = "TYPE=";
       
   870     QCOMPARE(mReaderPrivate->paramValue(param, mAsciiCodec),QString());
       
   871 
       
   872     // Name and equals sign, but value has only spaces
       
   873     param = "TYPE=  \t ";
       
   874     QCOMPARE(mReaderPrivate->paramValue(param, mAsciiCodec),QString());
       
   875 
       
   876     // Both name and value, spaces before the value
       
   877     param = "TYPE= \t  WORK";
       
   878     QCOMPARE(mReaderPrivate->paramValue(param, mAsciiCodec),
       
   879              QString::fromAscii("WORK"));
       
   880 
       
   881     // Both name and value, no spaces before the value
       
   882     param = "ENCODING=QUOTED-PRINTABLE";
       
   883     QCOMPARE(mReaderPrivate->paramValue(param, mAsciiCodec),
       
   884              QString::fromAscii("QUOTED-PRINTABLE"));
       
   885 
       
   886     // Test wide character support.
       
   887     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
   888     param = codec->fromUnicode(QString::fromAscii("TYPE=WORK"));
       
   889     QCOMPARE(mReaderPrivate->paramValue(param, codec),
       
   890              QString::fromAscii("WORK"));
       
   891 #endif
       
   892 }
       
   893 
       
   894 void tst_QVersitReader::testExtractPart()
       
   895 {
       
   896 #ifndef QT_BUILD_INTERNAL
       
   897     QSKIP("Testing private API", SkipSingle);
       
   898 #else
       
   899     QByteArray originalStr;
       
   900 
       
   901     // Negative starting position
       
   902     QCOMPARE(mReaderPrivate->extractPart(originalStr,-1,1), QByteArray());
       
   903 
       
   904     // Empty original string
       
   905     QCOMPARE(mReaderPrivate->extractPart(originalStr,0,1), QByteArray());
       
   906 
       
   907     // Trimmed substring empty
       
   908     originalStr = " \t \t";
       
   909     QCOMPARE(mReaderPrivate->extractPart(originalStr,0,4), QByteArray());
       
   910 
       
   911     // The given substring length is greater than the original string length
       
   912     originalStr = "ENCODING=7BIT";
       
   913     QCOMPARE(mReaderPrivate->extractPart(originalStr,0,100), originalStr);
       
   914 
       
   915     // Non-empty substring, from the beginning
       
   916     originalStr = " TYPE=WORK ; X-PARAM=X-VALUE; ENCODING=8BIT";
       
   917     QCOMPARE(mReaderPrivate->extractPart(originalStr,0,11),
       
   918              QByteArray("TYPE=WORK"));
       
   919 
       
   920     // Non-empty substring, from the middle
       
   921     QCOMPARE(mReaderPrivate->extractPart(originalStr,12,16),
       
   922              QByteArray("X-PARAM=X-VALUE"));
       
   923 
       
   924     // Non-empty substring, from the middle to the end
       
   925     QCOMPARE(mReaderPrivate->extractPart(originalStr,29),
       
   926              QByteArray("ENCODING=8BIT"));
       
   927 #endif
       
   928 }
       
   929 
       
   930 void tst_QVersitReader::testExtractParts()
       
   931 {
       
   932 #ifndef QT_BUILD_INTERNAL
       
   933     QSKIP("Testing private API", SkipSingle);
       
   934 #else
       
   935     QList<QByteArray> parts;
       
   936 
       
   937     // Empty value
       
   938     QByteArray text;
       
   939     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   940     QVERIFY(parts.isEmpty());
       
   941 
       
   942     // Only separator
       
   943     text = ";";
       
   944     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   945     QVERIFY(parts.isEmpty());
       
   946 
       
   947     // One part
       
   948     text = "part";
       
   949     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   950     QCOMPARE(parts.count(),1);
       
   951     QCOMPARE(QString::fromAscii(parts[0]),QString::fromAscii("part"));
       
   952 
       
   953     // Separator in the beginning, one part
       
   954     text = ";part";
       
   955     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   956     QCOMPARE(parts.count(),1);
       
   957     QCOMPARE(QString::fromAscii(parts[0]),QString::fromAscii("part"));
       
   958 
       
   959     // Separator in the end, one part
       
   960     text = "part;";
       
   961     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   962     QCOMPARE(parts.count(),1);
       
   963     QCOMPARE(QString::fromAscii(parts[0]),QString::fromAscii("part"));
       
   964 
       
   965     // One part that contains escaped separator
       
   966     text = "part\\;";
       
   967     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   968     QCOMPARE(parts.count(),1);
       
   969     QCOMPARE(QString::fromAscii(parts[0]),QString::fromAscii("part\\;"));
       
   970 
       
   971     // Two parts
       
   972     text = "part1;part2";
       
   973     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   974     QCOMPARE(parts.count(),2);
       
   975     QCOMPARE(QString::fromAscii(parts[0]),QString::fromAscii("part1"));
       
   976     QCOMPARE(QString::fromAscii(parts[1]),QString::fromAscii("part2"));
       
   977 
       
   978     // Two parts that contain escaped separators
       
   979     text = "pa\\;rt1;par\\;t2";
       
   980     parts = mReaderPrivate->extractParts(text,";", mAsciiCodec);
       
   981     QCOMPARE(parts.count(),2);
       
   982     QCOMPARE(QString::fromAscii(parts[0]),QString::fromAscii("pa\\;rt1"));
       
   983     QCOMPARE(QString::fromAscii(parts[1]),QString::fromAscii("par\\;t2"));
       
   984 
       
   985     // Test wide character support
       
   986     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
   987     text = codec->fromUnicode(QString::fromAscii("part1;part2"));
       
   988     parts = mReaderPrivate->extractParts(text,";", codec);
       
   989     QCOMPARE(parts.count(),2);
       
   990     QCOMPARE(codec->toUnicode(parts[0]),QString::fromAscii("part1"));
       
   991     QCOMPARE(codec->toUnicode(parts[1]),QString::fromAscii("part2"));
       
   992 #endif
       
   993 }
       
   994 
       
   995 void tst_QVersitReader::testExtractPropertyGroupsAndName()
       
   996 {
       
   997 #ifndef QT_BUILD_INTERNAL
       
   998     QSKIP("Testing private API", SkipSingle);
       
   999 #else
       
  1000     QPair<QStringList,QString> groupsAndName;
       
  1001 
       
  1002     // Empty string
       
  1003     VersitCursor cursor(QByteArray(" "));
       
  1004     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1005     QCOMPARE(groupsAndName.first.count(),0);
       
  1006     QCOMPARE(groupsAndName.second,QString());
       
  1007 
       
  1008     // No value -> returns empty string and no groups
       
  1009     QByteArray property("TEL");
       
  1010     cursor.setData(property);
       
  1011     cursor.selection = property.size();
       
  1012     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1013     QCOMPARE(groupsAndName.first.count(),0);
       
  1014     QCOMPARE(groupsAndName.second,QString());
       
  1015 
       
  1016     // Simple name and value
       
  1017     property = "TEL:123";
       
  1018     cursor.setData(property);
       
  1019     cursor.selection = property.size();
       
  1020     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1021     QCOMPARE(groupsAndName.first.count(),0);
       
  1022     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1023 
       
  1024     // One whitespace before colon
       
  1025     property = "TEL :123";
       
  1026     cursor.setData(property);
       
  1027     cursor.selection = property.size();
       
  1028     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1029     QCOMPARE(groupsAndName.first.count(),0);
       
  1030     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1031 
       
  1032     // Several whitespaces before colon
       
  1033     property = "TEL \t  :123";
       
  1034     cursor.setData(property);
       
  1035     cursor.selection = property.size();
       
  1036     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1037     QCOMPARE(groupsAndName.first.count(),0);
       
  1038     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1039 
       
  1040     // Name contains a group
       
  1041     property = "group1.TEL:1234";
       
  1042     cursor.setData(property);
       
  1043     cursor.selection = property.size();
       
  1044     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1045     QCOMPARE(groupsAndName.first.count(),1);
       
  1046     QCOMPARE(groupsAndName.first.takeFirst(),QString::fromAscii("group1"));
       
  1047     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1048 
       
  1049     // Name contains more than one group
       
  1050     property = "group1.group2.TEL:12345";
       
  1051     cursor.setData(property);
       
  1052     cursor.selection = property.size();
       
  1053     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1054     QCOMPARE(groupsAndName.first.count(),2);
       
  1055     QCOMPARE(groupsAndName.first.takeFirst(),QString::fromAscii("group1"));
       
  1056     QCOMPARE(groupsAndName.first.takeFirst(),QString::fromAscii("group2"));
       
  1057     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1058     QCOMPARE(cursor.position, 17);
       
  1059 
       
  1060     // Property contains one parameter
       
  1061     property = "TEL;WORK:123";
       
  1062     cursor.setData(property);
       
  1063     cursor.selection = property.size();
       
  1064     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1065     QCOMPARE(groupsAndName.first.count(),0);
       
  1066     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1067 
       
  1068     // Property contains several parameters
       
  1069     property = "EMAIL;INTERNET;ENCODING=QUOTED-PRINTABLE:user=40ovi.com";
       
  1070     cursor.setData(property);
       
  1071     cursor.selection = property.size();
       
  1072     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1073     QCOMPARE(groupsAndName.first.count(),0);
       
  1074     QCOMPARE(groupsAndName.second,QString::fromAscii("EMAIL"));
       
  1075 
       
  1076     // Name contains an escaped semicolon
       
  1077     property = "X-proper\\;ty:value";
       
  1078     cursor.setData(property);
       
  1079     cursor.selection = property.size();
       
  1080     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, mAsciiCodec);
       
  1081     QCOMPARE(groupsAndName.first.count(),0);
       
  1082     QCOMPARE(groupsAndName.second,QString::fromAscii("X-proper\\;ty"));
       
  1083 
       
  1084     // Test wide character support
       
  1085     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
  1086     property = codec->fromUnicode(QString::fromAscii("group1.group2.TEL;WORK:123"));
       
  1087     cursor.setData(property);
       
  1088     cursor.selection = property.size();
       
  1089     groupsAndName = mReaderPrivate->extractPropertyGroupsAndName(cursor, codec);
       
  1090     QCOMPARE(groupsAndName.first.count(),2);
       
  1091     QCOMPARE(groupsAndName.first.takeFirst(),QString::fromAscii("group1"));
       
  1092     QCOMPARE(groupsAndName.first.takeFirst(),QString::fromAscii("group2"));
       
  1093     QCOMPARE(groupsAndName.second,QString::fromAscii("TEL"));
       
  1094     QCOMPARE(cursor.position, 36); // 2 bytes * 17 characters + 2 byte BOM.
       
  1095 #endif
       
  1096 }
       
  1097 
       
  1098 void tst_QVersitReader::testExtractVCard21PropertyParams()
       
  1099 {
       
  1100 #ifndef QT_BUILD_INTERNAL
       
  1101     QSKIP("Testing private API", SkipSingle);
       
  1102 #else
       
  1103     // No parameters
       
  1104     VersitCursor cursor(QByteArray(":123"));
       
  1105     cursor.setSelection(cursor.data.size());
       
  1106     QCOMPARE(mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec).count(), 0);
       
  1107 
       
  1108     // "Empty" parameter
       
  1109     cursor.setData(QByteArray(";:123"));
       
  1110     cursor.setSelection(cursor.data.size());
       
  1111     QCOMPARE(mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec).count(), 0);
       
  1112 
       
  1113     // Semicolon found, but no value for the property
       
  1114     cursor.setData(QByteArray(";TYPE=X-TYPE"));
       
  1115     cursor.setSelection(cursor.data.size());
       
  1116     QCOMPARE(mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec).count(), 0);
       
  1117 
       
  1118     // The property name contains an escaped semicolon, no parameters
       
  1119     cursor.setData(QByteArray(":value"));
       
  1120     cursor.setSelection(cursor.data.size());
       
  1121     QCOMPARE(mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec).count(), 0);
       
  1122 
       
  1123     // The property value contains a semicolon, no parameters
       
  1124     cursor.setData(QByteArray(":va;lue"));
       
  1125     cursor.setSelection(cursor.data.size());
       
  1126     QCOMPARE(mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec).count(), 0);
       
  1127 
       
  1128     // One parameter
       
  1129     cursor.setData(QByteArray(";HOME:123"));
       
  1130     cursor.setSelection(cursor.data.size());
       
  1131     QMultiHash<QString,QString> params = mReaderPrivate->extractVCard21PropertyParams(cursor,
       
  1132                                                                                    mAsciiCodec);
       
  1133     QCOMPARE(1, params.count());
       
  1134     QCOMPARE(1, params.values(QString::fromAscii("TYPE")).count());
       
  1135     QCOMPARE(params.values(QString::fromAscii("TYPE"))[0],QString::fromAscii("HOME"));
       
  1136 
       
  1137     // Two parameters of the same type
       
  1138     cursor.setData(QByteArray(";HOME;VOICE:123"));
       
  1139     cursor.setSelection(cursor.data.size());
       
  1140     params = mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec);
       
  1141     QCOMPARE(2, params.count());
       
  1142     QCOMPARE(2, params.values(QString::fromAscii("TYPE")).count());
       
  1143     QCOMPARE(params.values(QString::fromAscii("TYPE"))[0],QString::fromAscii("HOME"));
       
  1144     QCOMPARE(params.values(QString::fromAscii("TYPE"))[1],QString::fromAscii("VOICE"));
       
  1145 
       
  1146     // Two parameters, several empty parameters (extra semicolons)
       
  1147     cursor.setData(QByteArray(";;;;HOME;;;;;VOICE;;;:123"));
       
  1148     cursor.setSelection(cursor.data.size());
       
  1149     params = mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec);
       
  1150     QCOMPARE(2, params.count());
       
  1151     QCOMPARE(2, params.values(QString::fromAscii("TYPE")).count());
       
  1152     QCOMPARE(params.values(QString::fromAscii("TYPE"))[0],QString::fromAscii("HOME"));
       
  1153     QCOMPARE(params.values(QString::fromAscii("TYPE"))[1],QString::fromAscii("VOICE"));
       
  1154 
       
  1155     // Two parameters with different types
       
  1156     cursor.setData(QByteArray(";INTERNET;ENCODING=QUOTED-PRINTABLE:user=40ovi.com"));
       
  1157     cursor.setSelection(cursor.data.size());
       
  1158     params.clear();
       
  1159     params = mReaderPrivate->extractVCard21PropertyParams(cursor, mAsciiCodec);
       
  1160     QCOMPARE(2, params.count());
       
  1161     QList<QString> typeParams = params.values(QString::fromAscii("TYPE"));
       
  1162     QCOMPARE(1, typeParams.count());
       
  1163     QCOMPARE(typeParams[0],QString::fromAscii("INTERNET"));
       
  1164     QList<QString> encodingParams = params.values(QString::fromAscii("ENCODING"));
       
  1165     QCOMPARE(1, encodingParams.count());
       
  1166     QCOMPARE(encodingParams[0],QString::fromAscii("QUOTED-PRINTABLE"));
       
  1167 
       
  1168     // Test wide character support.
       
  1169     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
  1170     QByteArray data = VersitUtils::encode(";HOME;CHARSET=UTF-16:123", codec);
       
  1171     cursor.setData(data);
       
  1172     cursor.setSelection(cursor.data.size());
       
  1173     params = mReaderPrivate->extractVCard21PropertyParams(cursor, codec);
       
  1174     QCOMPARE(2, params.count());
       
  1175     typeParams = params.values(QString::fromAscii("TYPE"));
       
  1176     QCOMPARE(1, typeParams.count());
       
  1177     QCOMPARE(typeParams[0],QString::fromAscii("HOME"));
       
  1178     encodingParams = params.values(QString::fromAscii("CHARSET"));
       
  1179     QCOMPARE(1, encodingParams.count());
       
  1180     QCOMPARE(encodingParams[0],QString::fromAscii("UTF-16"));
       
  1181 #endif
       
  1182 }
       
  1183 
       
  1184 void tst_QVersitReader::testExtractVCard30PropertyParams()
       
  1185 {
       
  1186 #ifndef QT_BUILD_INTERNAL
       
  1187     QSKIP("Testing private API", SkipSingle);
       
  1188 #else
       
  1189     // No parameters
       
  1190     VersitCursor cursor(QByteArray(":123"));
       
  1191     cursor.setSelection(cursor.data.size());
       
  1192     QCOMPARE(mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec).count(), 0);
       
  1193 
       
  1194     // One parameter
       
  1195     cursor.setData(QByteArray(";TYPE=HOME:123"));
       
  1196     cursor.setSelection(cursor.data.size());
       
  1197     QMultiHash<QString,QString> params = mReaderPrivate->extractVCard30PropertyParams(cursor,
       
  1198                                                                                    mAsciiCodec);
       
  1199     QCOMPARE(params.count(), 1);
       
  1200     QCOMPARE(params.values(QString::fromAscii("TYPE")).count(), 1);
       
  1201     QCOMPARE(params.values(QString::fromAscii("TYPE"))[0], QString::fromAscii("HOME"));
       
  1202 
       
  1203     // One parameter with an escaped semicolon
       
  1204     cursor.setData(QByteArray(";para\\;meter:value"));
       
  1205     cursor.setSelection(cursor.data.size());
       
  1206     params = mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec);
       
  1207     QCOMPARE(params.count(), 1);
       
  1208     QCOMPARE(params.values(QString::fromAscii("TYPE")).count(), 1);
       
  1209     QCOMPARE(params.values(QString::fromAscii("TYPE"))[0], QString::fromAscii("para;meter"));
       
  1210 
       
  1211     // One parameter with and escaped comma in the name and the value
       
  1212     cursor.setData(QByteArray(";X-PA\\,RAM=VAL\\,UE:123"));
       
  1213     cursor.setSelection(cursor.data.size());
       
  1214     params = mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec);
       
  1215     QCOMPARE(params.count(), 1);
       
  1216     QCOMPARE(params.values(QString::fromAscii("X-PA,RAM")).count(), 1);
       
  1217     QCOMPARE(params.values(QString::fromAscii("X-PA,RAM"))[0], QString::fromAscii("VAL,UE"));
       
  1218 
       
  1219     // Two parameters of the same type
       
  1220     cursor.setData(QByteArray(";TYPE=HOME,VOICE:123"));
       
  1221     cursor.setSelection(cursor.data.size());
       
  1222     params = mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec);
       
  1223     QCOMPARE(params.count(), 2);
       
  1224     QCOMPARE(params.values(QString::fromAscii("TYPE")).count(), 2);
       
  1225     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("HOME")));
       
  1226     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("VOICE")));
       
  1227 
       
  1228     // Two parameters of the same type in separate name-values
       
  1229     cursor.setData(QByteArray(";TYPE=HOME;TYPE=VOICE:123"));
       
  1230     cursor.setSelection(cursor.data.size());
       
  1231     params = mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec);
       
  1232     QCOMPARE(params.count(), 2);
       
  1233     QCOMPARE(params.values(QString::fromAscii("TYPE")).count(), 2);
       
  1234     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("HOME")));
       
  1235     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("VOICE")));
       
  1236 
       
  1237     // Three parameters of the same type
       
  1238     cursor.setData(QByteArray(";TYPE=PREF,HOME,VOICE:123"));
       
  1239     cursor.setSelection(cursor.data.size());
       
  1240     params = mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec);
       
  1241     QCOMPARE(params.count(), 3);
       
  1242     QCOMPARE(params.values(QString::fromAscii("TYPE")).count(), 3);
       
  1243     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("PREF")));
       
  1244     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("HOME")));
       
  1245     QVERIFY(params.values(QString::fromAscii("TYPE")).contains(QString::fromAscii("VOICE")));
       
  1246 
       
  1247     // Two parameters with different types
       
  1248     cursor.setData(QByteArray(";TYPE=HOME;X-PARAM=X-VALUE:Home Street 1"));
       
  1249     cursor.setSelection(cursor.data.size());
       
  1250     params.clear();
       
  1251     params = mReaderPrivate->extractVCard30PropertyParams(cursor, mAsciiCodec);
       
  1252     QCOMPARE(params.count(), 2);
       
  1253     QList<QString> typeParams = params.values(QString::fromAscii("TYPE"));
       
  1254     QCOMPARE(typeParams.count(), 1);
       
  1255     QCOMPARE(typeParams[0],QString::fromAscii("HOME"));
       
  1256     QList<QString> encodingParams = params.values(QString::fromAscii("X-PARAM"));
       
  1257     QCOMPARE(encodingParams.count(), 1);
       
  1258     QCOMPARE(encodingParams[0],QString::fromAscii("X-VALUE"));
       
  1259 
       
  1260     // Test wide character support.
       
  1261     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
  1262     QByteArray data = VersitUtils::encode(";TIPE=HOME,VOICE;CHARSET=UTF-16:123", codec);
       
  1263     cursor.setData(data);
       
  1264     cursor.setSelection(cursor.data.size());
       
  1265     params = mReaderPrivate->extractVCard30PropertyParams(cursor, codec);
       
  1266     QCOMPARE(params.count(), 3);
       
  1267     typeParams = params.values(QString::fromAscii("TIPE"));
       
  1268     QCOMPARE(params.values(QString::fromAscii("TIPE")).count(), 2);
       
  1269     QVERIFY(params.values(QString::fromAscii("TIPE")).contains(QString::fromAscii("HOME")));
       
  1270     QVERIFY(params.values(QString::fromAscii("TIPE")).contains(QString::fromAscii("VOICE")));
       
  1271     encodingParams = params.values(QString::fromAscii("CHARSET"));
       
  1272     QCOMPARE(1, encodingParams.count());
       
  1273     QCOMPARE(encodingParams[0],QString::fromAscii("UTF-16"));
       
  1274 #endif
       
  1275 }
       
  1276 
       
  1277 void tst_QVersitReader::testExtractParams()
       
  1278 {
       
  1279 #ifndef QT_BUILD_INTERNAL
       
  1280     QSKIP("Testing private API", SkipSingle);
       
  1281 #else
       
  1282     VersitCursor cursor;
       
  1283     QByteArray data = ":123";
       
  1284     cursor.setData(data);
       
  1285     cursor.setPosition(0);
       
  1286     cursor.setSelection(cursor.data.size());
       
  1287     QList<QByteArray> params = mReaderPrivate->extractParams(cursor, mAsciiCodec);
       
  1288     QCOMPARE(params.size(), 0);
       
  1289     QCOMPARE(cursor.position, 1);
       
  1290 
       
  1291     data = "a;b:123";
       
  1292     cursor.setData(data);
       
  1293     cursor.setPosition(0);
       
  1294     cursor.setSelection(cursor.data.size());
       
  1295     params = mReaderPrivate->extractParams(cursor, mAsciiCodec);
       
  1296     QCOMPARE(params.size(), 2);
       
  1297     QCOMPARE(cursor.position, 4);
       
  1298     QCOMPARE(params.at(0), QByteArray("a"));
       
  1299     QCOMPARE(params.at(1), QByteArray("b"));
       
  1300 
       
  1301     QTextCodec* codec = QTextCodec::codecForName("UTF-16BE");
       
  1302     data = VersitUtils::encode(":123", codec);
       
  1303     cursor.setData(data);
       
  1304     cursor.setPosition(0);
       
  1305     cursor.setSelection(cursor.data.size());
       
  1306     params = mReaderPrivate->extractParams(cursor, codec);
       
  1307     QCOMPARE(params.size(), 0);
       
  1308     QCOMPARE(cursor.position, 2);
       
  1309 
       
  1310     data = VersitUtils::encode("a;b:123", codec);
       
  1311     cursor.setData(data);
       
  1312     cursor.setPosition(0);
       
  1313     cursor.setSelection(cursor.data.size());
       
  1314     params = mReaderPrivate->extractParams(cursor, codec);
       
  1315     QCOMPARE(params.size(), 2);
       
  1316     QCOMPARE(cursor.position, 8);
       
  1317 #endif
       
  1318 }
       
  1319 
       
  1320 Q_DECLARE_METATYPE(QList<QString>)
       
  1321 
       
  1322 void tst_QVersitReader::testReadLine()
       
  1323 {
       
  1324 #ifndef QT_BUILD_INTERNAL
       
  1325     QSKIP("Testing private API", SkipSingle);
       
  1326 #else
       
  1327     QFETCH(QByteArray, codecName);
       
  1328     QFETCH(QString, data);
       
  1329     QFETCH(QList<QString>, expectedLines);
       
  1330 
       
  1331     QTextCodec* codec = QTextCodec::codecForName(codecName);
       
  1332     QTextEncoder* encoder = codec->makeEncoder();
       
  1333     encoder->fromUnicode(QString());
       
  1334 
       
  1335     QByteArray bytes(encoder->fromUnicode(data));
       
  1336 
       
  1337     mInputDevice->close();
       
  1338     mInputDevice->setData(bytes);
       
  1339     mInputDevice->open(QIODevice::ReadWrite);
       
  1340 
       
  1341     LineReader lineReader(mInputDevice, codec, 10);
       
  1342 
       
  1343     // Check that all expected lines are read.
       
  1344     foreach (QString expectedLine, expectedLines) {
       
  1345         QByteArray expectedBytes(encoder->fromUnicode(expectedLine));
       
  1346         QVERIFY(!lineReader.atEnd());
       
  1347         VersitCursor line = lineReader.readLine();
       
  1348         QVERIFY(line.data.indexOf(expectedBytes) == line.position);
       
  1349         QCOMPARE(line.selection - line.position, expectedBytes.length());
       
  1350     }
       
  1351     // And that there are no more lines
       
  1352     VersitCursor line = lineReader.readLine();
       
  1353     QCOMPARE(line.selection, line.position);
       
  1354     QVERIFY(lineReader.atEnd());
       
  1355 
       
  1356     delete encoder;
       
  1357 #endif
       
  1358 }
       
  1359 
       
  1360 void tst_QVersitReader::testReadLine_data()
       
  1361 {
       
  1362 #ifdef QT_BUILD_INTERNAL
       
  1363     // Note: for this test, we set mLineReader to read 10 bytes at a time.  Lines of multiples of
       
  1364     // 10 bytes are hence border cases.
       
  1365     QTest::addColumn<QByteArray>("codecName");
       
  1366     QTest::addColumn<QString>("data");
       
  1367     QTest::addColumn<QList<QString> >("expectedLines");
       
  1368 
       
  1369     QList<QByteArray> codecNames;
       
  1370     codecNames << "UTF-8" << "UTF-16";
       
  1371 
       
  1372     foreach (QByteArray codecName, codecNames) {
       
  1373         QTest::newRow("empty " + codecName)
       
  1374                 << codecName
       
  1375                 << ""
       
  1376                 << QList<QString>();
       
  1377 
       
  1378         QTest::newRow("one line " + codecName)
       
  1379                 << codecName
       
  1380                 << "line"
       
  1381                 << (QList<QString>() << QLatin1String("line"));
       
  1382 
       
  1383         QTest::newRow("one ten-byte line " + codecName)
       
  1384                 << codecName
       
  1385                 << "tenletters"
       
  1386                 << (QList<QString>() << QLatin1String("tenletters"));
       
  1387 
       
  1388         QTest::newRow("one long line " + codecName)
       
  1389                 << codecName
       
  1390                 << "one line longer than ten characters"
       
  1391                 << (QList<QString>() << QLatin1String("one line longer than ten characters"));
       
  1392 
       
  1393         QTest::newRow("one terminated line " + codecName)
       
  1394                 << codecName
       
  1395                 << "one line longer than ten characters\r\n"
       
  1396                 << (QList<QString>() << QLatin1String("one line longer than ten characters"));
       
  1397 
       
  1398         QTest::newRow("two lines " + codecName)
       
  1399                 << codecName
       
  1400                 << "two\r\nlines"
       
  1401                 << (QList<QString>() << QLatin1String("two") << QLatin1String("lines"));
       
  1402 
       
  1403         QTest::newRow("two terminated lines " + codecName)
       
  1404                 << codecName
       
  1405                 << "two\r\nlines\r\n"
       
  1406                 << (QList<QString>() << QLatin1String("two") << QLatin1String("lines"));
       
  1407 
       
  1408         QTest::newRow("two long lines " + codecName)
       
  1409                 << codecName
       
  1410                 << "one line longer than ten characters\r\nanother line\r\n"
       
  1411                 << (QList<QString>() << QLatin1String("one line longer than ten characters") << QLatin1String("another line"));
       
  1412 
       
  1413         QTest::newRow("two full lines " + codecName)
       
  1414                 << codecName
       
  1415                 << "tenletters\r\n8letters\r\n"
       
  1416                 << (QList<QString>() << QLatin1String("tenletters") << QLatin1String("8letters"));
       
  1417 
       
  1418         QTest::newRow("a nine-byte line " + codecName)
       
  1419                 << codecName
       
  1420                 << "9 letters\r\nanother line\r\n"
       
  1421                 << (QList<QString>() << QLatin1String("9 letters") << QLatin1String("another line"));
       
  1422 
       
  1423         QTest::newRow("a blank line " + codecName)
       
  1424                 << codecName
       
  1425                 << "one\r\n\r\ntwo\r\n"
       
  1426                 << (QList<QString>() << QLatin1String("one") << QLatin1String("two"));
       
  1427 
       
  1428         QTest::newRow("folded lines " + codecName)
       
  1429                 << codecName
       
  1430                 << "folded\r\n  line\r\nsecond line\r\n"
       
  1431                 << (QList<QString>() << QLatin1String("folded line") << QLatin1String("second line"));
       
  1432 
       
  1433         QTest::newRow("multiply folded lines " + codecName)
       
  1434                 << codecName
       
  1435                 << "fo\r\n lded\r\n  line\r\nseco\r\n\tnd l\r\n ine\r\n"
       
  1436                 << (QList<QString>() << QLatin1String("folded line") << QLatin1String("second line"));
       
  1437 
       
  1438         QTest::newRow("fold hidden after a chunk " + codecName)
       
  1439                 << codecName
       
  1440                 << "8letters\r\n  on one line\r\n"
       
  1441                 << (QList<QString>() << QLatin1String("8letters on one line"));
       
  1442 
       
  1443         QTest::newRow("three mac lines " + codecName)
       
  1444                 << codecName
       
  1445                 << "one\rtwo\rthree\r"
       
  1446                 << (QList<QString>() << QLatin1String("one") << QLatin1String("two") << QLatin1String("three"));
       
  1447     }
       
  1448 #endif
       
  1449 }
       
  1450 
       
  1451 void tst_QVersitReader::testByteArrayInput()
       
  1452 {
       
  1453     delete mReader;
       
  1454     const QByteArray& oneDocument =
       
  1455         "BEGIN:VCARD\r\nVERSION:2.1\r\nFN:John\r\nEND:VCARD\r\n";
       
  1456 
       
  1457     mReader = new QVersitReader(oneDocument);
       
  1458     QVERIFY(mReader->device() == 0);
       
  1459     QVERIFY(mReader->startReading());
       
  1460     QVERIFY(mReader->waitForFinished());
       
  1461     QList<QVersitDocument> results = mReader->results();
       
  1462     QCOMPARE(mReader->state(), QVersitReader::FinishedState);
       
  1463     QCOMPARE(mReader->error(), QVersitReader::NoError);
       
  1464     QCOMPARE(results.count(),1);
       
  1465     QVersitDocument result = results.first();
       
  1466     QCOMPARE(result.type(), QVersitDocument::VCard21Type);
       
  1467     QList<QVersitProperty> properties = result.properties();
       
  1468     QCOMPARE(properties.length(), 1);
       
  1469     QCOMPARE(properties.first().name(), QLatin1String("FN"));
       
  1470     QCOMPARE(properties.first().value(), QLatin1String("John"));
       
  1471 }
       
  1472 
       
  1473 void tst_QVersitReader::testRemoveBackSlashEscaping()
       
  1474 {
       
  1475 #ifndef QT_BUILD_INTERNAL
       
  1476     QSKIP("Testing private API", SkipSingle);
       
  1477 #else
       
  1478     // Empty string
       
  1479     QString input;
       
  1480     QVersitReaderPrivate::removeBackSlashEscaping(input);
       
  1481     QCOMPARE(input,QString());
       
  1482 
       
  1483     // Nothing to escape in the string
       
  1484     input = QString::fromAscii("Nothing to escape");
       
  1485     QVersitReaderPrivate::removeBackSlashEscaping(input);
       
  1486     QCOMPARE(input,QString::fromAscii("Nothing to escape"));
       
  1487 
       
  1488     // Line break, semicolon, backslash and comma in the string
       
  1489     input = QString::fromAscii("These should be unescaped \\n \\N \\; \\, \\\\");
       
  1490     QVersitReaderPrivate::removeBackSlashEscaping(input);
       
  1491     QCOMPARE(input, QString::fromAscii("These should be unescaped \r\n \r\n ; , \\"));
       
  1492 
       
  1493     // Don't remove escaping within quotes
       
  1494     input = QString::fromAscii("\"Quoted \\n \\N \\; \\,\"");
       
  1495     QVersitReaderPrivate::removeBackSlashEscaping(input);
       
  1496     QCOMPARE(input, QString::fromAscii("\"Quoted \\n \\N \\; \\,\""));
       
  1497 #endif
       
  1498 }
       
  1499 
       
  1500 QTEST_MAIN(tst_QVersitReader)
       
  1501