diff -r 000000000000 -r 1918ee327afb tests/auto/qtextpiecetable/tst_qtextpiecetable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/auto/qtextpiecetable/tst_qtextpiecetable.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1152 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#define private public + +#include +#include +#include +#include +#include +#include +#include +#include "../qtextdocument/common.h" + +//TESTED_FILES=gui/text/qtextdocument_p.cpp gui/text/qtextdocument_p.h + +class tst_QTextPieceTable : public QObject +{ + Q_OBJECT + +public: + tst_QTextPieceTable(); + + +public slots: + void init(); + void cleanup(); +private slots: + void insertion1(); + void insertion2(); + void insertion3(); + void insertion4(); + void insertion5(); + + void removal1(); + void removal2(); + void removal3(); + void removal4(); + + void undoRedo1(); + void undoRedo2(); + void undoRedo3(); + void undoRedo4(); + void undoRedo5(); + void undoRedo6(); + void undoRedo7(); + void undoRedo8(); + void undoRedo9(); + void undoRedo10(); + void undoRedo11(); + + void checkDocumentChanged(); + void checkDocumentChanged2(); + void setBlockFormat(); + + void blockInsertion(); + void blockInsertion2(); + + void blockRemoval1(); + void blockRemoval2(); + void blockRemoval3(); + void blockRemoval4(); + void blockRemoval5(); + + void checkBlockSeparation(); + + void checkFrames1(); + void removeFrameDirect(); + void removeWithChildFrame(); + void clearWithFrames(); + +private: + QTextDocument *doc; + QTextDocumentPrivate *table; + int blockFormatIndex; + int charFormatIndex; +}; + +tst_QTextPieceTable::tst_QTextPieceTable() +{ doc = 0; table = 0; } + + +void tst_QTextPieceTable::init() +{ + doc = new QTextDocument(0); + table = doc->d_func(); + blockFormatIndex = table->formatCollection()->indexForFormat(QTextBlockFormat()); + charFormatIndex = table->formatCollection()->indexForFormat(QTextCharFormat()); +} + +void tst_QTextPieceTable::cleanup() +{ + delete doc; + doc = 0; +} + +void tst_QTextPieceTable::insertion1() +{ + table->insert(0, "aacc", charFormatIndex); + QCOMPARE(table->plainText(), QString("aacc")); + table->insert(2, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("aabbcc")); + table->insert(1, "1", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1abbcc")); + table->insert(6, "d", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1abbcdc")); + table->insert(8, "z", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1abbcdcz")); +} + +void tst_QTextPieceTable::insertion2() +{ + table->insert(0, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("bb")); +} + +void tst_QTextPieceTable::insertion3() +{ + QString compare; + for (int i = 0; i < 20000; ++i) { + int pos = rand() % (i+1); + QChar c((unsigned short)(i & 0xff) + 1); + QString str; + str += c; + table->insert(pos, str, charFormatIndex); + compare.insert(pos, str); + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::insertion4() +{ + QString compare; + for (int i = 0; i < 20000; ++i) { + int pos = rand() % (i+1); + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + table->insert(pos, str, charFormatIndex); + compare.insert(pos, str); + // if (table->text() != compare) { + // qDebug("compare failed: i=%d (current char=%c) insert at %d\nexpected '%s'\ngot '%s'", i, (i % 26) + (i>25?'A':'a'), pos, compare.latin1(), table->text().latin1()); + // exit(12); + // } + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::insertion5() +{ + QString compare; + for (int i = 0; i < 20000; ++i) { + int pos = rand() % (i+1); + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + if (c == 'a') { + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + str = QChar(QChar::ParagraphSeparator); + } else { + table->insert(pos, str, charFormatIndex); + } + compare.insert(pos, str); + } + QVERIFY(table->plainText() == compare); + for (QTextBlock it = table->blocksBegin(); it != table->blocksEnd(); it = it.next()) { + QTextDocumentPrivate::FragmentIterator fit = table->find(it.position()); + QVERIFY(fit.position() == it.position()); + } +} + +void tst_QTextPieceTable::removal1() +{ + table->insert(0, "abbccc", charFormatIndex); + QCOMPARE(table->plainText(), QString("abbccc")); + table->remove(1, 2); + QCOMPARE(table->plainText(), QString("accc")); + table->insert(1, "1", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1ccc")); + table->remove(4, 1); + QCOMPARE(table->plainText(), QString("a1cc")); + table->insert(4, "z", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1ccz")); +} + +void tst_QTextPieceTable::removal2() +{ + table->insert(0, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("bb")); + table->remove(0, 2); + QCOMPARE(table->plainText(), QString("")); + table->insertBlock(0, blockFormatIndex, charFormatIndex); + QCOMPARE(table->plainText(), QString(QChar(QChar::ParagraphSeparator))); + table->remove(0, 1); + QCOMPARE(table->plainText(), QString("")); + + table->insert(0, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("bb")); + table->insertBlock(1, blockFormatIndex, charFormatIndex); + QCOMPARE(table->plainText(), QString("b") + QString(QChar(QChar::ParagraphSeparator)) + QString("b")); + table->remove(1, 1); + QCOMPARE(table->plainText(), QString("bb")); +} + +void tst_QTextPieceTable::removal3() +{ + QString compare; + int l = 0; + for (int i = 0; i < 20000; ++i) { + bool remove = l && (rand() % 2); + int pos = rand() % (remove ? l : (l+1)); + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + if (remove && pos < table->length()) { + compare.remove(pos, 1); + table->remove(pos, 1); + } else { + compare.insert(pos, str); + table->insert(pos, str, charFormatIndex); + } + l += remove ? -1 : 2; + // if (table->text() != compare) { + // qDebug("compare failed: i=%d (current char=%c) insert at %d\nexpected '%s'\ngot '%s'", i, (i % 26) + (i>25?'A':'a'), pos, compare.latin1(), table->text().latin1()); + // exit(12); + // } + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::removal4() +{ + QString compare; + int l = 0; + for (int i = 0; i < 20000; ++i) { + bool remove = l && (rand() % 2); + int pos = (l > 1) ? rand() % (remove ? l-1 : l) : 0; + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + if (c != 'a') { + str += c; + str += c; + } else { + str = QChar(QChar::ParagraphSeparator); + } + if (remove && pos < table->length() - 1) { + compare.remove(pos, 1); + table->remove(pos, 1); + } else { + if (str[0] == QChar(QChar::ParagraphSeparator)) + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + else + table->insert(pos, str, charFormatIndex); + compare.insert(pos, str); + } + l += remove ? -1 : 2; +// if (table->plainText() != compare) { +// qDebug("compare failed: i=%d (current char=%c) insert at %d\nexpected '%s'\ngot '%s'", i, (i % 26) + (i>25?'A':'a'), pos, compare.latin1(), table->plainText().latin1()); +// exit(12); +// } + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::undoRedo1() +{ + table->insert(0, "01234567", charFormatIndex); + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab01234567")); + table->undo(); + QCOMPARE(table->plainText(), QString("01234567")); + table->redo(); + QCOMPARE(table->plainText(), QString("ab01234567")); + table->undo(); + table->insert(1, "c", charFormatIndex); + QCOMPARE(table->plainText(), QString("0c1234567")); + table->undo(); + QCOMPARE(table->plainText(), QString("01234567")); + table->undo(); + QVERIFY(table->plainText().isEmpty()); +} + +void tst_QTextPieceTable::undoRedo2() +{ + table->insert(0, "01", charFormatIndex); + table->insert(1, "a", charFormatIndex); + QCOMPARE(table->plainText(), QString("0a1")); + table->undo(); + QCOMPARE(table->plainText(), QString("01")); + table->undo(); + QCOMPARE(table->plainText(), QString("")); + table->redo(); + QCOMPARE(table->plainText(), QString("01")); + table->redo(); + QCOMPARE(table->plainText(), QString("0a1")); +} + +void tst_QTextPieceTable::undoRedo3() +{ + table->insert(0, "01", charFormatIndex); + table->insert(2, "ab", charFormatIndex); + table->remove(2, 1); + QCOMPARE(table->plainText(), QString("01b")); + table->undo(); + QCOMPARE(table->plainText(), QString("01ab")); + table->undo(); + QVERIFY(table->plainText().isEmpty()); + table->redo(); + QCOMPARE(table->plainText(), QString("01ab")); + table->redo(); + QCOMPARE(table->plainText(), QString("01b")); +} + +void tst_QTextPieceTable::undoRedo4() +{ + table->insert(0, "01", charFormatIndex); + table->insert(0, "ab", charFormatIndex); + table->remove(0, 1); + QCOMPARE(table->plainText(), QString("b01")); + table->undo(); + QCOMPARE(table->plainText(), QString("ab01")); + table->undo(); + QCOMPARE(table->plainText(), QString("01")); + table->undo(); + QCOMPARE(table->plainText(), QString("")); + table->redo(); + QCOMPARE(table->plainText(), QString("01")); + table->redo(); + QCOMPARE(table->plainText(), QString("ab01")); + table->redo(); + QCOMPARE(table->plainText(), QString("b01")); +} + +void tst_QTextPieceTable::undoRedo5() +{ + table->beginEditBlock(); + table->insert(0, "01", charFormatIndex); + table->remove(1, 1); + table->endEditBlock(); + QCOMPARE(table->plainText(), QString("0")); + table->undo(); + QCOMPARE(table->plainText(), QString("")); +} + +void tst_QTextPieceTable::undoRedo6() +{ + // this is essentially a test for the undoStack[undoPosition - 1].block = false in PieceTable::endUndoBlock() + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertText("Hello World"); + + cursor.insertBlock(); + cursor.insertText("Hello World2"); + + cursor.movePosition(QTextCursor::Start); + QTextBlockFormat bfmt; + bfmt.setAlignment(Qt::AlignHCenter); + cursor.setBlockFormat(bfmt); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); + + QTextCursor range = cursor; + range.clearSelection(); + range.movePosition(QTextCursor::Start); + range.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + + QTextCharFormat modifier; + modifier.setFontItalic(true); + range.mergeCharFormat(modifier); + + cursor.movePosition(QTextCursor::Start); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); + + doc.undo(); + + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); +} + +void tst_QTextPieceTable::undoRedo7() +{ + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab")); + + table->undo(); + QVERIFY(table->plainText().isEmpty()); +} + +void tst_QTextPieceTable::undoRedo8() +{ + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab")); + + table->remove(0, 1); + table->remove(0, 1); + + QVERIFY(table->plainText().isEmpty()); + table->undo(); + QCOMPARE(table->plainText(), QString("ab")); +} + +void tst_QTextPieceTable::undoRedo9() +{ + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab")); + + table->remove(1, 1); + table->remove(0, 1); + + QVERIFY(table->plainText().isEmpty()); + table->undo(); + QCOMPARE(table->plainText(), QString("ab")); +} + +void tst_QTextPieceTable::undoRedo10() +{ + // testcase for the beginUndoBlock/endUndoBlock calls being surrounded by an if (undoEnabled) + QTextCharFormat cf; + cf.setForeground(Qt::blue); + int cfIdx = table->formatCollection()->indexForFormat(cf); + + QTextBlockFormat f; + int idx = table->formatCollection()->indexForFormat(f); + + table->insert(0, "a", cfIdx); + table->insertBlock(1, idx, cfIdx); + table->insert(1, "b", cfIdx); + + cf.setForeground(Qt::red); + int newCfIdx = table->formatCollection()->indexForFormat(cf); + + table->setCharFormat(0, 3, cf, QTextDocumentPrivate::MergeFormat); + + QCOMPARE(table->find(0).value()->format, newCfIdx); + + table->undo(); + + QCOMPARE(table->find(0).value()->format, cfIdx); +} + +void tst_QTextPieceTable::undoRedo11() +{ + srand(3); + const int loops = 20; + QString compare; + int l = 0; + for (int i = 0; i < loops; ++i) { + bool remove = l && (rand() % 2); + int pos = (l > 1) ? rand() % (remove ? l-1 : l) : 0; + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + if (remove) { + compare.remove(pos, 1); + table->remove(pos, 1); + } else { + compare.insert(pos, str); + table->insert(pos, str, charFormatIndex); + } + l += remove ? -1 : 2; + } + QVERIFY(table->plainText() == compare); + for (int i = 0; i < loops; ++i) + table->undo(); + QVERIFY(table->plainText() == QString("")); + for (int i = 0; i < loops; ++i) + table->redo(); + QVERIFY(table->plainText() == compare); +} + + +void tst_QTextPieceTable::checkDocumentChanged() +{ + table->enableUndoRedo(false); + QTestDocumentLayout *layout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(layout); + + // single insert + layout->expect(0, 0, 15); + table->insert(0, "012345678901234", charFormatIndex); + QVERIFY(!layout->error); + + // single remove + layout->expect(0, 5, 0); + table->remove(0, 5); + QVERIFY(!layout->error); + + // symmetric insert/remove + layout->expect(0, 0, 0); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(0, 5); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 5, 5); + table->beginEditBlock(); + table->remove(0, 5); + table->insert(0, "01234", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + // replace + layout->expect(0, 3, 5); + table->beginEditBlock(); + table->remove(0, 3); + table->insert(0, "01234", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 0, 2); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(0, 3); + table->endEditBlock(); + QVERIFY(!layout->error); + + // insert + remove inside insert block + layout->expect(0, 0, 2); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(1, 3); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 0, 2); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(2, 3); + table->endEditBlock(); + QVERIFY(!layout->error); + + // insert + remove partly outside + layout->expect(0, 1, 0); + table->beginEditBlock(); + table->insert(1, "0", charFormatIndex); + table->remove(0, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 1, 1); + table->beginEditBlock(); + table->insert(1, "01", charFormatIndex); + table->remove(0, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 1, 2); + table->beginEditBlock(); + table->insert(1, "012", charFormatIndex); + table->remove(0, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(1, 1, 0); + table->beginEditBlock(); + table->insert(1, "0", charFormatIndex); + table->remove(1, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(1, 1, 1); + table->beginEditBlock(); + table->insert(1, "01", charFormatIndex); + table->remove(2, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(1, 1, 2); + table->beginEditBlock(); + table->insert(1, "012", charFormatIndex); + table->remove(3, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + // insert + remove non overlapping + layout->expect(0, 1, 1); + table->beginEditBlock(); + table->insert(1, "0", charFormatIndex); + table->remove(0, 1); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 2, 2); + table->beginEditBlock(); + table->insert(2, "1", charFormatIndex); + table->remove(0, 1); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 2, 2); + table->beginEditBlock(); + table->remove(0, 1); + table->insert(1, "0", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 3, 3); + table->beginEditBlock(); + table->remove(0, 1); + table->insert(2, "1", charFormatIndex); + table->endEditBlock(); + + + layout->expect(0, 3, 3); + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + table->beginEditBlock(); + table->setCharFormat(0, 1, fmt); + table->setCharFormat(2, 1, fmt); + table->endEditBlock(); + QVERIFY(!layout->error); +} + +void tst_QTextPieceTable::checkDocumentChanged2() +{ + QTestDocumentLayout *layout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(layout); + + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + int anotherCharFormatIndex = table->formatCollection()->indexForFormat(fmt); + + layout->expect(0, 0, 12); + table->beginEditBlock(); + table->insert(0, "0123", charFormatIndex); + table->insert(4, "4567", anotherCharFormatIndex); + table->insert(8, "8901", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + fmt.setFontItalic(true); + + layout->expect(1, 10, 10); + table->beginEditBlock(); + table->setCharFormat(8, 3, fmt); + table->setCharFormat(4, 4, fmt); + table->setCharFormat(1, 3, fmt); + table->endEditBlock(); + QVERIFY(!layout->error); +} + +void tst_QTextPieceTable::setBlockFormat() +{ + QTextBlockFormat bfmt; + int index = table->formatCollection()->indexForFormat(bfmt); + + table->insertBlock(0, index, charFormatIndex); + table->insertBlock(0, index, charFormatIndex); + table->insertBlock(0, index, charFormatIndex); + + QTextBlockFormat newbfmt = bfmt; + newbfmt.setAlignment(Qt::AlignRight); + index = table->formatCollection()->indexForFormat(bfmt); + QTextBlock b = table->blocksFind(1); + table->setBlockFormat(b, b, newbfmt); + + QVERIFY(table->blocksFind(0).blockFormat() == bfmt); + QVERIFY(table->blocksFind(1).blockFormat() == newbfmt); + QVERIFY(table->blocksFind(2).blockFormat() == bfmt); +} + + +void tst_QTextPieceTable::blockInsertion() +{ + QTextBlockFormat fmt; + fmt.setTopMargin(100); + int idx = table->formatCollection()->indexForFormat(fmt); + int charFormat = table->formatCollection()->indexForFormat(QTextCharFormat()); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + + table->insertBlock(0, idx, charFormat); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).blockFormat() == fmt); + + table->undo(); + QVERIFY(table->blockMap().length() == 1); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + + table->redo(); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).blockFormat() == fmt); +} + +void tst_QTextPieceTable::blockInsertion2() +{ + // caused evil failing assertion in fragmentmap + int pos = 0; + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + pos += 1; + table->insert(pos, "a", charFormatIndex); + pos += 1; + + pos -= 1; + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + QCOMPARE(table->blocksFind(0).position(), 0); + QCOMPARE(table->blocksFind(1).position(), 1); + QCOMPARE(table->blocksFind(2).position(), 2); +} + +/* + Tests correct removal behaviour when deleting over block boundaries or complete blocks. +*/ + +void tst_QTextPieceTable::blockRemoval1() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->beginEditBlock(); + table->remove(5, 5); + table->endEditBlock(); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt2); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(5).position() == 5); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt2); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(5).position() == 5); +} + +void tst_QTextPieceTable::blockRemoval2() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->remove(4, 1); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(6).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(6).position() == 0); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(6).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(6).position() == 0); +} + +void tst_QTextPieceTable::blockRemoval3() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->beginEditBlock(); + table->remove(3, 4); + table->endEditBlock(); + + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); +} + +void tst_QTextPieceTable::blockRemoval4() +{ +#if 0 + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->remove(3, 7); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); +#endif +} + +void tst_QTextPieceTable::blockRemoval5() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->beginEditBlock(); + table->remove(3, 8); + table->endEditBlock(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); +} + + +void tst_QTextPieceTable::checkBlockSeparation() +{ + table->insertBlock(0, blockFormatIndex, charFormatIndex); + table->insertBlock(1, blockFormatIndex, charFormatIndex); + + QVERIFY(table->find(0) != table->find(1)); +} + +void tst_QTextPieceTable::checkFrames1() +{ + QTextFrameFormat ffmt; + table->insert(0, "Hello", charFormatIndex); + QPointer frame = table->insertFrame(1, 3, ffmt); + QTextFrame *root = table->rootFrame(); + + QVERIFY(root == frame->parentFrame()); + + QVERIFY(root); + QVERIFY(root->parentFrame() == 0); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(frame->format() == ffmt); + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 4); + + + QPointer frame2 = table->insertFrame(2, 3, ffmt); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame); + QVERIFY(frame->childFrames().count() == 1); + QVERIFY(frame2->childFrames().count() == 0); + QVERIFY(frame2->parentFrame() == frame); + QVERIFY(frame2->firstPosition() == 3); + QVERIFY(frame2->lastPosition() == 4); + + QVERIFY(frame->format() == ffmt); + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 6); + + table->removeFrame(frame); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame2); + QVERIFY(!frame); + QVERIFY(frame2->childFrames().count() == 0); + QVERIFY(frame2->parentFrame() == root); + QVERIFY(frame2->firstPosition() == 2); + QVERIFY(frame2->lastPosition() == 3); + + table->undo(); + + frame = table->frameAt(2); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame); + QVERIFY(frame->childFrames().count() == 1); + QVERIFY(frame->childFrames().at(0) == frame2); + QVERIFY(frame2->childFrames().count() == 0); + QVERIFY(frame2->parentFrame() == frame); + QVERIFY(frame2->firstPosition() == 3); + QVERIFY(frame2->lastPosition() == 4); + + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 6); + + table->undo(); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame); + QVERIFY(frame->childFrames().count() == 0); + QVERIFY(!frame2); + + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 4); +} + +void tst_QTextPieceTable::removeFrameDirect() +{ + QTextFrameFormat ffmt; + table->insert(0, "Hello", charFormatIndex); + + QTextFrame *frame = table->insertFrame(1, 5, ffmt); + + QVERIFY(frame->parentFrame() == table->rootFrame()); + + const int start = frame->firstPosition() - 1; + const int end = frame->lastPosition(); + const int length = end - start + 1; + + table->remove(start, length); +} + +void tst_QTextPieceTable::removeWithChildFrame() +{ + /* + The piecetable layout is: + + ... + 1 BeginningOfFrame(first frame) + 2 text + 3 BeginningOfFrame(second frame) + 4 text + 5 text + 6 EndOfFrame(second frame) + 7 text + 8 text + 9 EndOfFrame(first frame) + ... + + The idea is to remove from [2] until [6], basically some trailing text and the second frame. + In this case frameAt(2) != frameAt(6), so the assertion in remove() needed an adjustement. + */ + QTextFrameFormat ffmt; + table->insert(0, "Hello World", charFormatIndex); + + QTextFrame *frame = table->insertFrame(1, 6, ffmt); + QTextFrame *childFrame = table->insertFrame(3, 5, ffmt); + + // used to give a failing assertion + table->remove(2, 5); + QVERIFY(true); +} + +void tst_QTextPieceTable::clearWithFrames() +{ + /* + The piecetable layout is: + + ... + 1 BeginningOfFrame(first frame) + 2 text + 3 EndOfFrame(first frame) + 4 BeginningOfFrame(second frame) + 5 text + 6 text + 7 EndOfFrame(second frame) + ... + + The idea is to remove from [1] until [7]. + */ + QTextFrameFormat ffmt; + table->insert(0, "Hello World", charFormatIndex); + + QTextFrame *firstFrame = table->insertFrame(1, 2, ffmt); + QTextFrame *secondFrame = table->insertFrame(4, 6, ffmt); + + const int start = firstFrame->firstPosition() - 1; + const int end = secondFrame->lastPosition(); + const int length = end - start + 1; + // used to give a failing assertion + table->remove(start, length); + QVERIFY(true); +} + +QTEST_MAIN(tst_QTextPieceTable) + + +#include "tst_qtextpiecetable.moc" +