void KisTileCompressorsTest::doRoundTrip(KisAbstractTileCompressor *compressor)
{
    quint8 defaultPixel = 0;
    KisTiledDataManager dm(1, &defaultPixel);

    quint8 oddPixel1 = 128;
    KisTileSP tile11;

    dm.clear(64, 64, 64, 64, &oddPixel1);

    tile11 = dm.getTile(1, 1, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile11->data(), TILESIZE));

    KoStoreFake fakeStore;
    KisFakePaintDeviceWriter writer(&fakeStore);
    
    bool retval = compressor->writeTile(tile11, writer);
    Q_ASSERT(retval);
    tile11 = 0;

    fakeStore.startReading();

    dm.clear();

    tile11 = dm.getTile(1, 1, false);
    QVERIFY(memoryIsFilled(defaultPixel, tile11->data(), TILESIZE));
    tile11 = 0;

    bool res = compressor->readTile(fakeStore.device(), &dm);
    Q_ASSERT(res);
    Q_UNUSED(res);
    tile11 = dm.getTile(1, 1, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile11->data(), TILESIZE));
    tile11 = 0;
}
void KisSwappedDataStoreTest::processTileData(qint32 column, KisTileData *td, KisSwappedDataStore &store)
{
    if(td->data()) {
        memset(td->data(), COLUMN2COLOR(column), TILESIZE);
        QVERIFY(memoryIsFilled(COLUMN2COLOR(column), td->data(), TILESIZE));

        // FIXME: take a lock of the tile data
        store.swapOutTileData(td);
    }
    else {
        // TODO: check num clones
        // FIXME: take a lock of the tile data
        store.swapInTileData(td);
        QVERIFY(memoryIsFilled(COLUMN2COLOR(column), td->data(), TILESIZE));
    }
}
void KisSwappedDataStoreTest::testRoundTrip()
{
    const qint32 pixelSize = 1;
    const quint8 defaultPixel = 128;
    const qint32 NUM_TILES = 10000;

    KisImageConfig config;
    config.setMaxSwapSize(4);
    config.setSwapSlabSize(1);
    config.setSwapWindowSize(1);


    KisSwappedDataStore store;

    QList<KisTileData*> tileDataList;
    for(qint32 i = 0; i < NUM_TILES; i++)
        tileDataList.append(new KisTileData(pixelSize, &defaultPixel, KisTileDataStore::instance()));

    for(qint32 i = 0; i < NUM_TILES; i++) {
        KisTileData *td = tileDataList[i];
        QVERIFY(memoryIsFilled(defaultPixel, td->data(), TILESIZE));

        memset(td->data(), COLUMN2COLOR(i), TILESIZE);
        QVERIFY(memoryIsFilled(COLUMN2COLOR(i), td->data(), TILESIZE));

        // FIXME: take a lock of the tile data
        store.swapOutTileData(td);
    }

    store.debugStatistics();

    for(qint32 i = 0; i < NUM_TILES; i++) {
        KisTileData *td = tileDataList[i];
        QVERIFY(!td->data());
        // TODO: check num clones

        // FIXME: take a lock of the tile data
        store.swapInTileData(td);
        QVERIFY(memoryIsFilled(COLUMN2COLOR(i), td->data(), TILESIZE));
    }

    store.debugStatistics();

    for(qint32 i = 0; i < NUM_TILES; i++)
        delete tileDataList[i];
}
void KisTileCompressorsTest::doLowLevelRoundTripIncompressible(KisAbstractTileCompressor *compressor)
{
    const qint32 pixelSize = 1;
    quint8 oddPixel1 = 128;
    quint8 oddPixel2 = 129;

    QFile file(QString(FILES_DATA_DIR) + QDir::separator() + "tile.png");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    QByteArray incompressibleArray = file.readAll();

    /**
     * A small hack to acquire a standalone tile data.
     * globalTileDataStore is not exported out of kritaimage.so,
     * so we get it from the data manager
     */
    KisTiledDataManager dm(pixelSize, &oddPixel1);
    KisTileSP tile = dm.getTile(0, 0, true);
    tile->lockForWrite();


    KisTileData *td = tile->tileData();
    QVERIFY(memoryIsFilled(oddPixel1, td->data(), TILESIZE));

    memcpy(td->data(), incompressibleArray.data(), TILESIZE);
    QVERIFY(!memcmp(td->data(), incompressibleArray.data(), TILESIZE));

    qint32 bufferSize = compressor->tileDataBufferSize(td);
    quint8 *buffer = new quint8[bufferSize];
    qint32 bytesWritten;
    compressor->compressTileData(td, buffer, bufferSize, bytesWritten);
    dbgKrita << ppVar(bytesWritten);


    memset(td->data(), oddPixel2, TILESIZE);
    QVERIFY(memoryIsFilled(oddPixel2, td->data(), TILESIZE));

    compressor->decompressTileData(buffer, bytesWritten, td);

    QVERIFY(!memcmp(td->data(), incompressibleArray.data(), TILESIZE));

    delete[] buffer;
    tile->unlock();
}
void KisTiledDataManagerTest::testTransactions()
{
    quint8 defaultPixel = 0;
    KisTiledDataManager dm(1, &defaultPixel);

    quint8 oddPixel1 = 128;
    quint8 oddPixel2 = 129;
    quint8 oddPixel3 = 130;

    KisTileSP tile00;
    KisTileSP oldTile00;

    // Create a named transaction: versioning is enabled
    KisMementoSP memento1 = dm.getMemento();
    dm.clear(0, 0, 64, 64, &oddPixel1);

    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(defaultPixel, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

    // Create an anonymous transaction: versioning is disabled
    dm.commit();
    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

    dm.clear(0, 0, 64, 64, &oddPixel2);

    // Versioning is disabled, i said! >:)
    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

    // And the last round: named transaction:
    KisMementoSP memento2 = dm.getMemento();
    dm.clear(0, 0, 64, 64, &oddPixel3);

    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel3, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

}
void KisTileCompressorsTest::doLowLevelRoundTrip(KisAbstractTileCompressor *compressor)
{
    const qint32 pixelSize = 1;
    quint8 oddPixel1 = 128;
    quint8 oddPixel2 = 129;

    /**
     * A small hack to acquire a standalone tile data.
     * globalTileDataStore is not exported out of kritaimage.so,
     * so we get it from the data manager
     */
    KisTiledDataManager dm(pixelSize, &oddPixel1);
    KisTileSP tile = dm.getTile(0, 0, true);
    tile->lockForWrite();


    KisTileData *td = tile->tileData();
    QVERIFY(memoryIsFilled(oddPixel1, td->data(), TILESIZE));

    qint32 bufferSize = compressor->tileDataBufferSize(td);
    quint8 *buffer = new quint8[bufferSize];
    qint32 bytesWritten;
    compressor->compressTileData(td, buffer, bufferSize, bytesWritten);
    dbgKrita << ppVar(bytesWritten);


    memset(td->data(), oddPixel2, TILESIZE);
    QVERIFY(memoryIsFilled(oddPixel2, td->data(), TILESIZE));

    compressor->decompressTileData(buffer, bytesWritten, td);

    QVERIFY(memoryIsFilled(oddPixel1, td->data(), TILESIZE));

    delete[] buffer;
    tile->unlock();
}
void KisTiledDataManagerTest::testUndoSetDefaultPixel()
{
    quint8 defaultPixel = 0;
    KisTiledDataManager dm(1, &defaultPixel);

    quint8 oddPixel1 = 128;
    quint8 oddPixel2 = 129;

    QRect fillRect(0,0,64,64);

    KisTileSP tile00;
    KisTileSP tile10;

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(defaultPixel, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));

    KisMementoSP memento1 = dm.getMemento();
    dm.clear(fillRect, &oddPixel1);
    dm.commit();

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));

    KisMementoSP memento2 = dm.getMemento();
    dm.setDefaultPixel(&oddPixel2);
    dm.commit();

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel2, tile10->data(), TILESIZE));

    dm.rollback(memento2);

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));

    dm.rollback(memento1);

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(defaultPixel, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));

    dm.rollforward(memento1);

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));

    dm.rollforward(memento2);

    tile00 = dm.getTile(0, 0, false);
    tile10 = dm.getTile(1, 0, false);
    QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel2, tile10->data(), TILESIZE));
}
void KisTiledDataManagerTest::testPurgeHistory()
{
    quint8 defaultPixel = 0;
    KisTiledDataManager dm(1, &defaultPixel);

    quint8 oddPixel1 = 128;
    quint8 oddPixel2 = 129;
    quint8 oddPixel3 = 130;
    quint8 oddPixel4 = 131;

    KisMementoSP memento1 = dm.getMemento();
    dm.clear(0, 0, 64, 64, &oddPixel1);
    dm.commit();

    KisMementoSP memento2 = dm.getMemento();
    dm.clear(0, 0, 64, 64, &oddPixel2);

    KisTileSP tile00;
    KisTileSP oldTile00;

    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

    dm.purgeHistory(memento1);

    /**
     * Nothing nas changed in the visible state of the data manager
     */

    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

    dm.commit();

    dm.purgeHistory(memento2);

    /**
     * We've removed all the history of the device, so it
     * became "unversioned".
     * NOTE: the return value for getOldTile() when there is no
     * history present is a subject for change
     */

    tile00 = dm.getTile(0, 0, false);
    oldTile00 = dm.getOldTile(0, 0);
    QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
    QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
    tile00 = oldTile00 = 0;

    /**
     * Just test we won't crash when the memento is not
     * present in history anymore
     */

    KisMementoSP memento3 = dm.getMemento();
    dm.clear(0, 0, 64, 64, &oddPixel3);
    dm.commit();

    KisMementoSP memento4 = dm.getMemento();
    dm.clear(0, 0, 64, 64, &oddPixel4);
    dm.commit();

    dm.rollback(memento4);

    dm.purgeHistory(memento3);
    dm.purgeHistory(memento4);
}