void ConversationModelTest::modifyEvent()
{
    ConversationModel model;
    model.enableContactChanges(false);
    watcher.setModel(&model);
    model.setQueryMode(EventModel::SyncQuery);
    QVERIFY(model.getEvents(group1.id()));

    Event event;
    /* modify invalid event */
    QVERIFY(!model.modifyEvent(event));

    QVERIFY(model.rowCount() > 0);

    int row = rand() % model.rowCount();
    event = model.event(model.index(row, 0));
    qDebug() << row << event.id() << event.freeText();
    event.setFreeText("modified event");
    QDateTime modified = event.lastModified();
    QVERIFY(model.modifyEvent(event));
    watcher.waitForSignals();
    QVERIFY(model.trackerIO().getEvent(event.id(), event));
    QCOMPARE(event.freeText(), QString("modified event"));

    QSKIP("Make nie:contentLastUpdated handling consistent", SkipSingle);
    event = model.event(model.index(row, 0));
    QCOMPARE(event.freeText(), QString("modified event"));
    QVERIFY(event.lastModified() > modified);
}
void Util::exportSMS(QTextStream &out) {
    GroupModel groupModel;
    groupModel.enableContactChanges(false);
    groupModel.setQueryMode(EventModel::SyncQuery);

    groupModel.getGroups();

    EventModel eventModel;
    ConversationModel model;
    model.enableContactChanges(false);
    model.setQueryMode(EventModel::SyncQuery);
    for (int i = 0; i < groupModel.rowCount(); i++) {
        Group g = groupModel.group(groupModel.index(i, 0));

        model.getEvents(g.id());

        // the events got by getEvents is reversed-ordered
        for (int i = model.rowCount() - 1; i >= 0; i--) {
            Event event = model.event(model.index(i, 0));
            out << QString(event.remoteUid() % QChar(',') %
                                      QString::number(event.direction()) % QChar(',') %
                                      event.startTime().toLocalTime().toString(QString("yyyy-MM-dd hh:mm:ss")) % QChar(',') %
                                      QChar('"') % event.freeText().replace(QChar('"'), QString("\"\"")) % QChar('"'));
            out << "\n";
        }
    }
}
void SyncModelTest::readAddedSmsEventsFromConvModel()
{
    //Adding 2 sms events to  group
    qsrand(QDateTime::currentDateTime().toTime_t());
    QDateTime sentReceivedTime = QDateTime::fromTime_t(qrand());
    QVERIFY(addEvent(4098, group.id(), sentReceivedTime, "121", "122", "Added grouped msg 1 # 121-122", false));
    QVERIFY(addEvent(4098, group.id(), sentReceivedTime, "121", "122", "Added grouped msg 2 # 121-122", false));

    //getting the first event and comparing
    ConversationModel convModel;
    convModel.enableContactChanges(false);
    convModel.setQueryMode(EventModel::SyncQuery);
    QVERIFY(convModel.getEvents(group.id()));
    QVERIFY(convModel.rowCount() == 2);

    for (int i = 0; i < 2; i++) {
        Event e = convModel.event(convModel.index(i, 0));
        if (i == 0) {
            QVERIFY(e.freeText() == "Added grouped msg 2 # 121-122");
        } else if (i == 1) {
            QVERIFY(e.freeText() == "Added grouped msg 1 # 121-122");
        }
    }

}
void ConversationModelTest::sorting()
{
    EventModel model;
    model.setQueryMode(EventModel::StreamedAsyncQuery);
    model.setFirstChunkSize(5);
    model.enableContactChanges(false);
    watcher.setModel(&model);

    //add events with the same timestamp
    QDateTime now = QDateTime::currentDateTime();
    QDateTime future = now.addSecs(10);

    addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                 group1.id(), "I", false, false, now);
    addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                 group1.id(), "II", false, false, now);
    addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                 group1.id(), "III", false, false, future);
    addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                 group1.id(), "IV", false, false, future);
    addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                 group1.id(), "V", false, false, future);

    watcher.waitForSignals(5, 5);

    ConversationModel conv;
    conv.setQueryMode(EventModel::StreamedAsyncQuery);
    conv.setFirstChunkSize(5);
    conv.enableContactChanges(false);
    QSignalSpy rowsInserted(&conv, SIGNAL(rowsInserted(const QModelIndex &, int, int)));

    QVERIFY(conv.getEvents(group1.id()));

    QVERIFY(waitSignal(rowsInserted));

    QVERIFY(conv.rowCount() >= 5 );

    QCOMPARE(conv.event(conv.index(0, 0)).freeText(), QLatin1String("V"));
    QCOMPARE(conv.event(conv.index(1, 0)).freeText(), QLatin1String("IV"));
    QCOMPARE(conv.event(conv.index(2, 0)).freeText(), QLatin1String("III"));
    QCOMPARE(conv.event(conv.index(3, 0)).freeText(), QLatin1String("II"));
    QCOMPARE(conv.event(conv.index(4, 0)).freeText(), QLatin1String("I"));
}
void ConversationModelTest::deleteEvent()
{
    ConversationModel model;
    model.enableContactChanges(false);
    watcher.setModel(&model);
    model.setQueryMode(EventModel::SyncQuery);
    QVERIFY(model.getEvents(group1.id()));

    Event event;
    /* delete invalid event */
    QVERIFY(!model.deleteEvent(event));

    int rows = model.rowCount();
    int row = rand() % rows;
    event = model.event(model.index(row, 0));
    qDebug() << row << event.id();
    QVERIFY(model.deleteEvent(event.id()));
    watcher.waitForSignals();
    QVERIFY(!model.trackerIO().getEvent(event.id(), event));
    QVERIFY(model.event(model.index(row, 0)).id() != event.id());
    QVERIFY(model.rowCount() == rows - 1);
}
void ConversationModelPerfTest::getEvents()
{
    QFETCH(int, messages);
    QFETCH(int, contacts);
    QFETCH(int, limit);

    qRegisterMetaType<QModelIndex>("QModelIndex");

    QDateTime startTime = QDateTime::currentDateTime();

    addTestGroups( group1, group2 );

    int commitBatchSize = 75;
    #ifdef PERF_BATCH_SIZE
    commitBatchSize = PERF_BATCH_SIZE;
    #endif

    EventModel addModel;
    QDateTime when = QDateTime::currentDateTime();
    QList<QString> remoteUids;

    qDebug() << __FUNCTION__ << "- Creating" << contacts << "new contacts";

    int ci = 0;
    while(ci < contacts) {
        ci++;
        QString phoneNumber = QString().setNum(qrand() % 10000000);
        remoteUids << phoneNumber;
        addTestContact(QString("Test Contact %1").arg(ci), phoneNumber);

        if(ci % commitBatchSize == 0 && ci < contacts) {
            qDebug() << __FUNCTION__ << "- adding" << commitBatchSize
                << "contacts (" << ci << "/" << contacts << ")";
            waitForIdle(5000);
        }
    }
    qDebug() << __FUNCTION__ << "- adding rest of the contacts ("
        << ci << "/" << contacts << ")";
    waitForIdle(5000);
    QTest::qWait(TIMEOUT);

    qDebug() << __FUNCTION__ << "- Creating" << messages << "new messages";

    QList<Event> eventList;

    int ei = 0;
    while(ei < messages) {
        ei++;

        Event::EventDirection direction;
        direction = qrand() % 2 > 0 ? Event::Inbound : Event::Outbound;

        Event e;
        e.setType(Event::SMSEvent);
        e.setDirection(direction);
        e.setGroupId(group1.id());
        e.setStartTime(when.addSecs(ei));
        e.setEndTime(when.addSecs(ei));
        e.setLocalUid(ACCOUNT1);
        e.setRemoteUid(remoteUids.at(0));
        e.setFreeText(randomMessage(qrand() % 49 + 1)); // Max 50 words / message
        e.setIsDraft(false);
        e.setIsMissedCall(false);

        eventList << e;

        if(ei % commitBatchSize == 0 && ei != messages) {
            qDebug() << __FUNCTION__ << "- adding" << commitBatchSize
                << "messages (" << ei << "/" << messages << ")";
            QVERIFY(addModel.addEvents(eventList, false));
            eventList.clear();
            waitForIdle();
        }
    }

    QVERIFY(addModel.addEvents(eventList, false));
    qDebug() << __FUNCTION__ << "- adding rest of the messages ("
        << ei << "/" << messages << ")";
    eventList.clear();
    waitForIdle();

    int iterations = 10;
    int sum = 0;
    QList<int> times;

    #ifdef PERF_ITERATIONS
    iterations = PERF_ITERATIONS;
    #endif

    char *iterVar = getenv("PERF_ITERATIONS");
    if (iterVar) {
        int iters = QString::fromAscii(iterVar).toInt();
        if (iters > 0) {
            iterations = iters;
        }
    }

    QTest::qWait(TIMEOUT);

    qDebug() << __FUNCTION__ << "- Fetching messages." << iterations << "iterations";
    for(int i = 0; i < iterations; i++) {

        ConversationModel fetchModel;
        bool result = false;

        QSignalSpy rowsInserted(&fetchModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)));

        if (limit < 0) {
            fetchModel.setQueryMode(EventModel::SyncQuery);
        } else {
            fetchModel.setQueryMode(EventModel::StreamedAsyncQuery);
            fetchModel.setFirstChunkSize(limit);
            fetchModel.setChunkSize(limit);
        }

        QTime time;
        time.start();
        result = fetchModel.getEvents(group1.id());

        if(limit >= 0) {
            while (time.elapsed() < 10000 && rowsInserted.isEmpty())
            QCoreApplication::processEvents();
        }

        int elapsed = time.elapsed();
        times << elapsed;
        sum += elapsed;
        qDebug("Time elapsed: %d ms", elapsed);

        QVERIFY(result);
        QVERIFY(fetchModel.rowCount() > 0);

        // With 1000 messages deleting model right away results in segfault
        waitForIdle();
    }

    if(logFile) {
        QTextStream out(logFile);

        out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << ": "
            << metaObject()->className() << "::" << QTest::currentTestFunction() << "("
            << QTest::currentDataTag() << ", " << iterations << " iterations)"
            << "\n";

        for (int i = 0; i < times.size(); i++) {
            out << times.at(i) << " ";
        }
        out << "\n";
    }

    qSort(times);
    float median = 0.0;
    if(iterations % 2 > 0) {
        median = times[(int)(iterations / 2)];
    } else {
        median = (times[iterations / 2] + times[iterations / 2 - 1]) / 2.0f;
    }

    float mean = sum / (float)iterations;
    int testSecs = startTime.secsTo(QDateTime::currentDateTime());

    qDebug("##### Mean: %.1f; Median: %.1f; Test time: %dsec", mean, median, testSecs);

    if(logFile) {
        QTextStream out(logFile);
        out << "Median average: " << (int)median << " ms. Test time: ";
        if (testSecs > 3600) { out << (testSecs / 3600) << "h "; }
        if (testSecs > 60) { out << ((testSecs % 3600) / 60) << "m "; }
        out << ((testSecs % 3600) % 60) << "s\n";
    }
}
void ConversationModelTest::addEvent()
{
    ConversationModel model;
    model.enableContactChanges(false);
    watcher.setModel(&model);
    model.setQueryMode(EventModel::SyncQuery);
    QVERIFY(model.getEvents(group1.id()));
    int rows = model.rowCount();

    QVERIFY(addTestEvent(model, Event::IMEvent, Event::Outbound, ACCOUNT1,
                         group1.id(), "added event") != -1);
    watcher.waitForSignals();
    rows++;
    QCOMPARE(model.rowCount(), rows);
    QCOMPARE(model.event(model.index(0, 0)).freeText(), QString("added event"));

    /* filtering by type */
    QVERIFY(model.setFilter(Event::IMEvent));
    rows = model.rowCount();
    QVERIFY(addTestEvent(model, Event::IMEvent, Event::Inbound, ACCOUNT1,
                         group1.id(), "im 1") != -1);
    watcher.waitForSignals();
    QVERIFY(addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                         group1.id(), "sms 1") != -1);
    watcher.waitForSignals();
    QCOMPARE(model.rowCount(), rows + 1);
    QCOMPARE(model.event(model.index(0, 0)).freeText(), QString("im 1"));

    /* filtering by account */
    QVERIFY(model.setFilter(Event::UnknownType, ACCOUNT1));
    rows = model.rowCount();
    QVERIFY(addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT2,
                         group1.id(), "account 2") != -1);
    watcher.waitForSignals();
    QVERIFY(addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT1,
                         group1.id(), "account 1") != -1);
    watcher.waitForSignals();
    QVERIFY(addTestEvent(model, Event::IMEvent, Event::Outbound, ACCOUNT1,
                         group1.id(), "account 1") != -1);
    watcher.waitForSignals();
    QCOMPARE(model.rowCount(), rows + 2);
    QCOMPARE(model.event(model.index(0, 0)).freeText(), QString("account 1"));

    /* filtering by direction */
    QVERIFY(model.setFilter(Event::UnknownType, "", Event::Inbound));
    rows = model.rowCount();
    QVERIFY(addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT2,
                         group1.id(), "in") != -1);
    watcher.waitForSignals();
    QVERIFY(addTestEvent(model, Event::SMSEvent, Event::Outbound, ACCOUNT1,
                         group1.id(), "out") != -1);
    watcher.waitForSignals();
    QVERIFY(addTestEvent(model, Event::IMEvent, Event::Inbound, ACCOUNT1,
                         group1.id(), "in") != -1);
    watcher.waitForSignals();
    QCOMPARE(model.rowCount(), rows + 2);
    QCOMPARE(model.event(model.index(0, 0)).freeText(), QString("in"));

    /* mixed filtering */
    QVERIFY(model.setFilter(Event::SMSEvent, ACCOUNT2, Event::Inbound));
    rows = model.rowCount();
    QVERIFY(addTestEvent(model, Event::IMEvent, Event::Inbound, ACCOUNT2,
                         group1.id(), "added event") != -1);
    watcher.waitForSignals();
    QCOMPARE(model.rowCount(), rows);
    QVERIFY(addTestEvent(model, Event::SMSEvent, Event::Inbound, ACCOUNT2,
                         group1.id(), "filtering works") != -1);
    watcher.waitForSignals();
    QCOMPARE(model.rowCount(), rows + 1);
    QCOMPARE(model.event(model.index(0, 0)).freeText(), QString("filtering works"));
}