text:
#include "ircbuffermodel.h"
#include "ircconnection.h"
#include "ircchannel.h"
#include "irccommand.h"
#include "ircbuffer.h"
#include "ircfilter.h"
#include <QtTest/QtTest>
#include "tst_ircclientserver.h"
#include "tst_ircdata.h"

class tst_IrcBufferModel : public tst_IrcClientServer
{
    Q_OBJECT

public:
    tst_IrcBufferModel();

private slots:
    void testDefaults();
    void testBufferInit();
    void testAddRemove();
    void testSorting();
    void testClear();
    void testPersistent();
    void testPrototypes();
    void testChanges();
    void testActive();
    void testRoles();
    void testAIM();
    void testQML();
    void testWarnings();
    void testMonitor();
};

Q_DECLARE_METATYPE(QModelIndex)
tst_IrcBufferModel::tst_IrcBufferModel()
{
    Irc::registerMetaTypes();
    qRegisterMetaType<QModelIndex>();
    qRegisterMetaType<IrcBuffer*>("IrcBuffer*");
    qRegisterMetaType<IrcChannel*>("IrcChannel*");
    qRegisterMetaType<IrcConnection*>("IrcConnection*");
    qRegisterMetaType<QList<IrcBuffer*> >("QList<IrcBuffer*>");
    qRegisterMetaType<QList<IrcChannel*> >("QList<IrcChannel*>");
}

void tst_IrcBufferModel::testDefaults()
{
    IrcBufferModel model;
    QCOMPARE(model.count(), 0);
    QVERIFY(model.isEmpty());
    QCOMPARE(model.sortOrder(), Qt::AscendingOrder);
    QCOMPARE(model.sortMethod(), Irc::SortByHand);
    QVERIFY(model.channels().isEmpty());
    QCOMPARE(model.displayRole(), Irc::TitleRole);
    QVERIFY(!model.isPersistent());
    QVERIFY(model.buffers().isEmpty());
    QVERIFY(!model.connection());
    QVERIFY(!model.network());
    QVERIFY(model.bufferPrototype());
    QVERIFY(model.channelPrototype());
    QVERIFY(!model.isMonitorEnabled());
}

void tst_IrcBufferModel::testBufferInit()
{
    IrcBufferModel model(connection);
    model.setSortMethod(Irc::SortByTitle);
    IrcBuffer* buffer1 = new IrcBuffer(&model);
    buffer1->setName(QStringLiteral("1"));
    model.add(buffer1);
    IrcBuffer* buffer2 = new IrcBuffer(&model);
    buffer2->setName(QStringLiteral("2"));
    model.add(buffer2);
}

void tst_IrcBufferModel::testAddRemove()
{
    IrcBufferModel model;

    QSignalSpy countSpy(&model, SIGNAL(countChanged(int)));
    QSignalSpy emptySpy(&model, SIGNAL(emptyChanged(bool)));
    QSignalSpy addedSpy(&model, SIGNAL(added(IrcBuffer*)));
    QSignalSpy removedSpy(&model, SIGNAL(removed(IrcBuffer*)));
    QSignalSpy aboutToBeAddedSpy(&model, SIGNAL(aboutToBeAdded(IrcBuffer*)));
    QSignalSpy aboutToBeRemovedSpy(&model, SIGNAL(aboutToBeRemoved(IrcBuffer*)));
    QSignalSpy buffersSpy(&model, SIGNAL(buffersChanged(QList<IrcBuffer*>)));
    QSignalSpy channelsSpy(&model, SIGNAL(channelsChanged(QStringList)));
    QVERIFY(countSpy.isValid());
    QVERIFY(emptySpy.isValid());
    QVERIFY(addedSpy.isValid());
    QVERIFY(removedSpy.isValid());
    QVERIFY(aboutToBeAddedSpy.isValid());
    QVERIFY(aboutToBeRemovedSpy.isValid());
    QVERIFY(buffersSpy.isValid());
    QVERIFY(channelsSpy.isValid());

    // IrcBuffer* IrcBufferModel::add(const QString& title)
    IrcBuffer* first = model.add(QStringLiteral("first"));
    QCOMPARE(model.count(), 1);
    QVERIFY(!model.isEmpty());
    QCOMPARE(model.get(0), first);
    QCOMPARE(model.find("first"), first);
    QCOMPARE(model.buffers(), QList<IrcBuffer*>() << first);
    QVERIFY(model.contains("first"));
    QCOMPARE(model.indexOf(first), 0);
    QVERIFY(model.channels().isEmpty());

    QCOMPARE(countSpy.count(), 1);
    QCOMPARE(countSpy.last().last().toInt(), 1);
    QCOMPARE(emptySpy.count(), 1);
    QCOMPARE(emptySpy.last().last().toBool(), false);
    QCOMPARE(aboutToBeAddedSpy.count(), 1);
    QCOMPARE(aboutToBeAddedSpy.last().last().value<IrcBuffer*>(), first);
    QCOMPARE(addedSpy.count(), 1);
    QCOMPARE(addedSpy.last().last().value<IrcBuffer*>(), first);
    QCOMPARE(buffersSpy.count(), 1);
    QCOMPARE(buffersSpy.last().last().value<QList<IrcBuffer*> >(), QList<IrcBuffer*>() << first);
    QCOMPARE(channelsSpy.count(), 0);

    QModelIndex firstIdx = model.index(first);
    QVERIFY(firstIdx.isValid());
    QCOMPARE(firstIdx.data(Irc::NameRole).toString(), QString("first"));
    QCOMPARE(firstIdx.data(Irc::TitleRole).toString(), QString("first"));
    QCOMPARE(firstIdx.data(Irc::PrefixRole).toString(), QString());
    QCOMPARE(firstIdx.data(Irc::BufferRole).value<IrcBuffer*>(), first);
    QVERIFY(!firstIdx.data(Irc::ChannelRole).value<IrcChannel*>());

    // void IrcBufferModel::add(IrcBuffer* buffer)
    IrcBuffer* second = new IrcBuffer(&model);
    second->setName(QStringLiteral("second"));
    model.add(second);
    QCOMPARE(model.count(), 2);
    QVERIFY(!model.isEmpty());
    QCOMPARE(model.get(1), second);
    QCOMPARE(model.find("second"), second);
    QCOMPARE(model.buffers(), QList<IrcBuffer*>() << first << second);
    QVERIFY(model.contains("second"));
    QCOMPARE(model.indexOf(second), 1);
    QVERIFY(model.channels().isEmpty());

    QCOMPARE(countSpy.count(), 2);
    QCOMPARE(countSpy.last().last().toInt(), 2);
    QCOMPARE(emptySpy.count(), 1);
    QCOMPARE(aboutToBeAddedSpy.count(), 2);
    QCOMPARE(aboutToBeAddedSpy.last().last().value<IrcBuffer*>(), second);
    QCOMPARE(addedSpy.count(), 2);
    QCOMPARE(addedSpy.last().last().value<IrcBuffer*>(), second);
    QCOMPARE(buffersSpy.count(), 2);
    QCOMPARE(buffersSpy.last().last().value<QList<IrcBuffer*> >(), QList<IrcBuffer*>() << first << second);
    QCOMPARE(channelsSpy.count(), 0);

    QModelIndex secondIdx = model.index(second);
    QVERIFY(secondIdx.isValid());
    QCOMPARE(secondIdx.data(Irc::NameRole).toString(), QString("second"));
    QCOMPARE(secondIdx.data(Irc::TitleRole).toString(), QString("second"));
    QCOMPARE(secondIdx.data(Irc::PrefixRole).toString(), QString());
    QCOMPARE(secondIdx.data(Irc::BufferRole).value<IrcBuffer*>(), second);
    QVERIFY(!secondIdx.data(Irc::ChannelRole).value<IrcChannel*>());

    // void IrcBufferModel::remove(IrcBuffer* buffer)
    model.remove(second);
    QCOMPARE(model.count(), 1);
    QVERIFY(!model.isEmpty());
    QVERIFY(!model.find("second"));
    QCOMPARE(model.buffers(), QList<IrcBuffer*>() << first);
    QVERIFY(!model.contains("second"));
    QVERIFY(model.channels().isEmpty());

    QCOMPARE(countSpy.count(), 3);
    QCOMPARE(countSpy.last().last().toInt(), 1);
    QCOMPARE(emptySpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSpy.count(), 1);
    QCOMPARE(removedSpy.count(), 1);
    QCOMPARE(buffersSpy.count(), 3);
    QCOMPARE(buffersSpy.last().last().value<QList<IrcBuffer*> >(), QList<IrcBuffer*>() << first);
    QCOMPARE(channelsSpy.count(), 0);

    // void IrcBufferModel::remove(const QString& title)
    model.remove(QStringLiteral("first"));
    QCOMPARE(model.count(), 0);
    QVERIFY(model.isEmpty());
    QVERIFY(!model.find("first"));
    QVERIFY(model.buffers().isEmpty());
    QVERIFY(!model.contains("first"));
    QVERIFY(model.channels().isEmpty());

    QCOMPARE(countSpy.count(), 4);
    QCOMPARE(countSpy.last().last().toInt(), 0);
    QCOMPARE(emptySpy.count(), 2);
    QCOMPARE(emptySpy.last().last().toBool(), true);
    QCOMPARE(aboutToBeRemovedSpy.count(), 2);
    QCOMPARE(removedSpy.count(), 2);
    QCOMPARE(buffersSpy.count(), 4);
    QCOMPARE(buffersSpy.last().last().value<QList<IrcBuffer*> >(), QList<IrcBuffer*>());
    QCOMPARE(channelsSpy.count(), 0);
}

void tst_IrcBufferModel::testSorting()
{
    IrcBufferModel staticModel(connection);
    IrcBufferModel dynamicModel(connection);

    connection->open();
    waitForOpened();
    waitForWritten(tst_IrcData::welcome());

    IrcBuffer* b = staticModel.add(QStringLiteral("b"));
    IrcBuffer* c = staticModel.add(QStringLiteral("#c"));
    IrcBuffer* a = staticModel.add(QStringLiteral("#a"));

    QList<IrcBuffer*> buffers =  QList<IrcBuffer*>() << b << c << a;
    QCOMPARE(staticModel.buffers(), buffers);

    // IGNORE INVALID COLUMNS
    staticModel.sort(-1, Qt::AscendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    staticModel.sort(1, Qt::AscendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    // STATIC - BY NAME - ASCENDING
    buffers =  QList<IrcBuffer*>() << a << b << c;
    staticModel.setSortMethod(Irc::SortByName);
    staticModel.sort(0, Qt::AscendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    // STATIC - BY NAME - DESCENDING
    buffers =  QList<IrcBuffer*>() << c << b << a;
    staticModel.setSortMethod(Irc::SortByName);
    staticModel.sort(0, Qt::DescendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    // STATIC - BY TITLE - ASCENDING
    buffers =  QList<IrcBuffer*>() << a << c << b;
    staticModel.setSortMethod(Irc::SortByTitle);
    staticModel.sort(0, Qt::AscendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    // STATIC - BY TITLE - DESCENDING
    buffers =  QList<IrcBuffer*>() << b << c << a;
    staticModel.setSortMethod(Irc::SortByTitle);
    staticModel.sort(0, Qt::DescendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    // STATIC - BY TITLE - ASCENDING & STICKY
    c->setSticky(true);
    buffers =  QList<IrcBuffer*>() << c << a << b;
    staticModel.setSortMethod(Irc::SortByTitle);
    staticModel.sort(0, Qt::AscendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    // STATIC - BY TITLE - ASCENDING & 2 STICKIES
    b->setSticky(true);
    buffers =  QList<IrcBuffer*>() << c << b << a;
    staticModel.setSortMethod(Irc::SortByTitle);
    staticModel.sort(0, Qt::AscendingOrder);
    QCOMPARE(staticModel.buffers(), buffers);

    b = dynamicModel.add(QStringLiteral("b"));
    c = dynamicModel.add(QStringLiteral("#c"));
    a = dynamicModel.add(QStringLiteral("#a"));

    // DYNAMIC - BY NAME - ASCENDING
    buffers =  QList<IrcBuffer*>() << a << b << c;
    dynamicModel.setSortMethod(Irc::SortByName);
    QCOMPARE(dynamicModel.buffers(), buffers);

    // DYNAMIC - BY TITLE - ASCENDING
    buffers =  QList<IrcBuffer*>() << a << c << b;
    dynamicModel.setSortMethod(Irc::SortByTitle);
    QCOMPARE(dynamicModel.buffers(), buffers);

    dynamicModel.setSortOrder(Qt::DescendingOrder);

    // DYNAMIC - BY NAME - DESCENDING
    buffers =  QList<IrcBuffer*>() << c << b << a;
    dynamicModel.setSortMethod(Irc::SortByName);
    QCOMPARE(dynamicModel.buffers(), buffers);

    // DYNAMIC - BY TITLE - DESCENDING
    buffers =  QList<IrcBuffer*>() << b << c << a;
    dynamicModel.setSortMethod(Irc::SortByTitle);
    QCOMPARE(dynamicModel.buffers(), buffers);

    // DO NOTHING
    dynamicModel.sort(Irc::SortByHand);
    QCOMPARE(dynamicModel.buffers(), buffers);
}

void tst_IrcBufferModel::testClear()
{
    IrcBufferModel model(connection);
    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome()));

    QPointer<IrcBuffer> a = model.add(QStringLiteral("#a"));
    QPointer<IrcBuffer> b = model.add(QStringLiteral("#b"));
    QPointer<IrcBuffer> c = model.add(QStringLiteral("c"));
    QPointer<IrcBuffer> d = model.add(QStringLiteral("d"));

    QSignalSpy countSpy(&model, SIGNAL(countChanged(int)));
    QSignalSpy buffersSpy(&model, SIGNAL(buffersChanged(QList<IrcBuffer*>)));
    QSignalSpy channelsSpy(&model, SIGNAL(channelsChanged(QStringList)));
    QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
    QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));

    QVERIFY(countSpy.isValid());
    QVERIFY(buffersSpy.isValid());
    QVERIFY(channelsSpy.isValid());
    QVERIFY(modelAboutToBeResetSpy.isValid());
    QVERIFY(modelResetSpy.isValid());

    b->setPersistent(true);
    d->setPersistent(true);

    // #a, #b*, c, d*
    model.clear();

    QCOMPARE(model.count(), 2);
    QCOMPARE(model.buffers(), QList<IrcBuffer*>() << b << d);
    QCOMPARE(model.channels(), QStringList() << "#b");

    QCOMPARE(model.get(0), b.data());
    QCOMPARE(model.get(1), d.data());
    QVERIFY(!model.get(2));
    QVERIFY(!model.find("#a"));
    QVERIFY(model.find("#b"));
    QVERIFY(!model.find("c"));
    QVERIFY(model.find("d"));
    QVERIFY(!model.contains("#a"));
    QVERIFY(model.contains("#b"));
    QVERIFY(!model.contains("c"));
    QVERIFY(model.contains("d"));

    QVERIFY(!a);
    QVERIFY(b);
    QVERIFY(!c);
    QVERIFY(d);

    QCOMPARE(countSpy.count(), 1);
    QCOMPARE(countSpy.last().at(0).toInt(), 2);

    QCOMPARE(buffersSpy.count(), 1);
    QCOMPARE(buffersSpy.last().at(0).value<QList<IrcBuffer*> >(), QList<IrcBuffer*>() << b << d);

    QCOMPARE(channelsSpy.count(), 1);
    QCOMPARE(channelsSpy.last().at(0).toStringList(), QStringList() << "#b");

    QCOMPARE(modelAboutToBeResetSpy.count(), 1);
    QCOMPARE(modelResetSpy.count(), 1);

    b->setPersistent(false);

    countSpy.clear();
    buffersSpy.clear();
    channelsSpy.clear();
    modelAboutToBeResetSpy.clear();
    modelResetSpy.clear();

    // #b, d*
    model.clear();

    QCOMPARE(model.count(), 1);
    QCOMPARE(model.buffers(), QList<IrcBuffer*>() << d);
    QCOMPARE(model.channels(), QStringList());

    QCOMPARE(model.get(0), d.data());
    QVERIFY(!model.get(1));
    QVERIFY(!model.find("#b"));
    QVERIFY(model.find("d"));
    QVERIFY(!model.contains("#b"));
    QVERIFY(model.contains("d"));

    QVERIFY(!b);
    QVERIFY(d);

    QCOMPARE(countSpy.count(), 1);
    QCOMPARE(countSpy.last().at(0).toInt(), 1);

    QCOMPARE(buffersSpy.count(), 1);
    QCOMPARE(buffersSpy.last().at(0).value<QList<IrcBuffer*> >(), QList<IrcBuffer*>() << d);

    QCOMPARE(channelsSpy.count(), 1);
    QCOMPARE(channelsSpy.last().at(0).toStringList(), QStringList());

    QCOMPARE(modelAboutToBeResetSpy.count(), 1);
    QCOMPARE(modelResetSpy.count(), 1);

    d->setPersistent(false);

    countSpy.clear();
    buffersSpy.clear();
    channelsSpy.clear();
    modelAboutToBeResetSpy.clear();
    modelResetSpy.clear();

    // d
    model.clear();

    QCOMPARE(model.count(), 0);
    QCOMPARE(model.buffers(), QList<IrcBuffer*>());
    QCOMPARE(model.channels(), QStringList());

    QVERIFY(!model.get(0));
    QVERIFY(!model.find("d"));
    QVERIFY(!model.contains("d"));

    QVERIFY(!d);

    QCOMPARE(countSpy.count(), 1);
    QCOMPARE(countSpy.last().at(0).toInt(), 0);

    QCOMPARE(buffersSpy.count(), 1);
    QCOMPARE(buffersSpy.last().at(0).value<QList<IrcBuffer*> >(), QList<IrcBuffer*>());

    QCOMPARE(channelsSpy.count(), 0);

    QCOMPARE(modelAboutToBeResetSpy.count(), 1);
    QCOMPARE(modelResetSpy.count(), 1);

    countSpy.clear();
    buffersSpy.clear();
    channelsSpy.clear();
    modelAboutToBeResetSpy.clear();
    modelResetSpy.clear();

    // <empty>
    model.clear();

    QCOMPARE(countSpy.count(), 0);
    QCOMPARE(buffersSpy.count(), 0);
    QCOMPARE(channelsSpy.count(), 0);
    QCOMPARE(modelAboutToBeResetSpy.count(), 0);
    QCOMPARE(modelResetSpy.count(), 0);

    QPointer<IrcBuffer> e = model.add(QStringLiteral("e"));
    QPointer<IrcBuffer> f = model.add(QStringLiteral("f"));

    e->setPersistent(true);
    f->setPersistent(true);

    countSpy.clear();
    buffersSpy.clear();
    channelsSpy.clear();
    modelAboutToBeResetSpy.clear();
    modelResetSpy.clear();

    // e*, f*
    model.clear();

    QVERIFY(e);
    QVERIFY(f);

    QCOMPARE(countSpy.count(), 0);
    QCOMPARE(buffersSpy.count(), 0);
    QCOMPARE(channelsSpy.count(), 0);
    QCOMPARE(modelAboutToBeResetSpy.count(), 0);
    QCOMPARE(modelResetSpy.count(), 0);

    qDeleteAll(model.buffers());

    QCOMPARE(model.count(), 0);
    QCOMPARE(model.buffers(), QList<IrcBuffer*>());
    QCOMPARE(model.channels(), QStringList());

    QVERIFY(!model.get(0));
    QVERIFY(!model.find("e"));
    QVERIFY(!model.find("f"));
    QVERIFY(!model.contains("e"));
    QVERIFY(!model.contains("f"));

    QVERIFY(!e);
    QVERIFY(!f);

    QCOMPARE(countSpy.count(), 2);
    QCOMPARE(countSpy.at(0).at(0).toInt(), 1);
    QCOMPARE(countSpy.at(1).at(0).toInt(), 0);

    QCOMPARE(buffersSpy.count(), 2);
    QCOMPARE(buffersSpy.at(0).at(0).value<QList<IrcBuffer*> >().count(), 1);
    QCOMPARE(buffersSpy.at(1).at(0).value<QList<IrcBuffer*> >(), QList<IrcBuffer*>());

    QCOMPARE(channelsSpy.count(), 0);

    QCOMPARE(modelAboutToBeResetSpy.count(), 0);
    QCOMPARE(modelResetSpy.count(), 0);
}

void tst_IrcBufferModel::testPersistent()
{
    IrcBufferModel model(connection);
    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome()));

    QVERIFY(waitForWritten(":communi!communi@hidd.en JOIN :#communi"));
    QCOMPARE(model.count(), 1);

    QPointer<IrcChannel> channel = model.get(0)->toChannel();
    QVERIFY(channel);

    QVERIFY(!model.isPersistent());
    QVERIFY(!channel->isPersistent());
    QVERIFY(waitForWritten(":communi!communi@hidd.en PART :#communi"));
    QVERIFY(model.isEmpty());
    QVERIFY(channel); // deleteLater()'d
    QCoreApplication::sendPostedEvents(channel, QEvent::DeferredDelete);
    QVERIFY(!channel); // deleteLater()'d

    QVERIFY(waitForWritten(":communi!communi@hidd.en JOIN :#communi"));
    QCOMPARE(model.count(), 1);
    channel = model.get(0)->toChannel();
    QVERIFY(channel);

    model.setPersistent(true);
    QVERIFY(model.isPersistent());
    QVERIFY(!channel->isPersistent());
    QVERIFY(waitForWritten(":communi!communi@hidd.en PART :#communi"));
    QVERIFY(channel);
    QCOMPARE(model.count(), 1);

    channel->setPersistent(true);
    QVERIFY(model.isPersistent());
    QVERIFY(channel->isPersistent());
    QVERIFY(waitForWritten(":communi!communi@hidd.en PART :#communi"));
    QVERIFY(channel);
    QCOMPARE(model.count(), 1);

    model.setPersistent(false);
    QVERIFY(!model.isPersistent());
    QVERIFY(channel->isPersistent());
    QVERIFY(waitForWritten(":communi!communi@hidd.en PART :#communi"));
    QVERIFY(channel);
    QCOMPARE(model.count(), 1);

    channel->setPersistent(false);
    QVERIFY(!model.isPersistent());
    QVERIFY(!channel->isPersistent());
    QVERIFY(waitForWritten(":communi!communi@hidd.en PART :#communi"));
    QVERIFY(model.isEmpty());
    QVERIFY(channel); // deleteLater()'d
    QCoreApplication::sendPostedEvents(channel, QEvent::DeferredDelete);
    QVERIFY(!channel); // deleteLater()'d
}

void tst_IrcBufferModel::testPrototypes()
{
    IrcBufferModel model;

    QSignalSpy bufferProtoSpy(&model, SIGNAL(bufferPrototypeChanged(IrcBuffer*)));
    QSignalSpy channelProtoSpy(&model, SIGNAL(channelPrototypeChanged(IrcChannel*)));
    QVERIFY(bufferProtoSpy.isValid());
    QVERIFY(channelProtoSpy.isValid());

    model.setBufferPrototype(nullptr);
    QVERIFY(model.bufferPrototype());
    QCOMPARE(bufferProtoSpy.count(), 1);

    model.setChannelPrototype(nullptr);
    QVERIFY(model.channelPrototype());
    QCOMPARE(channelProtoSpy.count(), 1);

    IrcBuffer* bufferProto = new IrcBuffer(&model);
    model.setBufferPrototype(bufferProto);
    QCOMPARE(model.bufferPrototype(), bufferProto);
    QCOMPARE(bufferProtoSpy.count(), 2);

    IrcChannel* channelProto = new IrcChannel(&model);
    model.setChannelPrototype(channelProto);
    QCOMPARE(model.channelPrototype(), channelProto);
    QCOMPARE(channelProtoSpy.count(), 2);
}

void tst_IrcBufferModel::testChanges()
{
    IrcBufferModel bufferModel;

    // IrcBufferModel signals
    QSignalSpy countChangedSpy(&bufferModel, SIGNAL(countChanged(int)));
    QSignalSpy addedSpy(&bufferModel, SIGNAL(added(IrcBuffer*)));
    QSignalSpy removedSpy(&bufferModel, SIGNAL(removed(IrcBuffer*)));
    QSignalSpy aboutToBeAddedSpy(&bufferModel, SIGNAL(aboutToBeAdded(IrcBuffer*)));
    QSignalSpy aboutToBeRemovedSpy(&bufferModel, SIGNAL(aboutToBeRemoved(IrcBuffer*)));
    QSignalSpy buffersChangedSpy(&bufferModel, SIGNAL(buffersChanged(QList<IrcBuffer*>)));
    QSignalSpy channelsChangedSpy(&bufferModel, SIGNAL(channelsChanged(QStringList)));

    QVERIFY(countChangedSpy.isValid());
    QVERIFY(addedSpy.isValid());
    QVERIFY(removedSpy.isValid());
    QVERIFY(aboutToBeAddedSpy.isValid());
    QVERIFY(aboutToBeRemovedSpy.isValid());
    QVERIFY(buffersChangedSpy.isValid());
    QVERIFY(channelsChangedSpy.isValid());

    int countChangedCount = 0;
    int aboutToBeAddedCount = 0, addedCount = 0;
    int aboutToBeRemovedCount = 0, removedCount = 0;
    int buffersChangedCount = 0;
    int channelsChangedCount = 0;

    QSignalSpy connectionChangedSpy(&bufferModel, SIGNAL(connectionChanged(IrcConnection*)));
    QSignalSpy networkChangedSpy(&bufferModel, SIGNAL(networkChanged(IrcNetwork*)));
    QSignalSpy messageIgnoredSpy(&bufferModel, SIGNAL(messageIgnored(IrcMessage*)));

    QVERIFY(connectionChangedSpy.isValid());
    QVERIFY(networkChangedSpy.isValid());
    QVERIFY(messageIgnoredSpy.isValid());

    int connectionChangedCount = 0;
    int networkChangedCount = 0;
    int messageIgnoredCount = 0;

    // relevant QAbstractItemModel signals
    QSignalSpy dataChangedSpy(&bufferModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
    QSignalSpy layoutAboutToBeChangedSpy(&bufferModel, SIGNAL(layoutAboutToBeChanged()));
    QSignalSpy layoutChangedSpy(&bufferModel, SIGNAL(layoutChanged()));
    QSignalSpy rowsAboutToBeInsertedSpy(&bufferModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
    QSignalSpy rowsInsertedSpy(&bufferModel, SIGNAL(rowsInserted(QModelIndex,int,int)));
    QSignalSpy rowsAboutToBeRemovedSpy(&bufferModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
    QSignalSpy rowsRemovedSpy(&bufferModel, SIGNAL(rowsRemoved(QModelIndex,int,int)));

    QVERIFY(dataChangedSpy.isValid());
    QVERIFY(layoutAboutToBeChangedSpy.isValid());
    QVERIFY(layoutChangedSpy.isValid());
    QVERIFY(rowsAboutToBeInsertedSpy.isValid());
    QVERIFY(rowsInsertedSpy.isValid());
    QVERIFY(rowsAboutToBeRemovedSpy.isValid());
    QVERIFY(rowsRemovedSpy.isValid());

    int dataChangedCount = 0;
    int layoutAboutToBeChangedCount = 0, layoutChangedCount = 0;
    int rowsAboutToBeInsertedCount = 0, rowsInsertedCount = 0;
    int rowsAboutToBeRemovedCount = 0, rowsRemovedCount = 0;

    bufferModel.setConnection(connection);
    QCOMPARE(connectionChangedSpy.count(), ++connectionChangedCount);
    QCOMPARE(networkChangedSpy.count(), ++networkChangedCount);

    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome()));

    messageIgnoredCount = tst_IrcData::welcome().split('\n').count(); // N lines + a combined motd msg

    QCOMPARE(bufferModel.count(), 0);
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QVERIFY(waitForWritten(":communi!communi@hidd.en JOIN :#communi"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QCOMPARE(bufferModel.count(), 1);

    QPointer<IrcChannel> communi = bufferModel.get(0)->toChannel();
    QVERIFY(communi);
    QCOMPARE(communi->title(), QString("#communi"));
    QCOMPARE(communi->name(), QString("communi"));
    QCOMPARE(communi->prefix(), QString("#"));

    int previousIndex = -1;

    QList<IrcBuffer*> buffers = QList<IrcBuffer*>() << communi;
    QStringList channels = QStringList() << QStringLiteral("#communi");

    int nextIndex = buffers.indexOf(communi);

    QCOMPARE(bufferModel.count(), buffers.count());
    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }
    QCOMPARE(bufferModel.channels(), channels);

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), ++aboutToBeAddedCount);
    QCOMPARE(aboutToBeAddedSpy.last().at(0).value<IrcBuffer*>(), communi.data());

    QCOMPARE(addedSpy.count(), ++addedCount);
    QCOMPARE(addedSpy.last().at(0).value<IrcBuffer*>(), communi.data());

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), ++channelsChangedCount);
    QCOMPARE(channelsChangedSpy.last().at(0).toStringList(), channels);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);

    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), ++rowsAboutToBeInsertedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(2).toInt(), nextIndex);

    QCOMPARE(rowsInsertedSpy.count(), ++rowsInsertedCount);
    QCOMPARE(rowsInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsInsertedSpy.last().at(2).toInt(), nextIndex);

    QVERIFY(waitForWritten(":ChanServ!ChanServ@services. NOTICE communi :fake..."));
    QCOMPARE(messageIgnoredSpy.count(), ++messageIgnoredCount);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    QCOMPARE(countChangedSpy.count(), countChangedCount);
    QCOMPARE(aboutToBeAddedSpy.count(), aboutToBeAddedCount);
    QCOMPARE(addedSpy.count(), addedCount);
    QCOMPARE(buffersChangedSpy.count(), buffersChangedCount);
    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);
    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);
    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.count(), rowsAboutToBeInsertedCount);
    QCOMPARE(rowsInsertedSpy.count(), rowsInsertedCount);

    QVERIFY(waitForWritten(":ChanServ!ChanServ@services. PRIVMSG communi :fake..."));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QPointer<IrcBuffer> ChanServ = bufferModel.get(1);
    QVERIFY(ChanServ);
    QCOMPARE(ChanServ->title(), QString("ChanServ"));
    QCOMPARE(ChanServ->name(), QString("ChanServ"));
    QCOMPARE(ChanServ->prefix(), QString());

    previousIndex = -1;

    buffers = QList<IrcBuffer*>() << communi << ChanServ;
    channels = QStringList() << QStringLiteral("#communi");

    nextIndex = buffers.indexOf(ChanServ);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    QCOMPARE(bufferModel.count(), buffers.count());
    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), ++aboutToBeAddedCount);
    QCOMPARE(aboutToBeAddedSpy.last().at(0).value<IrcBuffer*>(), ChanServ.data());

    QCOMPARE(addedSpy.count(), ++addedCount);
    QCOMPARE(addedSpy.last().at(0).value<IrcBuffer*>(), ChanServ.data());

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);

    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), ++rowsAboutToBeInsertedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(2).toInt(), nextIndex);

    QCOMPARE(rowsInsertedSpy.count(), ++rowsInsertedCount);
    QCOMPARE(rowsInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsInsertedSpy.last().at(2).toInt(), nextIndex);

    QVERIFY(waitForWritten(":ChanServ!ChanServ@services. NOTICE communi :fake..."));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    QCOMPARE(bufferModel.count(), buffers.count());
    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), countChangedCount);
    QCOMPARE(aboutToBeAddedSpy.count(), aboutToBeAddedCount);
    QCOMPARE(addedSpy.count(), addedCount);
    QCOMPARE(buffersChangedSpy.count(), buffersChangedCount);
    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);
    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);
    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.count(), rowsAboutToBeInsertedCount);
    QCOMPARE(rowsInsertedSpy.count(), rowsInsertedCount);

    QVERIFY(waitForWritten(":communi!communi@hidd.en JOIN :#libera"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QPointer<IrcChannel> libera = bufferModel.get(2)->toChannel();
    QVERIFY(libera);
    QCOMPARE(libera->title(), QString("#libera"));
    QCOMPARE(libera->name(), QString("libera"));
    QCOMPARE(libera->prefix(), QString("#"));

    previousIndex = -1;

    buffers = QList<IrcBuffer*>() << communi << ChanServ << libera;
    channels = QStringList() << QStringLiteral("#communi") << QStringLiteral("#libera");

    nextIndex = buffers.indexOf(libera);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), ++aboutToBeAddedCount);
    QCOMPARE(aboutToBeAddedSpy.last().at(0).value<IrcBuffer*>(), libera.data());

    QCOMPARE(addedSpy.count(), ++addedCount);
    QCOMPARE(addedSpy.last().at(0).value<IrcBuffer*>(), libera.data());

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), ++channelsChangedCount);
    QCOMPARE(channelsChangedSpy.last().at(0).toStringList(), channels);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);

    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), ++rowsAboutToBeInsertedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(2).toInt(), nextIndex);

    QCOMPARE(rowsInsertedSpy.count(), ++rowsInsertedCount);
    QCOMPARE(rowsInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsInsertedSpy.last().at(2).toInt(), nextIndex);

    bufferModel.setSortMethod(Irc::SortByTitle);
    QCOMPARE(layoutAboutToBeChangedSpy.count(), ++layoutAboutToBeChangedCount);
    QCOMPARE(layoutChangedSpy.count(), ++layoutChangedCount);

    previousIndex = -1;

    // Irc::SortByTitle
    buffers = QList<IrcBuffer*>() << communi << libera << ChanServ;
    channels = QStringList() << QStringLiteral("#communi") << QStringLiteral("#libera");

    nextIndex = -1;

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    bufferModel.setSortMethod(Irc::SortByName);
    QCOMPARE(layoutAboutToBeChangedSpy.count(), ++layoutAboutToBeChangedCount);
    QCOMPARE(layoutChangedSpy.count(), ++layoutChangedCount);

    bufferModel.setSortOrder(Qt::DescendingOrder);
    QCOMPARE(layoutAboutToBeChangedSpy.count(), ++layoutAboutToBeChangedCount);
    QCOMPARE(layoutChangedSpy.count(), ++layoutChangedCount);

    previousIndex = -1;

    // Irc::SortByName, Qt::DescendingOrder
    buffers = QList<IrcBuffer*>() << libera << communi << ChanServ;
    channels = QStringList() << QStringLiteral("#communi") << QStringLiteral("#libera");

    nextIndex = -1;

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QVERIFY(waitForWritten(":qtassistant!qtassistant@hidd.en PRIVMSG communi :hola"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QPointer<IrcBuffer> qtassistant = bufferModel.get(0);
    QVERIFY(qtassistant);
    QCOMPARE(qtassistant->title(), QString("qtassistant"));
    QCOMPARE(qtassistant->name(), QString("qtassistant"));
    QCOMPARE(qtassistant->prefix(), QString());

    previousIndex = -1;

    // Irc::SortByName, Qt::DescendingOrder
    buffers = QList<IrcBuffer*>() << qtassistant << libera << communi << ChanServ;
    channels = QStringList() << QStringLiteral("#communi") << QStringLiteral("#libera");

    nextIndex = buffers.indexOf(qtassistant);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), ++aboutToBeAddedCount);
    QCOMPARE(aboutToBeAddedSpy.last().at(0).value<IrcBuffer*>(), qtassistant.data());

    QCOMPARE(addedSpy.count(), ++addedCount);
    QCOMPARE(addedSpy.last().at(0).value<IrcBuffer*>(), qtassistant.data());

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);

    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), ++rowsAboutToBeInsertedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(2).toInt(), nextIndex);

    QCOMPARE(rowsInsertedSpy.count(), ++rowsInsertedCount);
    QCOMPARE(rowsInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsInsertedSpy.last().at(2).toInt(), nextIndex);

    QSignalSpy titleChangedSpy(qtassistant, SIGNAL(titleChanged(QString)));
    QSignalSpy nameChangedSpy(qtassistant, SIGNAL(nameChanged(QString)));
    QSignalSpy prefixChangedSpy(qtassistant, SIGNAL(prefixChanged(QString)));

    QVERIFY(titleChangedSpy.isValid());
    QVERIFY(nameChangedSpy.isValid());
    QVERIFY(prefixChangedSpy.isValid());

    int titleChangedCount = 0;
    int nameChangedCount = 0;
    int prefixChangedCount = 0;

    QVERIFY(waitForWritten(":qtassistant!qtassistant@hidd.en NICK assistant :hola"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QCOMPARE(qtassistant->title(), QString("assistant"));
    QCOMPARE(qtassistant->name(), QString("assistant"));
    QCOMPARE(qtassistant->prefix(), QString());

    QCOMPARE(titleChangedSpy.count(), ++titleChangedCount);
    QCOMPARE(nameChangedSpy.count(), ++nameChangedCount);
    QCOMPARE(prefixChangedSpy.count(), prefixChangedCount);

    previousIndex = buffers.indexOf(qtassistant);

    // Irc::SortByName, Qt::DescendingOrder
    buffers = QList<IrcBuffer*>() << libera << communi << ChanServ << qtassistant; // qtassistant=assistant
    channels = QStringList() << QStringLiteral("#communi") << QStringLiteral("#libera");

    nextIndex = buffers.indexOf(qtassistant);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), countChangedCount);

    QCOMPARE(aboutToBeAddedSpy.count(), aboutToBeAddedCount);

    QCOMPARE(addedSpy.count(), addedCount);

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);

    QCOMPARE(dataChangedSpy.count(), ++dataChangedCount);
    QModelIndex topLeft = dataChangedSpy.last().at(0).value<QModelIndex>();
    QModelIndex bottomRight = dataChangedSpy.last().at(0).value<QModelIndex>();
    QVERIFY(!topLeft.parent().isValid());
    QVERIFY(topLeft.isValid());
    QVERIFY(bottomRight.isValid());
    QVERIFY(topLeft == bottomRight);
    QCOMPARE(topLeft.row(), previousIndex);
    QCOMPARE(topLeft.column(), 0);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), ++rowsAboutToBeRemovedCount);
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(1).toInt(), previousIndex);
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(2).toInt(), previousIndex);

    QCOMPARE(rowsRemovedSpy.count(), ++rowsRemovedCount);
    QCOMPARE(rowsRemovedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsRemovedSpy.last().at(1).toInt(), previousIndex);
    QCOMPARE(rowsRemovedSpy.last().at(2).toInt(), previousIndex);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), ++rowsAboutToBeInsertedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(2).toInt(), nextIndex);

    QCOMPARE(rowsInsertedSpy.count(), ++rowsInsertedCount);
    QCOMPARE(rowsInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsInsertedSpy.last().at(2).toInt(), nextIndex);

    QVERIFY(waitForWritten(":communi!communi@hidd.en PART #communi"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QVERIFY(communi); // deleteLater()'d

    QCOMPARE(aboutToBeRemovedSpy.count(), ++aboutToBeRemovedCount);
    QCOMPARE(aboutToBeRemovedSpy.last().at(0).value<IrcBuffer*>(), communi.data());

    QCOMPARE(removedSpy.count(), ++removedCount);
    QCOMPARE(removedSpy.last().at(0).value<IrcBuffer*>(), communi.data());

    previousIndex = buffers.indexOf(communi);

    QCoreApplication::sendPostedEvents(communi, QEvent::DeferredDelete);
    QVERIFY(!communi);

    // Irc::SortByName, Qt::DescendingOrder
    buffers = QList<IrcBuffer*>() << libera << ChanServ << qtassistant; // qtassistant=assistant
    channels = QStringList() << QStringLiteral("#libera");

    nextIndex = buffers.indexOf(communi);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), aboutToBeAddedCount);

    QCOMPARE(addedSpy.count(), addedCount);

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), ++channelsChangedCount);
    QCOMPARE(channelsChangedSpy.last().at(0).toStringList(), channels);

    QCOMPARE(dataChangedSpy.count(), dataChangedCount);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), ++rowsAboutToBeRemovedCount);
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(1).toInt(), previousIndex);
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(2).toInt(), previousIndex);

    QCOMPARE(rowsRemovedSpy.count(), ++rowsRemovedCount);
    QCOMPARE(rowsRemovedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsRemovedSpy.last().at(1).toInt(), previousIndex);
    QCOMPARE(rowsRemovedSpy.last().at(2).toInt(), previousIndex);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), rowsAboutToBeInsertedCount);

    QCOMPARE(rowsInsertedSpy.count(), rowsInsertedCount);

    // note: implicit replies are not targeted since 3.5
    waitForWritten(":moorcock.libera.chat 324 communi #libera +s");
    QCOMPARE(messageIgnoredSpy.count(), ++messageIgnoredCount);
    QCOMPARE(libera->mode(), QString("+s"));

    QVERIFY(waitForWritten(":jpnurmi!jpnurmi@qt/jpnurmi KICK #libera communi"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QVERIFY(libera); // deleteLater()'d

    QCOMPARE(aboutToBeRemovedSpy.count(), ++aboutToBeRemovedCount);
    QCOMPARE(aboutToBeRemovedSpy.last().at(0).value<IrcBuffer*>(), libera.data());

    QCOMPARE(removedSpy.count(), ++removedCount);
    QCOMPARE(removedSpy.last().at(0).value<IrcBuffer*>(), libera.data());

    previousIndex = buffers.indexOf(libera);

    QCoreApplication::sendPostedEvents(libera, QEvent::DeferredDelete);
    QVERIFY(!libera);

    // Irc::SortByName, Qt::DescendingOrder
    buffers = QList<IrcBuffer*>() << ChanServ << qtassistant; // qtassistant=assistant
    channels = QStringList();

    nextIndex = buffers.indexOf(libera);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), aboutToBeAddedCount);

    QCOMPARE(addedSpy.count(), addedCount);

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), ++channelsChangedCount);
    QCOMPARE(channelsChangedSpy.last().at(0).toStringList(), channels);

    QCOMPARE(dataChangedSpy.count(), dataChangedCount);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), ++rowsAboutToBeRemovedCount);
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(1).toInt(), previousIndex);
    QCOMPARE(rowsAboutToBeRemovedSpy.last().at(2).toInt(), previousIndex);

    QCOMPARE(rowsRemovedSpy.count(), ++rowsRemovedCount);
    QCOMPARE(rowsRemovedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsRemovedSpy.last().at(1).toInt(), previousIndex);
    QCOMPARE(rowsRemovedSpy.last().at(2).toInt(), previousIndex);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), rowsAboutToBeInsertedCount);

    QCOMPARE(rowsInsertedSpy.count(), rowsInsertedCount);

    QVERIFY(waitForWritten(":communi!communi@hidd.en PRIVMSG jpnurmi :echo"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    QPointer<IrcBuffer> jpnurmi = bufferModel.get(0);
    QVERIFY(jpnurmi);
    QCOMPARE(jpnurmi->title(), QString("jpnurmi"));
    QCOMPARE(jpnurmi->name(), QString("jpnurmi"));
    QCOMPARE(jpnurmi->prefix(), QString());

    previousIndex = -1;

    // Irc::SortByName, Qt::DescendingOrder
    buffers = QList<IrcBuffer*>() << jpnurmi << ChanServ << qtassistant; // qtassistant=assistant
    channels = QStringList();

    nextIndex = buffers.indexOf(jpnurmi);

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
    }

    QCOMPARE(countChangedSpy.count(), ++countChangedCount);
    QCOMPARE(countChangedSpy.last().at(0).toInt(), buffers.count());

    QCOMPARE(aboutToBeAddedSpy.count(), ++aboutToBeAddedCount);
    QCOMPARE(aboutToBeAddedSpy.last().at(0).value<IrcBuffer*>(), jpnurmi.data());

    QCOMPARE(addedSpy.count(), ++addedCount);
    QCOMPARE(addedSpy.last().at(0).value<IrcBuffer*>(), jpnurmi.data());

    QCOMPARE(buffersChangedSpy.count(), ++buffersChangedCount);
    QCOMPARE(buffersChangedSpy.last().at(0).value<QList<IrcBuffer*> >(), buffers);

    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);

    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);

    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);

    QCOMPARE(rowsAboutToBeInsertedSpy.count(), ++rowsAboutToBeInsertedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsAboutToBeInsertedSpy.last().at(2).toInt(), nextIndex);

    QCOMPARE(rowsInsertedSpy.count(), ++rowsInsertedCount);
    QCOMPARE(rowsInsertedSpy.last().at(0).value<QModelIndex>(), QModelIndex());
    QCOMPARE(rowsInsertedSpy.last().at(1).toInt(), nextIndex);
    QCOMPARE(rowsInsertedSpy.last().at(2).toInt(), nextIndex);

    QVERIFY(waitForWritten(":communi!communi@hidd.en QUIT :bye"));
    QCOMPARE(messageIgnoredSpy.count(), messageIgnoredCount);

    serverSocket->close();
    QVERIFY(clientSocket->waitForDisconnected(100));
    QVERIFY(!connection->isConnected());
    QVERIFY(!connection->isActive());

    QCOMPARE(bufferModel.count(), buffers.count());
    QCOMPARE(bufferModel.buffers(), buffers);
    QCOMPARE(bufferModel.channels(), channels);

    for (int i = 0; i < bufferModel.count(); ++i) {
        QCOMPARE(bufferModel.get(i), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::BufferRole).value<IrcBuffer*>(), buffers.at(i));
        QCOMPARE(bufferModel.index(i).data(Irc::ChannelRole).value<IrcChannel*>(), buffers.at(i)->toChannel());
        QVERIFY(!buffers.at(i)->isActive());
    }

    QCOMPARE(countChangedSpy.count(), countChangedCount);
    QCOMPARE(aboutToBeAddedSpy.count(), aboutToBeAddedCount);
    QCOMPARE(addedSpy.count(), addedCount);
    QCOMPARE(buffersChangedSpy.count(), buffersChangedCount);
    QCOMPARE(channelsChangedSpy.count(), channelsChangedCount);
    QCOMPARE(dataChangedSpy.count(), dataChangedCount);
    QCOMPARE(rowsAboutToBeRemovedSpy.count(), rowsAboutToBeRemovedCount);
    QCOMPARE(rowsRemovedSpy.count(), rowsRemovedCount);
    QCOMPARE(rowsAboutToBeInsertedSpy.count(), rowsAboutToBeInsertedCount);
    QCOMPARE(rowsInsertedSpy.count(), rowsInsertedCount);
}

void tst_IrcBufferModel::testActive()
{
    IrcBufferModel bufferModel;
    bufferModel.setConnection(connection);

    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome()));

    QVERIFY(waitForWritten(":communi!communi@hidd.en JOIN :#communi"));

    IrcChannel* channel = bufferModel.get(0)->toChannel();
    IrcBuffer* query = bufferModel.add(QStringLiteral("qtassistant"));

    channel->setPersistent(true);
    query->setPersistent(true);

    QSignalSpy channelActiveSpy(channel, SIGNAL(activeChanged(bool)));
    QSignalSpy queryActiveSpy(query, SIGNAL(activeChanged(bool)));
    QVERIFY(channelActiveSpy.isValid());
    QVERIFY(queryActiveSpy.isValid());
    int channelActiveCount = 0;
    int queryActiveCount = 0;

    QVERIFY(channel->isActive());
    QVERIFY(query->isActive());

    connection->close();

    QVERIFY(!channel->isActive());
    QVERIFY(!query->isActive());

    QCOMPARE(channelActiveSpy.count(), ++channelActiveCount);
    QCOMPARE(queryActiveSpy.count(), ++queryActiveCount);

    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome()));

    QVERIFY(!channel->isActive());
    QVERIFY(query->isActive());

    QCOMPARE(channelActiveSpy.count(), channelActiveCount);
    QCOMPARE(queryActiveSpy.count(), ++queryActiveCount);

    QVERIFY(waitForWritten(":communi!communi@hidd.en JOIN :#communi"));

    QVERIFY(channel->isActive());
    QVERIFY(query->isActive());

    QCOMPARE(channelActiveSpy.count(), ++channelActiveCount);
    QCOMPARE(queryActiveSpy.count(), queryActiveCount);

    QVERIFY(waitForWritten(":communi!communi@hidd.en PART #communi"));

    QVERIFY(!channel->isActive());
    QVERIFY(query->isActive());

    QCOMPARE(channelActiveSpy.count(), ++channelActiveCount);
    QCOMPARE(queryActiveSpy.count(), queryActiveCount);

    connection->close();

    QVERIFY(!channel->isActive());
    QVERIFY(!query->isActive());

    QCOMPARE(channelActiveSpy.count(), channelActiveCount);
    QCOMPARE(queryActiveSpy.count(), ++queryActiveCount);
}

void tst_IrcBufferModel::testRoles()
{
    IrcBufferModel model;
    QHash<int, QByteArray> roles = model.roleNames();
    QCOMPARE(roles.take(Qt::DisplayRole), QByteArray("display"));
    QCOMPARE(roles.take(Irc::BufferRole), QByteArray("buffer"));
    QCOMPARE(roles.take(Irc::ChannelRole), QByteArray("channel"));
    QCOMPARE(roles.take(Irc::NameRole), QByteArray("name"));
    QCOMPARE(roles.take(Irc::PrefixRole), QByteArray("prefix"));
    QCOMPARE(roles.take(Irc::TitleRole), QByteArray("title"));
    QVERIFY(roles.isEmpty());
}

void tst_IrcBufferModel::testAIM()
{
    IrcBufferModel bufferModel(connection);
    IrcBuffer* a = bufferModel.add(QStringLiteral("#a"));
    IrcBuffer* b = bufferModel.add(QStringLiteral("#b"));
    IrcBuffer* c = bufferModel.add(QStringLiteral("c"));
    IrcBuffer* o = nullptr;

    QAbstractItemModel* aim = &bufferModel;
    QModelIndex ai = aim->index(0, 0);
    QModelIndex bi = aim->index(1, 0);
    QModelIndex ci = aim->index(2, 0);
    QModelIndex oi = aim->index(100, 100);

    QVERIFY(ai.isValid());
    QVERIFY(bi.isValid());
    QVERIFY(ci.isValid());
    QVERIFY(!oi.isValid());

    QCOMPARE(aim->rowCount(QModelIndex()), 3);
    QCOMPARE(aim->rowCount(ai), 0);

    QCOMPARE(aim->columnCount(QModelIndex()), 1);
    QCOMPARE(aim->columnCount(ai), 0);

    QCOMPARE(bufferModel.index(a), ai);
    QCOMPARE(bufferModel.index(b), bi);
    QCOMPARE(bufferModel.index(c), ci);
    QVERIFY(!bufferModel.index(o).isValid());

    QCOMPARE(bufferModel.buffer(ai), a);
    QCOMPARE(bufferModel.buffer(bi), b);
    QCOMPARE(bufferModel.buffer(ci), c);
    QVERIFY(!bufferModel.buffer(oi));

    bufferModel.setDisplayRole(Irc::TitleRole);
    QCOMPARE(aim->data(ai, Qt::DisplayRole).toString(), a->title());
    QCOMPARE(aim->data(bi, Qt::DisplayRole).toString(), b->title());
    QCOMPARE(aim->data(ci, Qt::DisplayRole).toString(), c->title());
    QVERIFY(aim->data(oi, Qt::DisplayRole).toString().isEmpty());

    bufferModel.setDisplayRole(Irc::BufferRole);
    QCOMPARE(aim->data(ai, Qt::DisplayRole).value<IrcBuffer*>(), a);
    QCOMPARE(aim->data(bi, Qt::DisplayRole).value<IrcBuffer*>(), b);
    QCOMPARE(aim->data(ci, Qt::DisplayRole).value<IrcBuffer*>(), c);
    QVERIFY(!aim->data(oi, Qt::DisplayRole).value<IrcBuffer*>());

    QCOMPARE(aim->data(ai, Irc::BufferRole).value<IrcBuffer*>(), a);
    QCOMPARE(aim->data(bi, Irc::BufferRole).value<IrcBuffer*>(), b);
    QCOMPARE(aim->data(ci, Irc::BufferRole).value<IrcBuffer*>(), c);
    QVERIFY(!aim->data(oi, Irc::BufferRole).value<IrcBuffer*>());

    QCOMPARE(aim->data(ai, Irc::ChannelRole).value<IrcChannel*>(), a->toChannel());
    QCOMPARE(aim->data(bi, Irc::ChannelRole).value<IrcChannel*>(), b->toChannel());
    QCOMPARE(aim->data(ci, Irc::ChannelRole).value<IrcChannel*>(), c->toChannel());
    QVERIFY(!aim->data(oi, Irc::ChannelRole).value<IrcChannel*>());

    QCOMPARE(aim->data(ai, Irc::TitleRole).toString(), a->title());
    QCOMPARE(aim->data(bi, Irc::TitleRole).toString(), b->title());
    QCOMPARE(aim->data(ci, Irc::TitleRole).toString(), c->title());
    QVERIFY(aim->data(oi, Irc::TitleRole).toString().isEmpty());

    QCOMPARE(aim->data(ai, Irc::NameRole).toString(), a->name());
    QCOMPARE(aim->data(bi, Irc::NameRole).toString(), b->name());
    QCOMPARE(aim->data(ci, Irc::NameRole).toString(), c->name());
    QVERIFY(aim->data(oi, Irc::NameRole).toString().isEmpty());

    QCOMPARE(aim->data(ai, Irc::PrefixRole).toString(), QString("#"));
    QCOMPARE(aim->data(bi, Irc::PrefixRole).toString(), QString("#"));
    QVERIFY(aim->data(ci, Irc::PrefixRole).toString().isEmpty());
    QVERIFY(aim->data(oi, Irc::PrefixRole).toString().isEmpty());
}

class FakeQmlBufferModel : public IrcBufferModel
{
    Q_OBJECT
    friend class tst_IrcBufferModel;

public slots:
    // -Wno-overloaded-virtual
    QVariant createBuffer(const QVariant& title)
    {
        IrcBuffer* buffer = IrcBufferModel::createBuffer(title.toString());
        buffer->setObjectName(QStringLiteral("QML buffer"));
        return QVariant::fromValue(buffer);
    }
    QVariant createChannel(const QVariant& title)
    {
        IrcChannel* channel = IrcBufferModel::createChannel(title.toString());
        channel->setObjectName(QStringLiteral("QML channel"));
        return QVariant::fromValue(channel);
    }
};

void tst_IrcBufferModel::testQML()
{
    FakeQmlBufferModel model;
    model.setConnection(connection);

    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome()));

    QCOMPARE(model.add("buffer")->objectName(), QString("QML buffer"));
    QCOMPARE(model.add("#channel")->objectName(), QString("QML channel"));
}

void tst_IrcBufferModel::testWarnings()
{
    IrcBufferModel model(connection);
    model.setConnection(connection);

    QTest::ignoreMessage(QtCriticalMsg, "IrcBufferModel::setConnection(): changing the connection on the fly is not supported.");

    IrcConnection another;
    model.setConnection(&another);
}

class TestCommandFilter : public QObject, public IrcCommandFilter
{
    Q_OBJECT
    Q_INTERFACES(IrcCommandFilter)

public:
    TestCommandFilter(IrcConnection* connection) { connection->installCommandFilter(this); }
    bool commandFilter(IrcCommand* command) override { commands += command->toString(); return false; }
    QStringList commands;
};

void tst_IrcBufferModel::testMonitor()
{
    TestCommandFilter filter(connection);

    IrcBufferModel model(connection);
    model.setMonitorEnabled(true);
    QVERIFY(model.isMonitorEnabled());

    connection->open();
    QVERIFY(waitForOpened());
    QVERIFY(waitForWritten(tst_IrcData::welcome("libera")));
    QVERIFY(connection->network()->numericLimit(IrcNetwork::MonitorCount) > 0);

    filter.commands.clear();

    IrcBuffer* buffer = model.add(QStringLiteral("jirssi"));
    QVERIFY(!buffer->isActive());
    QCOMPARE(filter.commands.count(), 1);
    QCOMPARE(filter.commands.last(), QString("MONITOR + jirssi"));

    QVERIFY(waitForWritten(":card.libera.chat 730 * :jirssi!~jpnurmi@88.95.51.136"));
    QVERIFY(buffer->isActive());

    QVERIFY(waitForWritten(":card.libera.chat 731 jipsu :jirssi"));
    QVERIFY(!buffer->isActive());

    model.remove(QStringLiteral("jirssi"));
    QCOMPARE(filter.commands.count(), 2);
    QCOMPARE(filter.commands.last(), QString("MONITOR - jirssi"));

    filter.commands.clear();

    // don't monitor channels
    buffer = model.add(QStringLiteral("#channel"));
    QCOMPARE(model.channels(), QStringList() << "#channel");
    QVERIFY(filter.commands.isEmpty());
    delete buffer;
    QVERIFY(filter.commands.isEmpty());
}

QTEST_MAIN(tst_IrcBufferModel)

#include "tst_ircbuffermodel.moc"


text:
package org.http4s
package client

@deprecated("Is a Blaze detail.  Will be removed from public API.", "0.23.8")
trait Connection[F[_]] {

  /** Determine if the connection is closed and resources have been freed */
  def isClosed: Boolean

  /** Determine if the connection is in a state that it can be recycled for another request. */
  def isRecyclable: Boolean

  /** Close down the connection, freeing resources and potentially aborting a [[Response]] */
  def shutdown(): Unit

  /** The key for requests we are able to serve */
  def requestKey: RequestKey
}

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>BLPAPI C++: Struct blpapi::Datetime::Offset</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="search/search.css" rel="stylesheet" type="text/css"/>

<link href="doxygen.css" rel="stylesheet" type="text/css"/>

Main Page

Components

Namespaces

Classes

Files

Class List

Class Hierarchy

Class Members

blpapi

blpapi::Datetime

blpapi::Datetime::Offset

Public Member Functions |
Public Attributes

blpapi::Datetime::Offset Struct Reference

#include <blpapi_datetime.h>

List of all members.

Public Member Functions

 	Offset (short minutesAheadOfUTC)

Public Attributes

short 	d_minutesAheadOfUTC

Constructor & Destructor Documentation

          blpapi::Datetime::Offset::Offset
          (
          short
           minutesAheadOfUTC
           )
           [explicit]

The behavior is undefined unless -840 <= minutesAheadOfUTC <= 840.

Member Data Documentation

          short blpapi::Datetime::Offset::d_minutesAheadOfUTC

The documentation for this struct was generated from the following file:

blpapi_datetime.h

<address class="footer">Generated on Fri Dec 6 2013 13:45:18 for BLPAPI 3.7.5 by

 1.7.1 </address>


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>
Uses of Class backtype.storm.task.WorkerTopologyContext (Storm Core 0.9.1-incubating-SNAPSHOT API)
</TITLE>

<META NAME="date" CONTENT="2014-02-04">

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">

      Overview
      Package
      Class
    Use
      Tree
      Deprecated
      Index
      Help

 PREV
 NEXT

  FRAMES
 NO FRAMES

  All Classes

Uses of Class
backtype.storm.task.WorkerTopologyContext

Packages that use WorkerTopologyContext

backtype.storm.grouping

backtype.storm.task

backtype.storm.testing

storm.trident.partition

Uses of WorkerTopologyContext in backtype.storm.grouping

Methods in backtype.storm.grouping with parameters of type WorkerTopologyContext

 void
CustomStreamGrouping.prepare(WorkerTopologyContext context,
        GlobalStreamId stream,
        List<Integer> targetTasks)

          Tells the stream grouping at runtime the tasks in the target bolt.

Uses of WorkerTopologyContext in backtype.storm.task

Subclasses of WorkerTopologyContext in backtype.storm.task

 class
TopologyContext

          A TopologyContext is given to bolts and spouts in their "prepare" and "open"
 methods, respectively.

Uses of WorkerTopologyContext in backtype.storm.testing

Methods in backtype.storm.testing with parameters of type WorkerTopologyContext

 void
NGrouping.prepare(WorkerTopologyContext context,
        GlobalStreamId stream,
        List<Integer> targetTasks)

Uses of WorkerTopologyContext in storm.trident.partition

Methods in storm.trident.partition with parameters of type WorkerTopologyContext

 void
IndexHashGrouping.prepare(WorkerTopologyContext context,
        GlobalStreamId stream,
        List<Integer> targetTasks)

 void
IdentityGrouping.prepare(WorkerTopologyContext context,
        GlobalStreamId stream,
        List<Integer> tasks)

 void
GlobalGrouping.prepare(WorkerTopologyContext context,
        GlobalStreamId stream,
        List<Integer> targets)

      Overview
      Package
      Class
    Use
      Tree
      Deprecated
      Index
      Help

 PREV
 NEXT

  FRAMES
 NO FRAMES

  All Classes

Copyright © 2014 The Apache Software Foundation. All Rights Reserved.


text:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:id="@+id/buttons"
        android:weightSum="3"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/add"
            android:text="Add"
            android:layout_weight="1"
            android:onClick="addItem"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <Button
            android:id="@+id/change"
            android:text="Change"
            android:layout_weight="1"
            android:onClick="changeItem"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <Button
            android:id="@+id/remove"
            android:text="Remove"
            android:layout_weight="1"
            android:onClick="removeItem"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_below="@id/buttons"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>


text:
#include <stdio.h>

#include <rte_malloc.h>
#include "cperf_options.h"
#include "cperf_test_vectors.h"
#include "cperf_verify_parser.h"

int
free_test_vector(struct cperf_test_vector *vector, struct cperf_options *opts)
{
	if (vector == NULL || opts == NULL)
		return -1;

	if (opts->test_file == NULL) {
		if (vector->iv.data)
			rte_free(vector->iv.data);
		if (vector->aad.data)
			rte_free(vector->aad.data);
		if (vector->digest.data)
			rte_free(vector->digest.data);
		rte_free(vector);

	} else {
		if (vector->plaintext.data)
			rte_free(vector->plaintext.data);
		if (vector->cipher_key.data)
			rte_free(vector->cipher_key.data);
		if (vector->auth_key.data)
			rte_free(vector->auth_key.data);
		if (vector->iv.data)
			rte_free(vector->iv.data);
		if (vector->ciphertext.data)
			rte_free(vector->ciphertext.data);
		if (vector->aad.data)
			rte_free(vector->aad.data);
		if (vector->digest.data)
			rte_free(vector->digest.data);
		rte_free(vector);
	}

	return 0;
}

/* trim leading and trailing spaces */
static char *
trim(char *str)
{
	char *start, *end;

	for (start = str; *start; start++) {
		if (!isspace((unsigned char) start[0]))
			break;
	}

	for (end = start + strlen(start); end > start + 1; end--) {
		if (!isspace((unsigned char) end[-1]))
			break;
	}

	*end = 0;

	/* Shift from "start" to the beginning of the string */
	if (start > str)
		memmove(str, start, (end - start) + 1);

	return str;
}

/* tokenization test values separated by a comma */
static int
parse_values(char *tokens, uint8_t **data, uint32_t *data_length)
{
	uint8_t n_tokens;
	uint32_t data_size = 32;
	uint8_t *values;
	char *tok, *error = NULL;

	tok = strtok(tokens, VALUE_DELIMITER);
	if (tok == NULL)
		return -1;

	values = (uint8_t *) rte_zmalloc(NULL, sizeof(uint8_t) * data_size, 0);
	if (values == NULL)
		return -1;

	n_tokens = 0;
	while (tok != NULL) {
		uint8_t *values_extended = NULL;

		if (n_tokens >= data_size) {

			data_size *= 2;

			values_extended = (uint8_t *) rte_realloc(values,
				sizeof(uint8_t) * data_size, 0);
			if (values_extended == NULL) {
				rte_free(values);
				return -1;
			}

			values = values_extended;
		}

		values[n_tokens] = (uint8_t) strtoul(tok, &error, 0);
		if ((error == NULL) || (*error != '\0')) {
			printf("Failed with convert '%s'\n", tok);
			rte_free(values);
			return -1;
		}

		tok = strtok(NULL, VALUE_DELIMITER);
		if (tok == NULL)
			break;

		n_tokens++;
	}

	uint8_t *resize_values = (uint8_t *) rte_realloc(values,
		sizeof(uint8_t) * (n_tokens + 1), 0);

	if (resize_values == NULL) {
		rte_free(values);
		return -1;
	}

	*data = resize_values;
	*data_length = n_tokens + 1;

	return 0;
}

/* checks the type of key and assigns data */
static int
parse_entry(char *entry, struct cperf_test_vector *vector)
{
	char *token, *key_token;
	uint8_t *data = NULL;
	int status;
	uint32_t data_length;

	/* get key */
	token = strtok(entry, ENTRY_DELIMITER);
	key_token = token;

	/* get values for key */
	token = strtok(NULL, ENTRY_DELIMITER);

	if (token == NULL) {
		printf("Expected 'key = values' but was '%.40s'..\n",
			key_token);
		return -1;
	}

	status = parse_values(token, &data, &data_length);
	if (status)
		return -1;

	/* compare keys */
	if (strstr(key_token, "plaintext")) {
		if (vector->plaintext.data)
			rte_free(vector->plaintext.data);
		vector->plaintext.data = data;
		vector->plaintext.length = data_length;
	} else if (strstr(key_token, "cipher_key")) {
		if (vector->cipher_key.data)
			rte_free(vector->cipher_key.data);
		vector->cipher_key.data = data;
		vector->cipher_key.length = data_length;
	} else if (strstr(key_token, "auth_key")) {
		if (vector->auth_key.data)
			rte_free(vector->auth_key.data);
		vector->auth_key.data = data;
		vector->auth_key.length = data_length;
	} else if (strstr(key_token, "iv")) {
		if (vector->iv.data)
			rte_free(vector->iv.data);
		vector->iv.data = data;
		vector->iv.phys_addr = rte_malloc_virt2phy(vector->iv.data);
		vector->iv.length = data_length;
	} else if (strstr(key_token, "ciphertext")) {
		if (vector->ciphertext.data)
			rte_free(vector->ciphertext.data);
		vector->ciphertext.data = data;
		vector->ciphertext.length = data_length;
	} else if (strstr(key_token, "aad")) {
		if (vector->aad.data)
			rte_free(vector->aad.data);
		vector->aad.data = data;
		vector->aad.phys_addr = rte_malloc_virt2phy(vector->aad.data);
		vector->aad.length = data_length;
	} else if (strstr(key_token, "digest")) {
		if (vector->digest.data)
			rte_free(vector->digest.data);
		vector->digest.data = data;
		vector->digest.phys_addr = rte_malloc_virt2phy(
			vector->digest.data);
		vector->digest.length = data_length;
	} else {
		printf("Not valid key: '%s'\n", trim(key_token));
		return -1;
	}

	return 0;
}

/* searches in the file for registry keys and values */
static int
parse_file(struct cperf_test_vector *v_vec, const char *path)
{
	FILE *fp;
	char *line = NULL, *entry = NULL;
	ssize_t read;
	size_t len = 0;
	int status = 0;

	fp = fopen(path, "r");
	if (fp == NULL) {
		printf("File %s does not exists\n", path);
		return -1;
	}

	while ((read = getline(&line, &len, fp)) != -1) {
		/* ignore comments and new lines */
		if (line[0] == '#' || line[0] == '/' || line[0] == '\n'
			|| line[0] == '\r' || line[0] == ' ')
			continue;

		trim(line);

		/* buffer for multiline */
		entry = (char *) rte_realloc(entry,
					sizeof(char) * strlen(line) + 1, 0);
		if (entry == NULL)
			return -1;

		memset(entry, 0, strlen(line) + 1);
		strncpy(entry, line, strlen(line));

		/* check if entry ends with , or = */
		if (entry[strlen(entry) - 1] == ','
			|| entry[strlen(entry) - 1] == '=') {
			while ((read = getline(&line, &len, fp)) != -1) {
				trim(line);

				/* extend entry about length of new line */
				char *entry_extended = (char *) rte_realloc(
					entry, sizeof(char)
						* (strlen(line) + strlen(entry))
						+ 1, 0);

				if (entry_extended == NULL)
					goto err;
				entry = entry_extended;

				strncat(entry, line, strlen(line));

				if (entry[strlen(entry) - 1] != ',')
					break;
			}
		}
		status = parse_entry(entry, v_vec);
		if (status) {
			printf("An error occurred while parsing!\n");
			goto err;
		}
	}

	fclose(fp);
	free(line);
	rte_free(entry);

	return 0;

err:
	if (fp)
		fclose(fp);
	if (line)
		free(line);
	if (entry)
		rte_free(entry);

	return -1;
}

struct cperf_test_vector*
cperf_test_vector_get_from_file(struct cperf_options *opts)
{
	int status;
	struct cperf_test_vector *test_vector = NULL;

	if (opts == NULL || opts->test_file == NULL)
		return test_vector;

	test_vector = (struct cperf_test_vector *) rte_zmalloc(NULL,
		sizeof(struct cperf_test_vector), 0);
	if (test_vector == NULL)
		return test_vector;

	/* filling the vector with data from a file */
	status = parse_file(test_vector, opts->test_file);
	if (status) {
		free_test_vector(test_vector, opts);
		return NULL;
	}

	/* other values not included in the file */
	test_vector->data.cipher_offset = 0;
	test_vector->data.cipher_length = opts->buffer_sz;

	test_vector->data.auth_offset = 0;
	test_vector->data.auth_length = opts->buffer_sz;

	return test_vector;
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
<title>Uses of Package com.hazelcast.web (Hazelcast Root 3.3.3 API)</title>
<meta name="date" content="2014-11-12">
<link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">

JavaScript is disabled on your browser.

Overview

Package

Class

Use

Tree

Deprecated

Index

Help

Prev

Next

Frames

No Frames

All Classes

Uses of Package
com.hazelcast.web

Packages that use com.hazelcast.web

Package
Description

com.hazelcast.web

Provides Hazelcast-based session replication.

com.hazelcast.web.spring

Provides Spring aware Hazelcast based session replication.

Classes in com.hazelcast.web used by com.hazelcast.web

Class and Description

AbstractWebDataEntryProcessor

A base class for EntryProcessors which will use the web data serializer.

WebFilter.HazelcastHttpSession

WebFilter.LocalCacheEntry

WebFilter.RequestWrapper

WebFilter.ResponseWrapper

Classes in com.hazelcast.web used by com.hazelcast.web.spring

Class and Description

WebFilter

Provides clustered sessions by backing session data with an IMap.

WebFilter.HazelcastHttpSession

WebFilter.RequestWrapper

Overview

Package

Class

Use

Tree

Deprecated

Index

Help

Prev

Next

Frames

No Frames

All Classes

Copyright © 2014 Hazelcast, Inc.. All Rights Reserved.


text:
package org.mozilla.javascript.ast;

import org.mozilla.javascript.Token;

/**
 * Node representing comments.
 * Node type is {@link Token#COMMENT}.

 *
 *
JavaScript effectively has five comment types:
 *

 *
// line comments

 *
/* block comments *\/

 *
/** jsdoc comments *\/

 *
<!-- html-open line comments

 *
^\\s*--> html-close line comments

 *

 *
 *
The first three should be familiar to Java programmers.  JsDoc comments
 * are really just block comments with some conventions about the formatting
 * within the comment delimiters.  Line and block comments are described in the
 * Ecma-262 specification.

 *
 *
SpiderMonkey and Rhino also support HTML comment syntax, but somewhat
 * counterintuitively, the syntax does not produce a block comment.  Instead,
 * everything from the string <!-- through the end of the line is considered
 * a comment, and if the token --> is the first non-whitespace on the line,
 * then the line is considered a line comment.  This is to support parsing
 * JavaScript in <script> HTML tags that has been "hidden" from very old
 * browsers by surrounding it with HTML comment delimiters.

 *
 * Note the node start position for Comment nodes is still relative to the
 * parent, but Comments are always stored directly in the AstRoot node, so
 * they are also effectively absolute offsets.
 */
public class Comment extends AstNode {

    private String value;
    private Token.CommentType commentType;
    private boolean parsed = false;

    {
        type = Token.COMMENT;
    }

    /**
     * Constructs a new Comment
     * @param pos the start position
     * @param len the length including delimiter(s)
     * @param type the comment type
     * @param value the value of the comment, as a string
     */
    public Comment(int pos, int len, Token.CommentType type, String value) {
        super(pos, len);
        commentType = type;
        this.value = value;
    }

    /**
     * Returns the comment style
     */
    public Token.CommentType getCommentType() {
        return commentType;
    }

    /**
     * Sets the comment style
     * @param type the comment style, a
     * {@link org.mozilla.javascript.Token.CommentType}
     */
    public void setCommentType(Token.CommentType type) {
        this.commentType = type;
    }

    /**
     * Returns a string of the comment value.
     */
    public String getValue() {
        return value;
    }

    @Override
    public String toSource(int depth) {
        StringBuilder sb = new StringBuilder(getLength() + 10);
        sb.append(makeIndent(depth));
        sb.append(value);
        return sb.toString();
    }

    /**
     * Comment nodes are not visited during normal visitor traversals,
     * but comply with the {@link AstNode#visit} interface.
     */
    @Override
    public void visit(NodeVisitor v) {
        v.visit(this);
    }

    public boolean isParsed() {
        return parsed;
    }

    public void setParsed(boolean parsed) {
        this.parsed = parsed;
    }
}


text:
package com.baidu.bjf.remoting.protobuf.enumeration;

import com.baidu.bjf.remoting.protobuf.FieldType;
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;

/**
 * Simple enum test for
 *
 * @author xiemalin
 * @since 1.4.0
 */
public class EnumPOJOClass2 {

    @Protobuf(fieldType = FieldType.ENUM)
    private EnumAttrPOJO enumAttr;

    /**
     * get the enumAttr
     * @return the enumAttr
     */
    public EnumAttrPOJO getEnumAttr() {
        return enumAttr;
    }

    /**
     * set enumAttr value to enumAttr
     * @param enumAttr the enumAttr to set
     */
    public void setEnumAttr(EnumAttrPOJO enumAttr) {
        this.enumAttr = enumAttr;
    }

}


text:
import { Counter, Gauge, Metric, Rate, Trend } from 'k6/metrics';

let metric: Metric;
let counter: Counter;
let gauge: Gauge;
let rate: Rate;
let trend: Trend;

// Counter
new Counter(); // $ExpectError
counter = new Counter('counter');
new Counter('counter', 5); // $ExpectError
counter = new Counter('counter', true);
metric = new Counter('counter');
gauge = new Counter('counter'); // $ExpectError

// Gauge
new Gauge(); // $ExpectError
gauge = new Gauge('gauge');
new Gauge('gauge', 5); // $ExpectError
gauge = new Gauge('gauge', true);
metric = new Gauge('gauge');
rate = new Gauge('gauge'); // $ExpectError

// Rate
new Rate(); // $ExpectError
rate = new Rate('rate');
new Rate('rate', 5); // $ExpectError
rate = new Rate('rate', true);
metric = new Rate('rate');
trend = new Rate('rate'); // $ExpectError

// Trend
new Trend(); // $ExpectError
trend = new Trend('trend');
new Trend('trend', 5); // $ExpectError
trend = new Trend('trend', true);
metric = new Trend('trend');
counter = new Trend('trend'); // $ExpectError


text:
@implementation MainGameScene

-(id) init
{
	self = [super init];
	return self;
}

-(void) loadWithInfo:(GameStartInfo *)info
{
	fieldLayer = [BattleFieldLayer node];
	messageLayer = [MessageLayer node];
	controlLayer = [ControlLayer node];

	[fieldLayer loadChapter:info.chapterId];

	layers = [[ActionLayers alloc] initWithField:fieldLayer Message:messageLayer];
	ActionDispatcher *dispatcher = [[ActionDispatcher alloc] initWithLayers:layers];
	[controlLayer setDispatcher:dispatcher];
	[dispatcher release];

	// add layer as a child to scene
	[self addChild: fieldLayer];
	[self addChild: messageLayer];
	[self addChild: controlLayer];
	[self schedule: @selector(step:)];

	[[[AIHandler alloc] initEnemyHandlerWithLayers:layers] autorelease];
	[[[AIHandler alloc] initNpcHandlerWithLayers:layers] autorelease];

	// Listeners

	eventLoader = [[EventLoaderFactory createEventLoader:info.chapterId] retain];
	[eventLoader loadWithLayers:layers];

	if ([info isKindOfClass:[ChapterRecord class]]) {
		[layers startNewGame:(ChapterRecord *)info];
	} else if ([info isKindOfClass:[BattleRecord class]]) {
		[layers loadGame:(BattleRecord *)info];
	}

}

-(void) step: (ccTime) delta
{
	[layers takeTick];
}

- (void) dealloc
{
	[layers release];
	[eventLoader release];
	[super dealloc];
}

@end


text:
import json, types

from .theExceptions import (CreationError, DeletionError, UpdateError)

__all__ = ["Document", "Edge"]

class Document(object) :
    """The class that represents a document. Documents are meant to be instanciated by collections"""

    def __init__(self, collection, jsonFieldInit = {}) :
        self.reset(collection, jsonFieldInit)
        self.typeName = "ArangoDoc"

    def reset(self, collection, jsonFieldInit = {}) :
        """replaces the current values in the document by those in jsonFieldInit"""
        self.collection = collection
        self.connection = self.collection.connection
        self.documentsURL = self.collection.documentsURL

        self._store = {}
        self._patchStore = {}

        self._id, self._rev, self._key = None, None, None
        self.URL = None

        self.set(jsonFieldInit)
        self.modified = True

    def setPrivates(self, fieldDict) :
        """will set self._id, self._rev and self._key field. Private fields (starting by '_') are all accessed using the self. interface,
        other fields are accessed through self[fielName], the same as regular dictionnary in python"""
        try :
            self._id = fieldDict["_id"]
            self.URL = "%s/%s" % (self.documentsURL, self._id)
            del(fieldDict["_id"])

            self._rev = fieldDict["_rev"]
            del(fieldDict["_rev"])

            self._key = fieldDict["_key"]
            del(fieldDict["_key"])
        except KeyError :
            self._id, self._rev, self._key = None, None, None
            self.URL = None

    def set(self, fieldDict = None) :
        """Sets the document according to values contained in the dictinnary fieldDict. This will also set self._id/_rev/_key"""

        if fieldDict and self._id is None :
            self.setPrivates(fieldDict)

        if self.collection._validation['on_set']:
            for k in list(fieldDict.keys()) :
                self[k] = fieldDict[k]
        else :
            self._store.update(fieldDict)

    def save(self, waitForSync = False, **docArgs) :
        """Saves the document to the database by either performing a POST (for a new document) or a PUT (complete document overwrite).
        If you want to only update the modified fields use the .path() function.
        Use docArgs to put things such as 'waitForSync = True' (for a full list cf ArangoDB's doc).
        It will only trigger a saving of the document if it has been modified since the last save. If you want to force the saving you can use forceSave()"""

        if self.modified :
            if self.collection._validation['on_save'] :
                self.validate(patch = False)

            params = dict(docArgs)
            params.update({'collection': self.collection.name, "waitForSync" : waitForSync })
            payload = {}
            payload.update(self._store)

            if self.URL is None :
                if self._key is not None :
                    payload["_key"] = self._key
                payload = json.dumps(payload)
                r = self.connection.session.post(self.documentsURL, params = params, data = payload)
                update = False
            else :
                payload = json.dumps(payload)
                r = self.connection.session.put(self.URL, params = params, data = payload)
                update = True

            data = r.json()

            if (r.status_code == 201 or r.status_code == 202) and "error" not in data :
                if update :
                    self._rev = data['_rev']
                else :
                    self.setPrivates(data)
            else :
                if update :
                    raise UpdateError(data['errorMessage'], data)
                else :
                    raise CreationError(data['errorMessage'], data)

            self.modified = False

        self._patchStore = {}

    def forceSave(self, **docArgs) :
        "saves even if the document has not been modified since the last save"
        self.modified = True
        self.save(**docArgs)

    def saveCopy(self) :
        "saves a copy of the object and become that copy. returns a tuple (old _key, new _key)"
        old_key = self._key
        self.reset(self.collection)
        self.save()
        return (old_key, self._key)

    def patch(self, keepNull = True, **docArgs) :
        """Saves the document by only updating the modified fields.
        The default behaviour concening the keepNull parameter is the opposite of ArangoDB's default, Null values won't be ignored
        Use docArgs for things such as waitForSync = True"""

        if self.collection._validation['on_save'] :
            self.validate(patch = True)

        if self.URL is None :
            raise ValueError("Cannot patch a document that was not previously saved")

        if len(self._patchStore) > 0 :
            params = dict(docArgs)
            params.update({'collection': self.collection.name, 'keepNull' : keepNull})
            payload = json.dumps(self._patchStore)

            r = self.connection.session.patch(self.URL, params = params, data = payload)
            data = r.json()
            if (r.status_code == 201 or r.status_code == 202) and "error" not in data :
                self._rev = data['_rev']
            else :
                raise UpdateError(data['errorMessage'], data)

            self.modified = False

        self._patchStore = {}

    def delete(self) :
        "deletes the document from the database"
        if self.URL is None :
            raise DeletionError("Can't delete a document that was not saved")
        r = self.connection.session.delete(self.URL)
        data = r.json()

        if (r.status_code != 200 and r.status_code != 202) or 'error' in data :
            raise DeletionError(data['errorMessage'], data)
        self.reset(self.collection)

        self.modified = True

    def validate(self, patch = False) :
        "validates either the whole store, or only the patch store( patch = True) of the document according to the collection's settings.If logErrors returns a dictionary of errros per field, else raises exceptions"
        if patch :
            return self.collection.validateDct(self._patchStore)
        else :
            return self.collection.validateDct(self._store)

    def getInEdges(self, edges, rawResults = False) :
        "An alias for getEdges() that returns only the in Edges"
        return self.getEdges(edges, inEdges = True, outEdges = False, rawResults = rawResults)

    def getOutEdges(self, edges, rawResults = False) :
        "An alias for getEdges() that returns only the out Edges"
        return self.getEdges(edges, inEdges = False, outEdges = True, rawResults = rawResults)

    def getEdges(self, edges, inEdges = True, outEdges = True, rawResults = False) :
        """returns in, out, or both edges linked to self belonging the collection 'edges'.
        If rawResults a arango results will be return as fetched, if false, will return a liste of Edge objects"""
        try :
            return edges.getEdges(self, inEdges, outEdges, rawResults)
        except AttributeError :
            raise AttributeError("%s does not seem to be a valid Edges object" % edges)

    def __getitem__(self, k) :
        """Document fields are accessed in a dictionary like fashion: doc[fieldName]. With the exceptions of private fiels (starting with '_')
        that are accessed as object fields: doc._key"""
        if self.collection._validation['allow_foreign_fields'] or self.collection.hasField(k) :
            return self._store.get(k)

        try :
            return self._store[k]
        except KeyError :
            raise KeyError("Document of collection '%s' has no field '%s', for a permissive behaviour set 'allow_foreign_fields' to True" % (self.collection.name, k))

    def __setitem__(self, k, v) :
        """Documents work just like dictionaries doc[fieldName] = value. With the exceptions of private fiels (starting with '_')
        that are accessed as object fields: doc._key"""

        def _recValidate(k, v) :
            if type(v) is dict :
                for kk, vv in v.items() :
                    newk = "%s.%s" % (k, kk)
                    _recValidate(newk, vv)
            else :
                self.collection.validateField(k, v)

        if self.collection._validation['on_set'] :
            _recValidate(k, v)

        self._store[k] = v
        if self.URL is not None :
            self._patchStore[k] = self._store[k]

        self.modified = True

    def __delitem__(self, k) :
        del(self._store[k])

    def __str__(self) :
        return "%s '%s': %s" % (self.typeName, self._id, repr(self._store))

    def __repr__(self) :
        return "%s '%s': %s" % (self.typeName, self._id, repr(self._store))

class Edge(Document) :
    """An Edge document"""
    def __init__(self, edgeCollection, jsonFieldInit = {}) :
        self.reset(edgeCollection, jsonFieldInit)

    def reset(self, edgeCollection, jsonFieldInit = {}) :
        Document.reset(self, edgeCollection, jsonFieldInit)
        self.typeName = "ArangoEdge"

    def links(self, fromVertice, toVertice, **edgeArgs) :
        """
        An alias to save that updates the _from and _to attributes.
        fromVertice and toVertice, can be either strings or documents. It they are unsaved documents, they will be automatically saved.
        """

        if fromVertice.__class__ is Document :
            if not fromVertice._id :
                fromVertice._id.save()

            self["_from"] = fromVertice._id
        elif (type(fromVertice) is bytes) or (type(fromVertice) is str) :
            self["_from"] = fromVertice

        if toVertice.__class__ is Document :
            if not toVertice._id :
                toVertice._id.save()

            self["_to"] = toVertice._id
        elif (type(toVertice) is bytes) or (type(toVertice) is str) :
            self["_to"] = toVertice

        self.save(**edgeArgs)

    def save(self, **edgeArgs) :
        """Works like Document's except that you must specify '_from' and '_to' vertices before.
        There's also a links() function especially for first saves."""

        import types

        if "_from" not in self._store or "_to" not in self._store :
            raise AttributeError("You must specify '_from' and '_to' attributes before saving. You can also use the function 'links()'")

        Document.save(self, **edgeArgs)


text:
import doctest
from insights.parsers import dnf_modules
from insights.tests import context_wrap

DNF_MODULES_INPUT = """
[postgresql]
name=postgresql
profiles=client
state=enabled
stream=9.6
[python36]
name=python36
profiles=
state=enabled
stream=3.6
[virt]
name=virt
profiles=
state=enabled
stream=rhel
"""

def test_dnf_modules():
    modules_config = dnf_modules.DnfModules(context_wrap(DNF_MODULES_INPUT))
    assert modules_config is not None
    assert 'postgresql' in modules_config.sections()
    assert 'python36' in modules_config.sections()
    assert 'virt' in modules_config.sections()
    assert 'enabled' == modules_config.get('postgresql', 'state')

def test_dnf_modules_doc_examples():
    failed, total = doctest.testmod(
        dnf_modules,
        globs={'dnf_modules': dnf_modules.DnfModules(context_wrap(DNF_MODULES_INPUT))}
    )
    assert failed == 0


text:
package io.spine.system.server.given.entity;

import io.spine.server.entity.EventFilter;
import io.spine.server.procman.ProcessManagerRepository;
import io.spine.system.server.PersonCreation;
import io.spine.system.server.PersonId;

/**
 * A repository of {@link PersonProcman}.
 */
public class PersonProcmanRepository
        extends ProcessManagerRepository<PersonId, PersonProcman, PersonCreation> {

    // Allow all events for the test purposes.
    @Override
    public EventFilter eventFilter() {
        return EventFilter.allowAll();
    }
}


text:
package cyanoboru.secrethitler.core;

/**
 * Created by cya on 21/10/16.
 */

public class PersonajeFascista implements CartaDeIdentidad {
    public String getPersonaje() {
        return "Fascista";
    }
}


text:
<?php

class Mock_saef_field_model {

	/* --------------------------------------------------------------
	 * PUBLIC METHODS
	 * ------------------------------------------------------------ */
	public function get_field_from_short_name($short_name) {}
	public function get_package_name() {}
	public function get_package_version() {}
	public function get_related_entries() {}
	public function get_site_id() {}
	public function get_usage_instructions() {}

}

/* End of file		: mock.saef_field_model.php */
/* File location	: system/tests/saef_field/mocks/mock.saef_field_model.php */


text:
package com.facebook.buck.jvm.java.classes;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import com.facebook.buck.io.file.MorePaths;
import com.facebook.buck.io.filesystem.ProjectFilesystem;
import com.facebook.buck.io.filesystem.TestProjectFilesystems;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class ClasspathTraversalTest {
  @Rule public TemporaryFolder tempDir = new TemporaryFolder();

  private Map<FileLike, String> traverse(Collection<File> files) throws IOException {
    Collection<Path> paths =
        files.stream().map(File::toPath).collect(ImmutableList.toImmutableList());
    ImmutableMap.Builder<FileLike, String> completeList = ImmutableMap.builder();
    ClasspathTraverser traverser = new DefaultClasspathTraverser();
    ProjectFilesystem filesystem =
        TestProjectFilesystems.createProjectFilesystem(tempDir.getRoot().toPath());
    traverser.traverse(
        new ClasspathTraversal(paths, filesystem) {
          @Override
          public void visit(FileLike fileLike) {
            String contents;
            try {
              contents = new FileLikeCharSource(fileLike).read();
            } catch (IOException e) {
              throw new RuntimeException(e);
            }
            completeList.put(fileLike, contents);
          }
        });
    return completeList.build();
  }

  private void verifyFileLike(int expectedFiles, File... paths) throws IOException {
    int fileLikeCount = 0;
    for (Map.Entry<FileLike, String> entry : traverse(Lists.newArrayList(paths)).entrySet()) {
      assertEquals(
          "Relative file-like path mismatch",
          MorePaths.pathWithPlatformSeparators(entry.getValue()),
          MorePaths.pathWithPlatformSeparators(entry.getKey().getRelativePath()));
      fileLikeCount++;
    }
    assertEquals(expectedFiles, fileLikeCount);
  }

  @Test
  public void testDirectoryAndFile() throws IOException {
    File notADirectory = tempDir.newFile("not_a_directory.txt");
    Files.write("not_a_directory.txt", notADirectory, Charsets.UTF_8);
    File yesADir = tempDir.newFolder("is_a_directory");
    Files.write("foo.txt", new File(yesADir, "foo.txt"), Charsets.UTF_8);
    Files.write("bar.txt", new File(yesADir, "bar.txt"), Charsets.UTF_8);
    File aSubDir = new File(yesADir, "fizzbuzz");
    assertTrue("Failed to create dir: " + aSubDir, aSubDir.mkdir());
    Files.write(
        MorePaths.pathWithPlatformSeparators("fizzbuzz/whatever.txt"),
        new File(aSubDir, "whatever.txt"),
        Charsets.UTF_8);
    verifyFileLike(4, notADirectory, yesADir);
  }

  @Test
  public void testZip() throws IOException {
    String[] files = {"test/foo.txt", "bar.txt", "test/baz.txt"};
    File file = tempDir.newFile("test.zip");
    try (ZipOutputStream zipOut =
        new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
      for (String filename : files) {
        ZipEntry entry = new ZipEntry(filename);
        zipOut.putNextEntry(entry);
        zipOut.write(filename.getBytes(Charsets.UTF_8));
      }
    }
    verifyFileLike(3, file);
  }
}


text:
#ifndef _ELYSIA_UTIL_THREAD_HPP_
#define _ELYSIA_UTIL_THREAD_HPP_

#include "Platform.hpp"

#if ELYSIA_PLATFORM != ELYSIA_PLATFORM_WINDOWS
#include <sys/time.h>
#endif

namespace Elysia {

/** Thread is a thin wrapper around std::thread which handles common
 *  thread initialization processes.  It is not intended to hide
 *  std::thread, but rather handle things like setting the thread up
 *  for profiling and crash handling.
 */
class Thread {
public:
    typedef std::function<void()> ThreadMainFunc;

    Thread() {
    }
    ~Thread() {
    }

    explicit Thread(String name, ThreadMainFunc f)
     : mImpl(
#if ELYSIA_PLATFORM != ELYSIA_PLATFORM_WINDOWS
         std::bind(
             &Thread::initThread, this, name, f
             , Thread::getProfilerData()
         )
#else
         std::bind(
             &Thread::initThread, this, name, f
         )
#endif
       )
    {
    }

    std::thread::id get_id() const {
        return mImpl.get_id();
    }

    bool joinable() const {
        return mImpl.joinable();
    }
    void join() {
        mImpl.join();
    }
    bool timed_join(const std::system_time& wait_until) {
        return mImpl.timed_join(wait_until);
    }

    template<typename TimeDuration>
    bool timed_join(TimeDuration const& rel_time) {
        return mImpl.timed_join(rel_time);
    }

    void detach() {
        mImpl.detach();
    }

    static unsigned hardware_concurrency() {
        return std::thread::hardware_concurrency();
    }

    void interrupt() {
        mImpl.interrupt();
    }

    bool interruption_requested() const {
        return mImpl.interruption_requested();
    }

    static void yield() {
        std::thread::yield();
    }

    static void sleep(const std::system_time& xt) {
        std::thread::sleep(xt);
    }
private:
#if ELYSIA_PLATFORM != ELYSIA_PLATFORM_WINDOWS
    typedef struct itimerval ProfilerData;
    static ProfilerData getProfilerData() {
        ProfilerData prof_data;
        getitimer(ITIMER_PROF, &prof_data);
        return prof_data;
    }

    static void setProfilerData(ProfilerData pd) {
        setitimer(ITIMER_PROF, &pd, NULL);
    }

    void initThread(String name, ThreadMainFunc f, ProfilerData pd) {
        setProfilerData(pd);
        f();
    }
#else
    void initThread(String name, ThreadMainFunc f) {
        f();
    }
#endif

    Thread(Thread& rhs);

    std::thread mImpl;
}; // class Thread

} // namespace Elysia

#endif //_ELYSIA_UTIL_THREAD_HPP_


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.scvmm.models;

import com.azure.core.annotation.Fluent;
import com.fasterxml.jackson.annotation.JsonProperty;

/** Defines the restore checkpoint action properties. */
@Fluent
public final class VirtualMachineRestoreCheckpoint {
    /*
     * ID of the checkpoint to be restored to.
     */
    @JsonProperty(value = "id")
    private String id;

    /**
     * Get the id property: ID of the checkpoint to be restored to.
     *
     * @return the id value.
     */
    public String id() {
        return this.id;
    }

    /**
     * Set the id property: ID of the checkpoint to be restored to.
     *
     * @param id the id value to set.
     * @return the VirtualMachineRestoreCheckpoint object itself.
     */
    public VirtualMachineRestoreCheckpoint withId(String id) {
        this.id = id;
        return this;
    }

    /**
     * Validates the instance.
     *
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
    }
}


text:
package storm.contrib.spring.topology;

import backtype.storm.Config;
import backtype.storm.generated.StormTopology;

import java.util.HashMap;
import java.util.Map;

/**
 * [Class Description]
 *
 * @author Grant Henke
 * @since 12/6/12
 */
public class SingleTopologySubmission implements TopologySubmission {

    private final Map<String, StormTopology> stormTopologies;
    private Config config;

    public SingleTopologySubmission(final String topologyId, final StormTopology stormTopology) {
        stormTopologies = new HashMap<String, StormTopology>();
        stormTopologies.put(topologyId, stormTopology);
        this.config = new Config();
    }

    public Map<String, StormTopology> getStormTopologies() {
        return stormTopologies;
    }

    public void setConfig(final Config config) {
        this.config = config;
    }

    public Config getConfig() {
        return config;
    }
}