qtmobility/plugins/contacts/symbian/tsrc/tst_performance/tst_performance.cpp
changeset 14 6fbed849b4f4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qtmobility/plugins/contacts/symbian/tsrc/tst_performance/tst_performance.cpp	Wed Jun 23 19:08:38 2010 +0300
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QObject>
+#include <qmobilityglobal.h>
+#include <qtcontacts.h>
+#include <QtTest/QtTest>
+#include <QDebug>
+#include <QFile>
+#include <qversitreader.h>
+#include <qversitcontactimporter.h>
+
+QTM_USE_NAMESPACE
+
+const QString testDataPath("c:/data/others");
+const QString resultFileName("c:/data/results/tst_performance_results.csv");
+
+class tst_Performance : public QObject
+{
+    Q_OBJECT
+
+private slots:  // Init & cleanup
+    void init();
+    void cleanup();
+
+private slots:  // Test cases
+    void validate_data();
+    void validate();
+    void fetch_data();
+    void fetch();
+
+private:
+    void addTestRows(QString fileNameFilter);
+    bool importContacts(QString vcardFileName, int &count);
+    bool detailsExist(QList<QContact> contacts, QStringList definitionNames);
+    void startBenchmark(QString benchmarkName);
+    bool endBenchmark(const int target);
+
+    QContactManager *m_cm;
+    QTime m_timer;
+    QString m_benchmarkName;
+};
+
+
+void tst_Performance::init()
+{
+    m_cm = new QContactManager("symbian");
+    m_cm->removeContacts(m_cm->contactIds(), 0);
+}
+
+void tst_Performance::cleanup()
+{
+    m_cm->removeContacts(m_cm->contactIds(), 0);
+    delete m_cm;
+}
+
+void tst_Performance::validate_data()
+{
+    // Path to a file containing vcards, constructed dynamically
+    QTest::addColumn<QString>("vcardFileName");
+
+   // Add new test row for each vcf file
+   addTestRows(QString("tst_performance_validate*.vcf"));
+}
+
+void tst_Performance::validate()
+{
+    QFETCH(QString, vcardFileName);
+
+    // Import contacts from the file into contacts database
+    int count(0);
+    QVERIFY(importContacts(vcardFileName, count));
+
+    // QContactName
+    QContactFetchHint nameHint;
+    nameHint.setDetailDefinitionsHint(QStringList() << QContactName::DefinitionName);
+    QList<QContact> contacts = m_cm->contacts(QList<QContactSortOrder>(), nameHint);
+    QCOMPARE(contacts.count(), count);
+    QVERIFY(detailsExist(contacts, QStringList() << QContactName::DefinitionName));
+
+    // QContactPhoneNumber
+    QContactFetchHint numberHint;
+    numberHint.setDetailDefinitionsHint(QStringList() << QContactPhoneNumber::DefinitionName);
+    contacts = m_cm->contacts(QList<QContactSortOrder>(), numberHint);
+    QCOMPARE(contacts.count(), count);
+    QVERIFY(detailsExist(contacts, QStringList() << QContactPhoneNumber::DefinitionName));
+
+    // QContactAddress
+    QContactFetchHint addressHint;
+    addressHint.setDetailDefinitionsHint(QStringList() << QContactAddress::DefinitionName);
+    contacts = m_cm->contacts(QList<QContactSortOrder>(), addressHint);
+    QCOMPARE(contacts.count(), count);
+    QVERIFY(detailsExist(contacts, QStringList() << QContactAddress::DefinitionName));
+}
+
+void tst_Performance::fetch_data()
+{
+    // Path to a file containing vcards, constructed dynamically
+    QTest::addColumn<QString>("vcardFileName");
+
+    // Add new test row for each vcf file
+    addTestRows(QString("tst_performance_fetch*.vcf"));
+}
+
+void tst_Performance::fetch()
+{
+    QFETCH(QString, vcardFileName);
+
+    // Import contacts from the file into contacts database
+    int count(0);
+    QVERIFY(importContacts(vcardFileName, count));
+
+    // The actual benchmark measurements begin... We cannot use QBENCHMARK
+    // since it does not give separate results for each operation, but shows
+    // only the latest result in the log. Also, it does not support writing the
+    // result into an external CSV file.
+
+    {
+        // measure contact id fetch
+        QList<QContactLocalId> ids;
+        startBenchmark(vcardFileName + QString(" / QContactManager::contactIds"));
+        ids = m_cm->contactIds();
+        QVERIFY(endBenchmark(0));
+        QCOMPARE(ids.count(), count);
+    }
+
+    {
+        // measure contact fetch
+        QList<QContact> contacts;
+        startBenchmark(vcardFileName + QString(" / QContactManager::contacts"));
+        contacts = m_cm->contacts();
+        QVERIFY(endBenchmark(0));
+        QCOMPARE(contacts.count(), count);
+    }
+
+    {
+        // measure contact fetch with fetch hint (only name)
+        QContactFetchHint hint;
+        hint.setDetailDefinitionsHint(QStringList() << QContactName::DefinitionName);
+        startBenchmark(vcardFileName + QString(" / QContactManager::contacts w/ detail definitions hint"));
+        QList<QContact> contacts = m_cm->contacts(QList<QContactSortOrder>(), hint);
+        QVERIFY(endBenchmark(0));
+        QCOMPARE(contacts.count(), count);
+    }
+
+    {
+        // measure contact fetch without relationships and binary blobs
+        QContactFetchHint hint;
+        hint.setOptimizationHints(QContactFetchHint::NoRelationships | QContactFetchHint::NoBinaryBlobs);
+        startBenchmark(vcardFileName + QString(" / QContactManager::contacts w/ optimization hints"));
+        QList<QContact> contacts = m_cm->contacts(QList<QContactSortOrder>(), hint);
+        QVERIFY(endBenchmark(0));
+        QCOMPARE(contacts.count(), count);
+    }
+
+    // TODO: measure sort
+    // TODO: measure filter etc...
+}
+
+void tst_Performance::addTestRows(QString fileNameFilter)
+{
+    // add new test row for each vcard file
+    QDir vcfDir(testDataPath);
+    QStringList tst_dataFiles = vcfDir.entryList(QStringList() << fileNameFilter);
+    foreach (QString tst_dataFile, tst_dataFiles) {
+        qDebug() << "Found new vcard file: " << tst_dataFile;
+        QTest::newRow(tst_dataFile.toAscii()) << tst_dataFile;
+    }
+}
+
+bool tst_Performance::importContacts(QString vcardFileName, int &contactCount)
+{
+    contactCount = 0;
+
+    QFile vcardFile(testDataPath + "/" + vcardFileName);
+    if (!vcardFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return false;
+    }
+
+    // Read contacts from vcard file
+    while (!vcardFile.atEnd()) {
+        QBuffer vcard;
+        QByteArray line = vcardFile.readLine();
+        if (line.startsWith(QByteArray("BEGIN:VCARD"))) {
+            vcard.open(QBuffer::ReadWrite);
+            vcard.write(line);
+            bool complete(false);
+            while (!complete && !vcardFile.atEnd()) {
+                line = vcardFile.readLine();
+                vcard.write(line);
+                if (line.contains(QByteArray("END:VCARD"))) {
+                    complete = true;
+                }
+            }
+
+            // Parse the input into QVersitDocuments
+            // Note: we could also use the more convenient QVersitReader(QByteArray) constructor.
+            QVersitReader reader(vcard.buffer());
+            if (!reader.startReading()) {return false;}
+            if (!reader.waitForFinished()) {return false;}
+
+            // Convert the QVersitDocuments to QContacts
+            QList<QVersitDocument> inputDocuments = reader.results();
+            QVersitContactImporter importer;
+            if (!importer.importDocuments(inputDocuments)) {
+                return false;
+            }
+
+            QList<QContact> contacts = importer.contacts();
+            if (!m_cm->saveContacts(&contacts, 0)) {
+                return false;
+            }
+            contactCount++;
+        }
+    }
+    //qDebug() << contactCount << "contacts added in total";
+    return true;
+}
+
+bool tst_Performance::detailsExist(QList<QContact> contacts, QStringList definitionNames)
+{
+    foreach(QContact contact, contacts) {
+        foreach (QString definitionName, definitionNames) {
+            QList<QContactDetail> details = contact.details(definitionName);
+            if (!details.count()) {
+                qDebug() << "Detail not found:" << definitionName;
+                return false;
+            }
+            foreach (QContactDetail detail, details) {
+                contact.removeDetail(&detail);
+            }
+        }
+
+        // Verify that there were no extra details (this is important from
+        // performance point of view; we don't want to waste time by giving
+        // details that the client does not need.
+        foreach (QContactDetail detail, contact.details()) {
+            // Skip "always on" details
+            if (detail.definitionName() != QContactDisplayLabel::DefinitionName
+                && detail.definitionName() != QContactType::DefinitionName
+                && detail.definitionName() != QContactGuid::DefinitionName
+                && detail.definitionName() != QContactTimestamp::DefinitionName) {
+                qDebug() << "Extra detail: " << detail.definitionName();
+                // displaylabel, type, guid, timestamp
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+void tst_Performance::startBenchmark(QString benchmarkName)
+{
+    qDebug() << "Starting benchmark" << benchmarkName;
+    m_benchmarkName = benchmarkName;
+    m_timer.start();
+}
+
+bool tst_Performance::endBenchmark(const int target)
+{
+    Q_ASSERT(!m_benchmarkName.isEmpty());
+    int result = m_timer.elapsed();
+    qDebug() << "The result for benchmark" << m_benchmarkName << "is [" << result << "]ms";
+    QFile resultFile(resultFileName);
+    if (resultFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
+        QTextStream out(&resultFile);
+        out << m_benchmarkName + QString(";") + QString::number(result) + "\r\n";
+        resultFile.close();
+    }
+
+    if (target == 0 || result <= target) {
+        return true;
+    }
+    qDebug() << "Target not reached!";
+    return false;
+}
+
+QTEST_MAIN(tst_Performance);
+#include "tst_performance.moc"